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

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: 
1.1.1.2 ! root      959:        if (++vp->v_writecount <= 0)
        !           960:                panic("union: v_writecount");
1.1       root      961:        *vpp = vp;
                    962:        return (0);
                    963: }
                    964: 
                    965: int
                    966: union_vn_close(vp, fmode, cred, p)
                    967:        struct vnode *vp;
                    968:        int fmode;
                    969:        struct ucred *cred;
                    970:        struct proc *p;
                    971: {
                    972: 
                    973:        if (fmode & FWRITE)
                    974:                --vp->v_writecount;
                    975:        return (VOP_CLOSE(vp, fmode, cred, p));
                    976: }
                    977: 
                    978: void
                    979: union_removed_upper(un)
                    980:        struct union_node *un;
                    981: {
                    982:        struct proc *p = current_proc();        /* XXX */
                    983: 
                    984:        union_newupper(un, NULLVP);
                    985:        if (un->un_flags & UN_CACHED) {
                    986:                un->un_flags &= ~UN_CACHED;
                    987:                LIST_REMOVE(un, un_cache);
                    988:        }
                    989: 
                    990:        if (un->un_flags & UN_ULOCK) {
                    991:                un->un_flags &= ~UN_ULOCK;
                    992:                VOP_UNLOCK(un->un_uppervp, 0, p);
                    993:        }
                    994: }
                    995: 
                    996: #if 0
                    997: struct vnode *
                    998: union_lowervp(vp)
                    999:        struct vnode *vp;
                   1000: {
                   1001:        struct union_node *un = VTOUNION(vp);
                   1002: 
                   1003:        if ((un->un_lowervp != NULLVP) &&
                   1004:            (vp->v_type == un->un_lowervp->v_type)) {
                   1005:                if (vget(un->un_lowervp, 0) == 0)
                   1006:                        return (un->un_lowervp);
                   1007:        }
                   1008: 
                   1009:        return (NULLVP);
                   1010: }
                   1011: #endif
                   1012: 
                   1013: /*
                   1014:  * determine whether a whiteout is needed
                   1015:  * during a remove/rmdir operation.
                   1016:  */
                   1017: int
                   1018: union_dowhiteout(un, cred, p)
                   1019:        struct union_node *un;
                   1020:        struct ucred *cred;
                   1021:        struct proc *p;
                   1022: {
                   1023:        struct vattr va;
                   1024: 
                   1025:        if (un->un_lowervp != NULLVP)
                   1026:                return (1);
                   1027: 
                   1028:        if (VOP_GETATTR(un->un_uppervp, &va, cred, p) == 0 &&
                   1029:            (va.va_flags & OPAQUE))
                   1030:                return (1);
                   1031: 
                   1032:        return (0);
                   1033: }
                   1034: 
                   1035: static void
                   1036: union_dircache_r(vp, vppp, cntp)
                   1037:        struct vnode *vp;
                   1038:        struct vnode ***vppp;
                   1039:        int *cntp;
                   1040: {
                   1041:        struct union_node *un;
                   1042: 
                   1043:        if (vp->v_op != union_vnodeop_p) {
                   1044:                if (vppp) {
                   1045:                        VREF(vp);
                   1046:                        *(*vppp)++ = vp;
                   1047:                        if (--(*cntp) == 0)
                   1048:                                panic("union: dircache table too small");
                   1049:                } else {
                   1050:                        (*cntp)++;
                   1051:                }
                   1052: 
                   1053:                return;
                   1054:        }
                   1055: 
                   1056:        un = VTOUNION(vp);
                   1057:        if (un->un_uppervp != NULLVP)
                   1058:                union_dircache_r(un->un_uppervp, vppp, cntp);
                   1059:        if (un->un_lowervp != NULLVP)
                   1060:                union_dircache_r(un->un_lowervp, vppp, cntp);
                   1061: }
                   1062: 
                   1063: struct vnode *
                   1064: union_dircache(vp, p)
                   1065:        struct vnode *vp;
                   1066:        struct proc *p;
                   1067: {
                   1068:        int cnt;
                   1069:        struct vnode *nvp;
                   1070:        struct vnode **vpp;
                   1071:        struct vnode **dircache;
                   1072:        struct union_node *un;
                   1073:        int error;
                   1074: 
                   1075:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
                   1076:        dircache = VTOUNION(vp)->un_dircache;
                   1077: 
                   1078:        nvp = NULLVP;
                   1079: 
                   1080:        if (dircache == 0) {
                   1081:                cnt = 0;
                   1082:                union_dircache_r(vp, 0, &cnt);
                   1083:                cnt++;
                   1084:                dircache = (struct vnode **)
                   1085:                                _MALLOC(cnt * sizeof(struct vnode *),
                   1086:                                        M_TEMP, M_WAITOK);
                   1087:                vpp = dircache;
                   1088:                union_dircache_r(vp, &vpp, &cnt);
                   1089:                *vpp = NULLVP;
                   1090:                vpp = dircache + 1;
                   1091:        } else {
                   1092:                vpp = dircache;
                   1093:                do {
                   1094:                        if (*vpp++ == VTOUNION(vp)->un_uppervp)
                   1095:                                break;
                   1096:                } while (*vpp != NULLVP);
                   1097:        }
                   1098: 
                   1099:        if (*vpp == NULLVP)
                   1100:                goto out;
                   1101: 
                   1102:        vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p);
                   1103:        VREF(*vpp);
                   1104:        error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, 0, *vpp, NULLVP, 0);
                   1105:        if (error)
                   1106:                goto out;
                   1107: 
                   1108:        VTOUNION(vp)->un_dircache = 0;
                   1109:        un = VTOUNION(nvp);
                   1110:        un->un_dircache = dircache;
                   1111: 
                   1112: out:
                   1113:        VOP_UNLOCK(vp, 0, p);
                   1114:        return (nvp);
                   1115: }

unix.superglobalmegacorp.com

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