Annotation of XNU/bsd/miscfs/union/union_subr.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.