Annotation of kernel/bsd/miscfs/union/union_vfsops.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
                     26: /*
                     27:  * Copyright (c) 1994, 1995 The Regents of the University of California.
                     28:  * Copyright (c) 1994, 1995 Jan-Simon Pendry.
                     29:  * All rights reserved.
                     30:  *
                     31:  * This code is derived from software donated 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_vfsops.c      8.20 (Berkeley) 5/20/95
                     63:  */
                     64: 
                     65: /*
                     66:  * Union Layer
                     67:  */
                     68: 
                     69: #include <sys/param.h>
                     70: #include <sys/systm.h>
                     71: #include <sys/time.h>
                     72: #include <sys/types.h>
                     73: #include <sys/proc.h>
                     74: #include <sys/vnode.h>
                     75: #include <sys/mount.h>
                     76: #include <sys/namei.h>
                     77: #include <sys/malloc.h>
                     78: #include <sys/filedesc.h>
                     79: #include <sys/queue.h>
                     80: #include <miscfs/union/union.h>
                     81: 
                     82: /*
                     83:  * Mount union filesystem
                     84:  */
                     85: int
                     86: union_mount(mp, path, data, ndp, p)
                     87:        struct mount *mp;
                     88:        char *path;
                     89:        caddr_t data;
                     90:        struct nameidata *ndp;
                     91:        struct proc *p;
                     92: {
                     93:        int error = 0;
                     94:        struct union_args args;
                     95:        struct vnode *lowerrootvp = NULLVP;
                     96:        struct vnode *upperrootvp = NULLVP;
                     97:        struct union_mount *um = 0;
                     98:        struct ucred *cred = 0;
                     99:        struct ucred *scred;
                    100:        struct vattr va;
                    101:        char *cp;
                    102:        int len;
                    103:        u_int size;
                    104: 
                    105: #ifdef UNION_DIAGNOSTIC
                    106:        printf("union_mount(mp = %x)\n", mp);
                    107: #endif
                    108: 
                    109:        /*
                    110:         * Update is a no-op
                    111:         */
                    112:        if (mp->mnt_flag & MNT_UPDATE) {
                    113:                /*
                    114:                 * Need to provide.
                    115:                 * 1. a way to convert between rdonly and rdwr mounts.
                    116:                 * 2. support for nfs exports.
                    117:                 */
                    118:                error = EOPNOTSUPP;
                    119:                goto bad;
                    120:        }
                    121: 
                    122:        /*
                    123:         * Get argument
                    124:         */
                    125:        if (error = copyin(data, (caddr_t)&args, sizeof(struct union_args)))
                    126:                goto bad;
                    127: 
                    128:        lowerrootvp = mp->mnt_vnodecovered;
                    129:        VREF(lowerrootvp);
                    130: 
                    131:        /*
                    132:         * Find upper node.
                    133:         */
                    134:        NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
                    135:               UIO_USERSPACE, args.target, p);
                    136: 
                    137:        if (error = namei(ndp))
                    138:                goto bad;
                    139: 
                    140:        upperrootvp = ndp->ni_vp;
                    141:        vrele(ndp->ni_dvp);
                    142:        ndp->ni_dvp = NULL;
                    143: 
                    144:        if (upperrootvp->v_type != VDIR) {
                    145:                error = EINVAL;
                    146:                goto bad;
                    147:        }
                    148:        
                    149: //     um = (struct union_mount *) malloc(sizeof(struct union_mount),
                    150: //                             M_UFSMNT, M_WAITOK);    /* XXX */
                    151:        MALLOC(um, struct union_mount *, sizeof(struct union_mount),
                    152:                                M_UFSMNT, M_WAITOK);
                    153: 
                    154:        /*
                    155:         * Keep a held reference to the target vnodes.
                    156:         * They are vrele'd in union_unmount.
                    157:         *
                    158:         * Depending on the _BELOW flag, the filesystems are
                    159:         * viewed in a different order.  In effect, this is the
                    160:         * same as providing a mount under option to the mount syscall.
                    161:         */
                    162: 
                    163:        um->um_op = args.mntflags & UNMNT_OPMASK;
                    164:        switch (um->um_op) {
                    165:        case UNMNT_ABOVE:
                    166:                um->um_lowervp = lowerrootvp;
                    167:                um->um_uppervp = upperrootvp;
                    168:                break;
                    169: 
                    170:        case UNMNT_BELOW:
                    171:                um->um_lowervp = upperrootvp;
                    172:                um->um_uppervp = lowerrootvp;
                    173:                break;
                    174: 
                    175:        case UNMNT_REPLACE:
                    176:                vrele(lowerrootvp);
                    177:                lowerrootvp = NULLVP;
                    178:                um->um_uppervp = upperrootvp;
                    179:                um->um_lowervp = lowerrootvp;
                    180:                break;
                    181: 
                    182:        default:
                    183:                error = EINVAL;
                    184:                goto bad;
                    185:        }
                    186: 
                    187:        /*
                    188:         * Unless the mount is readonly, ensure that the top layer
                    189:         * supports whiteout operations
                    190:         */
                    191:        if ((mp->mnt_flag & MNT_RDONLY) == 0) {
                    192:                error = VOP_WHITEOUT(um->um_uppervp, (struct componentname *) 0, LOOKUP);
                    193:                if (error)
                    194:                        goto bad;
                    195:        }
                    196: 
                    197:        um->um_cred = p->p_ucred;
                    198:        crhold(um->um_cred);
                    199:        um->um_cmode = UN_DIRMODE &~ p->p_fd->fd_cmask;
                    200: 
                    201:        /*
                    202:         * Depending on what you think the MNT_LOCAL flag might mean,
                    203:         * you may want the && to be || on the conditional below.
                    204:         * At the moment it has been defined that the filesystem is
                    205:         * only local if it is all local, ie the MNT_LOCAL flag implies
                    206:         * that the entire namespace is local.  If you think the MNT_LOCAL
                    207:         * flag implies that some of the files might be stored locally
                    208:         * then you will want to change the conditional.
                    209:         */
                    210:        if (um->um_op == UNMNT_ABOVE) {
                    211:                if (((um->um_lowervp == NULLVP) ||
                    212:                     (um->um_lowervp->v_mount->mnt_flag & MNT_LOCAL)) &&
                    213:                    (um->um_uppervp->v_mount->mnt_flag & MNT_LOCAL))
                    214:                        mp->mnt_flag |= MNT_LOCAL;
                    215:        }
                    216: 
                    217:        /*
                    218:         * Copy in the upper layer's RDONLY flag.  This is for the benefit
                    219:         * of lookup() which explicitly checks the flag, rather than asking
                    220:         * the filesystem for it's own opinion.  This means, that an update
                    221:         * mount of the underlying filesystem to go from rdonly to rdwr
                    222:         * will leave the unioned view as read-only.
                    223:         */
                    224:        mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY);
                    225: 
                    226:        mp->mnt_data = (qaddr_t) um;
                    227:        vfs_getnewfsid(mp);
                    228: 
                    229:        (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
                    230:        bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
                    231: 
                    232:        switch (um->um_op) {
                    233:        case UNMNT_ABOVE:
                    234:                cp = "<above>:";
                    235:                break;
                    236:        case UNMNT_BELOW:
                    237:                cp = "<below>:";
                    238:                break;
                    239:        case UNMNT_REPLACE:
                    240:                cp = "";
                    241:                break;
                    242:        }
                    243:        len = strlen(cp);
                    244:        bcopy(cp, mp->mnt_stat.f_mntfromname, len);
                    245: 
                    246:        cp = mp->mnt_stat.f_mntfromname + len;
                    247:        len = MNAMELEN - len;
                    248: 
                    249:        (void) copyinstr(args.target, cp, len - 1, &size);
                    250:        bzero(cp + size, len - size);
                    251: 
                    252: #ifdef UNION_DIAGNOSTIC
                    253:        printf("union_mount: from %s, on %s\n",
                    254:                mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
                    255: #endif
                    256:        return (0);
                    257: 
                    258: bad:
                    259:        if (um)
                    260:                _FREE(um, M_UFSMNT);
                    261:        if (cred != NOCRED)
                    262:                crfree(cred);
                    263:        if (upperrootvp)
                    264:                vrele(upperrootvp);
                    265:        if (lowerrootvp)
                    266:                vrele(lowerrootvp);
                    267:        return (error);
                    268: }
                    269: 
                    270: /*
                    271:  * VFS start.  Nothing needed here - the start routine
                    272:  * on the underlying filesystem(s) will have been called
                    273:  * when that filesystem was mounted.
                    274:  */
                    275: int
                    276: union_start(mp, flags, p)
                    277:        struct mount *mp;
                    278:        int flags;
                    279:        struct proc *p;
                    280: {
                    281: 
                    282:        return (0);
                    283: }
                    284: 
                    285: /*
                    286:  * Free reference to union layer
                    287:  */
                    288: int
                    289: union_unmount(mp, mntflags, p)
                    290:        struct mount *mp;
                    291:        int mntflags;
                    292:        struct proc *p;
                    293: {
                    294:        struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
                    295:        struct vnode *um_rootvp;
                    296:        int error;
                    297:        int freeing;
                    298:        int flags = 0;
                    299:        struct ucred *cred;
                    300: 
                    301: #ifdef UNION_DIAGNOSTIC
                    302:        printf("union_unmount(mp = %x)\n", mp);
                    303: #endif
                    304: 
                    305:        if (mntflags & MNT_FORCE)
                    306:                flags |= FORCECLOSE;
                    307: 
                    308:        if (error = union_root(mp, &um_rootvp))
                    309:                return (error);
                    310: 
                    311:        /*
                    312:         * Keep flushing vnodes from the mount list.
                    313:         * This is needed because of the un_pvp held
                    314:         * reference to the parent vnode.
                    315:         * If more vnodes have been freed on a given pass,
                    316:         * the try again.  The loop will iterate at most
                    317:         * (d) times, where (d) is the maximum tree depth
                    318:         * in the filesystem.
                    319:         */
                    320:        for (freeing = 0; vflush(mp, um_rootvp, flags) != 0;) {
                    321:                struct vnode *vp;
                    322:                int n;
                    323: 
                    324:                /* count #vnodes held on mount list */
                    325:                for (n = 0, vp = mp->mnt_vnodelist.lh_first;
                    326:                                vp != NULLVP;
                    327:                                vp = vp->v_mntvnodes.le_next)
                    328:                        n++;
                    329: 
                    330:                /* if this is unchanged then stop */
                    331:                if (n == freeing)
                    332:                        break;
                    333: 
                    334:                /* otherwise try once more time */
                    335:                freeing = n;
                    336:        }
                    337: 
                    338:        /* At this point the root vnode should have a single reference */
                    339:        if (um_rootvp->v_usecount > 1) {
                    340:                vput(um_rootvp);
                    341:                return (EBUSY);
                    342:        }
                    343: 
                    344: #ifdef UNION_DIAGNOSTIC
                    345:        vprint("union root", um_rootvp);
                    346: #endif  
                    347:        /*
                    348:         * Discard references to upper and lower target vnodes.
                    349:         */
                    350:        if (um->um_lowervp)
                    351:                vrele(um->um_lowervp);
                    352:        vrele(um->um_uppervp);
                    353:        cred = um->um_cred;
                    354:        if (cred != NOCRED) {
                    355:                um->um_cred = NOCRED;
                    356:                crfree(cred);
                    357:        }
                    358:        /*
                    359:         * Release reference on underlying root vnode
                    360:         */
                    361:        vput(um_rootvp);
                    362:        /*
                    363:         * And blow it away for future re-use
                    364:         */
                    365:        vgone(um_rootvp);
                    366:        /*
                    367:         * Finally, throw away the union_mount structure
                    368:         */
                    369:        _FREE(mp->mnt_data, M_UFSMNT);  /* XXX */
                    370:        mp->mnt_data = 0;
                    371:        return (0);
                    372: }
                    373: 
                    374: int
                    375: union_root(mp, vpp)
                    376:        struct mount *mp;
                    377:        struct vnode **vpp;
                    378: {
                    379:        struct proc *p = current_proc();        /* XXX */
                    380:        struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
                    381:        int error;
                    382:        int loselock;
                    383: 
                    384:        /*
                    385:         * Return locked reference to root.
                    386:         */
                    387:        VREF(um->um_uppervp);
                    388:        if ((um->um_op == UNMNT_BELOW) &&
                    389:             VOP_ISLOCKED(um->um_uppervp)) {
                    390:                loselock = 1;
                    391:        } else {
                    392:                vn_lock(um->um_uppervp, LK_EXCLUSIVE | LK_RETRY, p);
                    393:                loselock = 0;
                    394:        }
                    395:        if (um->um_lowervp)
                    396:                VREF(um->um_lowervp);
                    397:        error = union_allocvp(vpp, mp,
                    398:                              (struct vnode *) 0,
                    399:                              (struct vnode *) 0,
                    400:                              (struct componentname *) 0,
                    401:                              um->um_uppervp,
                    402:                              um->um_lowervp,
                    403:                              1);
                    404: 
                    405:        if (error) {
                    406:                if (loselock)
                    407:                        vrele(um->um_uppervp);
                    408:                else
                    409:                        vput(um->um_uppervp);
                    410:                if (um->um_lowervp)
                    411:                        vrele(um->um_lowervp);
                    412:        } else {
                    413:                if (loselock)
                    414:                        VTOUNION(*vpp)->un_flags &= ~UN_ULOCK;
                    415:        }
                    416: 
                    417:        return (error);
                    418: }
                    419: 
                    420: int
                    421: union_statfs(mp, sbp, p)
                    422:        struct mount *mp;
                    423:        struct statfs *sbp;
                    424:        struct proc *p;
                    425: {
                    426:        int error;
                    427:        struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
                    428:        struct statfs mstat;
                    429:        int lbsize;
                    430: 
                    431: #ifdef UNION_DIAGNOSTIC
                    432:        printf("union_statfs(mp = %x, lvp = %x, uvp = %x)\n", mp,
                    433:                        um->um_lowervp,
                    434:                        um->um_uppervp);
                    435: #endif
                    436: 
                    437:        bzero(&mstat, sizeof(mstat));
                    438: 
                    439:        if (um->um_lowervp) {
                    440:                error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, p);
                    441:                if (error)
                    442:                        return (error);
                    443:        }
                    444: 
                    445:        /* now copy across the "interesting" information and fake the rest */
                    446: #if 0
                    447:        sbp->f_type = mstat.f_type;
                    448:        sbp->f_flags = mstat.f_flags;
                    449:        sbp->f_bsize = mstat.f_bsize;
                    450:        sbp->f_iosize = mstat.f_iosize;
                    451: #endif
                    452:        lbsize = mstat.f_bsize;
                    453:        sbp->f_blocks = mstat.f_blocks;
                    454:        sbp->f_bfree = mstat.f_bfree;
                    455:        sbp->f_bavail = mstat.f_bavail;
                    456:        sbp->f_files = mstat.f_files;
                    457:        sbp->f_ffree = mstat.f_ffree;
                    458: 
                    459:        error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, p);
                    460:        if (error)
                    461:                return (error);
                    462: 
                    463:        sbp->f_flags = mstat.f_flags;
                    464:        sbp->f_bsize = mstat.f_bsize;
                    465:        sbp->f_iosize = mstat.f_iosize;
                    466: 
                    467:        /*
                    468:         * if the lower and upper blocksizes differ, then frig the
                    469:         * block counts so that the sizes reported by df make some
                    470:         * kind of sense.  none of this makes sense though.
                    471:         */
                    472: 
                    473:        if (mstat.f_bsize != lbsize)
                    474:                sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize;
                    475: 
                    476:        /*
                    477:         * The "total" fields count total resources in all layers,
                    478:         * the "free" fields count only those resources which are
                    479:         * free in the upper layer (since only the upper layer
                    480:         * is writeable).
                    481:         */
                    482:        sbp->f_blocks += mstat.f_blocks;
                    483:        sbp->f_bfree = mstat.f_bfree;
                    484:        sbp->f_bavail = mstat.f_bavail;
                    485:        sbp->f_files += mstat.f_files;
                    486:        sbp->f_ffree = mstat.f_ffree;
                    487: 
                    488:        if (sbp != &mp->mnt_stat) {
                    489:                sbp->f_type = mp->mnt_vfc->vfc_typenum;
                    490:                bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
                    491:                bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
                    492:                bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
                    493:        }
                    494:        return (0);
                    495: }
                    496: 
                    497: /*
                    498:  * XXX - Assumes no data cached at union layer.
                    499:  */
                    500: #define union_sync ((int (*) __P((struct mount *, int, struct ucred *, \
                    501:            struct proc *)))nullop)
                    502: 
                    503: #define union_fhtovp ((int (*) __P((struct mount *, struct fid *, \
                    504:            struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp)
                    505: int union_init __P((struct vfsconf *));
                    506: #define union_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
                    507:            struct proc *)))eopnotsupp)
                    508: #define union_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
                    509:            size_t, struct proc *)))eopnotsupp)
                    510: #define union_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
                    511:            eopnotsupp)
                    512: #define union_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
                    513: 
                    514: struct vfsops union_vfsops = {
                    515:        union_mount,
                    516:        union_start,
                    517:        union_unmount,
                    518:        union_root,
                    519:        union_quotactl,
                    520:        union_statfs,
                    521:        union_sync,
                    522:        union_vget,
                    523:        union_fhtovp,
                    524:        union_vptofh,
                    525:        union_init,
                    526:        union_sysctl,
                    527: };

unix.superglobalmegacorp.com

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