[BACK]Return to puffs_vfsops.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / fs / puffs

Annotation of src/sys/fs/puffs/puffs_vfsops.c, Revision 1.43

1.43    ! pooka       1: /*     $NetBSD: puffs_vfsops.c,v 1.42 2007/05/17 13:59:22 pooka Exp $  */
1.1       pooka       2:
                      3: /*
                      4:  * Copyright (c) 2005, 2006  Antti Kantee.  All Rights Reserved.
                      5:  *
                      6:  * Development of this software was supported by the
                      7:  * Google Summer of Code program and the Ulla Tuominen Foundation.
                      8:  * The Google SoC project was mentored by Bill Studenmund.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
                     20:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     21:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     22:  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     25:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     29:  * SUCH DAMAGE.
                     30:  */
                     31:
                     32: #include <sys/cdefs.h>
1.43    ! pooka      33: __KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.42 2007/05/17 13:59:22 pooka Exp $");
1.1       pooka      34:
                     35: #include <sys/param.h>
                     36: #include <sys/mount.h>
                     37: #include <sys/malloc.h>
                     38: #include <sys/extattr.h>
                     39: #include <sys/queue.h>
                     40: #include <sys/vnode.h>
                     41: #include <sys/dirent.h>
                     42: #include <sys/kauth.h>
1.26      pooka      43: #include <sys/fstrans.h>
1.1       pooka      44:
                     45: #include <lib/libkern/libkern.h>
                     46:
                     47: #include <fs/puffs/puffs_msgif.h>
                     48: #include <fs/puffs/puffs_sys.h>
                     49:
1.38      pooka      50: #include <nfs/nfsproto.h> /* for fh sizes */
                     51:
1.1       pooka      52: VFS_PROTOS(puffs);
                     53:
1.32      pooka      54: MALLOC_JUSTDEFINE(M_PUFFS, "puffs", "Pass-to-Userspace Framework File System");
1.1       pooka      55:
1.22      pooka      56: #ifndef PUFFS_PNODEBUCKETS
                     57: #define PUFFS_PNODEBUCKETS 256
                     58: #endif
                     59: #ifndef PUFFS_MAXPNODEBUCKETS
1.35      pooka      60: #define PUFFS_MAXPNODEBUCKETS 8192
1.22      pooka      61: #endif
1.35      pooka      62: int puffs_pnodebuckets_default = PUFFS_PNODEBUCKETS;
                     63: int puffs_maxpnodebuckets = PUFFS_MAXPNODEBUCKETS;
