union_vnops.c revision 50477
1/* 2 * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry. 3 * Copyright (c) 1992, 1993, 1994, 1995 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed 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_vnops.c 8.32 (Berkeley) 6/23/95 38 * $FreeBSD: head/sys/fs/unionfs/union_vnops.c 50477 1999-08-28 01:08:13Z peter $ 39 */ 40 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/proc.h> 44#include <sys/fcntl.h> 45#include <sys/stat.h> 46#include <sys/kernel.h> 47#include <sys/vnode.h> 48#include <sys/mount.h> 49#include <sys/namei.h> 50#include <sys/malloc.h> 51#include <sys/buf.h> 52#include <sys/lock.h> 53#include <miscfs/union/union.h> 54 55#define FIXUP(un, p) { \ 56 if (((un)->un_flags & UN_ULOCK) == 0) { \ 57 union_fixup(un, p); \ 58 } \ 59} 60 61static int union_abortop __P((struct vop_abortop_args *ap)); 62static int union_access __P((struct vop_access_args *ap)); 63static int union_advlock __P((struct vop_advlock_args *ap)); 64static int union_bmap __P((struct vop_bmap_args *ap)); 65static int union_close __P((struct vop_close_args *ap)); 66static int union_create __P((struct vop_create_args *ap)); 67static void union_fixup __P((struct union_node *un, struct proc *p)); 68static int union_fsync __P((struct vop_fsync_args *ap)); 69static int union_getattr __P((struct vop_getattr_args *ap)); 70static int union_inactive __P((struct vop_inactive_args *ap)); 71static int union_ioctl __P((struct vop_ioctl_args *ap)); 72static int union_islocked __P((struct vop_islocked_args *ap)); 73static int union_lease __P((struct vop_lease_args *ap)); 74static int union_link __P((struct vop_link_args *ap)); 75static int union_lock __P((struct vop_lock_args *ap)); 76static int union_lookup __P((struct vop_lookup_args *ap)); 77static int union_lookup1 __P((struct vnode *udvp, struct vnode **dvpp, 78 struct vnode **vpp, 79 struct componentname *cnp)); 80static int union_mkdir __P((struct vop_mkdir_args *ap)); 81static int union_mknod __P((struct vop_mknod_args *ap)); 82static int union_mmap __P((struct vop_mmap_args *ap)); 83static int union_open __P((struct vop_open_args *ap)); 84static int union_pathconf __P((struct vop_pathconf_args *ap)); 85static int union_print __P((struct vop_print_args *ap)); 86static int union_read __P((struct vop_read_args *ap)); 87static int union_readdir __P((struct vop_readdir_args *ap)); 88static int union_readlink __P((struct vop_readlink_args *ap)); 89static int union_reclaim __P((struct vop_reclaim_args *ap)); 90static int union_remove __P((struct vop_remove_args *ap)); 91static int union_rename __P((struct vop_rename_args *ap)); 92static int union_revoke __P((struct vop_revoke_args *ap)); 93static int union_rmdir __P((struct vop_rmdir_args *ap)); 94static int union_poll __P((struct vop_poll_args *ap)); 95static int union_setattr __P((struct vop_setattr_args *ap)); 96static int union_strategy __P((struct vop_strategy_args *ap)); 97static int union_symlink __P((struct vop_symlink_args *ap)); 98static int union_unlock __P((struct vop_unlock_args *ap)); 99static int union_whiteout __P((struct vop_whiteout_args *ap)); 100static int union_write __P((struct vop_read_args *ap)); 101 102static void 103union_fixup(un, p) 104 struct union_node *un; 105 struct proc *p; 106{ 107 108 vn_lock(un->un_uppervp, LK_EXCLUSIVE | LK_RETRY, p); 109 un->un_flags |= UN_ULOCK; 110} 111 112static int 113union_lookup1(udvp, dvpp, vpp, cnp) 114 struct vnode *udvp; 115 struct vnode **dvpp; 116 struct vnode **vpp; 117 struct componentname *cnp; 118{ 119 int error; 120 struct proc *p = cnp->cn_proc; 121 struct vnode *tdvp; 122 struct vnode *dvp; 123 struct mount *mp; 124 125 dvp = *dvpp; 126 127 /* 128 * If stepping up the directory tree, check for going 129 * back across the mount point, in which case do what 130 * lookup would do by stepping back down the mount 131 * hierarchy. 132 */ 133 if (cnp->cn_flags & ISDOTDOT) { 134 while ((dvp != udvp) && (dvp->v_flag & VROOT)) { 135 /* 136 * Don't do the NOCROSSMOUNT check 137 * at this level. By definition, 138 * union fs deals with namespaces, not 139 * filesystems. 140 */ 141 tdvp = dvp; 142 *dvpp = dvp = dvp->v_mount->mnt_vnodecovered; 143 vput(tdvp); 144 VREF(dvp); 145 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 146 } 147 } 148 149 error = VOP_LOOKUP(dvp, &tdvp, cnp); 150 if (error) 151 return (error); 152 153 /* 154 * The parent directory will have been unlocked, unless lookup 155 * found the last component. In which case, re-lock the node 156 * here to allow it to be unlocked again (phew) in union_lookup. 157 */ 158 if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN)) 159 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 160 161 dvp = tdvp; 162 163 /* 164 * Lastly check if the current node is a mount point in 165 * which case walk up the mount hierarchy making sure not to 166 * bump into the root of the mount tree (ie. dvp != udvp). 167 */ 168 while (dvp != udvp && (dvp->v_type == VDIR) && 169 (mp = dvp->v_mountedhere)) { 170 171 if (vfs_busy(mp, 0, 0, p)) 172 continue; 173 174 error = VFS_ROOT(mp, &tdvp); 175 vfs_unbusy(mp, p); 176 if (error) { 177 vput(dvp); 178 return (error); 179 } 180 181 vput(dvp); 182 dvp = tdvp; 183 } 184 185 *vpp = dvp; 186 return (0); 187} 188 189static int 190union_lookup(ap) 191 struct vop_lookup_args /* { 192 struct vnodeop_desc *a_desc; 193 struct vnode *a_dvp; 194 struct vnode **a_vpp; 195 struct componentname *a_cnp; 196 } */ *ap; 197{ 198 int error; 199 int uerror, lerror; 200 struct vnode *uppervp, *lowervp; 201 struct vnode *upperdvp, *lowerdvp; 202 struct vnode *dvp = ap->a_dvp; 203 struct union_node *dun = VTOUNION(dvp); 204 struct componentname *cnp = ap->a_cnp; 205 struct proc *p = cnp->cn_proc; 206 int lockparent = cnp->cn_flags & LOCKPARENT; 207 struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount); 208 struct ucred *saved_cred = NULL; 209 int iswhiteout; 210 struct vattr va; 211 212 213 /* 214 * Disallow write attemps to the filesystem mounted read-only. 215 */ 216 if ((cnp->cn_flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && 217 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 218 return (EROFS); 219 220#ifdef notyet 221 if (cnp->cn_namelen == 3 && 222 cnp->cn_nameptr[2] == '.' && 223 cnp->cn_nameptr[1] == '.' && 224 cnp->cn_nameptr[0] == '.') { 225 dvp = *ap->a_vpp = LOWERVP(ap->a_dvp); 226 if (dvp == NULLVP) 227 return (ENOENT); 228 VREF(dvp); 229 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 230 if (!lockparent || !(cnp->cn_flags & ISLASTCN)) 231 VOP_UNLOCK(ap->a_dvp, 0, p); 232 return (0); 233 } 234#endif 235 236 cnp->cn_flags |= LOCKPARENT; 237 238 upperdvp = dun->un_uppervp; 239 lowerdvp = dun->un_lowervp; 240 uppervp = NULLVP; 241 lowervp = NULLVP; 242 iswhiteout = 0; 243 244 if (cnp->cn_flags & ISDOTDOT) { 245 if (upperdvp != NULL) 246 VREF(upperdvp); 247 if (lowerdvp != NULL) 248 VREF(lowerdvp); 249 } 250 251 /* 252 * do the lookup in the upper level. 253 * if that level comsumes additional pathnames, 254 * then assume that something special is going 255 * on and just return that vnode. 256 */ 257 if (upperdvp != NULLVP) { 258 FIXUP(dun, p); 259 /* 260 * If we're doing `..' in the underlying filesystem, 261 * we must drop our lock on the union node before 262 * going up the tree in the lower file system--if we block 263 * on the lowervp lock, and that's held by someone else 264 * coming down the tree and who's waiting for our lock, 265 * we would be hosed. 266 */ 267 if (cnp->cn_flags & ISDOTDOT) { 268 /* retain lock on underlying VP: */ 269 dun->un_flags |= UN_KLOCK; 270 VOP_UNLOCK(dvp, 0, p); 271 } 272 uerror = union_lookup1(um->um_uppervp, &upperdvp, 273 &uppervp, cnp); 274 /* 275 * Disallow write attemps to the filesystem mounted read-only. 276 */ 277 if (uerror == EJUSTRETURN && (cnp->cn_flags & ISLASTCN) && 278 (dvp->v_mount->mnt_flag & MNT_RDONLY) && 279 (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) { 280 if (!lockparent) 281 cnp->cn_flags &= ~LOCKPARENT; 282 return (EROFS); 283 } 284 285 if (cnp->cn_flags & ISDOTDOT) { 286 if (dun->un_uppervp == upperdvp) { 287 /* 288 * We got the underlying bugger back locked... 289 * now take back the union node lock. Since we 290 * hold the uppervp lock, we can diddle union 291 * locking flags at will. :) 292 */ 293 dun->un_flags |= UN_ULOCK; 294 } 295 /* 296 * If upperdvp got swapped out, it means we did 297 * some mount point magic, and we do not have 298 * dun->un_uppervp locked currently--so we get it 299 * locked here (don't set the UN_ULOCK flag). 300 */ 301 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 302 } 303 304 /*if (uppervp == upperdvp) 305 dun->un_flags |= UN_KLOCK;*/ 306 307 if (cnp->cn_consume != 0) { 308 *ap->a_vpp = uppervp; 309 if (!lockparent) 310 cnp->cn_flags &= ~LOCKPARENT; 311 error = uerror; 312 goto out; 313 } 314 if (uerror == ENOENT || uerror == EJUSTRETURN) { 315 if (cnp->cn_flags & ISWHITEOUT) { 316 iswhiteout = 1; 317 } else if (lowerdvp != NULLVP) { 318 lerror = VOP_GETATTR(upperdvp, &va, 319 cnp->cn_cred, cnp->cn_proc); 320 if (lerror == 0 && (va.va_flags & OPAQUE)) 321 iswhiteout = 1; 322 } 323 } 324 } else { 325 uerror = ENOENT; 326 } 327 328 /* 329 * in a similar way to the upper layer, do the lookup 330 * in the lower layer. this time, if there is some 331 * component magic going on, then vput whatever we got 332 * back from the upper layer and return the lower vnode 333 * instead. 334 */ 335 if (lowerdvp != NULLVP && !iswhiteout) { 336 int nameiop; 337 338 vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY, p); 339 340 /* 341 * Only do a LOOKUP on the bottom node, since 342 * we won't be making changes to it anyway. 343 */ 344 nameiop = cnp->cn_nameiop; 345 cnp->cn_nameiop = LOOKUP; 346 if (um->um_op == UNMNT_BELOW) { 347 saved_cred = cnp->cn_cred; 348 cnp->cn_cred = um->um_cred; 349 } 350 /* 351 * We shouldn't have to worry about locking interactions 352 * between the lower layer and our union layer (w.r.t. 353 * `..' processing) because we don't futz with lowervp 354 * locks in the union-node instantiation code path. 355 */ 356 lerror = union_lookup1(um->um_lowervp, &lowerdvp, 357 &lowervp, cnp); 358 if (um->um_op == UNMNT_BELOW) 359 cnp->cn_cred = saved_cred; 360 cnp->cn_nameiop = nameiop; 361 362 if (lowervp != lowerdvp) 363 VOP_UNLOCK(lowerdvp, 0, p); 364 365 if (cnp->cn_consume != 0 || lerror == EACCES) { 366 if (lerror == EACCES) 367 lowervp = NULLVP; 368 if (uppervp != NULLVP) { 369 if (uppervp == upperdvp) 370 vrele(uppervp); 371 else 372 vput(uppervp); 373 uppervp = NULLVP; 374 } 375 *ap->a_vpp = lowervp; 376 if (!lockparent) 377 cnp->cn_flags &= ~LOCKPARENT; 378 error = lerror; 379 goto out; 380 } 381 } else { 382 lerror = ENOENT; 383 if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) { 384 lowervp = LOWERVP(dun->un_pvp); 385 if (lowervp != NULLVP) { 386 VREF(lowervp); 387 vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY, p); 388 lerror = 0; 389 } 390 } 391 } 392 393 if (!lockparent) 394 cnp->cn_flags &= ~LOCKPARENT; 395 396 /* 397 * at this point, we have uerror and lerror indicating 398 * possible errors with the lookups in the upper and lower 399 * layers. additionally, uppervp and lowervp are (locked) 400 * references to existing vnodes in the upper and lower layers. 401 * 402 * there are now three cases to consider. 403 * 1. if both layers returned an error, then return whatever 404 * error the upper layer generated. 405 * 406 * 2. if the top layer failed and the bottom layer succeeded 407 * then two subcases occur. 408 * a. the bottom vnode is not a directory, in which 409 * case just return a new union vnode referencing 410 * an empty top layer and the existing bottom layer. 411 * b. the bottom vnode is a directory, in which case 412 * create a new directory in the top-level and 413 * continue as in case 3. 414 * 415 * 3. if the top layer succeeded then return a new union 416 * vnode referencing whatever the new top layer and 417 * whatever the bottom layer returned. 418 */ 419 420 *ap->a_vpp = NULLVP; 421 422 /* case 1. */ 423 if ((uerror != 0) && (lerror != 0)) { 424 error = uerror; 425 goto out; 426 } 427 428 /* case 2. */ 429 if (uerror != 0 /* && (lerror == 0) */ ) { 430 if (lowervp->v_type == VDIR) { /* case 2b. */ 431 dun->un_flags &= ~UN_ULOCK; 432 VOP_UNLOCK(upperdvp, 0, p); 433 uerror = union_mkshadow(um, upperdvp, cnp, &uppervp); 434 vn_lock(upperdvp, LK_EXCLUSIVE | LK_RETRY, p); 435 dun->un_flags |= UN_ULOCK; 436 437 if (uerror) { 438 if (lowervp != NULLVP) { 439 vput(lowervp); 440 lowervp = NULLVP; 441 } 442 error = uerror; 443 goto out; 444 } 445 } 446 } 447 448 if (lowervp != NULLVP) 449 VOP_UNLOCK(lowervp, 0, p); 450 451 error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp, 452 uppervp, lowervp, 1); 453 454 if (error) { 455 if (uppervp != NULLVP) 456 vput(uppervp); 457 if (lowervp != NULLVP) 458 vrele(lowervp); 459 } else { 460 if (*ap->a_vpp != dvp) 461 if (!lockparent || !(cnp->cn_flags & ISLASTCN)) 462 VOP_UNLOCK(dvp, 0, p); 463#ifdef DIAGNOSTIC 464 if (cnp->cn_namelen == 1 && 465 cnp->cn_nameptr[0] == '.' && 466 *ap->a_vpp != dvp) { 467 panic("union_lookup returning . (%p) not same as startdir (%p)", 468 ap->a_vpp, dvp); 469 } 470#endif 471 } 472 473out: 474 if (cnp->cn_flags & ISDOTDOT) { 475 if (upperdvp != NULL) 476 vrele(upperdvp); 477 if (lowerdvp != NULL) 478 vrele(lowerdvp); 479 } 480 481 return (error); 482} 483 484static int 485union_create(ap) 486 struct vop_create_args /* { 487 struct vnode *a_dvp; 488 struct vnode **a_vpp; 489 struct componentname *a_cnp; 490 struct vattr *a_vap; 491 } */ *ap; 492{ 493 struct union_node *dun = VTOUNION(ap->a_dvp); 494 struct vnode *dvp = dun->un_uppervp; 495 struct componentname *cnp = ap->a_cnp; 496 struct proc *p = cnp->cn_proc; 497 498 if (dvp != NULLVP) { 499 struct vnode *vp; 500 struct mount *mp; 501 int error; 502 503 FIXUP(dun, p); 504 505 dun->un_flags |= UN_KLOCK; 506 VOP_UNLOCK(ap->a_dvp, 0, p); 507 error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap); 508 if (error) { 509 dun->un_flags |= UN_ULOCK; 510 return (error); 511 } 512 513 mp = ap->a_dvp->v_mount; 514 VOP_UNLOCK(dvp, 0, p); 515 error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp, 516 NULLVP, 1); 517 if (error) 518 vput(vp); 519 vn_lock(ap->a_dvp, LK_EXCLUSIVE| LK_RETRY, p); 520 return (error); 521 } 522 523 return (EROFS); 524} 525 526static int 527union_whiteout(ap) 528 struct vop_whiteout_args /* { 529 struct vnode *a_dvp; 530 struct componentname *a_cnp; 531 int a_flags; 532 } */ *ap; 533{ 534 struct union_node *un = VTOUNION(ap->a_dvp); 535 struct componentname *cnp = ap->a_cnp; 536 struct proc *p = cnp->cn_proc; 537 538 if (un->un_uppervp == NULLVP) 539 return (EOPNOTSUPP); 540 541 FIXUP(un, p); 542 return (VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags)); 543} 544 545static int 546union_mknod(ap) 547 struct vop_mknod_args /* { 548 struct vnode *a_dvp; 549 struct vnode **a_vpp; 550 struct componentname *a_cnp; 551 struct vattr *a_vap; 552 } */ *ap; 553{ 554 struct union_node *dun = VTOUNION(ap->a_dvp); 555 struct vnode *dvp = dun->un_uppervp; 556 struct componentname *cnp = ap->a_cnp; 557 struct proc *p = cnp->cn_proc; 558 559 if (dvp != NULLVP) { 560 struct vnode *vp; 561 struct mount *mp; 562 int error; 563 564 FIXUP(dun, p); 565 566 dun->un_flags |= UN_KLOCK; 567 VOP_UNLOCK(ap->a_dvp, 0, p); 568 error = VOP_MKNOD(dvp, &vp, cnp, ap->a_vap); 569 if (error) { 570 dun->un_flags |= UN_ULOCK; 571 return (error); 572 } 573 574 if (vp != NULLVP) { 575 mp = ap->a_dvp->v_mount; 576 VOP_UNLOCK(dvp, 0, p); 577 error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, 578 cnp, vp, NULLVP, 1); 579 if (error) 580 vput(vp); 581 vn_lock(ap->a_dvp, LK_EXCLUSIVE| LK_RETRY, p); 582 } else { 583 dun->un_flags |= UN_ULOCK; 584 } 585 return (error); 586 } 587 588 return (EROFS); 589} 590 591static int 592union_open(ap) 593 struct vop_open_args /* { 594 struct vnodeop_desc *a_desc; 595 struct vnode *a_vp; 596 int a_mode; 597 struct ucred *a_cred; 598 struct proc *a_p; 599 } */ *ap; 600{ 601 struct union_node *un = VTOUNION(ap->a_vp); 602 struct vnode *tvp; 603 int mode = ap->a_mode; 604 struct ucred *cred = ap->a_cred; 605 struct proc *p = ap->a_p; 606 int error; 607 608 /* 609 * If there is an existing upper vp then simply open that. 610 */ 611 tvp = un->un_uppervp; 612 if (tvp == NULLVP) { 613 /* 614 * If the lower vnode is being opened for writing, then 615 * copy the file contents to the upper vnode and open that, 616 * otherwise can simply open the lower vnode. 617 */ 618 tvp = un->un_lowervp; 619 if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) { 620 error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p); 621 if (error == 0) 622 error = VOP_OPEN(un->un_uppervp, mode, cred, p); 623 return (error); 624 } 625 626 /* 627 * Just open the lower vnode 628 */ 629 un->un_openl++; 630 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); 631 error = VOP_OPEN(tvp, mode, cred, p); 632 VOP_UNLOCK(tvp, 0, p); 633 634 return (error); 635 } 636 637 FIXUP(un, p); 638 639 error = VOP_OPEN(tvp, mode, cred, p); 640 641 return (error); 642} 643 644static int 645union_close(ap) 646 struct vop_close_args /* { 647 struct vnode *a_vp; 648 int a_fflag; 649 struct ucred *a_cred; 650 struct proc *a_p; 651 } */ *ap; 652{ 653 struct union_node *un = VTOUNION(ap->a_vp); 654 struct vnode *vp; 655 656 if ((vp = un->un_uppervp) == NULLVP) { 657#ifdef UNION_DIAGNOSTIC 658 if (un->un_openl <= 0) 659 panic("union: un_openl cnt"); 660#endif 661 --un->un_openl; 662 vp = un->un_lowervp; 663 } 664 665 ap->a_vp = vp; 666 return (VCALL(vp, VOFFSET(vop_close), ap)); 667} 668 669/* 670 * Check access permission on the union vnode. 671 * The access check being enforced is to check 672 * against both the underlying vnode, and any 673 * copied vnode. This ensures that no additional 674 * file permissions are given away simply because 675 * the user caused an implicit file copy. 676 */ 677static int 678union_access(ap) 679 struct vop_access_args /* { 680 struct vnodeop_desc *a_desc; 681 struct vnode *a_vp; 682 int a_mode; 683 struct ucred *a_cred; 684 struct proc *a_p; 685 } */ *ap; 686{ 687 struct union_node *un = VTOUNION(ap->a_vp); 688 struct proc *p = ap->a_p; 689 int error = EACCES; 690 struct vnode *vp; 691 struct vnode *savedvp; 692 693 /* 694 * Disallow write attempts on filesystems mounted read-only. 695 */ 696 if (ap->a_mode & VWRITE && (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) { 697 switch (ap->a_vp->v_type) { 698 case VREG: 699 case VDIR: 700 case VLNK: 701 return (EROFS); 702 default: 703 break; 704 } 705 } 706 if ((vp = un->un_uppervp) != NULLVP) { 707 FIXUP(un, p); 708 ap->a_vp = vp; 709 return (VCALL(vp, VOFFSET(vop_access), ap)); 710 } 711 712 if ((vp = un->un_lowervp) != NULLVP) { 713 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 714 savedvp = ap->a_vp; 715 ap->a_vp = vp; 716 error = VCALL(vp, VOFFSET(vop_access), ap); 717 if (error == 0) { 718 struct union_mount *um = MOUNTTOUNIONMOUNT(savedvp->v_mount); 719 720 if (um->um_op == UNMNT_BELOW) { 721 ap->a_cred = um->um_cred; 722 error = VCALL(vp, VOFFSET(vop_access), ap); 723 } 724 } 725 VOP_UNLOCK(vp, 0, p); 726 if (error) 727 return (error); 728 } 729 730 return (error); 731} 732 733/* 734 * We handle getattr only to change the fsid and 735 * track object sizes 736 */ 737static int 738union_getattr(ap) 739 struct vop_getattr_args /* { 740 struct vnode *a_vp; 741 struct vattr *a_vap; 742 struct ucred *a_cred; 743 struct proc *a_p; 744 } */ *ap; 745{ 746 int error; 747 struct union_node *un = VTOUNION(ap->a_vp); 748 struct vnode *vp = un->un_uppervp; 749 struct proc *p = ap->a_p; 750 struct vattr *vap; 751 struct vattr va; 752 753 754 /* 755 * Some programs walk the filesystem hierarchy by counting 756 * links to directories to avoid stat'ing all the time. 757 * This means the link count on directories needs to be "correct". 758 * The only way to do that is to call getattr on both layers 759 * and fix up the link count. The link count will not necessarily 760 * be accurate but will be large enough to defeat the tree walkers. 761 */ 762 763 vap = ap->a_vap; 764 765 vp = un->un_uppervp; 766 if (vp != NULLVP) { 767 /* 768 * It's not clear whether VOP_GETATTR is to be 769 * called with the vnode locked or not. stat() calls 770 * it with (vp) locked, and fstat calls it with 771 * (vp) unlocked. 772 * In the mean time, compensate here by checking 773 * the union_node's lock flag. 774 */ 775 if (un->un_flags & UN_LOCKED) 776 FIXUP(un, p); 777 778 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); 779 if (error) 780 return (error); 781 union_newsize(ap->a_vp, vap->va_size, VNOVAL); 782 } 783 784 if (vp == NULLVP) { 785 vp = un->un_lowervp; 786 } else if (vp->v_type == VDIR && un->un_lowervp != NULLVP) { 787 vp = un->un_lowervp; 788 vap = &va; 789 } else { 790 vp = NULLVP; 791 } 792 793 if (vp != NULLVP) { 794 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); 795 if (error) 796 return (error); 797 union_newsize(ap->a_vp, VNOVAL, vap->va_size); 798 } 799 800 if ((vap != ap->a_vap) && (vap->va_type == VDIR)) 801 ap->a_vap->va_nlink += vap->va_nlink; 802 803 return (0); 804} 805 806static int 807union_setattr(ap) 808 struct vop_setattr_args /* { 809 struct vnode *a_vp; 810 struct vattr *a_vap; 811 struct ucred *a_cred; 812 struct proc *a_p; 813 } */ *ap; 814{ 815 struct union_node *un = VTOUNION(ap->a_vp); 816 struct proc *p = ap->a_p; 817 struct vattr *vap = ap->a_vap; 818 int error; 819 820 /* 821 * Disallow write attempts on filesystems mounted read-only. 822 */ 823 if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) && 824 (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || 825 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 826 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)) 827 return (EROFS); 828 829 /* 830 * Handle case of truncating lower object to zero size, 831 * by creating a zero length upper object. This is to 832 * handle the case of open with O_TRUNC and O_CREAT. 833 */ 834 if ((un->un_uppervp == NULLVP) && 835 /* assert(un->un_lowervp != NULLVP) */ 836 (un->un_lowervp->v_type == VREG)) { 837 error = union_copyup(un, (ap->a_vap->va_size != 0), 838 ap->a_cred, ap->a_p); 839 if (error) 840 return (error); 841 } 842 843 /* 844 * Try to set attributes in upper layer, 845 * otherwise return read-only filesystem error. 846 */ 847 if (un->un_uppervp != NULLVP) { 848 FIXUP(un, p); 849 error = VOP_SETATTR(un->un_uppervp, ap->a_vap, 850 ap->a_cred, ap->a_p); 851 if ((error == 0) && (ap->a_vap->va_size != VNOVAL)) 852 union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL); 853 } else { 854 error = EROFS; 855 } 856 857 return (error); 858} 859 860static int 861union_read(ap) 862 struct vop_read_args /* { 863 struct vnode *a_vp; 864 struct uio *a_uio; 865 int a_ioflag; 866 struct ucred *a_cred; 867 } */ *ap; 868{ 869 int error; 870 struct proc *p = ap->a_uio->uio_procp; 871 struct vnode *vp = OTHERVP(ap->a_vp); 872 int dolock = (vp == LOWERVP(ap->a_vp)); 873 874 if (dolock) 875 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 876 else 877 FIXUP(VTOUNION(ap->a_vp), p); 878 error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); 879 if (dolock) 880 VOP_UNLOCK(vp, 0, p); 881 882 /* 883 * XXX 884 * perhaps the size of the underlying object has changed under 885 * our feet. take advantage of the offset information present 886 * in the uio structure. 887 */ 888 if (error == 0) { 889 struct union_node *un = VTOUNION(ap->a_vp); 890 off_t cur = ap->a_uio->uio_offset; 891 892 if (vp == un->un_uppervp) { 893 if (cur > un->un_uppersz) 894 union_newsize(ap->a_vp, cur, VNOVAL); 895 } else { 896 if (cur > un->un_lowersz) 897 union_newsize(ap->a_vp, VNOVAL, cur); 898 } 899 } 900 901 return (error); 902} 903 904static int 905union_write(ap) 906 struct vop_read_args /* { 907 struct vnode *a_vp; 908 struct uio *a_uio; 909 int a_ioflag; 910 struct ucred *a_cred; 911 } */ *ap; 912{ 913 int error; 914 struct vnode *vp; 915 struct union_node *un = VTOUNION(ap->a_vp); 916 struct proc *p = ap->a_uio->uio_procp; 917 918 vp = UPPERVP(ap->a_vp); 919 if (vp == NULLVP) 920 panic("union: missing upper layer in write"); 921 922 FIXUP(un, p); 923 error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); 924 925 /* 926 * the size of the underlying object may be changed by the 927 * write. 928 */ 929 if (error == 0) { 930 off_t cur = ap->a_uio->uio_offset; 931 932 if (cur > un->un_uppersz) 933 union_newsize(ap->a_vp, cur, VNOVAL); 934 } 935 936 return (error); 937} 938 939static int 940union_lease(ap) 941 struct vop_lease_args /* { 942 struct vnode *a_vp; 943 struct proc *a_p; 944 struct ucred *a_cred; 945 int a_flag; 946 } */ *ap; 947{ 948 register struct vnode *ovp = OTHERVP(ap->a_vp); 949 950 ap->a_vp = ovp; 951 return (VCALL(ovp, VOFFSET(vop_lease), ap)); 952} 953 954static int 955union_ioctl(ap) 956 struct vop_ioctl_args /* { 957 struct vnode *a_vp; 958 int a_command; 959 caddr_t a_data; 960 int a_fflag; 961 struct ucred *a_cred; 962 struct proc *a_p; 963 } */ *ap; 964{ 965 register struct vnode *ovp = OTHERVP(ap->a_vp); 966 967 ap->a_vp = ovp; 968 return (VCALL(ovp, VOFFSET(vop_ioctl), ap)); 969} 970 971static int 972union_poll(ap) 973 struct vop_poll_args /* { 974 struct vnode *a_vp; 975 int a_events; 976 struct ucred *a_cred; 977 struct proc *a_p; 978 } */ *ap; 979{ 980 register struct vnode *ovp = OTHERVP(ap->a_vp); 981 982 ap->a_vp = ovp; 983 return (VCALL(ovp, VOFFSET(vop_poll), ap)); 984} 985 986static int 987union_revoke(ap) 988 struct vop_revoke_args /* { 989 struct vnode *a_vp; 990 int a_flags; 991 struct proc *a_p; 992 } */ *ap; 993{ 994 struct vnode *vp = ap->a_vp; 995 996 if (UPPERVP(vp)) 997 VOP_REVOKE(UPPERVP(vp), ap->a_flags); 998 if (LOWERVP(vp)) 999 VOP_REVOKE(LOWERVP(vp), ap->a_flags); 1000 vgone(vp); 1001 return (0); 1002} 1003 1004static int 1005union_mmap(ap) 1006 struct vop_mmap_args /* { 1007 struct vnode *a_vp; 1008 int a_fflags; 1009 struct ucred *a_cred; 1010 struct proc *a_p; 1011 } */ *ap; 1012{ 1013 register struct vnode *ovp = OTHERVP(ap->a_vp); 1014 1015 ap->a_vp = ovp; 1016 return (VCALL(ovp, VOFFSET(vop_mmap), ap)); 1017} 1018 1019static int 1020union_fsync(ap) 1021 struct vop_fsync_args /* { 1022 struct vnode *a_vp; 1023 struct ucred *a_cred; 1024 int a_waitfor; 1025 struct proc *a_p; 1026 } */ *ap; 1027{ 1028 int error = 0; 1029 struct proc *p = ap->a_p; 1030 struct vnode *targetvp = OTHERVP(ap->a_vp); 1031 struct union_node *un; 1032 1033 if (targetvp != NULLVP) { 1034 int dolock = (targetvp == LOWERVP(ap->a_vp)); 1035 1036 un = VTOUNION(ap->a_vp); 1037 if (dolock) 1038 vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p); 1039 else { 1040 un = VTOUNION(ap->a_vp); 1041 if ((un->un_flags & UN_ULOCK) == 0 && 1042 targetvp->v_data != NULL && 1043 ((struct lock *)targetvp->v_data)->lk_lockholder 1044 == curproc->p_pid && 1045 VOP_ISLOCKED(targetvp) != 0) 1046 return 0; /* XXX */ 1047 1048 FIXUP(un, p); 1049 } 1050 1051 error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, p); 1052 if (dolock) 1053 VOP_UNLOCK(targetvp, 0, p); 1054 } 1055 1056 return (error); 1057} 1058 1059static int 1060union_remove(ap) 1061 struct vop_remove_args /* { 1062 struct vnode *a_dvp; 1063 struct vnode *a_vp; 1064 struct componentname *a_cnp; 1065 } */ *ap; 1066{ 1067 struct union_node *dun = VTOUNION(ap->a_dvp); 1068 struct union_node *un = VTOUNION(ap->a_vp); 1069 struct componentname *cnp = ap->a_cnp; 1070 struct proc *p = cnp->cn_proc; 1071 int error; 1072 1073 if (dun->un_uppervp == NULLVP) 1074 panic("union remove: null upper vnode"); 1075 1076 if (un->un_uppervp != NULLVP) { 1077 struct vnode *dvp = dun->un_uppervp; 1078 struct vnode *vp = un->un_uppervp; 1079 1080 FIXUP(dun, p); 1081 dun->un_flags |= UN_KLOCK; 1082 VOP_UNLOCK(ap->a_dvp, 0, p); 1083 FIXUP(un, p); 1084 un->un_flags |= UN_KLOCK; 1085 VOP_UNLOCK(ap->a_vp, 0, p); 1086 1087 if (union_dowhiteout(un, cnp->cn_cred, p)) 1088 cnp->cn_flags |= DOWHITEOUT; 1089 error = VOP_REMOVE(dvp, vp, cnp); 1090#if 0 1091 /* XXX */ 1092 if (!error) 1093 union_removed_upper(un); 1094#endif 1095 dun->un_flags |= UN_ULOCK; 1096 un->un_flags |= UN_ULOCK; 1097 } else { 1098 FIXUP(dun, p); 1099 error = union_mkwhiteout( 1100 MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), 1101 dun->un_uppervp, ap->a_cnp, un->un_path); 1102 } 1103 1104 return (error); 1105} 1106 1107static int 1108union_link(ap) 1109 struct vop_link_args /* { 1110 struct vnode *a_tdvp; 1111 struct vnode *a_vp; 1112 struct componentname *a_cnp; 1113 } */ *ap; 1114{ 1115 struct componentname *cnp = ap->a_cnp; 1116 struct proc *p = cnp->cn_proc; 1117 struct union_node *dun = VTOUNION(ap->a_tdvp); 1118 struct vnode *vp; 1119 struct vnode *tdvp; 1120 int error = 0; 1121 1122 1123 if (ap->a_tdvp->v_op != ap->a_vp->v_op) { 1124 vp = ap->a_vp; 1125 } else { 1126 struct union_node *tun = VTOUNION(ap->a_vp); 1127 if (tun->un_uppervp == NULLVP) { 1128 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); 1129 if (dun->un_uppervp == tun->un_dirvp) { 1130 dun->un_flags &= ~UN_ULOCK; 1131 VOP_UNLOCK(dun->un_uppervp, 0, p); 1132 } 1133 error = union_copyup(tun, 1, cnp->cn_cred, p); 1134 if (dun->un_uppervp == tun->un_dirvp) { 1135 vn_lock(dun->un_uppervp, 1136 LK_EXCLUSIVE | LK_RETRY, p); 1137 dun->un_flags |= UN_ULOCK; 1138 } 1139 VOP_UNLOCK(ap->a_vp, 0, p); 1140 } 1141 vp = tun->un_uppervp; 1142 } 1143 1144 tdvp = dun->un_uppervp; 1145 if (tdvp == NULLVP) 1146 error = EROFS; 1147 1148 if (error) 1149 return (error); 1150 1151 FIXUP(dun, p); 1152 dun->un_flags |= UN_KLOCK; 1153 VOP_UNLOCK(ap->a_tdvp, 0, p); 1154 1155 error = VOP_LINK(tdvp, vp, cnp); 1156 1157 dun->un_flags |= UN_ULOCK; 1158 1159 return (error); 1160} 1161 1162static int 1163union_rename(ap) 1164 struct vop_rename_args /* { 1165 struct vnode *a_fdvp; 1166 struct vnode *a_fvp; 1167 struct componentname *a_fcnp; 1168 struct vnode *a_tdvp; 1169 struct vnode *a_tvp; 1170 struct componentname *a_tcnp; 1171 } */ *ap; 1172{ 1173 int error; 1174 1175 struct vnode *fdvp = ap->a_fdvp; 1176 struct vnode *fvp = ap->a_fvp; 1177 struct vnode *tdvp = ap->a_tdvp; 1178 struct vnode *tvp = ap->a_tvp; 1179 1180 if (fdvp->v_op == union_vnodeop_p) { /* always true */ 1181 struct union_node *un = VTOUNION(fdvp); 1182 if (un->un_uppervp == NULLVP) { 1183 /* 1184 * this should never happen in normal 1185 * operation but might if there was 1186 * a problem creating the top-level shadow 1187 * directory. 1188 */ 1189 error = EXDEV; 1190 goto bad; 1191 } 1192 1193 fdvp = un->un_uppervp; 1194 VREF(fdvp); 1195 vrele(ap->a_fdvp); 1196 } 1197 1198 if (fvp->v_op == union_vnodeop_p) { /* always true */ 1199 struct union_node *un = VTOUNION(fvp); 1200 if (un->un_uppervp == NULLVP) { 1201 /* XXX: should do a copyup */ 1202 error = EXDEV; 1203 goto bad; 1204 } 1205 1206 if (un->un_lowervp != NULLVP) 1207 ap->a_fcnp->cn_flags |= DOWHITEOUT; 1208 1209 fvp = un->un_uppervp; 1210 VREF(fvp); 1211 vrele(ap->a_fvp); 1212 } 1213 1214 if (tdvp->v_op == union_vnodeop_p) { 1215 struct union_node *un = VTOUNION(tdvp); 1216 if (un->un_uppervp == NULLVP) { 1217 /* 1218 * this should never happen in normal 1219 * operation but might if there was 1220 * a problem creating the top-level shadow 1221 * directory. 1222 */ 1223 error = EXDEV; 1224 goto bad; 1225 } 1226 1227 tdvp = un->un_uppervp; 1228 VREF(tdvp); 1229 un->un_flags |= UN_KLOCK; 1230 vput(ap->a_tdvp); 1231 } 1232 1233 if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) { 1234 struct union_node *un = VTOUNION(tvp); 1235 1236 tvp = un->un_uppervp; 1237 if (tvp != NULLVP) { 1238 VREF(tvp); 1239 un->un_flags |= UN_KLOCK; 1240 } 1241 vput(ap->a_tvp); 1242 } 1243 1244 return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp)); 1245 1246bad: 1247 vrele(fdvp); 1248 vrele(fvp); 1249 vput(tdvp); 1250 if (tvp != NULLVP) 1251 vput(tvp); 1252 1253 return (error); 1254} 1255 1256static int 1257union_mkdir(ap) 1258 struct vop_mkdir_args /* { 1259 struct vnode *a_dvp; 1260 struct vnode **a_vpp; 1261 struct componentname *a_cnp; 1262 struct vattr *a_vap; 1263 } */ *ap; 1264{ 1265 struct union_node *dun = VTOUNION(ap->a_dvp); 1266 struct vnode *dvp = dun->un_uppervp; 1267 struct componentname *cnp = ap->a_cnp; 1268 struct proc *p = cnp->cn_proc; 1269 1270 if (dvp != NULLVP) { 1271 struct vnode *vp; 1272 int error; 1273 1274 FIXUP(dun, p); 1275 dun->un_flags |= UN_KLOCK; 1276 VOP_UNLOCK(ap->a_dvp, 0, p); 1277 error = VOP_MKDIR(dvp, &vp, cnp, ap->a_vap); 1278 if (error) { 1279 dun->un_flags |= UN_ULOCK; 1280 return (error); 1281 } 1282 1283 VOP_UNLOCK(dvp, 0, p); 1284 error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp, 1285 NULLVP, cnp, vp, NULLVP, 1); 1286 if (error) 1287 vput(vp); 1288 vn_lock(ap->a_dvp, LK_EXCLUSIVE| LK_RETRY, p); 1289 1290 return (error); 1291 } 1292 1293 return (EROFS); 1294} 1295 1296static int 1297union_rmdir(ap) 1298 struct vop_rmdir_args /* { 1299 struct vnode *a_dvp; 1300 struct vnode *a_vp; 1301 struct componentname *a_cnp; 1302 } */ *ap; 1303{ 1304 struct union_node *dun = VTOUNION(ap->a_dvp); 1305 struct union_node *un = VTOUNION(ap->a_vp); 1306 struct componentname *cnp = ap->a_cnp; 1307 struct proc *p = cnp->cn_proc; 1308 int error; 1309 1310 if (dun->un_uppervp == NULLVP) 1311 panic("union rmdir: null upper vnode"); 1312 1313 if (un->un_uppervp != NULLVP) { 1314 struct vnode *dvp = dun->un_uppervp; 1315 struct vnode *vp = un->un_uppervp; 1316 1317 FIXUP(dun, p); 1318 dun->un_flags |= UN_KLOCK; 1319 VOP_UNLOCK(ap->a_dvp, 0, p); 1320 FIXUP(un, p); 1321 un->un_flags |= UN_KLOCK; 1322 VOP_UNLOCK(ap->a_vp, 0, p); 1323 1324 if (union_dowhiteout(un, cnp->cn_cred, p)) 1325 cnp->cn_flags |= DOWHITEOUT; 1326 error = VOP_RMDIR(dvp, vp, ap->a_cnp); 1327#if 0 1328 /* XXX */ 1329 if (!error) 1330 union_removed_upper(un); 1331#endif 1332 dun->un_flags |= UN_ULOCK; 1333 un->un_flags |= UN_ULOCK; 1334 } else { 1335 FIXUP(dun, p); 1336 error = union_mkwhiteout( 1337 MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), 1338 dun->un_uppervp, ap->a_cnp, un->un_path); 1339 } 1340 1341 return (error); 1342} 1343 1344static int 1345union_symlink(ap) 1346 struct vop_symlink_args /* { 1347 struct vnode *a_dvp; 1348 struct vnode **a_vpp; 1349 struct componentname *a_cnp; 1350 struct vattr *a_vap; 1351 char *a_target; 1352 } */ *ap; 1353{ 1354 struct union_node *dun = VTOUNION(ap->a_dvp); 1355 struct vnode *dvp = dun->un_uppervp; 1356 struct componentname *cnp = ap->a_cnp; 1357 struct proc *p = cnp->cn_proc; 1358 1359 if (dvp != NULLVP) { 1360 struct vnode *vp; 1361 int error; 1362 1363 FIXUP(dun, p); 1364 dun->un_flags |= UN_KLOCK; 1365 VOP_UNLOCK(ap->a_dvp, 0, p); 1366 error = VOP_SYMLINK(dvp, &vp, cnp, ap->a_vap, ap->a_target); 1367 dun->un_flags |= UN_ULOCK; 1368 *ap->a_vpp = NULLVP; 1369 return (error); 1370 } 1371 1372 return (EROFS); 1373} 1374 1375/* 1376 * union_readdir works in concert with getdirentries and 1377 * readdir(3) to provide a list of entries in the unioned 1378 * directories. getdirentries is responsible for walking 1379 * down the union stack. readdir(3) is responsible for 1380 * eliminating duplicate names from the returned data stream. 1381 */ 1382static int 1383union_readdir(ap) 1384 struct vop_readdir_args /* { 1385 struct vnode *a_vp; 1386 struct uio *a_uio; 1387 struct ucred *a_cred; 1388 int *a_eofflag; 1389 u_long *a_cookies; 1390 int a_ncookies; 1391 } */ *ap; 1392{ 1393 struct union_node *un = VTOUNION(ap->a_vp); 1394 struct vnode *uvp = un->un_uppervp; 1395 struct proc *p = ap->a_uio->uio_procp; 1396 1397 if (uvp == NULLVP) 1398 return (0); 1399 1400 FIXUP(un, p); 1401 ap->a_vp = uvp; 1402 return (VCALL(uvp, VOFFSET(vop_readdir), ap)); 1403} 1404 1405static int 1406union_readlink(ap) 1407 struct vop_readlink_args /* { 1408 struct vnode *a_vp; 1409 struct uio *a_uio; 1410 struct ucred *a_cred; 1411 } */ *ap; 1412{ 1413 int error; 1414 struct uio *uio = ap->a_uio; 1415 struct proc *p = uio->uio_procp; 1416 struct vnode *vp = OTHERVP(ap->a_vp); 1417 int dolock = (vp == LOWERVP(ap->a_vp)); 1418 1419 if (dolock) 1420 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1421 else 1422 FIXUP(VTOUNION(ap->a_vp), p); 1423 ap->a_vp = vp; 1424 error = VCALL(vp, VOFFSET(vop_readlink), ap); 1425 if (dolock) 1426 VOP_UNLOCK(vp, 0, p); 1427 1428 return (error); 1429} 1430 1431static int 1432union_abortop(ap) 1433 struct vop_abortop_args /* { 1434 struct vnode *a_dvp; 1435 struct componentname *a_cnp; 1436 } */ *ap; 1437{ 1438 int error; 1439 struct componentname *cnp = ap->a_cnp; 1440 struct proc *p = cnp->cn_proc; 1441 struct vnode *vp = OTHERVP(ap->a_dvp); 1442 struct union_node *un = VTOUNION(ap->a_dvp); 1443 int islocked = un->un_flags & UN_LOCKED; 1444 int dolock = (vp == LOWERVP(ap->a_dvp)); 1445 1446 if (islocked) { 1447 if (dolock) 1448 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1449 else 1450 FIXUP(VTOUNION(ap->a_dvp), p); 1451 } 1452 ap->a_dvp = vp; 1453 error = VCALL(vp, VOFFSET(vop_abortop), ap); 1454 if (islocked && dolock) 1455 VOP_UNLOCK(vp, 0, p); 1456 1457 return (error); 1458} 1459 1460static int 1461union_inactive(ap) 1462 struct vop_inactive_args /* { 1463 struct vnode *a_vp; 1464 struct proc *a_p; 1465 } */ *ap; 1466{ 1467 struct vnode *vp = ap->a_vp; 1468 struct proc *p = ap->a_p; 1469 struct union_node *un = VTOUNION(vp); 1470 struct vnode **vpp; 1471 1472 /* 1473 * Do nothing (and _don't_ bypass). 1474 * Wait to vrele lowervp until reclaim, 1475 * so that until then our union_node is in the 1476 * cache and reusable. 1477 * 1478 * NEEDSWORK: Someday, consider inactive'ing 1479 * the lowervp and then trying to reactivate it 1480 * with capabilities (v_id) 1481 * like they do in the name lookup cache code. 1482 * That's too much work for now. 1483 */ 1484 1485 if (un->un_dircache != 0) { 1486 for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) 1487 vrele(*vpp); 1488 free(un->un_dircache, M_TEMP); 1489 un->un_dircache = 0; 1490 } 1491 1492 VOP_UNLOCK(vp, 0, p); 1493 1494 if ((un->un_flags & UN_CACHED) == 0) 1495 vgone(vp); 1496 1497 return (0); 1498} 1499 1500static int 1501union_reclaim(ap) 1502 struct vop_reclaim_args /* { 1503 struct vnode *a_vp; 1504 } */ *ap; 1505{ 1506 1507 union_freevp(ap->a_vp); 1508 1509 return (0); 1510} 1511 1512static int 1513union_lock(ap) 1514 struct vop_lock_args *ap; 1515{ 1516 struct vnode *vp = ap->a_vp; 1517 struct proc *p = ap->a_p; 1518 int flags = ap->a_flags; 1519 struct union_node *un; 1520 int error; 1521 1522 vop_nolock(ap); 1523 /* 1524 * Need to do real lockmgr-style locking here. 1525 * in the mean time, draining won't work quite right, 1526 * which could lead to a few race conditions. 1527 * the following test was here, but is not quite right, we 1528 * still need to take the lock: 1529 if ((flags & LK_TYPE_MASK) == LK_DRAIN) 1530 return (0); 1531 */ 1532 flags &= ~LK_INTERLOCK; 1533 1534start: 1535 un = VTOUNION(vp); 1536 1537 if (un->un_uppervp != NULLVP) { 1538 if (((un->un_flags & UN_ULOCK) == 0) && 1539 (vp->v_usecount != 0)) { 1540 error = vn_lock(un->un_uppervp, flags, p); 1541 if (error) 1542 return (error); 1543 un->un_flags |= UN_ULOCK; 1544 } 1545#ifdef DIAGNOSTIC 1546 if (un->un_flags & UN_KLOCK) { 1547 vprint("dangling upper lock", vp); 1548 panic("union: dangling upper lock"); 1549 } 1550#endif 1551 } 1552 1553 if (un->un_flags & UN_LOCKED) { 1554#ifdef DIAGNOSTIC 1555 if (curproc && un->un_pid == curproc->p_pid && 1556 un->un_pid > -1 && curproc->p_pid > -1) 1557 panic("union: locking against myself"); 1558#endif 1559 un->un_flags |= UN_WANT; 1560 tsleep((caddr_t)&un->un_flags, PINOD, "unionlk2", 0); 1561 goto start; 1562 } 1563 1564#ifdef DIAGNOSTIC 1565 if (curproc) 1566 un->un_pid = curproc->p_pid; 1567 else 1568 un->un_pid = -1; 1569#endif 1570 1571 un->un_flags |= UN_LOCKED; 1572 return (0); 1573} 1574 1575/* 1576 * When operations want to vput() a union node yet retain a lock on 1577 * the upper vnode (say, to do some further operations like link(), 1578 * mkdir(), ...), they set UN_KLOCK on the union node, then call 1579 * vput() which calls VOP_UNLOCK() and comes here. union_unlock() 1580 * unlocks the union node (leaving the upper vnode alone), clears the 1581 * KLOCK flag, and then returns to vput(). The caller then does whatever 1582 * is left to do with the upper vnode, and ensures that it gets unlocked. 1583 * 1584 * If UN_KLOCK isn't set, then the upper vnode is unlocked here. 1585 */ 1586static int 1587union_unlock(ap) 1588 struct vop_unlock_args /* { 1589 struct vnode *a_vp; 1590 int a_flags; 1591 struct proc *a_p; 1592 } */ *ap; 1593{ 1594 struct union_node *un = VTOUNION(ap->a_vp); 1595 struct proc *p = ap->a_p; 1596 1597#ifdef DIAGNOSTIC 1598 if ((un->un_flags & UN_LOCKED) == 0) 1599 panic("union: unlock unlocked node"); 1600 if (curproc && un->un_pid != curproc->p_pid && 1601 curproc->p_pid > -1 && un->un_pid > -1) 1602 panic("union: unlocking other process's union node"); 1603#endif 1604 1605 un->un_flags &= ~UN_LOCKED; 1606 1607 if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK) 1608 VOP_UNLOCK(un->un_uppervp, 0, p); 1609 1610 un->un_flags &= ~(UN_ULOCK|UN_KLOCK); 1611 1612 if (un->un_flags & UN_WANT) { 1613 un->un_flags &= ~UN_WANT; 1614 wakeup((caddr_t) &un->un_flags); 1615 } 1616 1617#ifdef DIAGNOSTIC 1618 un->un_pid = 0; 1619#endif 1620 vop_nounlock(ap); 1621 1622 return (0); 1623} 1624 1625static int 1626union_bmap(ap) 1627 struct vop_bmap_args /* { 1628 struct vnode *a_vp; 1629 daddr_t a_bn; 1630 struct vnode **a_vpp; 1631 daddr_t *a_bnp; 1632 int *a_runp; 1633 int *a_runb; 1634 } */ *ap; 1635{ 1636 int error; 1637 struct proc *p = curproc; /* XXX */ 1638 struct vnode *vp = OTHERVP(ap->a_vp); 1639 int dolock = (vp == LOWERVP(ap->a_vp)); 1640 1641 if (dolock) 1642 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1643 else 1644 FIXUP(VTOUNION(ap->a_vp), p); 1645 ap->a_vp = vp; 1646 error = VCALL(vp, VOFFSET(vop_bmap), ap); 1647 if (dolock) 1648 VOP_UNLOCK(vp, 0, p); 1649 1650 return (error); 1651} 1652 1653static int 1654union_print(ap) 1655 struct vop_print_args /* { 1656 struct vnode *a_vp; 1657 } */ *ap; 1658{ 1659 struct vnode *vp = ap->a_vp; 1660 1661 printf("\ttag VT_UNION, vp=%p, uppervp=%p, lowervp=%p\n", 1662 vp, UPPERVP(vp), LOWERVP(vp)); 1663 if (UPPERVP(vp) != NULLVP) 1664 vprint("union: upper", UPPERVP(vp)); 1665 if (LOWERVP(vp) != NULLVP) 1666 vprint("union: lower", LOWERVP(vp)); 1667 1668 return (0); 1669} 1670 1671static int 1672union_islocked(ap) 1673 struct vop_islocked_args /* { 1674 struct vnode *a_vp; 1675 } */ *ap; 1676{ 1677 1678 return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0); 1679} 1680 1681static int 1682union_pathconf(ap) 1683 struct vop_pathconf_args /* { 1684 struct vnode *a_vp; 1685 int a_name; 1686 int *a_retval; 1687 } */ *ap; 1688{ 1689 int error; 1690 struct proc *p = curproc; /* XXX */ 1691 struct vnode *vp = OTHERVP(ap->a_vp); 1692 int dolock = (vp == LOWERVP(ap->a_vp)); 1693 1694 if (dolock) 1695 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1696 else 1697 FIXUP(VTOUNION(ap->a_vp), p); 1698 ap->a_vp = vp; 1699 error = VCALL(vp, VOFFSET(vop_pathconf), ap); 1700 if (dolock) 1701 VOP_UNLOCK(vp, 0, p); 1702 1703 return (error); 1704} 1705 1706static int 1707union_advlock(ap) 1708 struct vop_advlock_args /* { 1709 struct vnode *a_vp; 1710 caddr_t a_id; 1711 int a_op; 1712 struct flock *a_fl; 1713 int a_flags; 1714 } */ *ap; 1715{ 1716 register struct vnode *ovp = OTHERVP(ap->a_vp); 1717 1718 ap->a_vp = ovp; 1719 return (VCALL(ovp, VOFFSET(vop_advlock), ap)); 1720} 1721 1722 1723/* 1724 * XXX - vop_strategy must be hand coded because it has no 1725 * vnode in its arguments. 1726 * This goes away with a merged VM/buffer cache. 1727 */ 1728static int 1729union_strategy(ap) 1730 struct vop_strategy_args /* { 1731 struct vnode *a_vp; 1732 struct buf *a_bp; 1733 } */ *ap; 1734{ 1735 struct buf *bp = ap->a_bp; 1736 struct vnode *othervp = OTHERVP(bp->b_vp); 1737 1738#ifdef DIAGNOSTIC 1739 if (othervp == NULLVP) 1740 panic("union_strategy: nil vp"); 1741 if (((bp->b_flags & B_READ) == 0) && 1742 (othervp == LOWERVP(bp->b_vp))) 1743 panic("union_strategy: writing to lowervp"); 1744#endif 1745 1746 return (VOP_STRATEGY(othervp, bp)); 1747} 1748 1749/* 1750 * Global vfs data structures 1751 */ 1752vop_t **union_vnodeop_p; 1753static struct vnodeopv_entry_desc union_vnodeop_entries[] = { 1754 { &vop_default_desc, (vop_t *) vop_defaultop }, 1755 { &vop_abortop_desc, (vop_t *) union_abortop }, 1756 { &vop_access_desc, (vop_t *) union_access }, 1757 { &vop_advlock_desc, (vop_t *) union_advlock }, 1758 { &vop_bmap_desc, (vop_t *) union_bmap }, 1759 { &vop_close_desc, (vop_t *) union_close }, 1760 { &vop_create_desc, (vop_t *) union_create }, 1761 { &vop_fsync_desc, (vop_t *) union_fsync }, 1762 { &vop_getattr_desc, (vop_t *) union_getattr }, 1763 { &vop_inactive_desc, (vop_t *) union_inactive }, 1764 { &vop_ioctl_desc, (vop_t *) union_ioctl }, 1765 { &vop_islocked_desc, (vop_t *) union_islocked }, 1766 { &vop_lease_desc, (vop_t *) union_lease }, 1767 { &vop_link_desc, (vop_t *) union_link }, 1768 { &vop_lock_desc, (vop_t *) union_lock }, 1769 { &vop_lookup_desc, (vop_t *) union_lookup }, 1770 { &vop_mkdir_desc, (vop_t *) union_mkdir }, 1771 { &vop_mknod_desc, (vop_t *) union_mknod }, 1772 { &vop_mmap_desc, (vop_t *) union_mmap }, 1773 { &vop_open_desc, (vop_t *) union_open }, 1774 { &vop_pathconf_desc, (vop_t *) union_pathconf }, 1775 { &vop_poll_desc, (vop_t *) union_poll }, 1776 { &vop_print_desc, (vop_t *) union_print }, 1777 { &vop_read_desc, (vop_t *) union_read }, 1778 { &vop_readdir_desc, (vop_t *) union_readdir }, 1779 { &vop_readlink_desc, (vop_t *) union_readlink }, 1780 { &vop_reclaim_desc, (vop_t *) union_reclaim }, 1781 { &vop_remove_desc, (vop_t *) union_remove }, 1782 { &vop_rename_desc, (vop_t *) union_rename }, 1783 { &vop_revoke_desc, (vop_t *) union_revoke }, 1784 { &vop_rmdir_desc, (vop_t *) union_rmdir }, 1785 { &vop_setattr_desc, (vop_t *) union_setattr }, 1786 { &vop_strategy_desc, (vop_t *) union_strategy }, 1787 { &vop_symlink_desc, (vop_t *) union_symlink }, 1788 { &vop_unlock_desc, (vop_t *) union_unlock }, 1789 { &vop_whiteout_desc, (vop_t *) union_whiteout }, 1790 { &vop_write_desc, (vop_t *) union_write }, 1791 { NULL, NULL } 1792}; 1793static struct vnodeopv_desc union_vnodeop_opv_desc = 1794 { &union_vnodeop_p, union_vnodeop_entries }; 1795 1796VNODEOP_SET(union_vnodeop_opv_desc); 1797