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