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