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