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