1 /* 2 * Copyright (c) 1994, 1995 The Regents of the University of California. 3 * Copyright (c) 1994, 1995 Jan-Simon Pendry. 4 * All rights reserved. 5 * 6 * This code is derived from software donated to Berkeley by 7 * Jan-Simon Pendry. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95 38 * $FreeBSD$ 39 */ 40 41 /* 42 * Union Layer 43 */ 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/kernel.h> 48 #include <sys/lock.h> 49 #include <sys/mutex.h> 50 #include <sys/proc.h> 51 #include <sys/vnode.h> 52 #include <sys/mount.h> 53 #include <sys/namei.h> 54 #include <sys/malloc.h> 55 #include <sys/filedesc.h> 56 #include <fs/unionfs/union.h> 57 58 static MALLOC_DEFINE(M_UNIONFSMNT, "UNION mount", "UNION mount structure"); 59 60 extern int union_init(struct vfsconf *); 61 static int union_mount(struct mount *mp, struct nameidata *ndp, 62 struct thread *td); 63 static int union_root(struct mount *mp, struct vnode **vpp); 64 static int union_statfs(struct mount *mp, struct statfs *sbp, 65 struct thread *td); 66 static int union_unmount(struct mount *mp, int mntflags, 67 struct thread *td); 68 69 /* 70 * Mount union filesystem 71 */ 72 static int 73 union_mount(mp, ndp, td) 74 struct mount *mp; 75 struct nameidata *ndp; 76 struct thread *td; 77 { 78 int error = 0; 79 struct vfsoptlist *opts; 80 struct vnode *lowerrootvp = NULLVP; 81 struct vnode *upperrootvp = NULLVP; 82 struct union_mount *um = 0; 83 struct ucred *cred = 0; 84 char *cp = 0, *target; 85 int op; 86 int len; 87 u_int size; 88 89 UDEBUG(("union_mount(mp = %p)\n", (void *)mp)); 90 91 opts = mp->mnt_optnew; 92 /* 93 * Disable clustered write, otherwise system becomes unstable. 94 */ 95 mp->mnt_flag |= MNT_NOCLUSTERW; 96 97 /* 98 * Update is a no-op 99 */ 100 if (mp->mnt_flag & MNT_UPDATE) 101 /* 102 * Need to provide. 103 * 1. a way to convert between rdonly and rdwr mounts. 104 * 2. support for nfs exports. 105 */ 106 return (EOPNOTSUPP); 107 108 /* 109 * Get arguments. 110 */ 111 error = vfs_getopt(opts, "target", (void **)&target, &len); 112 if (error || target[len - 1] != '\0') 113 return (EINVAL); 114 115 op = 0; 116 if (vfs_getopt(opts, "below", NULL, NULL) == 0) 117 op = UNMNT_BELOW; 118 if (vfs_getopt(opts, "replace", NULL, NULL) == 0) { 119 /* These options are mutually exclusive. */ 120 if (op) 121 return (EINVAL); 122 op = UNMNT_REPLACE; 123 } 124 /* 125 * UNMNT_ABOVE is the default. 126 */ 127 if (op == 0) 128 op = UNMNT_ABOVE; 129 130 /* 131 * Obtain lower vnode. Vnode is stored in mp->mnt_vnodecovered. 132 * We need to reference it but not lock it. 133 */ 134 135 lowerrootvp = mp->mnt_vnodecovered; 136 VREF(lowerrootvp); 137 138 #if 0 139 /* 140 * Unlock lower node to avoid deadlock. 141 */ 142 if (lowerrootvp->v_op == union_vnodeop_p) 143 VOP_UNLOCK(lowerrootvp, 0, td); 144 #endif 145 146 /* 147 * Obtain upper vnode by calling namei() on the path. The 148 * upperrootvp will be turned referenced but not locked. 149 */ 150 NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT, UIO_SYSSPACE, target, td); 151 152 error = namei(ndp); 153 154 #if 0 155 if (lowerrootvp->v_op == union_vnodeop_p) 156 vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY, td); 157 #endif 158 if (error) 159 goto bad; 160 161 NDFREE(ndp, NDF_ONLY_PNBUF); 162 upperrootvp = ndp->ni_vp; 163 vrele(ndp->ni_dvp); 164 ndp->ni_dvp = NULL; 165 166 UDEBUG(("mount_root UPPERVP %p locked = %d\n", upperrootvp, 167 VOP_ISLOCKED(upperrootvp, NULL))); 168 169 /* 170 * Check multi union mount to avoid `lock myself again' panic. 171 * Also require that it be a directory. 172 */ 173 if (upperrootvp == VTOUNION(lowerrootvp)->un_uppervp) { 174 #ifdef DIAGNOSTIC 175 printf("union_mount: multi union mount?\n"); 176 #endif 177 error = EDEADLK; 178 goto bad; 179 } 180 181 if (upperrootvp->v_type != VDIR) { 182 error = EINVAL; 183 goto bad; 184 } 185 186 /* 187 * Allocate our union_mount structure and populate the fields. 188 * The vnode references are stored in the union_mount as held, 189 * unlocked references. Depending on the _BELOW flag, the 190 * filesystems are viewed in a different order. In effect this 191 * is the same as providing a mount-under option to the mount 192 * syscall. 193 */ 194 195 um = (struct union_mount *) malloc(sizeof(struct union_mount), 196 M_UNIONFSMNT, M_WAITOK | M_ZERO); 197 198 um->um_op = op; 199 200 switch (um->um_op) { 201 case UNMNT_ABOVE: 202 um->um_lowervp = lowerrootvp; 203 um->um_uppervp = upperrootvp; 204 upperrootvp = NULL; 205 lowerrootvp = NULL; 206 break; 207 208 case UNMNT_BELOW: 209 um->um_lowervp = upperrootvp; 210 um->um_uppervp = lowerrootvp; 211 upperrootvp = NULL; 212 lowerrootvp = NULL; 213 break; 214 215 case UNMNT_REPLACE: 216 vrele(lowerrootvp); 217 lowerrootvp = NULL; 218 um->um_uppervp = upperrootvp; 219 um->um_lowervp = lowerrootvp; 220 upperrootvp = NULL; 221 break; 222 223 default: 224 error = EINVAL; 225 goto bad; 226 } 227 228 /* 229 * Unless the mount is readonly, ensure that the top layer 230 * supports whiteout operations 231 */ 232 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 233 error = VOP_WHITEOUT(um->um_uppervp, NULL, LOOKUP); 234 if (error) 235 goto bad; 236 } 237 238 um->um_cred = crhold(td->td_ucred); 239 FILEDESC_LOCK(td->td_proc->p_fd); 240 um->um_cmode = UN_DIRMODE &~ td->td_proc->p_fd->fd_cmask; 241 FILEDESC_UNLOCK(td->td_proc->p_fd); 242 243 /* 244 * Depending on what you think the MNT_LOCAL flag might mean, 245 * you may want the && to be || on the conditional below. 246 * At the moment it has been defined that the filesystem is 247 * only local if it is all local, ie the MNT_LOCAL flag implies 248 * that the entire namespace is local. If you think the MNT_LOCAL 249 * flag implies that some of the files might be stored locally 250 * then you will want to change the conditional. 251 */ 252 if (um->um_op == UNMNT_ABOVE) { 253 if (((um->um_lowervp == NULLVP) || 254 (um->um_lowervp->v_mount->mnt_flag & MNT_LOCAL)) && 255 (um->um_uppervp->v_mount->mnt_flag & MNT_LOCAL)) 256 mp->mnt_flag |= MNT_LOCAL; 257 } 258 259 /* 260 * Copy in the upper layer's RDONLY flag. This is for the benefit 261 * of lookup() which explicitly checks the flag, rather than asking 262 * the filesystem for its own opinion. This means, that an update 263 * mount of the underlying filesystem to go from rdonly to rdwr 264 * will leave the unioned view as read-only. 265 */ 266 mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY); 267 268 mp->mnt_data = (qaddr_t) um; 269 vfs_getnewfsid(mp); 270 271 switch (um->um_op) { 272 case UNMNT_ABOVE: 273 cp = "<above>:"; 274 break; 275 case UNMNT_BELOW: 276 cp = "<below>:"; 277 break; 278 case UNMNT_REPLACE: 279 cp = ""; 280 break; 281 } 282 len = strlen(cp); 283 bcopy(cp, mp->mnt_stat.f_mntfromname, len); 284 285 cp = mp->mnt_stat.f_mntfromname + len; 286 len = MNAMELEN - len; 287 288 (void) copystr(target, cp, len - 1, &size); 289 bzero(cp + size, len - size); 290 291 (void)union_statfs(mp, &mp->mnt_stat, td); 292 293 UDEBUG(("union_mount: from %s, on %s\n", 294 mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname)); 295 return (0); 296 297 bad: 298 if (um) { 299 if (um->um_uppervp) 300 vrele(um->um_uppervp); 301 if (um->um_lowervp) 302 vrele(um->um_lowervp); 303 /* XXX other fields */ 304 free(um, M_UNIONFSMNT); 305 } 306 if (cred) 307 crfree(cred); 308 if (upperrootvp) 309 vrele(upperrootvp); 310 if (lowerrootvp) 311 vrele(lowerrootvp); 312 return (error); 313 } 314 315 /* 316 * Free reference to union layer 317 */ 318 static int 319 union_unmount(mp, mntflags, td) 320 struct mount *mp; 321 int mntflags; 322 struct thread *td; 323 { 324 struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 325 int error; 326 int freeing; 327 int flags = 0; 328 329 UDEBUG(("union_unmount(mp = %p)\n", (void *)mp)); 330 331 if (mntflags & MNT_FORCE) 332 flags |= FORCECLOSE; 333 334 /* 335 * Keep flushing vnodes from the mount list. 336 * This is needed because of the un_pvp held 337 * reference to the parent vnode. 338 * If more vnodes have been freed on a given pass, 339 * the try again. The loop will iterate at most 340 * (d) times, where (d) is the maximum tree depth 341 * in the filesystem. 342 */ 343 for (freeing = 0; (error = vflush(mp, 0, flags)) != 0;) { 344 struct vnode *vp; 345 int n; 346 347 /* count #vnodes held on mount list */ 348 mtx_lock(&mntvnode_mtx); 349 n = 0; 350 TAILQ_FOREACH(vp, &mp->mnt_nvnodelist, v_nmntvnodes) 351 n++; 352 mtx_unlock(&mntvnode_mtx); 353 354 /* if this is unchanged then stop */ 355 if (n == freeing) 356 break; 357 358 /* otherwise try once more time */ 359 freeing = n; 360 } 361 362 /* If the most recent vflush failed, the filesystem is still busy. */ 363 if (error) 364 return (error); 365 366 /* 367 * Discard references to upper and lower target vnodes. 368 */ 369 if (um->um_lowervp) 370 vrele(um->um_lowervp); 371 vrele(um->um_uppervp); 372 crfree(um->um_cred); 373 /* 374 * Finally, throw away the union_mount structure 375 */ 376 free(mp->mnt_data, M_UNIONFSMNT); /* XXX */ 377 mp->mnt_data = 0; 378 return (0); 379 } 380 381 static int 382 union_root(mp, vpp) 383 struct mount *mp; 384 struct vnode **vpp; 385 { 386 struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 387 int error; 388 389 /* 390 * Supply an unlocked reference to um_uppervp and to um_lowervp. It 391 * is possible for um_uppervp to be locked without the associated 392 * root union_node being locked. We let union_allocvp() deal with 393 * it. 394 */ 395 UDEBUG(("union_root UPPERVP %p locked = %d\n", um->um_uppervp, 396 VOP_ISLOCKED(um->um_uppervp, NULL))); 397 398 VREF(um->um_uppervp); 399 if (um->um_lowervp) 400 VREF(um->um_lowervp); 401 402 error = union_allocvp(vpp, mp, NULLVP, NULLVP, NULL, 403 um->um_uppervp, um->um_lowervp, 1); 404 UDEBUG(("error %d\n", error)); 405 UDEBUG(("union_root2 UPPERVP %p locked = %d\n", um->um_uppervp, 406 VOP_ISLOCKED(um->um_uppervp, NULL))); 407 408 return (error); 409 } 410 411 static int 412 union_statfs(mp, sbp, td) 413 struct mount *mp; 414 struct statfs *sbp; 415 struct thread *td; 416 { 417 int error; 418 struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 419 struct statfs mstat; 420 int lbsize; 421 422 UDEBUG(("union_statfs(mp = %p, lvp = %p, uvp = %p)\n", 423 (void *)mp, (void *)um->um_lowervp, (void *)um->um_uppervp)); 424 425 bzero(&mstat, sizeof(mstat)); 426 427 if (um->um_lowervp) { 428 error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, td); 429 if (error) 430 return (error); 431 } 432 433 /* now copy across the "interesting" information and fake the rest */ 434 #if 0 435 sbp->f_type = mstat.f_type; 436 sbp->f_flags = mstat.f_flags; 437 sbp->f_bsize = mstat.f_bsize; 438 sbp->f_iosize = mstat.f_iosize; 439 #endif 440 lbsize = mstat.f_bsize; 441 sbp->f_blocks = mstat.f_blocks; 442 sbp->f_bfree = mstat.f_bfree; 443 sbp->f_bavail = mstat.f_bavail; 444 sbp->f_files = mstat.f_files; 445 sbp->f_ffree = mstat.f_ffree; 446 447 error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, td); 448 if (error) 449 return (error); 450 451 sbp->f_flags = mstat.f_flags; 452 sbp->f_bsize = mstat.f_bsize; 453 sbp->f_iosize = mstat.f_iosize; 454 455 /* 456 * if the lower and upper blocksizes differ, then frig the 457 * block counts so that the sizes reported by df make some 458 * kind of sense. none of this makes sense though. 459 */ 460 461 if (mstat.f_bsize != lbsize) 462 sbp->f_blocks = ((off_t) sbp->f_blocks * lbsize) / mstat.f_bsize; 463 464 /* 465 * The "total" fields count total resources in all layers, 466 * the "free" fields count only those resources which are 467 * free in the upper layer (since only the upper layer 468 * is writeable). 469 */ 470 sbp->f_blocks += mstat.f_blocks; 471 sbp->f_bfree = mstat.f_bfree; 472 sbp->f_bavail = mstat.f_bavail; 473 sbp->f_files += mstat.f_files; 474 sbp->f_ffree = mstat.f_ffree; 475 476 if (sbp != &mp->mnt_stat) { 477 sbp->f_type = mp->mnt_vfc->vfc_typenum; 478 bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 479 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 480 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 481 } 482 return (0); 483 } 484 485 static struct vfsops union_vfsops = { 486 NULL, 487 vfs_stdstart, /* underlying start already done */ 488 union_unmount, 489 union_root, 490 vfs_stdquotactl, 491 union_statfs, 492 vfs_stdsync, /* XXX assumes no cached data on union level */ 493 vfs_stdvget, 494 vfs_stdfhtovp, 495 vfs_stdcheckexp, 496 vfs_stdvptofh, 497 union_init, 498 vfs_stduninit, 499 vfs_stdextattrctl, 500 union_mount, 501 }; 502 503 VFS_SET(union_vfsops, unionfs, VFCF_LOOPBACK); 504