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

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
        !            26: /*
        !            27:  * Copyright (c) 1994, 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.