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