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