|
|
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) 1994 Jan-Simon Pendry ! 28: * Copyright (c) 1994 ! 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_subr.c 8.20 (Berkeley) 5/20/95 ! 63: */ ! 64: ! 65: #include <sys/param.h> ! 66: #include <sys/systm.h> ! 67: #include <sys/proc.h> ! 68: #include <sys/time.h> ! 69: #include <sys/kernel.h> ! 70: #include <sys/vnode.h> ! 71: #include <sys/namei.h> ! 72: #include <sys/malloc.h> ! 73: #include <sys/file.h> ! 74: #include <sys/filedesc.h> ! 75: #include <sys/queue.h> ! 76: #include <sys/mount.h> ! 77: #include <sys/stat.h> ! 78: #include <miscfs/union/union.h> ! 79: ! 80: #if DIAGNOSTIC ! 81: #include <sys/proc.h> ! 82: #endif ! 83: ! 84: /* must be power of two, otherwise change UNION_HASH() */ ! 85: #define NHASH 32 ! 86: ! 87: /* unsigned int ... */ ! 88: #define UNION_HASH(u, l) \ ! 89: (((((unsigned long) (u)) + ((unsigned long) l)) >> 8) & (NHASH-1)) ! 90: ! 91: static LIST_HEAD(unhead, union_node) unhead[NHASH]; ! 92: static int unvplock[NHASH]; ! 93: ! 94: int ! 95: union_init() ! 96: { ! 97: int i; ! 98: ! 99: for (i = 0; i < NHASH; i++) ! 100: LIST_INIT(&unhead[i]); ! 101: bzero((caddr_t) unvplock, sizeof(unvplock)); ! 102: } ! 103: ! 104: static int ! 105: union_list_lock(ix) ! 106: int ix; ! 107: { ! 108: ! 109: if (unvplock[ix] & UN_LOCKED) { ! 110: unvplock[ix] |= UN_WANT; ! 111: sleep((caddr_t) &unvplock[ix], PINOD); ! 112: return (1); ! 113: } ! 114: ! 115: unvplock[ix] |= UN_LOCKED; ! 116: ! 117: return (0); ! 118: } ! 119: ! 120: static void ! 121: union_list_unlock(ix) ! 122: int ix; ! 123: { ! 124: ! 125: unvplock[ix] &= ~UN_LOCKED; ! 126: ! 127: if (unvplock[ix] & UN_WANT) { ! 128: unvplock[ix] &= ~UN_WANT; ! 129: wakeup((caddr_t) &unvplock[ix]); ! 130: } ! 131: } ! 132: ! 133: void ! 134: union_updatevp(un, uppervp, lowervp) ! 135: struct union_node *un; ! 136: struct vnode *uppervp; ! 137: struct vnode *lowervp; ! 138: { ! 139: int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp); ! 140: int nhash = UNION_HASH(uppervp, lowervp); ! 141: int docache = (lowervp != NULLVP || uppervp != NULLVP); ! 142: int lhash, hhash, uhash; ! 143: ! 144: /* ! 145: * Ensure locking is ordered from lower to higher ! 146: * to avoid deadlocks. ! 147: */ ! 148: if (nhash < ohash) { ! 149: lhash = nhash; ! 150: uhash = ohash; ! 151: } else { ! 152: lhash = ohash; ! 153: uhash = nhash; ! 154: } ! 155: ! 156: if (lhash != uhash) ! 157: while (union_list_lock(lhash)) ! 158: continue; ! 159: ! 160: while (union_list_lock(uhash)) ! 161: continue; ! 162: ! 163: if (ohash != nhash || !docache) { ! 164: if (un->un_flags & UN_CACHED) { ! 165: un->un_flags &= ~UN_CACHED; ! 166: LIST_REMOVE(un, un_cache); ! 167: } ! 168: } ! 169: ! 170: if (ohash != nhash) ! 171: union_list_unlock(ohash); ! 172: ! 173: if (un->un_lowervp != lowervp) { ! 174: if (un->un_lowervp) { ! 175: vrele(un->un_lowervp); ! 176: if (un->un_path) { ! 177: _FREE(un->un_path, M_TEMP); ! 178: un->un_path = 0; ! 179: } ! 180: if (un->un_dirvp) { ! 181: vrele(un->un_dirvp); ! 182: un->un_dirvp = NULLVP; ! 183: } ! 184: } ! 185: un->un_lowervp = lowervp; ! 186: un->un_lowersz = VNOVAL; ! 187: } ! 188: ! 189: if (un->un_uppervp != uppervp) { ! 190: if (un->un_uppervp) ! 191: vrele(un->un_uppervp); ! 192: ! 193: un->un_uppervp = uppervp; ! 194: un->un_uppersz = VNOVAL; ! 195: } ! 196: ! 197: if (docache && (ohash != nhash)) { ! 198: LIST_INSERT_HEAD(&unhead[nhash], un, un_cache); ! 199: un->un_flags |= UN_CACHED; ! 200: } ! 201: ! 202: union_list_unlock(nhash); ! 203: } ! 204: ! 205: void ! 206: union_newlower(un, lowervp) ! 207: struct union_node *un; ! 208: struct vnode *lowervp; ! 209: { ! 210: ! 211: union_updatevp(un, un->un_uppervp, lowervp); ! 212: } ! 213: ! 214: void ! 215: union_newupper(un, uppervp) ! 216: struct union_node *un; ! 217: struct vnode *uppervp; ! 218: { ! 219: ! 220: union_updatevp(un, uppervp, un->un_lowervp); ! 221: } ! 222: ! 223: /* ! 224: * Keep track of size changes in the underlying vnodes. ! 225: * If the size changes, then callback to the vm layer ! 226: * giving priority to the upper layer size. ! 227: */ ! 228: void ! 229: union_newsize(vp, uppersz, lowersz) ! 230: struct vnode *vp; ! 231: off_t uppersz, lowersz; ! 232: { ! 233: struct union_node *un; ! 234: off_t sz; ! 235: ! 236: /* only interested in regular files */ ! 237: if (vp->v_type != VREG) ! 238: return; ! 239: ! 240: un = VTOUNION(vp); ! 241: sz = VNOVAL; ! 242: ! 243: if ((uppersz != VNOVAL) && (un->un_uppersz != uppersz)) { ! 244: un->un_uppersz = uppersz; ! 245: if (sz == VNOVAL) ! 246: sz = un->un_uppersz; ! 247: } ! 248: ! 249: if ((lowersz != VNOVAL) && (un->un_lowersz != lowersz)) { ! 250: un->un_lowersz = lowersz; ! 251: if (sz == VNOVAL) ! 252: sz = un->un_lowersz; ! 253: } ! 254: ! 255: if (sz != VNOVAL) { ! 256: #ifdef UNION_DIAGNOSTIC ! 257: printf("union: %s size now %ld\n", ! 258: uppersz != VNOVAL ? "upper" : "lower", (long) sz); ! 259: #endif ! 260: vnode_pager_setsize(vp, sz); ! 261: } ! 262: } ! 263: ! 264: /* ! 265: * allocate a union_node/vnode pair. the vnode is ! 266: * referenced and locked. the new vnode is returned ! 267: * via (vpp). (mp) is the mountpoint of the union filesystem, ! 268: * (dvp) is the parent directory where the upper layer object ! 269: * should exist (but doesn't) and (cnp) is the componentname ! 270: * information which is partially copied to allow the upper ! 271: * layer object to be created at a later time. (uppervp) ! 272: * and (lowervp) reference the upper and lower layer objects ! 273: * being mapped. either, but not both, can be nil. ! 274: * if supplied, (uppervp) is locked. ! 275: * the reference is either maintained in the new union_node ! 276: * object which is allocated, or they are vrele'd. ! 277: * ! 278: * all union_nodes are maintained on a singly-linked ! 279: * list. new nodes are only allocated when they cannot ! 280: * be found on this list. entries on the list are ! 281: * removed when the vfs reclaim entry is called. ! 282: * ! 283: * a single lock is kept for the entire list. this is ! 284: * needed because the getnewvnode() function can block ! 285: * waiting for a vnode to become free, in which case there ! 286: * may be more than one process trying to get the same ! 287: * vnode. this lock is only taken if we are going to ! 288: * call getnewvnode, since the kernel itself is single-threaded. ! 289: * ! 290: * if an entry is found on the list, then call vget() to ! 291: * take a reference. this is done because there may be ! 292: * zero references to it and so it needs to removed from ! 293: * the vnode free list. ! 294: */ ! 295: int ! 296: union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp, docache) ! 297: struct vnode **vpp; ! 298: struct mount *mp; ! 299: struct vnode *undvp; /* parent union vnode */ ! 300: struct vnode *dvp; /* may be null */ ! 301: struct componentname *cnp; /* may be null */ ! 302: struct vnode *uppervp; /* may be null */ ! 303: struct vnode *lowervp; /* may be null */ ! 304: int docache; ! 305: { ! 306: int error; ! 307: struct union_node *un; ! 308: struct union_node **pp; ! 309: struct vnode *xlowervp = NULLVP; ! 310: struct union_mount *um = MOUNTTOUNIONMOUNT(mp); ! 311: int hash; ! 312: int vflag; ! 313: int try; ! 314: ! 315: if (uppervp == NULLVP && lowervp == NULLVP) ! 316: panic("union: unidentifiable allocation"); ! 317: ! 318: if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) { ! 319: xlowervp = lowervp; ! 320: lowervp = NULLVP; ! 321: } ! 322: ! 323: /* detect the root vnode (and aliases) */ ! 324: vflag = 0; ! 325: if ((uppervp == um->um_uppervp) && ! 326: ((lowervp == NULLVP) || lowervp == um->um_lowervp)) { ! 327: if (lowervp == NULLVP) { ! 328: lowervp = um->um_lowervp; ! 329: if (lowervp != NULLVP) ! 330: VREF(lowervp); ! 331: } ! 332: vflag = VROOT; ! 333: } ! 334: ! 335: loop: ! 336: if (!docache) { ! 337: un = 0; ! 338: } else for (try = 0; try < 3; try++) { ! 339: switch (try) { ! 340: case 0: ! 341: if (lowervp == NULLVP) ! 342: continue; ! 343: hash = UNION_HASH(uppervp, lowervp); ! 344: break; ! 345: ! 346: case 1: ! 347: if (uppervp == NULLVP) ! 348: continue; ! 349: hash = UNION_HASH(uppervp, NULLVP); ! 350: break; ! 351: ! 352: case 2: ! 353: if (lowervp == NULLVP) ! 354: continue; ! 355: hash = UNION_HASH(NULLVP, lowervp); ! 356: break; ! 357: } ! 358: ! 359: while (union_list_lock(hash)) ! 360: continue; ! 361: ! 362: for (un = unhead[hash].lh_first; un != 0; ! 363: un = un->un_cache.le_next) { ! 364: if ((un->un_lowervp == lowervp || ! 365: un->un_lowervp == NULLVP) && ! 366: (un->un_uppervp == uppervp || ! 367: un->un_uppervp == NULLVP) && ! 368: (UNIONTOV(un)->v_mount == mp)) { ! 369: if (vget(UNIONTOV(un), 0, ! 370: cnp ? cnp->cn_proc : NULL)) { ! 371: union_list_unlock(hash); ! 372: goto loop; ! 373: } ! 374: break; ! 375: } ! 376: } ! 377: ! 378: union_list_unlock(hash); ! 379: ! 380: if (un) ! 381: break; ! 382: } ! 383: ! 384: if (un) { ! 385: /* ! 386: * Obtain a lock on the union_node. ! 387: * uppervp is locked, though un->un_uppervp ! 388: * may not be. this doesn't break the locking ! 389: * hierarchy since in the case that un->un_uppervp ! 390: * is not yet locked it will be vrele'd and replaced ! 391: * with uppervp. ! 392: */ ! 393: ! 394: if ((dvp != NULLVP) && (uppervp == dvp)) { ! 395: /* ! 396: * Access ``.'', so (un) will already ! 397: * be locked. Since this process has ! 398: * the lock on (uppervp) no other ! 399: * process can hold the lock on (un). ! 400: */ ! 401: #if DIAGNOSTIC ! 402: if ((un->un_flags & UN_LOCKED) == 0) ! 403: panic("union: . not locked"); ! 404: else if (current_proc() && un->un_pid != current_proc()->p_pid && ! 405: un->un_pid > -1 && current_proc()->p_pid > -1) ! 406: panic("union: allocvp not lock owner"); ! 407: #endif ! 408: } else { ! 409: if (un->un_flags & UN_LOCKED) { ! 410: vrele(UNIONTOV(un)); ! 411: un->un_flags |= UN_WANT; ! 412: sleep((caddr_t) &un->un_flags, PINOD); ! 413: goto loop; ! 414: } ! 415: un->un_flags |= UN_LOCKED; ! 416: ! 417: #if DIAGNOSTIC ! 418: if (current_proc()) ! 419: un->un_pid = current_proc()->p_pid; ! 420: else ! 421: un->un_pid = -1; ! 422: #endif ! 423: } ! 424: ! 425: /* ! 426: * At this point, the union_node is locked, ! 427: * un->un_uppervp may not be locked, and uppervp ! 428: * is locked or nil. ! 429: */ ! 430: ! 431: /* ! 432: * Save information about the upper layer. ! 433: */ ! 434: if (uppervp != un->un_uppervp) { ! 435: union_newupper(un, uppervp); ! 436: } else if (uppervp) { ! 437: vrele(uppervp); ! 438: } ! 439: ! 440: if (un->un_uppervp) { ! 441: un->un_flags |= UN_ULOCK; ! 442: un->un_flags &= ~UN_KLOCK; ! 443: } ! 444: ! 445: /* ! 446: * Save information about the lower layer. ! 447: * This needs to keep track of pathname ! 448: * and directory information which union_vn_create ! 449: * might need. ! 450: */ ! 451: if (lowervp != un->un_lowervp) { ! 452: union_newlower(un, lowervp); ! 453: if (cnp && (lowervp != NULLVP)) { ! 454: un->un_hash = cnp->cn_hash; ! 455: MALLOC(un->un_path, caddr_t, cnp->cn_namelen+1, ! 456: M_TEMP, M_WAITOK); ! 457: bcopy(cnp->cn_nameptr, un->un_path, ! 458: cnp->cn_namelen); ! 459: un->un_path[cnp->cn_namelen] = '\0'; ! 460: VREF(dvp); ! 461: un->un_dirvp = dvp; ! 462: } ! 463: } else if (lowervp) { ! 464: vrele(lowervp); ! 465: } ! 466: *vpp = UNIONTOV(un); ! 467: return (0); ! 468: } ! 469: ! 470: if (docache) { ! 471: /* ! 472: * otherwise lock the vp list while we call getnewvnode ! 473: * since that can block. ! 474: */ ! 475: hash = UNION_HASH(uppervp, lowervp); ! 476: ! 477: if (union_list_lock(hash)) ! 478: goto loop; ! 479: } ! 480: ! 481: error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp); ! 482: if (error) { ! 483: if (uppervp) { ! 484: if (dvp == uppervp) ! 485: vrele(uppervp); ! 486: else ! 487: vput(uppervp); ! 488: } ! 489: if (lowervp) ! 490: vrele(lowervp); ! 491: ! 492: goto out; ! 493: } ! 494: ! 495: MALLOC((*vpp)->v_data, void *, sizeof(struct union_node), ! 496: M_TEMP, M_WAITOK); ! 497: ! 498: (*vpp)->v_flag |= vflag; ! 499: if (uppervp) ! 500: (*vpp)->v_type = uppervp->v_type; ! 501: else ! 502: (*vpp)->v_type = lowervp->v_type; ! 503: un = VTOUNION(*vpp); ! 504: un->un_vnode = *vpp; ! 505: un->un_uppervp = uppervp; ! 506: un->un_uppersz = VNOVAL; ! 507: un->un_lowervp = lowervp; ! 508: un->un_lowersz = VNOVAL; ! 509: un->un_pvp = undvp; ! 510: if (undvp != NULLVP) ! 511: VREF(undvp); ! 512: un->un_dircache = 0; ! 513: un->un_openl = 0; ! 514: un->un_flags = UN_LOCKED; ! 515: if (un->un_uppervp) ! 516: un->un_flags |= UN_ULOCK; ! 517: #if DIAGNOSTIC ! 518: if (current_proc()) ! 519: un->un_pid = current_proc()->p_pid; ! 520: else ! 521: un->un_pid = -1; ! 522: #endif ! 523: if (cnp && (lowervp != NULLVP)) { ! 524: un->un_hash = cnp->cn_hash; ! 525: un->un_path = _MALLOC(cnp->cn_namelen+1, M_TEMP, M_WAITOK); ! 526: bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); ! 527: un->un_path[cnp->cn_namelen] = '\0'; ! 528: VREF(dvp); ! 529: un->un_dirvp = dvp; ! 530: } else { ! 531: un->un_hash = 0; ! 532: un->un_path = 0; ! 533: un->un_dirvp = 0; ! 534: } ! 535: ! 536: if (docache) { ! 537: LIST_INSERT_HEAD(&unhead[hash], un, un_cache); ! 538: un->un_flags |= UN_CACHED; ! 539: } ! 540: ! 541: if (xlowervp) ! 542: vrele(xlowervp); ! 543: ! 544: out: ! 545: if (docache) ! 546: union_list_unlock(hash); ! 547: ! 548: return (error); ! 549: } ! 550: ! 551: int ! 552: union_freevp(vp) ! 553: struct vnode *vp; ! 554: { ! 555: struct union_node *un = VTOUNION(vp); ! 556: ! 557: if (un->un_flags & UN_CACHED) { ! 558: un->un_flags &= ~UN_CACHED; ! 559: LIST_REMOVE(un, un_cache); ! 560: } ! 561: ! 562: if (un->un_pvp != NULLVP) ! 563: vrele(un->un_pvp); ! 564: if (un->un_uppervp != NULLVP) ! 565: vrele(un->un_uppervp); ! 566: if (un->un_lowervp != NULLVP) ! 567: vrele(un->un_lowervp); ! 568: if (un->un_dirvp != NULLVP) ! 569: vrele(un->un_dirvp); ! 570: if (un->un_path) ! 571: _FREE(un->un_path, M_TEMP); ! 572: ! 573: FREE(vp->v_data, M_TEMP); ! 574: vp->v_data = 0; ! 575: ! 576: return (0); ! 577: } ! 578: ! 579: /* ! 580: * copyfile. copy the vnode (fvp) to the vnode (tvp) ! 581: * using a sequence of reads and writes. both (fvp) ! 582: * and (tvp) are locked on entry and exit. ! 583: */ ! 584: int ! 585: union_copyfile(fvp, tvp, cred, p) ! 586: struct vnode *fvp; ! 587: struct vnode *tvp; ! 588: struct ucred *cred; ! 589: struct proc *p; ! 590: { ! 591: char *buf; ! 592: struct uio uio; ! 593: struct iovec iov; ! 594: int error = 0; ! 595: ! 596: /* ! 597: * strategy: ! 598: * allocate a buffer of size MAXPHYSIO. ! 599: * loop doing reads and writes, keeping track ! 600: * of the current uio offset. ! 601: * give up at the first sign of trouble. ! 602: */ ! 603: ! 604: uio.uio_procp = p; ! 605: uio.uio_segflg = UIO_SYSSPACE; ! 606: uio.uio_offset = 0; ! 607: ! 608: VOP_UNLOCK(fvp, 0, p); /* XXX */ ! 609: VOP_LEASE(fvp, p, cred, LEASE_READ); ! 610: vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ ! 611: VOP_UNLOCK(tvp, 0, p); /* XXX */ ! 612: VOP_LEASE(tvp, p, cred, LEASE_WRITE); ! 613: vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ ! 614: ! 615: buf = _MALLOC(MAXPHYSIO, M_TEMP, M_WAITOK); ! 616: ! 617: /* ugly loop follows... */ ! 618: do { ! 619: off_t offset = uio.uio_offset; ! 620: ! 621: uio.uio_iov = &iov; ! 622: uio.uio_iovcnt = 1; ! 623: iov.iov_base = buf; ! 624: iov.iov_len = MAXPHYSIO; ! 625: uio.uio_resid = iov.iov_len; ! 626: uio.uio_rw = UIO_READ; ! 627: error = VOP_READ(fvp, &uio, 0, cred); ! 628: ! 629: if (error == 0) { ! 630: uio.uio_iov = &iov; ! 631: uio.uio_iovcnt = 1; ! 632: iov.iov_base = buf; ! 633: iov.iov_len = MAXPHYSIO - uio.uio_resid; ! 634: uio.uio_offset = offset; ! 635: uio.uio_rw = UIO_WRITE; ! 636: uio.uio_resid = iov.iov_len; ! 637: ! 638: if (uio.uio_resid == 0) ! 639: break; ! 640: ! 641: do { ! 642: error = VOP_WRITE(tvp, &uio, 0, cred); ! 643: } while ((uio.uio_resid > 0) && (error == 0)); ! 644: } ! 645: ! 646: } while (error == 0); ! 647: ! 648: _FREE(buf, M_TEMP); ! 649: return (error); ! 650: } ! 651: ! 652: /* ! 653: * (un) is assumed to be locked on entry and remains ! 654: * locked on exit. ! 655: */ ! 656: int ! 657: union_copyup(un, docopy, cred, p) ! 658: struct union_node *un; ! 659: int docopy; ! 660: struct ucred *cred; ! 661: struct proc *p; ! 662: { ! 663: int error; ! 664: struct vnode *lvp, *uvp; ! 665: ! 666: error = union_vn_create(&uvp, un, p); ! 667: if (error) ! 668: return (error); ! 669: ! 670: /* at this point, uppervp is locked */ ! 671: union_newupper(un, uvp); ! 672: un->un_flags |= UN_ULOCK; ! 673: ! 674: lvp = un->un_lowervp; ! 675: ! 676: if (docopy) { ! 677: /* ! 678: * XX - should not ignore errors ! 679: * from VOP_CLOSE ! 680: */ ! 681: vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p); ! 682: error = VOP_OPEN(lvp, FREAD, cred, p); ! 683: if (error == 0) { ! 684: error = union_copyfile(lvp, uvp, cred, p); ! 685: VOP_UNLOCK(lvp, 0, p); ! 686: (void) VOP_CLOSE(lvp, FREAD, cred, p); ! 687: } ! 688: #ifdef UNION_DIAGNOSTIC ! 689: if (error == 0) ! 690: uprintf("union: copied up %s\n", un->un_path); ! 691: #endif ! 692: ! 693: } ! 694: un->un_flags &= ~UN_ULOCK; ! 695: VOP_UNLOCK(uvp, 0, p); ! 696: union_vn_close(uvp, FWRITE, cred, p); ! 697: vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY, p); ! 698: un->un_flags |= UN_ULOCK; ! 699: ! 700: /* ! 701: * Subsequent IOs will go to the top layer, so ! 702: * call close on the lower vnode and open on the ! 703: * upper vnode to ensure that the filesystem keeps ! 704: * its references counts right. This doesn't do ! 705: * the right thing with (cred) and (FREAD) though. ! 706: * Ignoring error returns is not right, either. ! 707: */ ! 708: if (error == 0) { ! 709: int i; ! 710: ! 711: for (i = 0; i < un->un_openl; i++) { ! 712: (void) VOP_CLOSE(lvp, FREAD, cred, p); ! 713: (void) VOP_OPEN(uvp, FREAD, cred, p); ! 714: } ! 715: un->un_openl = 0; ! 716: } ! 717: ! 718: return (error); ! 719: ! 720: } ! 721: ! 722: static int ! 723: union_relookup(um, dvp, vpp, cnp, cn, path, pathlen) ! 724: struct union_mount *um; ! 725: struct vnode *dvp; ! 726: struct vnode **vpp; ! 727: struct componentname *cnp; ! 728: struct componentname *cn; ! 729: char *path; ! 730: int pathlen; ! 731: { ! 732: int error; ! 733: ! 734: /* ! 735: * A new componentname structure must be faked up because ! 736: * there is no way to know where the upper level cnp came ! 737: * from or what it is being used for. This must duplicate ! 738: * some of the work done by NDINIT, some of the work done ! 739: * by namei, some of the work done by lookup and some of ! 740: * the work done by VOP_LOOKUP when given a CREATE flag. ! 741: * Conclusion: Horrible. ! 742: * ! 743: * The pathname buffer will be FREEed by VOP_MKDIR. ! 744: */ ! 745: cn->cn_namelen = pathlen; ! 746: cn->cn_pnbuf = _MALLOC_ZONE(cn->cn_namelen+1, M_NAMEI, M_WAITOK); ! 747: cn->cn_pnlen = cn->cn_namelen+1; ! 748: bcopy(path, cn->cn_pnbuf, cn->cn_namelen); ! 749: cn->cn_pnbuf[cn->cn_namelen] = '\0'; ! 750: ! 751: cn->cn_nameiop = CREATE; ! 752: cn->cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN); ! 753: cn->cn_proc = cnp->cn_proc; ! 754: if (um->um_op == UNMNT_ABOVE) ! 755: cn->cn_cred = cnp->cn_cred; ! 756: else ! 757: cn->cn_cred = um->um_cred; ! 758: cn->cn_nameptr = cn->cn_pnbuf; ! 759: cn->cn_hash = cnp->cn_hash; ! 760: cn->cn_consume = cnp->cn_consume; ! 761: ! 762: VREF(dvp); ! 763: error = relookup(dvp, vpp, cn); ! 764: if (!error) ! 765: vrele(dvp); ! 766: ! 767: return (error); ! 768: } ! 769: ! 770: /* ! 771: * Create a shadow directory in the upper layer. ! 772: * The new vnode is returned locked. ! 773: * ! 774: * (um) points to the union mount structure for access to the ! 775: * the mounting process's credentials. ! 776: * (dvp) is the directory in which to create the shadow directory. ! 777: * it is unlocked on entry and exit. ! 778: * (cnp) is the componentname to be created. ! 779: * (vpp) is the returned newly created shadow directory, which ! 780: * is returned locked. ! 781: */ ! 782: int ! 783: union_mkshadow(um, dvp, cnp, vpp) ! 784: struct union_mount *um; ! 785: struct vnode *dvp; ! 786: struct componentname *cnp; ! 787: struct vnode **vpp; ! 788: { ! 789: int error; ! 790: struct vattr va; ! 791: struct proc *p = cnp->cn_proc; ! 792: struct componentname cn; ! 793: ! 794: error = union_relookup(um, dvp, vpp, cnp, &cn, ! 795: cnp->cn_nameptr, cnp->cn_namelen); ! 796: if (error) ! 797: return (error); ! 798: ! 799: if (*vpp) { ! 800: VOP_ABORTOP(dvp, &cn); ! 801: VOP_UNLOCK(dvp, 0, p); ! 802: vrele(*vpp); ! 803: *vpp = NULLVP; ! 804: return (EEXIST); ! 805: } ! 806: ! 807: /* ! 808: * policy: when creating the shadow directory in the ! 809: * upper layer, create it owned by the user who did ! 810: * the mount, group from parent directory, and mode ! 811: * 777 modified by umask (ie mostly identical to the ! 812: * mkdir syscall). (jsp, kb) ! 813: */ ! 814: ! 815: VATTR_NULL(&va); ! 816: va.va_type = VDIR; ! 817: va.va_mode = um->um_cmode; ! 818: ! 819: /* VOP_LEASE: dvp is locked */ ! 820: VOP_LEASE(dvp, p, cn.cn_cred, LEASE_WRITE); ! 821: ! 822: error = VOP_MKDIR(dvp, vpp, &cn, &va); ! 823: return (error); ! 824: } ! 825: ! 826: /* ! 827: * Create a whiteout entry in the upper layer. ! 828: * ! 829: * (um) points to the union mount structure for access to the ! 830: * the mounting process's credentials. ! 831: * (dvp) is the directory in which to create the whiteout. ! 832: * it is locked on entry and exit. ! 833: * (cnp) is the componentname to be created. ! 834: */ ! 835: int ! 836: union_mkwhiteout(um, dvp, cnp, path) ! 837: struct union_mount *um; ! 838: struct vnode *dvp; ! 839: struct componentname *cnp; ! 840: char *path; ! 841: { ! 842: int error; ! 843: struct vattr va; ! 844: struct proc *p = cnp->cn_proc; ! 845: struct vnode *wvp; ! 846: struct componentname cn; ! 847: ! 848: VOP_UNLOCK(dvp, 0, p); ! 849: error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path)); ! 850: if (error) { ! 851: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); ! 852: return (error); ! 853: } ! 854: ! 855: if (wvp) { ! 856: VOP_ABORTOP(dvp, &cn); ! 857: vrele(dvp); ! 858: vrele(wvp); ! 859: return (EEXIST); ! 860: } ! 861: ! 862: /* VOP_LEASE: dvp is locked */ ! 863: VOP_LEASE(dvp, p, p->p_ucred, LEASE_WRITE); ! 864: ! 865: error = VOP_WHITEOUT(dvp, &cn, CREATE); ! 866: if (error) ! 867: VOP_ABORTOP(dvp, &cn); ! 868: ! 869: vrele(dvp); ! 870: ! 871: return (error); ! 872: } ! 873: ! 874: /* ! 875: * union_vn_create: creates and opens a new shadow file ! 876: * on the upper union layer. this function is similar ! 877: * in spirit to calling vn_open but it avoids calling namei(). ! 878: * the problem with calling namei is that a) it locks too many ! 879: * things, and b) it doesn't start at the "right" directory, ! 880: * whereas relookup is told where to start. ! 881: */ ! 882: int ! 883: union_vn_create(vpp, un, p) ! 884: struct vnode **vpp; ! 885: struct union_node *un; ! 886: struct proc *p; ! 887: { ! 888: struct vnode *vp; ! 889: struct ucred *cred = p->p_ucred; ! 890: struct vattr vat; ! 891: struct vattr *vap = &vat; ! 892: int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL); ! 893: int error; ! 894: int cmode = UN_FILEMODE & ~p->p_fd->fd_cmask; ! 895: char *cp; ! 896: struct componentname cn; ! 897: ! 898: *vpp = NULLVP; ! 899: ! 900: /* ! 901: * Build a new componentname structure (for the same ! 902: * reasons outlines in union_mkshadow). ! 903: * The difference here is that the file is owned by ! 904: * the current user, rather than by the person who ! 905: * did the mount, since the current user needs to be ! 906: * able to write the file (that's why it is being ! 907: * copied in the first place). ! 908: */ ! 909: cn.cn_namelen = strlen(un->un_path); ! 910: cn.cn_pnbuf = (caddr_t) _MALLOC_ZONE(cn.cn_namelen+1, ! 911: M_NAMEI, M_WAITOK); ! 912: cn.cn_pnlen = cn.cn_namelen+1; ! 913: bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1); ! 914: cn.cn_nameiop = CREATE; ! 915: cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN); ! 916: cn.cn_proc = p; ! 917: cn.cn_cred = p->p_ucred; ! 918: cn.cn_nameptr = cn.cn_pnbuf; ! 919: cn.cn_hash = un->un_hash; ! 920: cn.cn_consume = 0; ! 921: ! 922: VREF(un->un_dirvp); ! 923: if (error = relookup(un->un_dirvp, &vp, &cn)) ! 924: return (error); ! 925: vrele(un->un_dirvp); ! 926: ! 927: if (vp) { ! 928: VOP_ABORTOP(un->un_dirvp, &cn); ! 929: if (un->un_dirvp == vp) ! 930: vrele(un->un_dirvp); ! 931: else ! 932: vput(un->un_dirvp); ! 933: vrele(vp); ! 934: return (EEXIST); ! 935: } ! 936: ! 937: /* ! 938: * Good - there was no race to create the file ! 939: * so go ahead and create it. The permissions ! 940: * on the file will be 0666 modified by the ! 941: * current user's umask. Access to the file, while ! 942: * it is unioned, will require access to the top *and* ! 943: * bottom files. Access when not unioned will simply ! 944: * require access to the top-level file. ! 945: * TODO: confirm choice of access permissions. ! 946: */ ! 947: VATTR_NULL(vap); ! 948: vap->va_type = VREG; ! 949: vap->va_mode = cmode; ! 950: VOP_LEASE(un->un_dirvp, p, cred, LEASE_WRITE); ! 951: if (error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap)) ! 952: return (error); ! 953: ! 954: if (error = VOP_OPEN(vp, fmode, cred, p)) { ! 955: vput(vp); ! 956: return (error); ! 957: } ! 958: ! 959: vp->v_writecount++; ! 960: *vpp = vp; ! 961: return (0); ! 962: } ! 963: ! 964: int ! 965: union_vn_close(vp, fmode, cred, p) ! 966: struct vnode *vp; ! 967: int fmode; ! 968: struct ucred *cred; ! 969: struct proc *p; ! 970: { ! 971: ! 972: if (fmode & FWRITE) ! 973: --vp->v_writecount; ! 974: return (VOP_CLOSE(vp, fmode, cred, p)); ! 975: } ! 976: ! 977: void ! 978: union_removed_upper(un) ! 979: struct union_node *un; ! 980: { ! 981: struct proc *p = current_proc(); /* XXX */ ! 982: ! 983: union_newupper(un, NULLVP); ! 984: if (un->un_flags & UN_CACHED) { ! 985: un->un_flags &= ~UN_CACHED; ! 986: LIST_REMOVE(un, un_cache); ! 987: } ! 988: ! 989: if (un->un_flags & UN_ULOCK) { ! 990: un->un_flags &= ~UN_ULOCK; ! 991: VOP_UNLOCK(un->un_uppervp, 0, p); ! 992: } ! 993: } ! 994: ! 995: #if 0 ! 996: struct vnode * ! 997: union_lowervp(vp) ! 998: struct vnode *vp; ! 999: { ! 1000: struct union_node *un = VTOUNION(vp); ! 1001: ! 1002: if ((un->un_lowervp != NULLVP) && ! 1003: (vp->v_type == un->un_lowervp->v_type)) { ! 1004: if (vget(un->un_lowervp, 0) == 0) ! 1005: return (un->un_lowervp); ! 1006: } ! 1007: ! 1008: return (NULLVP); ! 1009: } ! 1010: #endif ! 1011: ! 1012: /* ! 1013: * determine whether a whiteout is needed ! 1014: * during a remove/rmdir operation. ! 1015: */ ! 1016: int ! 1017: union_dowhiteout(un, cred, p) ! 1018: struct union_node *un; ! 1019: struct ucred *cred; ! 1020: struct proc *p; ! 1021: { ! 1022: struct vattr va; ! 1023: ! 1024: if (un->un_lowervp != NULLVP) ! 1025: return (1); ! 1026: ! 1027: if (VOP_GETATTR(un->un_uppervp, &va, cred, p) == 0 && ! 1028: (va.va_flags & OPAQUE)) ! 1029: return (1); ! 1030: ! 1031: return (0); ! 1032: } ! 1033: ! 1034: static void ! 1035: union_dircache_r(vp, vppp, cntp) ! 1036: struct vnode *vp; ! 1037: struct vnode ***vppp; ! 1038: int *cntp; ! 1039: { ! 1040: struct union_node *un; ! 1041: ! 1042: if (vp->v_op != union_vnodeop_p) { ! 1043: if (vppp) { ! 1044: VREF(vp); ! 1045: *(*vppp)++ = vp; ! 1046: if (--(*cntp) == 0) ! 1047: panic("union: dircache table too small"); ! 1048: } else { ! 1049: (*cntp)++; ! 1050: } ! 1051: ! 1052: return; ! 1053: } ! 1054: ! 1055: un = VTOUNION(vp); ! 1056: if (un->un_uppervp != NULLVP) ! 1057: union_dircache_r(un->un_uppervp, vppp, cntp); ! 1058: if (un->un_lowervp != NULLVP) ! 1059: union_dircache_r(un->un_lowervp, vppp, cntp); ! 1060: } ! 1061: ! 1062: struct vnode * ! 1063: union_dircache(vp, p) ! 1064: struct vnode *vp; ! 1065: struct proc *p; ! 1066: { ! 1067: int cnt; ! 1068: struct vnode *nvp; ! 1069: struct vnode **vpp; ! 1070: struct vnode **dircache; ! 1071: struct union_node *un; ! 1072: int error; ! 1073: ! 1074: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1075: dircache = VTOUNION(vp)->un_dircache; ! 1076: ! 1077: nvp = NULLVP; ! 1078: ! 1079: if (dircache == 0) { ! 1080: cnt = 0; ! 1081: union_dircache_r(vp, 0, &cnt); ! 1082: cnt++; ! 1083: dircache = (struct vnode **) ! 1084: _MALLOC(cnt * sizeof(struct vnode *), ! 1085: M_TEMP, M_WAITOK); ! 1086: vpp = dircache; ! 1087: union_dircache_r(vp, &vpp, &cnt); ! 1088: *vpp = NULLVP; ! 1089: vpp = dircache + 1; ! 1090: } else { ! 1091: vpp = dircache; ! 1092: do { ! 1093: if (*vpp++ == VTOUNION(vp)->un_uppervp) ! 1094: break; ! 1095: } while (*vpp != NULLVP); ! 1096: } ! 1097: ! 1098: if (*vpp == NULLVP) ! 1099: goto out; ! 1100: ! 1101: vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p); ! 1102: VREF(*vpp); ! 1103: error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, 0, *vpp, NULLVP, 0); ! 1104: if (error) ! 1105: goto out; ! 1106: ! 1107: VTOUNION(vp)->un_dircache = 0; ! 1108: un = VTOUNION(nvp); ! 1109: un->un_dircache = dircache; ! 1110: ! 1111: out: ! 1112: VOP_UNLOCK(vp, 0, p); ! 1113: return (nvp); ! 1114: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.