1.22      pooka      64:
1.1       pooka      65: int
                     66: puffs_mount(struct mount *mp, const char *path, void *data,
                     67:            struct nameidata *ndp, struct lwp *l)
                     68: {
1.22      pooka      69:        struct puffs_mount *pmp = NULL;
1.34      pooka      70:        struct puffs_kargs *args;
1.17      pooka      71:        char namebuf[PUFFSNAMESIZE+sizeof(PUFFS_NAMEPREFIX)+1]; /* spooky */
1.22      pooka      72:        int error = 0, i;
1.1       pooka      73:
                     74:        if (mp->mnt_flag & MNT_GETARGS) {
                     75:                pmp = MPTOPUFFSMP(mp);
1.34      pooka      76:                return copyout(&pmp->pmp_args,data,sizeof(struct puffs_kargs));
1.1       pooka      77:        }
                     78:
                     79:        /* update is not supported currently */
                     80:        if (mp->mnt_flag & MNT_UPDATE)
                     81:                return EOPNOTSUPP;
                     82:
                     83:        /*
                     84:         * We need the file system name
                     85:         */
                     86:        if (!data)
                     87:                return EINVAL;
                     88:
1.34      pooka      89:        MALLOC(args, struct puffs_kargs *, sizeof(struct puffs_kargs),
1.17      pooka      90:            M_PUFFS, M_WAITOK);
                     91:
1.34      pooka      92:        error = copyin(data, args, sizeof(struct puffs_kargs));
1.1       pooka      93:        if (error)
1.17      pooka      94:                goto out;
                     95:
                     96:        /* devel phase */
                     97:        if (args->pa_vers != (PUFFSVERSION | PUFFSDEVELVERS)) {
                     98:                printf("puffs_mount: development version mismatch\n");
                     99:                error = EINVAL;
                    100:                goto out;
                    101:        }
1.1       pooka     102:
1.8       pooka     103:        /* nuke spy bits */
1.17      pooka     104:        args->pa_flags &= PUFFS_KFLAG_MASK;
1.8       pooka     105:
1.38      pooka     106:        /* sanitize file handle length */
                    107:        if (PUFFS_TOFHSIZE(args->pa_fhsize) > FHANDLE_SIZE_MAX) {
                    108:                printf("puffs_mount: handle size %zu too large\n",
                    109:                    args->pa_fhsize);
                    110:                error = EINVAL;
                    111:                goto out;
                    112:        }
                    113:        /* sanity check file handle max sizes */
                    114:        if (args->pa_fhsize && args->pa_fhflags & PUFFS_FHFLAG_PROTOMASK) {
                    115:                size_t kfhsize = PUFFS_TOFHSIZE(args->pa_fhsize);
                    116:
                    117:                if (args->pa_fhflags & PUFFS_FHFLAG_NFSV2) {
                    118:                        if (NFSX_FHTOOBIG_P(kfhsize, 0)) {
                    119:                                printf("puffs_mount: fhsize larger than "
                    120:                                    "NFSv2 max %d\n",
                    121:                                    PUFFS_FROMFHSIZE(NFSX_V2FH));
                    122:                                error = EINVAL;
                    123:                                goto out;
                    124:                        }
                    125:                }
                    126:
                    127:                if (args->pa_fhflags & PUFFS_FHFLAG_NFSV3) {
                    128:                        if (NFSX_FHTOOBIG_P(kfhsize, 1)) {
                    129:                                printf("puffs_mount: fhsize larger than "
                    130:                                    "NFSv3 max %d\n",
                    131:                                    PUFFS_FROMFHSIZE(NFSX_V3FHMAX));
                    132:                                error = EINVAL;
                    133:                                goto out;
                    134:                        }
                    135:                }
                    136:        }
                    137:
1.1       pooka     138:        /* build real name */
1.17      pooka     139:        (void)strlcpy(namebuf, PUFFS_NAMEPREFIX, sizeof(namebuf));
                    140:        (void)strlcat(namebuf, args->pa_name, sizeof(namebuf));
1.1       pooka     141:
                    142:        /* inform user server if it got the max request size it wanted */
1.17      pooka     143:        if (args->pa_maxreqlen == 0 || args->pa_maxreqlen > PUFFS_REQ_MAXSIZE)
                    144:                args->pa_maxreqlen = PUFFS_REQ_MAXSIZE;
                    145:        else if (args->pa_maxreqlen < PUFFS_REQSTRUCT_MAX)
                    146:                args->pa_maxreqlen = PUFFS_REQSTRUCT_MAX;
                    147:        (void)strlcpy(args->pa_name, namebuf, sizeof(args->pa_name));
1.1       pooka     148:
1.40      pooka     149:        if (args->pa_nhashbuckets == 0)
                    150:                args->pa_nhashbuckets = puffs_pnodebuckets_default;
                    151:        if (args->pa_nhashbuckets < 1)
                    152:                args->pa_nhashbuckets = 1;
                    153:        if (args->pa_nhashbuckets > PUFFS_MAXPNODEBUCKETS) {
                    154:                args->pa_nhashbuckets = puffs_maxpnodebuckets;
                    155:                printf("puffs_mount: using %d hash buckets. "
                    156:                    "adjust puffs_maxpnodebuckets for more\n",
                    157:                    puffs_maxpnodebuckets);
                    158:        }
                    159:
1.34      pooka     160:        error = copyout(args, data, sizeof(struct puffs_kargs));
1.1       pooka     161:        if (error)
1.17      pooka     162:                goto out;
1.1       pooka     163:
                    164:        error = set_statvfs_info(path, UIO_USERSPACE, namebuf,
                    165:            UIO_SYSSPACE, mp, l);
                    166:        if (error)
1.17      pooka     167:                goto out;
1.10      pooka     168:        mp->mnt_stat.f_iosize = DEV_BSIZE;
1.1       pooka     169:
1.42      pooka     170:        /*
                    171:         * We can't handle the VFS_STATVFS() mount_domount() does
                    172:         * after VFS_MOUNT() because we'd deadlock, so handle it
                    173:         * here already.
                    174:         */
                    175:        copy_statvfs_info(&args->pa_svfsb, mp);
                    176:        (void)memcpy(&mp->mnt_stat, &args->pa_svfsb, sizeof(mp->mnt_stat));
                    177:
1.1       pooka     178:        MALLOC(pmp, struct puffs_mount *, sizeof(struct puffs_mount),
                    179:            M_PUFFS, M_WAITOK | M_ZERO);
                    180:
1.6       pooka     181:        mp->mnt_fs_bshift = DEV_BSHIFT;
                    182:        mp->mnt_dev_bshift = DEV_BSHIFT;
                    183:        mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
1.1       pooka     184:        mp->mnt_data = pmp;
1.26      pooka     185:        mp->mnt_iflag |= IMNT_HAS_TRANS;
1.6       pooka     186:
1.1       pooka     187:        pmp->pmp_status = PUFFSTAT_MOUNTING;
                    188:        pmp->pmp_nextreq = 0;
                    189:        pmp->pmp_mp = mp;
1.17      pooka     190:        pmp->pmp_req_maxsize = args->pa_maxreqlen;
                    191:        pmp->pmp_args = *args;
1.1       pooka     192:
1.40      pooka     193:        pmp->pmp_npnodehash = args->pa_nhashbuckets;
1.22      pooka     194:        pmp->pmp_pnodehash = malloc
                    195:            (sizeof(struct puffs_pnode_hashlist *) * pmp->pmp_npnodehash,
                    196:            M_PUFFS, M_WAITOK);
                    197:        for (i = 0; i < pmp->pmp_npnodehash; i++)
                    198:                LIST_INIT(&pmp->pmp_pnodehash[i]);
                    199:
1.1       pooka     200:        /*
                    201:         * Inform the fileops processing code that we have a mountpoint.
                    202:         * If it doesn't know about anyone with our pid/fd having the
                    203:         * device open, punt
                    204:         */
1.17      pooka     205:        if (puffs_setpmp(l->l_proc->p_pid, args->pa_fd, pmp)) {
                    206:                error = ENOENT;
                    207:                goto out;
1.1       pooka     208:        }
                    209:
1.42      pooka     210:        /* XXX: check parameters */
                    211:        pmp->pmp_root_cookie = args->pa_root_cookie;
                    212:        pmp->pmp_root_vtype = args->pa_root_vtype;
                    213:        pmp->pmp_root_vsize = args->pa_root_vsize;
                    214:        pmp->pmp_root_rdev = args->pa_root_rdev;
                    215:
1.31      pooka     216:        mutex_init(&pmp->pmp_lock, MUTEX_DEFAULT, IPL_NONE);
                    217:        cv_init(&pmp->pmp_req_waiter_cv, "puffsget");
1.41      pooka     218:        cv_init(&pmp->pmp_refcount_cv, "puffsref");
1.31      pooka     219:        cv_init(&pmp->pmp_unmounting_cv, "puffsum");
1.1       pooka     220:        TAILQ_INIT(&pmp->pmp_req_touser);
                    221:        TAILQ_INIT(&pmp->pmp_req_replywait);
                    222:        TAILQ_INIT(&pmp->pmp_req_sizepark);
                    223:
                    224:        DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n",
                    225:            mp, MPTOPUFFSMP(mp)));
                    226:
                    227:        vfs_getnewfsid(mp);
                    228:
