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.6 (Berkeley) 02/04/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 * If going back up the directory tree, then the parent directory 64 * will have been unlocked, unless lookup found the last 65 * component. In which case, re-lock the node here to allow 66 * it to be unlocked again (phew) in union_lookup. 67 */ 68 if ((cnp->cn_flags & ISDOTDOT) && !(cnp->cn_flags & ISLASTCN)) 69 VOP_LOCK(dvp); 70 71 dvp = tdvp; 72 73 /* 74 * Lastly check if the current node is a mount point in 75 * which cse walk up the mount hierarchy making sure not to 76 * bump into the root of the mount tree (ie. dvp != udvp). 77 */ 78 while (dvp != udvp && (dvp->v_type == VDIR) && 79 (mp = dvp->v_mountedhere) && 80 (cnp->cn_flags & NOCROSSMOUNT) == 0) { 81 82 if (mp->mnt_flag & MNT_MLOCK) { 83 mp->mnt_flag |= MNT_MWAIT; 84 sleep((caddr_t) mp, PVFS); 85 continue; 86 } 87 88 if (error = VFS_ROOT(mp, &tdvp)) { 89 vput(dvp); 90 return (error); 91 } 92 93 vput(dvp); 94 dvp = tdvp; 95 } 96 97 *vpp = dvp; 98 return (0); 99 } 100 101 int 102 union_lookup(ap) 103 struct vop_lookup_args /* { 104 struct vnodeop_desc *a_desc; 105 struct vnode *a_dvp; 106 struct vnode **a_vpp; 107 struct componentname *a_cnp; 108 } */ *ap; 109 { 110 int error; 111 int uerror, lerror; 112 struct vnode *uppervp, *lowervp; 113 struct vnode *upperdvp, *lowerdvp; 114 struct vnode *dvp = ap->a_dvp; 115 struct union_node *dun = VTOUNION(dvp); 116 struct componentname *cnp = ap->a_cnp; 117 int lockparent = cnp->cn_flags & LOCKPARENT; 118 int rdonly = cnp->cn_flags & RDONLY; 119 struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount); 120 121 cnp->cn_flags |= LOCKPARENT; 122 123 upperdvp = dun->un_uppervp; 124 lowerdvp = dun->un_lowervp; 125 uppervp = NULLVP; 126 lowervp = NULLVP; 127 128 /* 129 * do the lookup in the upper level. 130 * if that level comsumes additional pathnames, 131 * then assume that something special is going 132 * on and just return that vnode. 133 */ 134 if (upperdvp) { 135 VOP_LOCK(upperdvp); 136 uerror = union_lookup1(um->um_uppervp, upperdvp, 137 &uppervp, cnp); 138 if (uppervp != upperdvp) 139 VOP_UNLOCK(upperdvp); 140 141 if (cnp->cn_consume != 0) { 142 *ap->a_vpp = uppervp; 143 if (!lockparent) 144 cnp->cn_flags &= ~LOCKPARENT; 145 return (uerror); 146 } 147 } else { 148 uerror = ENOENT; 149 } 150 151 /* 152 * in a similar way to the upper layer, do the lookup 153 * in the lower layer. this time, if there is some 154 * component magic going on, then vput whatever we got 155 * back from the upper layer and return the lower vnode 156 * instead. 157 */ 158 if (lowerdvp) { 159 VOP_LOCK(lowerdvp); 160 lerror = union_lookup1(um->um_lowervp, lowerdvp, 161 &lowervp, cnp); 162 if (lowervp != lowerdvp) 163 VOP_UNLOCK(lowerdvp); 164 165 if (cnp->cn_consume != 0) { 166 if (uppervp) { 167 vput(uppervp); 168 uppervp = NULLVP; 169 } 170 *ap->a_vpp = lowervp; 171 if (!lockparent) 172 cnp->cn_flags &= ~LOCKPARENT; 173 return (lerror); 174 } 175 } else { 176 lerror = ENOENT; 177 } 178 179 if (!lockparent) 180 cnp->cn_flags &= ~LOCKPARENT; 181 182 /* 183 * at this point, we have uerror and lerror indicating 184 * possible errors with the lookups in the upper and lower 185 * layers. additionally, uppervp and lowervp are (locked) 186 * references to existing vnodes in the upper and lower layers. 187 * 188 * there are now three cases to consider. 189 * 1. if both layers returned an error, then return whatever 190 * error the upper layer generated. 191 * 192 * 2. if the top layer failed and the bottom layer succeeded 193 * then two subcases occur. 194 * a. the bottom vnode is not a directory, in which 195 * case just return a new union vnode referencing 196 * an empty top layer and the existing bottom layer. 197 * b. the bottom vnode is a directory, in which case 198 * create a new directory in the top-level and 199 * continue as in case 3. 200 * 201 * 3. if the top layer succeeded then return a new union 202 * vnode referencing whatever the new top layer and 203 * whatever the bottom layer returned. 204 */ 205 206 /* case 1. */ 207 if ((uerror != 0) && (lerror != 0)) { 208 *ap->a_vpp = NULLVP; 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 shoudl 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 (void) VOP_CLOSE(un->un_uppervp, FWRITE); 406 VOP_LOCK(un->un_uppervp); 407 if (!error) 408 uprintf("union: copied up\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_open; i++) { 421 (void) VOP_CLOSE(tvp, FREAD); 422 (void) VOP_OPEN(un->un_uppervp, FREAD, cred, p); 423 } 424 un->un_open = 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_open++; 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 DIAGNOSTIC 457 if (un->un_open <= 0) 458 panic("union: un_open cnt"); 459 #endif 460 --un->un_open; 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 } else { 702 /* 703 * XXX: should create a whiteout here 704 */ 705 vput(ap->a_dvp); 706 vput(ap->a_vp); 707 error = EROFS; 708 } 709 710 return (error); 711 } 712 713 int 714 union_link(ap) 715 struct vop_link_args /* { 716 struct vnode *a_vp; 717 struct vnode *a_tdvp; 718 struct componentname *a_cnp; 719 } */ *ap; 720 { 721 int error; 722 struct union_node *dun = VTOUNION(ap->a_vp); 723 struct union_node *un = VTOUNION(ap->a_tdvp); 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 VOP_LOCK(dvp); 731 vput(ap->a_vp); 732 VREF(vp); 733 vrele(ap->a_tdvp); 734 735 error = VOP_LINK(dvp, vp, ap->a_cnp); 736 } else { 737 /* 738 * XXX: need to copy to upper layer 739 * and do the link there. 740 */ 741 vput(ap->a_vp); 742 vrele(ap->a_tdvp); 743 error = EROFS; 744 } 745 746 return (error); 747 } 748 749 int 750 union_rename(ap) 751 struct vop_rename_args /* { 752 struct vnode *a_fdvp; 753 struct vnode *a_fvp; 754 struct componentname *a_fcnp; 755 struct vnode *a_tdvp; 756 struct vnode *a_tvp; 757 struct componentname *a_tcnp; 758 } */ *ap; 759 { 760 int error; 761 762 struct vnode *fdvp = ap->a_fdvp; 763 struct vnode *fvp = ap->a_fvp; 764 struct vnode *tdvp = ap->a_tdvp; 765 struct vnode *tvp = ap->a_tvp; 766 767 if (fdvp->v_op == union_vnodeop_p) { /* always true */ 768 struct union_node *un = VTOUNION(fdvp); 769 if (un->un_uppervp == NULLVP) { 770 error = EROFS; 771 goto bad; 772 } 773 774 fdvp = un->un_uppervp; 775 VREF(fdvp); 776 vrele(ap->a_fdvp); 777 } 778 779 if (fvp->v_op == union_vnodeop_p) { /* always true */ 780 struct union_node *un = VTOUNION(fvp); 781 if (un->un_uppervp == NULLVP) { 782 error = EROFS; 783 goto bad; 784 } 785 786 fvp = un->un_uppervp; 787 VREF(fvp); 788 vrele(ap->a_fvp); 789 } 790 791 if (tdvp->v_op == union_vnodeop_p) { 792 struct union_node *un = VTOUNION(tdvp); 793 if (un->un_uppervp == NULLVP) { 794 error = EROFS; 795 goto bad; 796 } 797 798 tdvp = un->un_uppervp; 799 VREF(tdvp); 800 VOP_LOCK(tdvp); 801 vput(ap->a_tdvp); 802 } 803 804 if (tvp && tvp->v_op == union_vnodeop_p) { 805 struct union_node *un = VTOUNION(tvp); 806 if (un->un_uppervp == NULLVP) { 807 error = EROFS; 808 goto bad; 809 } 810 811 tvp = un->un_uppervp; 812 VREF(tvp); 813 VOP_LOCK(tvp); 814 vput(ap->a_tvp); 815 } 816 817 return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp)); 818 819 bad: 820 vrele(fdvp); 821 vrele(fvp); 822 vput(tdvp); 823 if (tvp) 824 vput(tvp); 825 826 return (error); 827 } 828 829 int 830 union_mkdir(ap) 831 struct vop_mkdir_args /* { 832 struct vnode *a_dvp; 833 struct vnode **a_vpp; 834 struct componentname *a_cnp; 835 struct vattr *a_vap; 836 } */ *ap; 837 { 838 struct union_node *un = VTOUNION(ap->a_dvp); 839 struct vnode *dvp = un->un_uppervp; 840 841 if (dvp) { 842 int error; 843 struct vnode *vp; 844 845 VREF(dvp); 846 VOP_LOCK(dvp); 847 vput(ap->a_dvp); 848 error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap); 849 if (error) 850 return (error); 851 852 VOP_UNLOCK(vp); 853 error = union_allocvp( 854 ap->a_vpp, 855 ap->a_dvp->v_mount, 856 ap->a_dvp, 857 NULLVP, 858 ap->a_cnp, 859 vp, 860 NULLVP); 861 if (error) 862 vrele(vp); 863 return (error); 864 } 865 866 vput(ap->a_dvp); 867 return (EROFS); 868 } 869 870 int 871 union_rmdir(ap) 872 struct vop_rmdir_args /* { 873 struct vnode *a_dvp; 874 struct vnode *a_vp; 875 struct componentname *a_cnp; 876 } */ *ap; 877 { 878 int error; 879 struct union_node *dun = VTOUNION(ap->a_dvp); 880 struct union_node *un = VTOUNION(ap->a_vp); 881 882 if (dun->un_uppervp && un->un_uppervp) { 883 struct vnode *dvp = dun->un_uppervp; 884 struct vnode *vp = un->un_uppervp; 885 886 VREF(dvp); 887 VOP_LOCK(dvp); 888 vput(ap->a_dvp); 889 VREF(vp); 890 VOP_LOCK(vp); 891 vput(ap->a_vp); 892 893 error = VOP_REMOVE(dvp, vp, ap->a_cnp); 894 } else { 895 /* 896 * XXX: should create a whiteout here 897 */ 898 vput(ap->a_dvp); 899 vput(ap->a_vp); 900 error = EROFS; 901 } 902 903 return (error); 904 } 905 906 int 907 union_symlink(ap) 908 struct vop_symlink_args /* { 909 struct vnode *a_dvp; 910 struct vnode **a_vpp; 911 struct componentname *a_cnp; 912 struct vattr *a_vap; 913 char *a_target; 914 } */ *ap; 915 { 916 struct union_node *un = VTOUNION(ap->a_dvp); 917 struct vnode *dvp = un->un_uppervp; 918 919 if (dvp) { 920 int error; 921 struct vnode *vp; 922 struct mount *mp = ap->a_dvp->v_mount; 923 924 VREF(dvp); 925 VOP_LOCK(dvp); 926 vput(ap->a_dvp); 927 error = VOP_SYMLINK(dvp, &vp, ap->a_cnp, 928 ap->a_vap, ap->a_target); 929 *ap->a_vpp = NULLVP; 930 return (error); 931 } 932 933 vput(ap->a_dvp); 934 return (EROFS); 935 } 936 937 /* 938 * union_readdir works in concert with getdirentries and 939 * readdir(3) to provide a list of entries in the unioned 940 * directories. getdirentries is responsible for walking 941 * down the union stack. readdir(3) is responsible for 942 * eliminating duplicate names from the returned data stream. 943 */ 944 int 945 union_readdir(ap) 946 struct vop_readdir_args /* { 947 struct vnodeop_desc *a_desc; 948 struct vnode *a_vp; 949 struct uio *a_uio; 950 struct ucred *a_cred; 951 } */ *ap; 952 { 953 int error = 0; 954 struct union_node *un = VTOUNION(ap->a_vp); 955 956 if (un->un_uppervp) { 957 struct vnode *vp = OTHERVP(ap->a_vp); 958 959 VOP_LOCK(vp); 960 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 961 VOP_UNLOCK(vp); 962 } 963 964 return (error); 965 } 966 967 int 968 union_readlink(ap) 969 struct vop_readlink_args /* { 970 struct vnode *a_vp; 971 struct uio *a_uio; 972 struct ucred *a_cred; 973 } */ *ap; 974 { 975 int error; 976 struct vnode *vp = OTHERVP(ap->a_vp); 977 978 VOP_LOCK(vp); 979 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 980 VOP_UNLOCK(vp); 981 982 return (error); 983 } 984 985 int 986 union_abortop(ap) 987 struct vop_abortop_args /* { 988 struct vnode *a_dvp; 989 struct componentname *a_cnp; 990 } */ *ap; 991 { 992 int error; 993 struct vnode *vp = OTHERVP(ap->a_dvp); 994 struct union_node *un = VTOUNION(ap->a_dvp); 995 int islocked = un->un_flags & UN_LOCKED; 996 997 if (islocked) 998 VOP_LOCK(vp); 999 error = VOP_ABORTOP(vp, ap->a_cnp); 1000 if (islocked) 1001 VOP_UNLOCK(vp); 1002 1003 return (error); 1004 } 1005 1006 int 1007 union_inactive(ap) 1008 struct vop_inactive_args /* { 1009 struct vnode *a_vp; 1010 } */ *ap; 1011 { 1012 1013 /* 1014 * Do nothing (and _don't_ bypass). 1015 * Wait to vrele lowervp until reclaim, 1016 * so that until then our union_node is in the 1017 * cache and reusable. 1018 * 1019 * NEEDSWORK: Someday, consider inactive'ing 1020 * the lowervp and then trying to reactivate it 1021 * with capabilities (v_id) 1022 * like they do in the name lookup cache code. 1023 * That's too much work for now. 1024 */ 1025 1026 #ifdef DIAGNOSTIC 1027 struct union_node *un = VTOUNION(ap->a_vp); 1028 1029 if (un->un_flags & UN_LOCKED) 1030 panic("union: inactivating locked node"); 1031 #endif 1032 1033 return (0); 1034 } 1035 1036 int 1037 union_reclaim(ap) 1038 struct vop_reclaim_args /* { 1039 struct vnode *a_vp; 1040 } */ *ap; 1041 { 1042 struct vnode *vp = ap->a_vp; 1043 struct union_node *un = VTOUNION(vp); 1044 struct vnode *uppervp = un->un_uppervp; 1045 struct vnode *lowervp = un->un_lowervp; 1046 struct vnode *dirvp = un->un_dirvp; 1047 char *path = un->un_path; 1048 1049 /* 1050 * Note: in vop_reclaim, vp->v_op == dead_vnodeop_p, 1051 * so we can't call VOPs on ourself. 1052 */ 1053 /* After this assignment, this node will not be re-used. */ 1054 un->un_uppervp = NULLVP; 1055 un->un_lowervp = NULLVP; 1056 un->un_dirvp = NULLVP; 1057 un->un_path = NULL; 1058 union_freevp(vp); 1059 if (uppervp) 1060 vrele(uppervp); 1061 if (lowervp) 1062 vrele(lowervp); 1063 if (dirvp) 1064 vrele(dirvp); 1065 if (path) 1066 free(path, M_TEMP); 1067 return (0); 1068 } 1069 1070 int 1071 union_lock(ap) 1072 struct vop_lock_args *ap; 1073 { 1074 struct union_node *un = VTOUNION(ap->a_vp); 1075 1076 while (un->un_flags & UN_LOCKED) { 1077 #ifdef DIAGNOSTIC 1078 if (curproc && un->un_pid == curproc->p_pid && 1079 un->un_pid > -1 && curproc->p_pid > -1) 1080 panic("union: locking against myself"); 1081 #endif 1082 un->un_flags |= UN_WANT; 1083 sleep((caddr_t) &un->un_flags, PINOD); 1084 } 1085 un->un_flags |= UN_LOCKED; 1086 1087 #ifdef DIAGNOSTIC 1088 if (curproc) 1089 un->un_pid = curproc->p_pid; 1090 else 1091 un->un_pid = -1; 1092 #endif 1093 } 1094 1095 int 1096 union_unlock(ap) 1097 struct vop_lock_args *ap; 1098 { 1099 struct union_node *un = VTOUNION(ap->a_vp); 1100 1101 #ifdef DIAGNOSTIC 1102 if ((un->un_flags & UN_LOCKED) == 0) 1103 panic("union: unlock unlocked node"); 1104 if (curproc && un->un_pid != curproc->p_pid && 1105 curproc->p_pid > -1 && un->un_pid > -1) 1106 panic("union: unlocking other process's union node"); 1107 #endif 1108 1109 un->un_flags &= ~UN_LOCKED; 1110 if (un->un_flags & UN_WANT) { 1111 un->un_flags &= ~UN_WANT; 1112 wakeup((caddr_t) &un->un_flags); 1113 } 1114 1115 #ifdef DIAGNOSTIC 1116 un->un_pid = 0; 1117 #endif 1118 } 1119 1120 int 1121 union_bmap(ap) 1122 struct vop_bmap_args /* { 1123 struct vnode *a_vp; 1124 daddr_t a_bn; 1125 struct vnode **a_vpp; 1126 daddr_t *a_bnp; 1127 int *a_runp; 1128 } */ *ap; 1129 { 1130 int error; 1131 struct vnode *vp = OTHERVP(ap->a_vp); 1132 1133 VOP_LOCK(vp); 1134 error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp); 1135 VOP_UNLOCK(vp); 1136 1137 return (error); 1138 } 1139 1140 int 1141 union_print(ap) 1142 struct vop_print_args /* { 1143 struct vnode *a_vp; 1144 } */ *ap; 1145 { 1146 struct vnode *vp = ap->a_vp; 1147 1148 printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n", 1149 vp, UPPERVP(vp), LOWERVP(vp)); 1150 return (0); 1151 } 1152 1153 int 1154 union_islocked(ap) 1155 struct vop_islocked_args /* { 1156 struct vnode *a_vp; 1157 } */ *ap; 1158 { 1159 1160 return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0); 1161 } 1162 1163 int 1164 union_pathconf(ap) 1165 struct vop_pathconf_args /* { 1166 struct vnode *a_vp; 1167 int a_name; 1168 int *a_retval; 1169 } */ *ap; 1170 { 1171 int error; 1172 struct vnode *vp = OTHERVP(ap->a_vp); 1173 1174 VOP_LOCK(vp); 1175 error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval); 1176 VOP_UNLOCK(vp); 1177 1178 return (error); 1179 } 1180 1181 int 1182 union_advlock(ap) 1183 struct vop_advlock_args /* { 1184 struct vnode *a_vp; 1185 caddr_t a_id; 1186 int a_op; 1187 struct flock *a_fl; 1188 int a_flags; 1189 } */ *ap; 1190 { 1191 1192 return (VOP_ADVLOCK(OTHERVP(ap->a_vp), ap->a_id, ap->a_op, 1193 ap->a_fl, ap->a_flags)); 1194 } 1195 1196 1197 /* 1198 * XXX - vop_strategy must be hand coded because it has no 1199 * vnode in its arguments. 1200 * This goes away with a merged VM/buffer cache. 1201 */ 1202 int 1203 union_strategy(ap) 1204 struct vop_strategy_args /* { 1205 struct buf *a_bp; 1206 } */ *ap; 1207 { 1208 struct buf *bp = ap->a_bp; 1209 int error; 1210 struct vnode *savedvp; 1211 1212 savedvp = bp->b_vp; 1213 bp->b_vp = OTHERVP(bp->b_vp); 1214 1215 #ifdef DIAGNOSTIC 1216 if (bp->b_vp == NULLVP) 1217 panic("union_strategy: nil vp"); 1218 if (((bp->b_flags & B_READ) == 0) && 1219 (bp->b_vp == LOWERVP(savedvp))) 1220 panic("union_strategy: writing to lowervp"); 1221 #endif 1222 1223 error = VOP_STRATEGY(bp); 1224 bp->b_vp = savedvp; 1225 1226 return (error); 1227 } 1228 1229 /* 1230 * Global vfs data structures 1231 */ 1232 int (**union_vnodeop_p)(); 1233 struct vnodeopv_entry_desc union_vnodeop_entries[] = { 1234 { &vop_default_desc, vn_default_error }, 1235 { &vop_lookup_desc, union_lookup }, /* lookup */ 1236 { &vop_create_desc, union_create }, /* create */ 1237 { &vop_mknod_desc, union_mknod }, /* mknod */ 1238 { &vop_open_desc, union_open }, /* open */ 1239 { &vop_close_desc, union_close }, /* close */ 1240 { &vop_access_desc, union_access }, /* access */ 1241 { &vop_getattr_desc, union_getattr }, /* getattr */ 1242 { &vop_setattr_desc, union_setattr }, /* setattr */ 1243 { &vop_read_desc, union_read }, /* read */ 1244 { &vop_write_desc, union_write }, /* write */ 1245 { &vop_ioctl_desc, union_ioctl }, /* ioctl */ 1246 { &vop_select_desc, union_select }, /* select */ 1247 { &vop_mmap_desc, union_mmap }, /* mmap */ 1248 { &vop_fsync_desc, union_fsync }, /* fsync */ 1249 { &vop_seek_desc, union_seek }, /* seek */ 1250 { &vop_remove_desc, union_remove }, /* remove */ 1251 { &vop_link_desc, union_link }, /* link */ 1252 { &vop_rename_desc, union_rename }, /* rename */ 1253 { &vop_mkdir_desc, union_mkdir }, /* mkdir */ 1254 { &vop_rmdir_desc, union_rmdir }, /* rmdir */ 1255 { &vop_symlink_desc, union_symlink }, /* symlink */ 1256 { &vop_readdir_desc, union_readdir }, /* readdir */ 1257 { &vop_readlink_desc, union_readlink }, /* readlink */ 1258 { &vop_abortop_desc, union_abortop }, /* abortop */ 1259 { &vop_inactive_desc, union_inactive }, /* inactive */ 1260 { &vop_reclaim_desc, union_reclaim }, /* reclaim */ 1261 { &vop_lock_desc, union_lock }, /* lock */ 1262 { &vop_unlock_desc, union_unlock }, /* unlock */ 1263 { &vop_bmap_desc, union_bmap }, /* bmap */ 1264 { &vop_strategy_desc, union_strategy }, /* strategy */ 1265 { &vop_print_desc, union_print }, /* print */ 1266 { &vop_islocked_desc, union_islocked }, /* islocked */ 1267 { &vop_pathconf_desc, union_pathconf }, /* pathconf */ 1268 { &vop_advlock_desc, union_advlock }, /* advlock */ 1269 #ifdef notdef 1270 { &vop_blkatoff_desc, union_blkatoff }, /* blkatoff */ 1271 { &vop_valloc_desc, union_valloc }, /* valloc */ 1272 { &vop_vfree_desc, union_vfree }, /* vfree */ 1273 { &vop_truncate_desc, union_truncate }, /* truncate */ 1274 { &vop_update_desc, union_update }, /* update */ 1275 { &vop_bwrite_desc, union_bwrite }, /* bwrite */ 1276 #endif 1277 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 1278 }; 1279 struct vnodeopv_desc union_vnodeop_opv_desc = 1280 { &union_vnodeop_p, union_vnodeop_entries }; 1281