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

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

unix.superglobalmegacorp.com

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