1.17      pooka     229:  out:
1.22      pooka     230:        if (error && pmp && pmp->pmp_pnodehash)
                    231:                free(pmp->pmp_pnodehash, M_PUFFS);
                    232:        if (error && pmp)
                    233:                FREE(pmp, M_PUFFS);
1.17      pooka     234:        FREE(args, M_PUFFS);
                    235:        return error;
1.1       pooka     236: }
                    237:
                    238: int
1.42      pooka     239: puffs_start(struct mount *mp, int flags, struct lwp *l)
1.1       pooka     240: {
1.42      pooka     241:        struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.1       pooka     242:
1.42      pooka     243:        KASSERT(pmp->pmp_status == PUFFSTAT_MOUNTING);
1.1       pooka     244:        pmp->pmp_status = PUFFSTAT_RUNNING;
                    245:
                    246:        return 0;
                    247: }
                    248:
                    249: int
                    250: puffs_unmount(struct mount *mp, int mntflags, struct lwp *l)
                    251: {
                    252:        struct puffs_mount *pmp;
                    253:        int error, force;
                    254:
                    255:        PUFFS_VFSREQ(unmount);
                    256:
                    257:        error = 0;
                    258:        force = mntflags & MNT_FORCE;
                    259:        pmp = MPTOPUFFSMP(mp);
                    260:
                    261:        DPRINTF(("puffs_unmount: detach filesystem from vfs, current "
                    262:            "status 0x%x\n", pmp->pmp_status));
                    263:
                    264:        /*
                    265:         * flush all the vnodes.  VOP_RECLAIM() takes care that the
                    266:         * root vnode does not get flushed until unmount.  The
                    267:         * userspace root node cookie is stored in the mount
                    268:         * structure, so we can always re-instantiate a root vnode,
                    269:         * should userspace unmount decide it doesn't want to
                    270:         * cooperate.
                    271:         */
                    272:        error = vflush(mp, NULLVP, force ? FORCECLOSE : 0);
                    273:        if (error)
                    274:                goto out;
                    275:
                    276:        /*
                    277:         * If we are not DYING, we should ask userspace's opinion
                    278:         * about the situation
                    279:         */
1.31      pooka     280:        mutex_enter(&pmp->pmp_lock);
1.1       pooka     281:        if (pmp->pmp_status != PUFFSTAT_DYING) {
1.16      pooka     282:                pmp->pmp_unmounting = 1;
1.31      pooka     283:                mutex_exit(&pmp->pmp_lock);
1.16      pooka     284:
1.1       pooka     285:                unmount_arg.pvfsr_flags = mntflags;
                    286:                unmount_arg.pvfsr_pid = puffs_lwp2pid(l);
1.16      pooka     287:
1.1       pooka     288:                error = puffs_vfstouser(pmp, PUFFS_VFS_UNMOUNT,
                    289:                     &unmount_arg, sizeof(unmount_arg));
1.16      pooka     290:                DPRINTF(("puffs_unmount: error %d force %d\n", error, force));
                    291:
1.31      pooka     292:                mutex_enter(&pmp->pmp_lock);
1.16      pooka     293:                pmp->pmp_unmounting = 0;
1.31      pooka     294:                cv_broadcast(&pmp->pmp_unmounting_cv);
1.1       pooka     295:        }
                    296:
                    297:        /*
                    298:         * if userspace cooperated or we really need to die,
                    299:         * screw what userland thinks and just die.
                    300:         */
                    301:        if (error == 0 || force) {
1.26      pooka     302:                /* tell waiters & other resources to go unwait themselves */
                    303:                puffs_userdead(pmp);
1.1       pooka     304:                puffs_nukebypmp(pmp);
1.26      pooka     305:
                    306:                /*
1.41      pooka     307:                 * Wait until there are no more users for the mount resource.
                    308:                 * Notice that this is hooked against transport_close
                    309:                 * and return from touser.  In an ideal world, it would
                    310:                 * be hooked against final return from all operations.
                    311:                 * But currently it works well enough, since nobody
                    312:                 * does weird blocking voodoo after return from touser().
1.26      pooka     313:                 */
1.41      pooka     314:                while (pmp->pmp_refcount != 0)
                    315:                        cv_wait(&pmp->pmp_refcount_cv, &pmp->pmp_lock);
1.31      pooka     316:                mutex_exit(&pmp->pmp_lock);
1.26      pooka     317:
                    318:                /* free resources now that we hopefully have no waiters left */
1.41      pooka     319:                cv_destroy(&pmp->pmp_unmounting_cv);
                    320:                cv_destroy(&pmp->pmp_refcount_cv);
1.31      pooka     321:                cv_destroy(&pmp->pmp_req_waiter_cv);
                    322:                mutex_destroy(&pmp->pmp_lock);
                    323:
1.22      pooka     324:                free(pmp->pmp_pnodehash, M_PUFFS);
1.1       pooka     325:                FREE(pmp, M_PUFFS);
                    326:                error = 0;
1.16      pooka     327:        } else {
1.31      pooka     328:                mutex_exit(&pmp->pmp_lock);
1.1       pooka     329:        }
                    330:
                    331:  out:
1.2       pooka     332:        DPRINTF(("puffs_unmount: return %d\n", error));
1.1       pooka     333:        return error;
                    334: }
                    335:
                    336: /*
                    337:  * This doesn't need to travel to userspace
                    338:  */
                    339: int
                    340: puffs_root(struct mount *mp, struct vnode **vpp)
                    341: {
                    342:        struct puffs_mount *pmp;
                    343:        struct puffs_node *pn;
                    344:        struct vnode *vp;
                    345:
                    346:        pmp = MPTOPUFFSMP(mp);
                    347:
                    348:        /*
                    349:         * pmp_lock must be held if vref()'ing or vrele()'ing the
1.20      pooka     350:         * root vnode.  the latter is controlled by puffs_inactive().
1.1       pooka     351:         */
1.31      pooka     352:        mutex_enter(&pmp->pmp_lock);
1.1       pooka     353:        vp = pmp->pmp_root;
                    354:        if (vp) {
1.25      pooka     355:                simple_lock(&vp->v_interlock);
1.31      pooka     356:                mutex_exit(&pmp->pmp_lock);
1.1       pooka     357:                pn = VPTOPP(vp);
1.25      pooka     358:                if (vget(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK))
1.20      pooka     359:                        goto grabnew;
1.1       pooka     360:                *vpp = vp;
                    361:                return 0;
1.25      pooka     362:        } else
1.31      pooka     363:                mutex_exit(&pmp->pmp_lock);
1.25      pooka     364:
                    365:        /* XXX: this is wrong, so FIXME */
1.1       pooka     366:  grabnew:
                    367:
                    368:        /*
                    369:         * So, didn't have the magic root vnode available.
                    370:         * No matter, grab another an stuff it with the cookie.
                    371:         */
1.42      pooka     372:        if (puffs_getvnode(mp, pmp->pmp_root_cookie, pmp->pmp_root_vtype,
                    373:            pmp->pmp_root_vsize, pmp->pmp_root_rdev, &vp))
1.1       pooka     374:                panic("sloppy programming");
                    375:
1.31      pooka     376:        mutex_enter(&pmp->pmp_lock);
1.1       pooka     377:        /*
                    378:         * check if by mysterious force someone else created a root
                    379:         * vnode while we were executing.
                    380:         */
                    381:        if (pmp->pmp_root) {
                    382:                vref(pmp->pmp_root);
1.31      pooka     383:                mutex_exit(&pmp->pmp_lock);
1.1       pooka     384:                puffs_putvnode(vp);
                    385:                vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
                    386:                *vpp = pmp->pmp_root;
                    387:                return 0;
                    388:        }
                    389:
                    390:        /* store cache */
                    391:        vp->v_flag = VROOT;
                    392:        pmp->pmp_root = vp;
1.31      pooka     393:        mutex_exit(&pmp->pmp_lock);
1.1       pooka     394:
                    395:        vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
                    396:
                    397:        *vpp = vp;
                    398:        return 0;
                    399: }
                    400:
                    401: int
                    402: puffs_statvfs(struct mount *mp, struct statvfs *sbp, struct lwp *l)
                    403: {
                    404:        struct puffs_vfsreq_statvfs *statvfs_arg; /* too big for stack */
                    405:        struct puffs_mount *pmp;
                    406:        int error = 0;
                    407:
                    408:        pmp = MPTOPUFFSMP(mp);
                    409:
                    410:        /*
                    411:         * If we are mounting, it means that the userspace counterpart
                    412:         * is calling mount(2), but mount(2) also calls statvfs.  So
                    413:         * requesting statvfs from userspace would mean a deadlock.
                    414:         * Compensate.
                    415:         */
                    416:        if (pmp->pmp_status == PUFFSTAT_MOUNTING)
                    417:                return EINPROGRESS;
                    418:
                    419:        /* too big for stack */
                    420:        MALLOC(statvfs_arg, struct puffs_vfsreq_statvfs *,
                    421:            sizeof(struct puffs_vfsreq_statvfs), M_PUFFS, M_WAITOK | M_ZERO);
                    422:        statvfs_arg->pvfsr_pid = puffs_lwp2pid(l);
                    423:
                    424:        error = puffs_vfstouser(pmp, PUFFS_VFS_STATVFS,
                    425:            statvfs_arg, sizeof(*statvfs_arg));
1.11      pooka     426:        statvfs_arg->pvfsr_sb.f_iosize = DEV_BSIZE;
1.10      pooka     427:
1.1       pooka     428:        /*
                    429:         * Try to produce a sensible result even in the event
                    430:         * of userspace error.
                    431:         *
                    432:         * XXX: cache the copy in non-error case
                    433:         */
                    434:        if (!error) {
                    435:                copy_statvfs_info(&statvfs_arg->pvfsr_sb, mp);
                    436:                (void)memcpy(sbp, &statvfs_arg->pvfsr_sb,
                    437:                    sizeof(struct statvfs));
                    438:        } else {
                    439:                copy_statvfs_info(sbp, mp);
                    440:        }
                    441:
                    442:        FREE(statvfs_arg, M_PUFFS);
1.14      pooka     443:        return error;
1.1       pooka     444: }
                    445:
