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