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