1.26      pooka     446: static int
1.30      pooka     447: pageflush(struct mount *mp, kauth_cred_t cred,
                    448:        int waitfor, int suspending, struct lwp *l)
1.1       pooka     449: {
1.26      pooka     450:        struct puffs_node *pn;
1.18      pooka     451:        struct vnode *vp, *nvp;
1.30      pooka     452:        int error, rv;
1.1       pooka     453:
1.26      pooka     454:        KASSERT(((waitfor == MNT_WAIT) && suspending) == 0);
                    455:        KASSERT((suspending == 0)
                    456:            || (fstrans_is_owner(mp)
1.27      hannken   457:              && fstrans_getstate(mp) == FSTRANS_SUSPENDING));
1.1       pooka     458:
1.18      pooka     459:        error = 0;
                    460:
                    461:        /*
1.24      pooka     462:         * Sync all cached data from regular vnodes (which are not
                    463:         * currently locked, see below).  After this we call VFS_SYNC
                    464:         * for the fs server, which should handle data and metadata for
                    465:         * all the nodes it knows to exist.
1.18      pooka     466:         */
                    467:        simple_lock(&mntvnode_slock);
                    468:  loop:
                    469:        for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) {
                    470:                /* check if we're on the right list */
                    471:                if (vp->v_mount != mp)
                    472:                        goto loop;
                    473:
                    474:                simple_lock(&vp->v_interlock);
1.26      pooka     475:                pn = VPTOPP(vp);
1.18      pooka     476:                nvp = TAILQ_NEXT(vp, v_mntvnodes);
                    477:
1.19      pooka     478:                if (vp->v_type != VREG || UVM_OBJ_IS_CLEAN(&vp->v_uobj)) {
1.18      pooka     479:                        simple_unlock(&vp->v_interlock);
                    480:                        continue;
                    481:                }
                    482:
                    483:                simple_unlock(&mntvnode_slock);
1.21      pooka     484:
                    485:                /*
                    486:                 * Here we try to get a reference to the vnode and to
                    487:                 * lock it.  This is mostly cargo-culted, but I will
                    488:                 * offer an explanation to why I believe this might
                    489:                 * actually do the right thing.
                    490:                 *
                    491:                 * If the vnode is a goner, we quite obviously don't need
                    492:                 * to sync it.
                    493:                 *
                    494:                 * If the vnode was busy, we don't need to sync it because
                    495:                 * this is never called with MNT_WAIT except from
                    496:                 * dounmount(), when we are wait-flushing all the dirty
                    497:                 * vnodes through other routes in any case.  So there,
                    498:                 * sync() doesn't actually sync.  Happy now?
1.26      pooka     499:                 *
                    500:                 * NOTE: if we're suspending, vget() does NOT lock.
                    501:                 * See puffs_lock() for details.
1.21      pooka     502:                 */
1.18      pooka     503:                rv = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
                    504:                if (rv) {
                    505:                        simple_lock(&mntvnode_slock);
                    506:                        if (rv == ENOENT)
                    507:                                goto loop;
                    508:                        continue;
                    509:                }
                    510:
1.26      pooka     511:                /*
                    512:                 * Thread information to puffs_strategy() through the
                    513:                 * pnode flags: we want to issue the putpages operations
                    514:                 * as FAF if we're suspending, since it's very probable
                    515:                 * that our execution context is that of the userspace
                    516:                 * daemon.  We can do this because:
                    517:                 *   + we send the "going to suspend" prior to this part
                    518:                 *   + if any of the writes fails in userspace, it's the
                    519:                 *     file system server's problem to decide if this was a
                    520:                 *     failed snapshot when it gets the "snapshot complete"
                    521:                 *     notification.
                    522:                 *   + if any of the writes fail in the kernel already, we
                    523:                 *     immediately fail *and* notify the user server of
                    524:                 *     failure.
                    525:                 *
                    526:                 * We also do FAFs if we're called from the syncer.  This
                    527:                 * is just general optimization for trickle sync: no need
                    528:                 * to really guarantee that the stuff ended on backing
                    529:                 * storage.
                    530:                 * TODO: Maybe also hint the user server of this twist?
                    531:                 */
1.30      pooka     532:                if (suspending || waitfor == MNT_LAZY) {
                    533:                        simple_lock(&vp->v_interlock);
1.26      pooka     534:                        pn->pn_stat |= PNODE_SUSPEND;
1.30      pooka     535:                        simple_unlock(&vp->v_interlock);
                    536:                }
                    537:                rv = VOP_FSYNC(vp, cred, waitfor, 0, 0, l);
1.26      pooka     538:                if (suspending || waitfor == MNT_LAZY) {
                    539:                        simple_lock(&vp->v_interlock);
                    540:                        pn->pn_stat &= ~PNODE_SUSPEND;
                    541:                        simple_unlock(&vp->v_interlock);
                    542:                }
1.21      pooka     543:                if (rv)
1.18      pooka     544:                        error = rv;
                    545:                vput(vp);
                    546:                simple_lock(&mntvnode_slock);
                    547:        }
                    548:        simple_unlock(&mntvnode_slock);
                    549:
