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 pathbuf *pb; 82 struct componentname fakecn; 83 struct nameidata nd, *ndp; 84 struct vattr va; 85 struct union_args *args = data; 86 kauth_cred_t cred; 87 size_t size; 88 size_t len; 89 const char *cp; 90 char *xp; 91 92 if (*data_len < sizeof *args) 93 return EINVAL; 94 95 UNIONFSDEBUG("unionfs_mount(mp = %p)\n", (void *)mp); 96 97 error = 0; 98 below = 0; 99 uid = 0; 100 gid = 0; 101 udir = 0; 102 ufile = 0; 103 copymode = UNIONFS_TRANSPARENT; /* default */ 104 whitemode = UNIONFS_WHITE_ALWAYS; 105 ndp = &nd; 106 cred = kauth_cred_get(); 107 108 if (mp->mnt_flag & MNT_ROOTFS) { 109 printf("union_mount: cannot union mount root filesystem\n"); 110 return (EOPNOTSUPP); 111 } 112 113 if (mp->mnt_flag & MNT_GETARGS) { 114 ump = MOUNTTOUNIONFSMOUNT(mp); 115 if (ump == NULL) 116 return EIO; 117 args->target = NULL; 118 args->mntflags = ump->um_op; 119 *data_len = sizeof *args; 120 return 0; 121 } 122 123 /* 124 * Update is a no operation. 125 */ 126 if (mp->mnt_flag & MNT_UPDATE) { 127 printf("union_mount: cannot update union mount\n"); 128 return (EOPNOTSUPP); 129 } 130 131 vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); 132 error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred); 133 if (!error) { 134 if (udir == 0) 135 udir = va.va_mode; 136 if (ufile == 0) 137 ufile = va.va_mode; 138 uid = va.va_uid; 139 gid = va.va_gid; 140 } 141 VOP_UNLOCK(mp->mnt_vnodecovered); 142 if (error) 143 return (error); 144 145 switch (args->mntflags & UNMNT_OPMASK) { 146 case UNMNT_ABOVE: 147 below = 0; 148 break; 149 150 case UNMNT_BELOW: 151 below = 1; 152 break; 153 154 case UNMNT_REPLACE: 155 default: 156 return EINVAL; 157 } 158 159 /* If copymode is UNIONFS_TRADITIONAL, uid/gid is mounted user. */ 160 if (copymode == UNIONFS_TRADITIONAL) { 161 uid = kauth_cred_getuid(cred); 162 gid = kauth_cred_getgid(cred); 163 } 164 165 UNIONFSDEBUG("unionfs_mount: uid=%d, gid=%d\n", uid, gid); 166 UNIONFSDEBUG("unionfs_mount: udir=0%03o, ufile=0%03o\n", udir, ufile); 167 UNIONFSDEBUG("unionfs_mount: copymode=%d\n", copymode); 168 169 /* 170 * Find upper node 171 */ 172 error = pathbuf_copyin(args->target, &pb); 173 if (error) { 174 return error; 175 } 176 NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, pb); 177 if ((error = namei(ndp))) { 178 pathbuf_destroy(pb); 179 return error; 180 } 181 182 /* get root vnodes */ 183 lowerrootvp = mp->mnt_vnodecovered; 184 upperrootvp = ndp->ni_vp; 185 186 vrele(ndp->ni_dvp); 187 ndp->ni_dvp = NULLVP; 188 pathbuf_destroy(pb); 189 190 /* create unionfs_mount */ 191 ump = (struct unionfs_mount *)malloc(sizeof(struct unionfs_mount), 192 M_UNIONFSMNT, M_WAITOK | M_ZERO); 193 194 /* 195 * Save reference 196 */ 197 if (below) { 198 VOP_UNLOCK(upperrootvp); 199 vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY); 200 ump->um_lowervp = upperrootvp; 201 ump->um_uppervp = lowerrootvp; 202 } else { 203 ump->um_lowervp = lowerrootvp; 204 ump->um_uppervp = upperrootvp; 205 } 206 ump->um_rootvp = NULLVP; 207 ump->um_uid = uid; 208 ump->um_gid = gid; 209 ump->um_udir = udir; 210 ump->um_ufile = ufile; 211 ump->um_copymode = copymode; 212 ump->um_whitemode = whitemode; 213 214 if ((lowerrootvp->v_mount->mnt_iflag & IMNT_MPSAFE) && 215 (upperrootvp->v_mount->mnt_flag & IMNT_MPSAFE)) 216 mp->mnt_iflag |= IMNT_MPSAFE; 217 mp->mnt_data = ump; 218 219 /* 220 * Copy upper layer's RDONLY flag. 221 */ 222 mp->mnt_flag |= ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY; 223 224 /* 225 * Check whiteout 226 */ 227 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 228 memset(&fakecn, 0, sizeof(fakecn)); 229 fakecn.cn_nameiop = LOOKUP; 230 error = VOP_WHITEOUT(ump->um_uppervp, &fakecn, LOOKUP); 231 if (error) { 232 if (below) { 233 VOP_UNLOCK(ump->um_uppervp); 234 vrele(upperrootvp); 235 } else 236 vput(ump->um_uppervp); 237 free(ump, M_UNIONFSMNT); 238 mp->mnt_data = NULL; 239 return (error); 240 } 241 } 242 243 /* 244 * Unlock the node 245 */ 246 VOP_UNLOCK(ump->um_uppervp); 247 248 ump->um_op = args->mntflags & UNMNT_OPMASK; 249 250 /* 251 * Get the unionfs root vnode. 252 */ 253 error = unionfs_nodeget(mp, ump->um_uppervp, ump->um_lowervp, 254 NULLVP, &(ump->um_rootvp), NULL); 255 vrele(upperrootvp); 256 if (error) { 257 free(ump, M_UNIONFSMNT); 258 mp->mnt_data = NULL; 259 return (error); 260 } 261 262 /* 263 * Check mnt_flag 264 */ 265 if ((ump->um_lowervp->v_mount->mnt_flag & MNT_LOCAL) && 266 (ump->um_uppervp->v_mount->mnt_flag & MNT_LOCAL)) 267 mp->mnt_flag |= MNT_LOCAL; 268 269 /* 270 * Get new fsid 271 */ 272 vfs_getnewfsid(mp); 273 274 error = set_statvfs_info(path, UIO_USERSPACE, NULL, UIO_USERSPACE, 275 mp->mnt_op->vfs_name, mp, curlwp); 276 if (error) { 277 unionfs_noderem(ump->um_rootvp); 278 free(ump, M_UNIONFSMNT); 279 mp->mnt_data = NULL; 280 return (error); 281 } 282 283 switch (ump->um_op) { 284 case UNMNT_ABOVE: 285 cp = "<above>:"; 286 break; 287 case UNMNT_BELOW: 288 cp = "<below>:"; 289 break; 290 default: 291 panic("union_mount: bad um_op"); 292 break; 293 } 294 len = strlen(cp); 295 memcpy(mp->mnt_stat.f_mntfromname, cp, len); 296 xp = mp->mnt_stat.f_mntfromname + len; 297 len = MNAMELEN - len; 298 (void) copyinstr(args->target, xp, len - 1, &size); 299 memset(xp + size, 0, len - size); 300 301 UNIONFSDEBUG("unionfs_mount: from %s, on %s\n", 302 mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 303 304 return (0); 305 } 306 307 /* 308 * Free reference to unionfs layer 309 */ 310 int 311 unionfs_unmount(struct mount *mp, int mntflags) 312 { 313 struct unionfs_mount *ump; 314 int error; 315 int freeing; 316 int flags; 317 318 UNIONFSDEBUG("unionfs_unmount: mp = %p\n", (void *)mp); 319 320 ump = MOUNTTOUNIONFSMOUNT(mp); 321 flags = 0; 322 323 if (mntflags & MNT_FORCE) 324 flags |= FORCECLOSE; 325 326 /* vflush (no need to call vrele) */ 327 for (freeing = 0; (error = vflush(mp, NULL, flags)) != 0;) { 328 struct vnode *vp; 329 int n; 330 331 /* count #vnodes held on mount list */ 332 n = 0; 333 TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) 334 n++; 335 336 /* if this is unchanged then stop */ 337 if (n == freeing) 338 break; 339 340 /* otherwise try once more time */ 341 freeing = n; 342 } 343 344 if (error) 345 return (error); 346 347 free(ump, M_UNIONFSMNT); 348 mp->mnt_data = NULL; 349 350 return (0); 351 } 352 353 int 354 unionfs_root(struct mount *mp, struct vnode **vpp) 355 { 356 struct unionfs_mount *ump; 357 struct vnode *vp; 358 359 ump = MOUNTTOUNIONFSMOUNT(mp); 360 vp = ump->um_rootvp; 361 362 UNIONFSDEBUG("unionfs_root: rootvp=%p locked=%x\n", 363 vp, VOP_ISLOCKED(vp)); 364 365 vref(vp); 366 vn_lock(vp, LK_EXCLUSIVE); 367 368 *vpp = vp; 369 370 return (0); 371 } 372 373 int 374 unionfs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg) 375 { 376 struct unionfs_mount *ump; 377 378 ump = MOUNTTOUNIONFSMOUNT(mp); 379 380 /* 381 * Writing is always performed to upper vnode. 382 */ 383 return (VFS_QUOTACTL(ump->um_uppervp->v_mount, cmd, uid, arg)); 384 } 385 386 int 387 unionfs_statvfs(struct mount *mp, struct statvfs *sbp) 388 { 389 struct unionfs_mount *ump; 390 int error; 391 uint64_t lbsize; 392 struct statvfs *sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK | M_ZERO); 393 394 ump = MOUNTTOUNIONFSMOUNT(mp); 395 396 UNIONFSDEBUG("unionfs_statvfs(mp = %p, lvp = %p, uvp = %p)\n", 397 (void *)mp, (void *)ump->um_lowervp, (void *)ump->um_uppervp); 398 399 error = VFS_STATVFS(ump->um_lowervp->v_mount, sbuf); 400 if (error) 401 goto done; 402 403 /* now copy across the "interesting" information and fake the rest */ 404 sbp->f_blocks = sbuf->f_blocks; 405 sbp->f_files = sbuf->f_files; 406 407 lbsize = sbuf->f_bsize; 408 409 error = VFS_STATVFS(ump->um_uppervp->v_mount, sbuf); 410 if (error) 411 goto done; 412 413 /* 414 * The FS type etc is copy from upper vfs. 415 * (write able vfs have priority) 416 */ 417 sbp->f_flag = sbuf->f_flag; 418 sbp->f_bsize = sbuf->f_bsize; 419 sbp->f_iosize = sbuf->f_iosize; 420 421 if (sbuf->f_bsize != lbsize) 422 sbp->f_blocks = ((off_t)sbp->f_blocks * lbsize) / sbuf->f_bsize; 423 424 sbp->f_blocks += sbuf->f_blocks; 425 sbp->f_bfree = sbuf->f_bfree; 426 sbp->f_bavail = sbuf->f_bavail; 427 sbp->f_files += sbuf->f_files; 428 sbp->f_ffree = sbuf->f_ffree; 429 430 done: 431 free(sbuf, M_TEMP); 432 return (error); 433 } 434 435 int 436 unionfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) 437 { 438 /* nothing to do */ 439 return (0); 440 } 441 442 int 443 unionfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) 444 { 445 return (EOPNOTSUPP); 446 } 447 448 int 449 unionfs_fhtovp(struct mount *mp, struct fid *fidp, struct vnode **vpp) 450 { 451 return (EOPNOTSUPP); 452 } 453 454 int 455 unionfs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, 456 int namespace, const char *attrname) 457 { 458 struct unionfs_mount *ump; 459 struct unionfs_node *unp; 460 461 ump = MOUNTTOUNIONFSMOUNT(mp); 462 unp = VTOUNIONFS(filename_vp); 463 464 if (unp->un_uppervp != NULLVP) { 465 return (VFS_EXTATTRCTL(ump->um_uppervp->v_mount, cmd, 466 unp->un_uppervp, namespace, attrname)); 467 } else { 468 return (VFS_EXTATTRCTL(ump->um_lowervp->v_mount, cmd, 469 unp->un_lowervp, namespace, attrname)); 470 } 471 } 472 473 /* 474 * Initialize 475 */ 476 void 477 unionfs_init(void) 478 { 479 UNIONFSDEBUG("unionfs_init\n"); /* printed during system boot */ 480 } 481 482 static int 483 unionfs_renamelock_enter(struct mount *mp) 484 { 485 struct unionfs_mount *um = MOUNTTOUNIONFSMOUNT(mp); 486 487 /* Lock just the upper fs, where the action happens. */ 488 return VFS_RENAMELOCK_ENTER(um->um_uppervp->v_mount); 489 } 490 491 static void 492 unionfs_renamelock_exit(struct mount *mp) 493 { 494 struct unionfs_mount *um = MOUNTTOUNIONFSMOUNT(mp); 495 496 VFS_RENAMELOCK_EXIT(um->um_uppervp->v_mount); 497 } 498 499 int 500 unionfs_start(struct mount *mp, int flags) 501 { 502 503 return (0); 504 } 505 506 void 507 unionfs_done(void) 508 { 509 510 /* Make sure to unset the readdir hook. */ 511 vn_union_readdir_hook = NULL; 512 } 513 514 extern const struct vnodeopv_desc unionfs_vnodeop_opv_desc; 515 516 const struct vnodeopv_desc * const unionfs_vnodeopv_descs[] = { 517 &unionfs_vnodeop_opv_desc, 518 NULL, 519 }; 520 521 struct vfsops unionfs_vfsops = { 522 MOUNT_UNION, 523 sizeof (struct unionfs_args), 524 unionfs_mount, 525 unionfs_start, 526 unionfs_unmount, 527 unionfs_root, 528 (void *)eopnotsupp, /* vfs_quotactl */ 529 unionfs_statvfs, 530 unionfs_sync, 531 unionfs_vget, 532 (void *)eopnotsupp, /* vfs_fhtovp */ 533 (void *)eopnotsupp, /* vfs_vptofh */ 534 unionfs_init, 535 NULL, /* vfs_reinit */ 536 unionfs_done, 537 NULL, /* vfs_mountroot */ 538 (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp, 539 vfs_stdextattrctl, 540 (void *)eopnotsupp, /* vfs_suspendctl */ 541 unionfs_renamelock_enter, 542 unionfs_renamelock_exit, 543 (void *)eopnotsupp, 544 unionfs_vnodeopv_descs, 545 0, /* vfs_refcount */ 546 { NULL, NULL }, 547 }; 548 549 static int 550 unionfs_modcmd(modcmd_t cmd, void *arg) 551 { 552 int error; 553 554 switch (cmd) { 555 case MODULE_CMD_INIT: 556 error = vfs_attach(&unionfs_vfsops); 557 if (error != 0) 558 break; 559 sysctl_createv(&unionfs_sysctl_log, 0, NULL, NULL, 560 CTLFLAG_PERMANENT, 561 CTLTYPE_NODE, "vfs", NULL, 562 NULL, 0, NULL, 0, 563 CTL_VFS, CTL_EOL); 564 sysctl_createv(&unionfs_sysctl_log, 0, NULL, NULL, 565 CTLFLAG_PERMANENT, 566 CTLTYPE_NODE, "union", 567 SYSCTL_DESCR("Union file system"), 568 NULL, 0, NULL, 0, 569 CTL_VFS, 15, CTL_EOL); 570 /* 571 * XXX the "15" above could be dynamic, thereby eliminating 572 * one more instance of the "number to vfs" mapping problem, 573 * but "15" is the order as taken from sys/mount.h 574 */ 575 break; 576 case MODULE_CMD_FINI: 577 error = vfs_detach(&unionfs_vfsops); 578 if (error != 0) 579 break; 580 sysctl_teardown(&unionfs_sysctl_log); 581 break; 582 default: 583 error = ENOTTY; 584 break; 585 } 586 587 return (error); 588 } 589