1 /*- 2 * Copyright (c) 1994, 1995 The Regents of the University of California. 3 * Copyright (c) 1994, 1995 Jan-Simon Pendry. 4 * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc. 5 * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org> 6 * All rights reserved. 7 * 8 * This code is derived from software donated to Berkeley by 9 * Jan-Simon Pendry. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95 36 * $FreeBSD: src/sys/fs/unionfs/union_vfsops.c,v 1.89 2008/01/13 14:44:06 attilio Exp $ 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/lock.h> 43 #include <sys/malloc.h> 44 #include <sys/mount.h> 45 #include <sys/namei.h> 46 #include <sys/proc.h> 47 #include <sys/vnode.h> 48 #include <sys/stat.h> 49 #include <sys/sysctl.h> 50 #include <sys/module.h> 51 52 #include <fs/unionfs/unionfs.h> 53 54 MODULE(MODULE_CLASS_VFS, unionfs, "layerfs"); 55 56 MALLOC_DEFINE(M_UNIONFSMNT, "UNIONFS mount", "UNIONFS mount structure"); 57 58 struct vfsops unionfs_vfsops; 59 60 VFS_PROTOS(unionfs); 61 62 static struct sysctllog *unionfs_sysctl_log; 63 64 /* 65 * Mount unionfs layer. 66 */ 67 int 68 unionfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) 69 { 70 int error; 71 struct vnode *lowerrootvp; 72 struct vnode *upperrootvp; 73 struct unionfs_mount *ump; 74 int below; 75 uid_t uid; 76 gid_t gid; 77 u_short udir; 78 u_short ufile; 79 unionfs_copymode copymode; 80 unionfs_whitemode whitemode; 81 struct componentname fakecn; 82 struct nameidata nd, *ndp; 83 struct vattr va; 84 struct union_args *args = data; 85 kauth_cred_t cred; 86 size_t size; 87 size_t len; 88 const char *cp; 89 char *xp; 90 91 if (*data_len < sizeof *args) 92 return EINVAL; 93 94 UNIONFSDEBUG("unionfs_mount(mp = %p)\n", (void *)mp); 95 96 error = 0; 97 below = 0; 98 uid = 0; 99 gid = 0; 100 udir = 0; 101 ufile = 0; 102 copymode = UNIONFS_TRANSPARENT; /* default */ 103 whitemode = UNIONFS_WHITE_ALWAYS; 104 ndp = &nd; 105 cred = kauth_cred_get(); 106 107 if (mp->mnt_flag & MNT_ROOTFS) { 108 printf("union_mount: cannot union mount root filesystem\n"); 109 return (EOPNOTSUPP); 110 } 111 112 if (mp->mnt_flag & MNT_GETARGS) { 113 ump = MOUNTTOUNIONFSMOUNT(mp); 114 if (ump == NULL) 115 return EIO; 116 args->target = NULL; 117 args->mntflags = ump->um_op; 118 *data_len = sizeof *args; 119 return 0; 120 } 121 122 /* 123 * Update is a no operation. 124 */ 125 if (mp->mnt_flag & MNT_UPDATE) { 126 printf("union_mount: cannot update union mount\n"); 127 return (EOPNOTSUPP); 128 } 129 130 vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); 131 error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred); 132 if (!error) { 133 if (udir == 0) 134 udir = va.va_mode; 135 if (ufile == 0) 136 ufile = va.va_mode; 137 uid = va.va_uid; 138 gid = va.va_gid; 139 } 140 VOP_UNLOCK(mp->mnt_vnodecovered); 141 if (error) 142 return (error); 143 144 switch (args->mntflags & UNMNT_OPMASK) { 145 case UNMNT_ABOVE: 146 below = 0; 147 break; 148 149 case UNMNT_BELOW: 150 below = 1; 151 break; 152 153 case UNMNT_REPLACE: 154 default: 155 return EINVAL; 156 } 157 158 /* If copymode is UNIONFS_TRADITIONAL, uid/gid is mounted user. */ 159 if (copymode == UNIONFS_TRADITIONAL) { 160 uid = kauth_cred_getuid(cred); 161 gid = kauth_cred_getgid(cred); 162 } 163 164 UNIONFSDEBUG("unionfs_mount: uid=%d, gid=%d\n", uid, gid); 165 UNIONFSDEBUG("unionfs_mount: udir=0%03o, ufile=0%03o\n", udir, ufile); 166 UNIONFSDEBUG("unionfs_mount: copymode=%d\n", copymode); 167 168 /* 169 * Find upper node 170 */ 171 NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, args->target); 172 if ((error = namei(ndp))) 173 return (error); 174 175 /* get root vnodes */ 176 lowerrootvp = mp->mnt_vnodecovered; 177 upperrootvp = ndp->ni_vp; 178 179 vrele(ndp->ni_dvp); 180 ndp->ni_dvp = NULLVP; 181 182 /* create unionfs_mount */ 183 ump = (struct unionfs_mount *)malloc(sizeof(struct unionfs_mount), 184 M_UNIONFSMNT, M_WAITOK | M_ZERO); 185 186 /* 187 * Save reference 188 */ 189 if (below) { 190 VOP_UNLOCK(upperrootvp); 191 vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY); 192 ump->um_lowervp = upperrootvp; 193 ump->um_uppervp = lowerrootvp; 194 } else { 195 ump->um_lowervp = lowerrootvp; 196 ump->um_uppervp = upperrootvp; 197 } 198 ump->um_rootvp = NULLVP; 199 ump->um_uid = uid; 200 ump->um_gid = gid; 201 ump->um_udir = udir; 202 ump->um_ufile = ufile; 203 ump->um_copymode = copymode; 204 ump->um_whitemode = whitemode; 205 206 if ((lowerrootvp->v_mount->mnt_iflag & IMNT_MPSAFE) && 207 (upperrootvp->v_mount->mnt_flag & IMNT_MPSAFE)) 208 mp->mnt_iflag |= IMNT_MPSAFE; 209 mp->mnt_data = ump; 210 211 /* 212 * Copy upper layer's RDONLY flag. 213 */ 214 mp->mnt_flag |= ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY; 215 216 /* 217 * Check whiteout 218 */ 219 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 220 memset(&fakecn, 0, sizeof(fakecn)); 221 fakecn.cn_nameiop = LOOKUP; 222 error = VOP_WHITEOUT(ump->um_uppervp, &fakecn, LOOKUP); 223 if (error) { 224 if (below) { 225 VOP_UNLOCK(ump->um_uppervp); 226 vrele(upperrootvp); 227 } else 228 vput(ump->um_uppervp); 229 free(ump, M_UNIONFSMNT); 230 mp->mnt_data = NULL; 231 return (error); 232 } 233 } 234 235 /* 236 * Unlock the node 237 */ 238 VOP_UNLOCK(ump->um_uppervp); 239 240 ump->um_op = args->mntflags & UNMNT_OPMASK; 241 242 /* 243 * Get the unionfs root vnode. 244 */ 245 error = unionfs_nodeget(mp, ump->um_uppervp, ump->um_lowervp, 246 NULLVP, &(ump->um_rootvp), NULL); 247 vrele(upperrootvp); 248 if (error) { 249 free(ump, M_UNIONFSMNT); 250 mp->mnt_data = NULL; 251 return (error); 252 } 253 254 /* 255 * Check mnt_flag 256 */ 257 if ((ump->um_lowervp->v_mount->mnt_flag & MNT_LOCAL) && 258 (ump->um_uppervp->v_mount->mnt_flag & MNT_LOCAL)) 259 mp->mnt_flag |= MNT_LOCAL; 260 261 /* 262 * Get new fsid 263 */ 264 vfs_getnewfsid(mp); 265 266 error = set_statvfs_info(path, UIO_USERSPACE, NULL, UIO_USERSPACE, 267 mp->mnt_op->vfs_name, mp, curlwp); 268 if (error) { 269 unionfs_noderem(ump->um_rootvp); 270 free(ump, M_UNIONFSMNT); 271 mp->mnt_data = NULL; 272 return (error); 273 } 274 275 switch (ump->um_op) { 276 case UNMNT_ABOVE: 277 cp = "<above>:"; 278 break; 279 case UNMNT_BELOW: 280 cp = "<below>:"; 281 break; 282 default: 283 panic("union_mount: bad um_op"); 284 break; 285 } 286 len = strlen(cp); 287 memcpy(mp->mnt_stat.f_mntfromname, cp, len); 288 xp = mp->mnt_stat.f_mntfromname + len; 289 len = MNAMELEN - len; 290 (void) copyinstr(args->target, xp, len - 1, &size); 291 memset(xp + size, 0, len - size); 292 293 UNIONFSDEBUG("unionfs_mount: from %s, on %s\n", 294 mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 295 296 return (0); 297 } 298 299 /* 300 * Free reference to unionfs layer 301 */ 302 int 303 unionfs_unmount(struct mount *mp, int mntflags) 304 { 305 struct unionfs_mount *ump; 306 int error; 307 int freeing; 308 int flags; 309 310 UNIONFSDEBUG("unionfs_unmount: mp = %p\n", (void *)mp); 311 312 ump = MOUNTTOUNIONFSMOUNT(mp); 313 flags = 0; 314 315 if (mntflags & MNT_FORCE) 316 flags |= FORCECLOSE; 317 318 /* vflush (no need to call vrele) */ 319 for (freeing = 0; (error = vflush(mp, NULL, flags)) != 0;) { 320 struct vnode *vp; 321 int n; 322 323 /* count #vnodes held on mount list */ 324 n = 0; 325 TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) 326 n++; 327 328 /* if this is unchanged then stop */ 329 if (n == freeing) 330 break; 331 332 /* otherwise try once more time */ 333 freeing = n; 334 } 335 336 if (error) 337 return (error); 338 339 free(ump, M_UNIONFSMNT); 340 mp->mnt_data = NULL; 341 342 return (0); 343 } 344 345 int 346 unionfs_root(struct mount *mp, struct vnode **vpp) 347 { 348 struct unionfs_mount *ump; 349 struct vnode *vp; 350 351 ump = MOUNTTOUNIONFSMOUNT(mp); 352 vp = ump->um_rootvp; 353 354 UNIONFSDEBUG("unionfs_root: rootvp=%p locked=%x\n", 355 vp, VOP_ISLOCKED(vp)); 356 357 vref(vp); 358 vn_lock(vp, LK_EXCLUSIVE); 359 360 *vpp = vp; 361 362 return (0); 363 } 364 365 int 366 unionfs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg) 367 { 368 struct unionfs_mount *ump; 369 370 ump = MOUNTTOUNIONFSMOUNT(mp); 371 372 /* 373 * Writing is always performed to upper vnode. 374 */ 375 return (VFS_QUOTACTL(ump->um_uppervp->v_mount, cmd, uid, arg)); 376 } 377 378 int 379 unionfs_statvfs(struct mount *mp, struct statvfs *sbp) 380 { 381 struct unionfs_mount *ump; 382 int error; 383 uint64_t lbsize; 384 struct statvfs *sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK | M_ZERO); 385 386 ump = MOUNTTOUNIONFSMOUNT(mp); 387 388 UNIONFSDEBUG("unionfs_statvfs(mp = %p, lvp = %p, uvp = %p)\n", 389 (void *)mp, (void *)ump->um_lowervp, (void *)ump->um_uppervp); 390 391 error = VFS_STATVFS(ump->um_lowervp->v_mount, sbuf); 392 if (error) 393 goto done; 394 395 /* now copy across the "interesting" information and fake the rest */ 396 sbp->f_blocks = sbuf->f_blocks; 397 sbp->f_files = sbuf->f_files; 398 399 lbsize = sbuf->f_bsize; 400 401 error = VFS_STATVFS(ump->um_uppervp->v_mount, sbuf); 402 if (error) 403 goto done; 404 405 /* 406 * The FS type etc is copy from upper vfs. 407 * (write able vfs have priority) 408 */ 409 sbp->f_flag = sbuf->f_flag; 410 sbp->f_bsize = sbuf->f_bsize; 411 sbp->f_iosize = sbuf->f_iosize; 412 413 if (sbuf->f_bsize != lbsize) 414 sbp->f_blocks = ((off_t)sbp->f_blocks * lbsize) / sbuf->f_bsize; 415 416 sbp->f_blocks += sbuf->f_blocks; 417 sbp->f_bfree = sbuf->f_bfree; 418 sbp->f_bavail = sbuf->f_bavail; 419 sbp->f_files += sbuf->f_files; 420 sbp->f_ffree = sbuf->f_ffree; 421 422 done: 423 free(sbuf, M_TEMP); 424 return (error); 425 } 426 427 int 428 unionfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) 429 { 430 /* nothing to do */ 431 return (0); 432 } 433 434 int 435 unionfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) 436 { 437 return (EOPNOTSUPP); 438 } 439 440 int 441 unionfs_fhtovp(struct mount *mp, struct fid *fidp, struct vnode **vpp) 442 { 443 return (EOPNOTSUPP); 444 } 445 446 int 447 unionfs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, 448 int namespace, const char *attrname) 449 { 450 struct unionfs_mount *ump; 451 struct unionfs_node *unp; 452 453 ump = MOUNTTOUNIONFSMOUNT(mp); 454 unp = VTOUNIONFS(filename_vp); 455 456 if (unp->un_uppervp != NULLVP) { 457 return (VFS_EXTATTRCTL(ump->um_uppervp->v_mount, cmd, 458 unp->un_uppervp, namespace, attrname)); 459 } else { 460 return (VFS_EXTATTRCTL(ump->um_lowervp->v_mount, cmd, 461 unp->un_lowervp, namespace, attrname)); 462 } 463 } 464 465 /* 466 * Initialize 467 */ 468 void 469 unionfs_init(void) 470 { 471 UNIONFSDEBUG("unionfs_init\n"); /* printed during system boot */ 472 } 473 474 static int 475 unionfs_renamelock_enter(struct mount *mp) 476 { 477 struct unionfs_mount *um = MOUNTTOUNIONFSMOUNT(mp); 478 479 /* Lock just the upper fs, where the action happens. */ 480 return VFS_RENAMELOCK_ENTER(um->um_uppervp->v_mount); 481 } 482 483 static void 484 unionfs_renamelock_exit(struct mount *mp) 485 { 486 struct unionfs_mount *um = MOUNTTOUNIONFSMOUNT(mp); 487 488 VFS_RENAMELOCK_EXIT(um->um_uppervp->v_mount); 489 } 490 491 int 492 unionfs_start(struct mount *mp, int flags) 493 { 494 495 return (0); 496 } 497 498 void 499 unionfs_done(void) 500 { 501 502 /* Make sure to unset the readdir hook. */ 503 vn_union_readdir_hook = NULL; 504 } 505 506 extern const struct vnodeopv_desc unionfs_vnodeop_opv_desc; 507 508 const struct vnodeopv_desc * const unionfs_vnodeopv_descs[] = { 509 &unionfs_vnodeop_opv_desc, 510 NULL, 511 }; 512 513 struct vfsops unionfs_vfsops = { 514 MOUNT_UNION, 515 sizeof (struct unionfs_args), 516 unionfs_mount, 517 unionfs_start, 518 unionfs_unmount, 519 unionfs_root, 520 (void *)eopnotsupp, /* vfs_quotactl */ 521 unionfs_statvfs, 522 unionfs_sync, 523 unionfs_vget, 524 (void *)eopnotsupp, /* vfs_fhtovp */ 525 (void *)eopnotsupp, /* vfs_vptofh */ 526 unionfs_init, 527 NULL, /* vfs_reinit */ 528 unionfs_done, 529 NULL, /* vfs_mountroot */ 530 (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp, 531 vfs_stdextattrctl, 532 (void *)eopnotsupp, /* vfs_suspendctl */ 533 unionfs_renamelock_enter, 534 unionfs_renamelock_exit, 535 (void *)eopnotsupp, 536 unionfs_vnodeopv_descs, 537 0, /* vfs_refcount */ 538 { NULL, NULL }, 539 }; 540 541 static int 542 unionfs_modcmd(modcmd_t cmd, void *arg) 543 { 544 int error; 545 546 switch (cmd) { 547 case MODULE_CMD_INIT: 548 error = vfs_attach(&unionfs_vfsops); 549 if (error != 0) 550 break; 551 sysctl_createv(&unionfs_sysctl_log, 0, NULL, NULL, 552 CTLFLAG_PERMANENT, 553 CTLTYPE_NODE, "vfs", NULL, 554 NULL, 0, NULL, 0, 555 CTL_VFS, CTL_EOL); 556 sysctl_createv(&unionfs_sysctl_log, 0, NULL, NULL, 557 CTLFLAG_PERMANENT, 558 CTLTYPE_NODE, "union", 559 SYSCTL_DESCR("Union file system"), 560 NULL, 0, NULL, 0, 561 CTL_VFS, 15, CTL_EOL); 562 /* 563 * XXX the "15" above could be dynamic, thereby eliminating 564 * one more instance of the "number to vfs" mapping problem, 565 * but "15" is the order as taken from sys/mount.h 566 */ 567 break; 568 case MODULE_CMD_FINI: 569 error = vfs_detach(&unionfs_vfsops); 570 if (error != 0) 571 break; 572 sysctl_teardown(&unionfs_sysctl_log); 573 break; 574 default: 575 error = ENOTTY; 576 break; 577 } 578 579 return (error); 580 } 581