1.26      pooka     550:        return error;
                    551: }
                    552:
                    553: int
                    554: puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
                    555:        struct lwp *l)
                    556: {
                    557:        int error, rv;
                    558:
                    559:        PUFFS_VFSREQ(sync);
                    560:
1.30      pooka     561:        error = pageflush(mp, cred, waitfor, 0, l);
1.26      pooka     562:
1.18      pooka     563:        /* sync fs */
1.1       pooka     564:        sync_arg.pvfsr_waitfor = waitfor;
                    565:        puffs_credcvt(&sync_arg.pvfsr_cred, cred);
                    566:        sync_arg.pvfsr_pid = puffs_lwp2pid(l);
                    567:
1.18      pooka     568:        rv = puffs_vfstouser(MPTOPUFFSMP(mp), PUFFS_VFS_SYNC,
1.1       pooka     569:            &sync_arg, sizeof(sync_arg));
1.18      pooka     570:        if (rv)
                    571:                error = rv;
1.1       pooka     572:
                    573:        return error;
                    574: }
                    575:
                    576: int
1.33      pooka     577: puffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
1.1       pooka     578: {
1.33      pooka     579:        struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.38      pooka     580:        struct puffs_vfsreq_fhtonode *fhtonode_argp;
1.33      pooka     581:        struct vnode *vp;
1.38      pooka     582:        size_t argsize;
1.33      pooka     583:        int error;
                    584:
1.38      pooka     585:        if (pmp->pmp_args.pa_fhsize == 0)
1.33      pooka     586:                return EOPNOTSUPP;
                    587:
1.39      pooka     588:        if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) {
                    589:                if (pmp->pmp_args.pa_fhsize < PUFFS_FROMFHSIZE(fhp->fid_len))
                    590:                        return EINVAL;
                    591:        } else {
                    592:                if (pmp->pmp_args.pa_fhsize != PUFFS_FROMFHSIZE(fhp->fid_len))
                    593:                        return EINVAL;
                    594:        }
