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