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