1.33      pooka     595:
1.38      pooka     596:        argsize = sizeof(struct puffs_vfsreq_fhtonode)
                    597:            + PUFFS_FROMFHSIZE(fhp->fid_len);
                    598:        fhtonode_argp = malloc(argsize, M_PUFFS, M_ZERO | M_WAITOK);
                    599:        fhtonode_argp->pvfsr_dsize = PUFFS_FROMFHSIZE(fhp->fid_len);
                    600:        memcpy(fhtonode_argp->pvfsr_data, fhp->fid_data,
                    601:            PUFFS_FROMFHSIZE(fhp->fid_len));
1.33      pooka     602:
1.38      pooka     603:        error = puffs_vfstouser(pmp, PUFFS_VFS_FHTOVP, fhtonode_argp, argsize);
1.33      pooka     604:        if (error)
1.38      pooka     605:                goto out;
1.33      pooka     606:
1.38      pooka     607:        vp = puffs_pnode2vnode(pmp, fhtonode_argp->pvfsr_fhcookie, 1);
1.33      pooka     608:        DPRINTF(("puffs_fhtovp: got cookie %p, existing vnode %p\n",
1.38      pooka     609:            fhtonode_argp->pvfsr_fhcookie, vp));
1.33      pooka     610:        if (!vp) {
1.38      pooka     611:                error = puffs_getvnode(mp, fhtonode_argp->pvfsr_fhcookie,
                    612:                    fhtonode_argp->pvfsr_vtype, fhtonode_argp->pvfsr_size,
                    613:                    fhtonode_argp->pvfsr_rdev, &vp);
1.33      pooka     614:                if (error)
1.38      pooka     615:                        goto out;
1.33      pooka     616:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    617:        }
1.1       pooka     618:
1.33      pooka     619:        *vpp = vp;
1.38      pooka     620:  out:
                    621:        free(fhtonode_argp, M_PUFFS);
                    622:        return error;
