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