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