1.1       pooka     623: }
                    624:
                    625: int
1.33      pooka     626: puffs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1.1       pooka     627: {
1.33      pooka     628:        struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1.38      pooka     629:        struct puffs_vfsreq_nodetofh *nodetofh_argp;
                    630:        size_t argsize;
1.33      pooka     631:        int error;
                    632:
1.38      pooka     633:        if (pmp->pmp_args.pa_fhsize == 0)
1.33      pooka     634:                return EOPNOTSUPP;
                    635:
1.38      pooka     636:        /* if file handles are static length, we can return immediately */
                    637:        if (((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) == 0)
                    638:            && (PUFFS_FROMFHSIZE(*fh_size) < pmp->pmp_args.pa_fhsize)) {
                    639:                *fh_size = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
1.33      pooka     640:                return E2BIG;
                    641:        }
1.1       pooka     642:
1.38      pooka     643:        argsize = sizeof(struct puffs_vfsreq_nodetofh)
                    644:            + PUFFS_FROMFHSIZE(*fh_size);
                    645:        nodetofh_argp = malloc(argsize, M_PUFFS, M_ZERO | M_WAITOK);
                    646:        nodetofh_argp->pvfsr_fhcookie = VPTOPNC(vp);
                    647:        nodetofh_argp->pvfsr_dsize = PUFFS_FROMFHSIZE(*fh_size);
                    648:
                    649:        error = puffs_vfstouser(pmp, PUFFS_VFS_VPTOFH, nodetofh_argp, argsize);
                    650:        if (error) {
                    651:                if (error == E2BIG)
                    652:                        *fh_size = PUFFS_TOFHSIZE(nodetofh_argp->pvfsr_dsize);
                    653:                goto out;
                    654:        }
                    655:
                    656:        if (PUFFS_TOFHSIZE(nodetofh_argp->pvfsr_dsize) > FHANDLE_SIZE_MAX) {
                    657:                /* XXX: wrong direction */
                    658:                error = EINVAL;
                    659:                goto out;
                    660:        }
1.33      pooka     661:
1.38      pooka     662:        if (*fh_size < PUFFS_TOFHSIZE(nodetofh_argp->pvfsr_dsize)) {
                    663:                *fh_size = PUFFS_TOFHSIZE(nodetofh_argp->pvfsr_dsize);
                    664:                error = E2BIG;
                    665:                goto out;
                    666:        }
                    667:        if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) {
                    668:                *fh_size = PUFFS_TOFHSIZE(nodetofh_argp->pvfsr_dsize);
                    669:        } else {
                    670:                *fh_size = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
                    671:        }
1.1       pooka     672:
1.38      pooka     673:        if (fhp) {
                    674:                fhp->fid_len = *fh_size;
                    675:                memcpy(fhp->fid_data,
                    676:                    nodetofh_argp->pvfsr_data, nodetofh_argp->pvfsr_dsize);
                    677:        }
1.1       pooka     678:
1.38      pooka     679:  out:
                    680:        free(nodetofh_argp, M_PUFFS);
                    681:        return error;
