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

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

unix.superglobalmegacorp.com

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