1.1       pooka     682: }
                    683:
                    684: void
                    685: puffs_init()
                    686: {
                    687:
1.5       pooka     688:        malloc_type_attach(M_PUFFS);
                    689:
1.31      pooka     690:        pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0,
                    691:            "puffpnpl", &pool_allocator_nointr, IPL_NONE);
                    692:        puffs_transport_init();
                    693:        puffs_msgif_init();
1.1       pooka     694: }
                    695:
                    696: void
                    697: puffs_done()
                    698: {
                    699:
1.31      pooka     700:        puffs_msgif_destroy();
                    701:        puffs_transport_destroy();
                    702:        pool_destroy(&puffs_pnpool);
                    703:
1.5       pooka     704:        malloc_type_detach(M_PUFFS);
1.1       pooka     705: }
                    706:
                    707: int
                    708: puffs_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ts)
                    709: {
                    710:
                    711:        return EOPNOTSUPP;
                    712: }
                    713:
1.26      pooka     714: int
                    715: puffs_suspendctl(struct mount *mp, int cmd)
                    716: {
                    717:        struct puffs_mount *pmp;
                    718:        int error;
                    719:
                    720:        pmp = MPTOPUFFSMP(mp);
                    721:        switch (cmd) {
                    722:        case SUSPEND_SUSPEND:
                    723:                DPRINTF(("puffs_suspendctl: suspending\n"));
1.27      hannken   724:                if ((error = fstrans_setstate(mp, FSTRANS_SUSPENDING)) != 0)
1.26      pooka     725:                        break;
                    726:                puffs_suspendtouser(pmp, PUFFS_SUSPEND_START);
                    727:
1.30      pooka     728:                error = pageflush(mp, FSCRED, 0, 1, curlwp);
1.26      pooka     729:                if (error == 0)
1.27      hannken   730:                        error = fstrans_setstate(mp, FSTRANS_SUSPENDED);
1.26      pooka     731:
                    732:                if (error != 0) {
                    733:                        puffs_suspendtouser(pmp, PUFFS_SUSPEND_ERROR);
1.27      hannken   734:                        (void) fstrans_setstate(mp, FSTRANS_NORMAL);
1.26      pooka     735:                        break;
                    736:                }
                    737:
                    738:                puffs_suspendtouser(pmp, PUFFS_SUSPEND_SUSPENDED);
                    739:
                    740:                break;
                    741:
                    742:        case SUSPEND_RESUME:
                    743:                DPRINTF(("puffs_suspendctl: resume\n"));
                    744:                error = 0;
1.27      hannken   745:                (void) fstrans_setstate(mp, FSTRANS_NORMAL);
1.26      pooka     746:                puffs_suspendtouser(pmp, PUFFS_SUSPEND_RESUME);
                    747:                break;
                    748:
                    749:        default:
                    750:                error = EINVAL;
                    751:                break;
                    752:        }
                    753:
                    754:        DPRINTF(("puffs_suspendctl: return %d\n", error));
                    755:        return error;
                    756: }
                    757:
1.1       pooka     758: const struct vnodeopv_desc * const puffs_vnodeopv_descs[] = {
                    759:        &puffs_vnodeop_opv_desc,
1.3       pooka     760:        &puffs_specop_opv_desc,
1.4       pooka     761:        &puffs_fifoop_opv_desc,
1.12      pooka     762:        &puffs_msgop_opv_desc,
1.1       pooka     763:        NULL,
                    764: };
                    765:
                    766: struct vfsops puffs_vfsops = {
                    767:        MOUNT_PUFFS,
                    768:        puffs_mount,            /* mount        */
                    769:        puffs_start,            /* start        */
                    770:        puffs_unmount,          /* unmount      */
                    771:        puffs_root,             /* root         */
1.33      pooka     772:        (void *)eopnotsupp,     /* quotactl     */
1.1       pooka     773:        puffs_statvfs,          /* statvfs      */
                    774:        puffs_sync,             /* sync         */
1.33      pooka     775:        (void *)eopnotsupp,     /* vget         */
                    776:        puffs_fhtovp,           /* fhtovp       */
                    777:        puffs_vptofh,           /* vptofh       */
1.1       pooka     778:        puffs_init,             /* init         */
                    779:        NULL,                   /* reinit       */
                    780:        puffs_done,             /* done         */
                    781:        NULL,                   /* mountroot    */
                    782:        puffs_snapshot,         /* snapshot     */
                    783:        vfs_stdextattrctl,      /* extattrctl   */
1.26      pooka     784:        puffs_suspendctl,       /* suspendctl   */
1.1       pooka     785:        puffs_vnodeopv_descs,   /* vnodeops     */
                    786:        0,                      /* refcount     */
                    787:        { NULL, NULL }
                    788: };
                    789: VFS_ATTACH(puffs_vfsops);

CVSweb <webmaster@jp.NetBSD.org>