[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.100.8.1

1.100.8.1! riz         1: /*     $NetBSD$        */
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.100.8.1! riz        33: __KERNEL_RCSID(0, "$NetBSD$");
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.47      ad         43: #include <sys/proc.h>
1.80      rumble     44: #include <sys/module.h>
1.84      pooka      45: #include <sys/kthread.h>
1.1       pooka      46:
1.99      manu       47: #include <uvm/uvm.h>
                     48:
1.68      pooka      49: #include <dev/putter/putter_sys.h>
1.1       pooka      50:
1.78      dholland   51: #include <miscfs/genfs/genfs.h>
                     52:
1.1       pooka      53: #include <fs/puffs/puffs_msgif.h>
                     54: #include <fs/puffs/puffs_sys.h>
                     55:
1.66      pooka      56: #include <lib/libkern/libkern.h>
                     57:
1.38      pooka      58: #include <nfs/nfsproto.h> /* for fh sizes */
                     59:
1.81      jmcneill   60: MODULE(MODULE_CLASS_VFS, puffs, "putter");
1.80      rumble     61:
1.73      pooka      62: VFS_PROTOS(puffs_vfsop);
1.1       pooka      63:
1.22      pooka      64: #ifndef PUFFS_PNODEBUCKETS
                     65: #define PUFFS_PNODEBUCKETS 256
                     66: #endif
                     67: #ifndef PUFFS_MAXPNODEBUCKETS
1.35      pooka      68: #define PUFFS_MAXPNODEBUCKETS 8192
1.22      pooka      69: #endif
1.35      pooka      70: int puffs_pnodebuckets_default = PUFFS_PNODEBUCKETS;
                     71: int puffs_maxpnodebuckets = PUFFS_MAXPNODEBUCKETS;
1.22      pooka      72:
1.70      pooka      73: #define BUCKETALLOC(a) (sizeof(struct puffs_pnode_hashlist *) * (a))
                     74:
1.66      pooka      75: static struct putter_ops puffs_putter = {
                     76:        .pop_getout     = puffs_msgif_getout,
                     77:        .pop_releaseout = puffs_msgif_releaseout,
                     78:        .pop_waitcount  = puffs_msgif_waitcount,
                     79:        .pop_dispatch   = puffs_msgif_dispatch,
                     80:        .pop_close      = puffs_msgif_close,
                     81: };
                     82:
1.92      pooka      83: /*
                     84:  * Try to ensure data structures used by the puffs protocol
                     85:  * do not unexpectedly change.
                     86:  */
                     87: #ifdef __i386__
                     88: CTASSERT(sizeof(struct puffs_kargs) == 3928);
                     89: CTASSERT(sizeof(struct vattr) == 136);
                     90: CTASSERT(sizeof(struct puffs_req) == 44);
                     91: #endif
                     92:
1.1       pooka      93: int
1.73      pooka      94: puffs_vfsop_mount(struct mount *mp, const char *path, void *data,
                     95:        size_t *data_len)
1.1       pooka      96: {
1.22      pooka      97:        struct puffs_mount *pmp = NULL;
1.34      pooka      98:        struct puffs_kargs *args;
1.51      pooka      99:        char fstype[_VFS_NAMELEN];
                    100:        char *p;
1.22      pooka     101:        int error = 0, i;
1.71      pooka     102:        pid_t mntpid = curlwp->l_proc->p_pid;
1.1       pooka     103:
1.48      dsl       104:        if (*data_len < sizeof *args)
                    105:                return EINVAL;
                    106:
1.1       pooka     107:        if (mp->mnt_flag & MNT_GETARGS) {
                    108:                pmp = MPTOPUFFSMP(mp);
1.48      dsl       109:                *(struct puffs_kargs *)data = pmp->pmp_args;
                    110:                *data_len = sizeof *args;
                    111:                return 0;
1.1       pooka     112:        }
                    113:
                    114:        /* update is not supported currently */
                    115:        if (mp->mnt_flag & MNT_UPDATE)
                    116:                return EOPNOTSUPP;
                    117:
                    118:        /*
                    119:         * We need the file system name
                    120:         */
                    121:        if (!data)
                    122:                return EINVAL;
                    123:
1.70      pooka     124:        args = (struct puffs_kargs *)data;
1.17      pooka     125:
1.89      pooka     126:        if (args->pa_vers != PUFFSVERSION) {
1.64      pooka     127:                printf("puffs_mount: development version mismatch: "
1.89      pooka     128:                    "kernel %d, lib %d\n", PUFFSVERSION, args->pa_vers);
1.17      pooka     129:                error = EINVAL;
                    130:                goto out;
                    131:        }
1.1       pooka     132:
1.54      pooka     133:        if ((args->pa_flags & ~PUFFS_KFLAG_MASK) != 0) {
                    134:                printf("puffs_mount: invalid KFLAGs 0x%x\n", args->pa_flags);
                    135:                error = EINVAL;
                    136:                goto out;
                    137:        }
                    138:        if ((args->pa_fhflags & ~PUFFS_FHFLAG_MASK) != 0) {
                    139:                printf("puffs_mount: invalid FHFLAGs 0x%x\n", args->pa_fhflags);
                    140:                error = EINVAL;
                    141:                goto out;
                    142:        }
                    143:
1.91      pooka     144:        for (i = 0; i < __arraycount(args->pa_spare); i++) {
                    145:                if (args->pa_spare[i] != 0) {
                    146:                        printf("puffs_mount: pa_spare[%d] = 0x%x\n",
                    147:                            i, args->pa_spare[i]);
                    148:                        error = EINVAL;
                    149:                        goto out;
                    150:                }
                    151:        }
                    152:
1.54      pooka     153:        /* use dummy value for passthrough */
                    154:        if (args->pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
                    155:                args->pa_fhsize = sizeof(struct fid);
1.8       pooka     156:
1.38      pooka     157:        /* sanitize file handle length */
                    158:        if (PUFFS_TOFHSIZE(args->pa_fhsize) > FHANDLE_SIZE_MAX) {
                    159:                printf("puffs_mount: handle size %zu too large\n",
                    160:                    args->pa_fhsize);
                    161:                error = EINVAL;
                    162:                goto out;
                    163:        }
                    164:        /* sanity check file handle max sizes */
                    165:        if (args->pa_fhsize && args->pa_fhflags & PUFFS_FHFLAG_PROTOMASK) {
                    166:                size_t kfhsize = PUFFS_TOFHSIZE(args->pa_fhsize);
                    167:
                    168:                if (args->pa_fhflags & PUFFS_FHFLAG_NFSV2) {
                    169:                        if (NFSX_FHTOOBIG_P(kfhsize, 0)) {
                    170:                                printf("puffs_mount: fhsize larger than "
                    171:                                    "NFSv2 max %d\n",
                    172:                                    PUFFS_FROMFHSIZE(NFSX_V2FH));
                    173:                                error = EINVAL;
                    174:                                goto out;
                    175:                        }
                    176:                }
                    177:
                    178:                if (args->pa_fhflags & PUFFS_FHFLAG_NFSV3) {
                    179:                        if (NFSX_FHTOOBIG_P(kfhsize, 1)) {
                    180:                                printf("puffs_mount: fhsize larger than "
                    181:                                    "NFSv3 max %d\n",
                    182:                                    PUFFS_FROMFHSIZE(NFSX_V3FHMAX));
                    183:                                error = EINVAL;
                    184:                                goto out;
                    185:                        }
                    186:                }
                    187:        }
                    188:
1.51      pooka     189:        /* don't allow non-printing characters (like my sweet umlauts.. snif) */
                    190:        args->pa_typename[sizeof(args->pa_typename)-1] = '\0';
                    191:        for (p = args->pa_typename; *p; p++)
                    192:                if (*p < ' ' || *p > '~')
                    193:                        *p = '.';
                    194:
                    195:        args->pa_mntfromname[sizeof(args->pa_mntfromname)-1] = '\0';
                    196:        for (p = args->pa_mntfromname; *p; p++)
                    197:                if (*p < ' ' || *p > '~')
                    198:                        *p = '.';
                    199:
1.1       pooka     200:        /* build real name */
1.51      pooka     201:        (void)strlcpy(fstype, PUFFS_TYPEPREFIX, sizeof(fstype));
                    202:        (void)strlcat(fstype, args->pa_typename, sizeof(fstype));
1.1       pooka     203:
                    204:        /* inform user server if it got the max request size it wanted */
1.63      pooka     205:        if (args->pa_maxmsglen == 0 || args->pa_maxmsglen > PUFFS_MSG_MAXSIZE)
                    206:                args->pa_maxmsglen = PUFFS_MSG_MAXSIZE;
                    207:        else if (args->pa_maxmsglen < 2*PUFFS_MSGSTRUCT_MAX)
                    208:                args->pa_maxmsglen = 2*PUFFS_MSGSTRUCT_MAX;
                    209:
1.51      pooka     210:        (void)strlcpy(args->pa_typename, fstype, sizeof(args->pa_typename));
1.1       pooka     211:
1.40      pooka     212:        if (args->pa_nhashbuckets == 0)
                    213:                args->pa_nhashbuckets = puffs_pnodebuckets_default;
                    214:        if (args->pa_nhashbuckets < 1)
                    215:                args->pa_nhashbuckets = 1;
                    216:        if (args->pa_nhashbuckets > PUFFS_MAXPNODEBUCKETS) {
                    217:                args->pa_nhashbuckets = puffs_maxpnodebuckets;
                    218:                printf("puffs_mount: using %d hash buckets. "
                    219:                    "adjust puffs_maxpnodebuckets for more\n",
                    220:                    puffs_maxpnodebuckets);
                    221:        }
                    222:
1.51      pooka     223:        error = set_statvfs_info(path, UIO_USERSPACE, args->pa_mntfromname,
1.71      pooka     224:            UIO_SYSSPACE, fstype, mp, curlwp);
1.1       pooka     225:        if (error)
1.17      pooka     226:                goto out;
1.10      pooka     227:        mp->mnt_stat.f_iosize = DEV_BSIZE;
1.94      pooka     228:        mp->mnt_stat.f_namemax = args->pa_svfsb.f_namemax;
1.1       pooka     229:
1.42      pooka     230:        /*
                    231:         * We can't handle the VFS_STATVFS() mount_domount() does
                    232:         * after VFS_MOUNT() because we'd deadlock, so handle it
                    233:         * here already.
                    234:         */
                    235:        copy_statvfs_info(&args->pa_svfsb, mp);
                    236:        (void)memcpy(&mp->mnt_stat, &args->pa_svfsb, sizeof(mp->mnt_stat));
                    237:
1.99      manu      238:        KASSERT(curlwp != uvm.pagedaemon_lwp);
1.70      pooka     239:        pmp = kmem_zalloc(sizeof(struct puffs_mount), KM_SLEEP);
1.1       pooka     240:
1.6       pooka     241:        mp->mnt_fs_bshift = DEV_BSHIFT;
                    242:        mp->mnt_dev_bshift = DEV_BSHIFT;
                    243:        mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
1.1       pooka     244:        mp->mnt_data = pmp;
1.6       pooka     245:
1.87      pooka     246: #if 0
                    247:        /*
                    248:         * XXX: puffs code is MPSAFE.  However, VFS really isn't.
                    249:         * Currently, there is nothing which protects an inode from
                    250:         * reclaim while there are threads inside the file system.
                    251:         * This means that in the event of a server crash, an MPSAFE
                    252:         * mount is likely to end up accessing invalid memory.  For the
                    253:         * non-mpsafe case, the kernel lock, general structure of
                    254:         * puffs and pmp_refcount protect the threads during escape.
                    255:         *
                    256:         * Fixing this will require:
                    257:         *  a) fixing vfs
                    258:         * OR
                    259:         *  b) adding a small sleep to puffs_msgif_close() between
                    260:         *     userdead() and dounmount().
                    261:         *     (well, this isn't really a fix, but would solve
                    262:         *     99.999% of the race conditions).
                    263:         *
                    264:         * Also, in the event of "b", unmount -f should be used,
                    265:         * like with any other file system, sparingly and only when
                    266:         * it is "known" to be safe.
                    267:         */
                    268:        mp->mnt_iflags |= IMNT_MPSAFE;
                    269: #endif
                    270:
1.1       pooka     271:        pmp->pmp_status = PUFFSTAT_MOUNTING;
                    272:        pmp->pmp_mp = mp;
1.63      pooka     273:        pmp->pmp_msg_maxsize = args->pa_maxmsglen;
1.17      pooka     274:        pmp->pmp_args = *args;
1.1       pooka     275:
1.40      pooka     276:        pmp->pmp_npnodehash = args->pa_nhashbuckets;
1.87      pooka     277:        pmp->pmp_pnodehash = kmem_alloc(BUCKETALLOC(pmp->pmp_npnodehash),
                    278:            KM_SLEEP);
1.22      pooka     279:        for (i = 0; i < pmp->pmp_npnodehash; i++)
                    280:                LIST_INIT(&pmp->pmp_pnodehash[i]);
1.57      pooka     281:        LIST_INIT(&pmp->pmp_newcookie);
1.22      pooka     282:
1.1       pooka     283:        /*
                    284:         * Inform the fileops processing code that we have a mountpoint.
                    285:         * If it doesn't know about anyone with our pid/fd having the
                    286:         * device open, punt
                    287:         */
1.66      pooka     288:        if ((pmp->pmp_pi
                    289:            = putter_attach(mntpid, args->pa_fd, pmp, &puffs_putter)) == NULL) {
1.17      pooka     290:                error = ENOENT;
                    291:                goto out;
1.1       pooka     292:        }
                    293:
1.42      pooka     294:        /* XXX: check parameters */
                    295:        pmp->pmp_root_cookie = args->pa_root_cookie;
                    296:        pmp->pmp_root_vtype = args->pa_root_vtype;
                    297:        pmp->pmp_root_vsize = args->pa_root_vsize;
                    298:        pmp->pmp_root_rdev = args->pa_root_rdev;
1.93      pooka     299:        pmp->pmp_docompat = args->pa_time32;
1.42      pooka     300:
1.31      pooka     301:        mutex_init(&pmp->pmp_lock, MUTEX_DEFAULT, IPL_NONE);
1.84      pooka     302:        mutex_init(&pmp->pmp_sopmtx, MUTEX_DEFAULT, IPL_NONE);
1.63      pooka     303:        cv_init(&pmp->pmp_msg_waiter_cv, "puffsget");
1.41      pooka     304:        cv_init(&pmp->pmp_refcount_cv, "puffsref");
1.31      pooka     305:        cv_init(&pmp->pmp_unmounting_cv, "puffsum");
1.84      pooka     306:        cv_init(&pmp->pmp_sopcv, "puffsop");
1.63      pooka     307:        TAILQ_INIT(&pmp->pmp_msg_touser);
                    308:        TAILQ_INIT(&pmp->pmp_msg_replywait);
1.84      pooka     309:        TAILQ_INIT(&pmp->pmp_sopreqs);
                    310:
                    311:        if ((error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
                    312:            puffs_sop_thread, pmp, NULL, "puffsop")) != 0)
                    313:                goto out;
                    314:        pmp->pmp_sopthrcount = 1;
1.1       pooka     315:
                    316:        DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n",
                    317:            mp, MPTOPUFFSMP(mp)));
                    318:
                    319:        vfs_getnewfsid(mp);
                    320:
1.17      pooka     321:  out:
1.84      pooka     322:        if (error && pmp && pmp->pmp_pi)
                    323:                putter_detach(pmp->pmp_pi);
1.22      pooka     324:        if (error && pmp && pmp->pmp_pnodehash)
1.70      pooka     325:                kmem_free(pmp->pmp_pnodehash, BUCKETALLOC(pmp->pmp_npnodehash));
1.22      pooka     326:        if (error && pmp)
1.70      pooka     327:                kmem_free(pmp, sizeof(struct puffs_mount));
1.17      pooka     328:        return error;
1.1       pooka     329: }
                    330:
                    331: int
1.73      pooka     332: puffs_vfsop_start(struct mount *mp, int flags)
1.1       pooka     333: {
1.42      pooka     334:        struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.1       pooka     335:
1.42      pooka     336:        KASSERT(pmp->pmp_status == PUFFSTAT_MOUNTING);
1.1       pooka     337:        pmp->pmp_status = PUFFSTAT_RUNNING;
                    338:
                    339:        return 0;
                    340: }
                    341:
                    342: int
1.73      pooka     343: puffs_vfsop_unmount(struct mount *mp, int mntflags)
1.1       pooka     344: {
1.63      pooka     345:        PUFFS_MSG_VARS(vfs, unmount);
1.1       pooka     346:        struct puffs_mount *pmp;
                    347:        int error, force;
                    348:
                    349:        error = 0;
                    350:        force = mntflags & MNT_FORCE;
                    351:        pmp = MPTOPUFFSMP(mp);
                    352:
                    353:        DPRINTF(("puffs_unmount: detach filesystem from vfs, current "
                    354:            "status 0x%x\n", pmp->pmp_status));
                    355:
                    356:        /*
                    357:         * flush all the vnodes.  VOP_RECLAIM() takes care that the
                    358:         * root vnode does not get flushed until unmount.  The
                    359:         * userspace root node cookie is stored in the mount
                    360:         * structure, so we can always re-instantiate a root vnode,
                    361:         * should userspace unmount decide it doesn't want to
                    362:         * cooperate.
                    363:         */
                    364:        error = vflush(mp, NULLVP, force ? FORCECLOSE : 0);
                    365:        if (error)
                    366:                goto out;
                    367:
                    368:        /*
                    369:         * If we are not DYING, we should ask userspace's opinion
                    370:         * about the situation
                    371:         */
1.31      pooka     372:        mutex_enter(&pmp->pmp_lock);
1.1       pooka     373:        if (pmp->pmp_status != PUFFSTAT_DYING) {
1.16      pooka     374:                pmp->pmp_unmounting = 1;
1.31      pooka     375:                mutex_exit(&pmp->pmp_lock);
1.16      pooka     376:
1.63      pooka     377:                PUFFS_MSG_ALLOC(vfs, unmount);
1.69      pooka     378:                puffs_msg_setinfo(park_unmount,
                    379:                    PUFFSOP_VFS, PUFFS_VFS_UNMOUNT, NULL);
1.63      pooka     380:                unmount_msg->pvfsr_flags = mntflags;
                    381:
1.69      pooka     382:                PUFFS_MSG_ENQUEUEWAIT(pmp, park_unmount, error);
1.63      pooka     383:                PUFFS_MSG_RELEASE(unmount);
1.16      pooka     384:
1.60      pooka     385:                error = checkerr(pmp, error, __func__);
1.16      pooka     386:                DPRINTF(("puffs_unmount: error %d force %d\n", error, force));
                    387:
1.31      pooka     388:                mutex_enter(&pmp->pmp_lock);
1.16      pooka     389:                pmp->pmp_unmounting = 0;
1.31      pooka     390:                cv_broadcast(&pmp->pmp_unmounting_cv);
1.1       pooka     391:        }
                    392:
                    393:        /*
                    394:         * if userspace cooperated or we really need to die,
                    395:         * screw what userland thinks and just die.
                    396:         */
                    397:        if (error == 0 || force) {
1.84      pooka     398:                struct puffs_sopreq *psopr;
                    399:
1.26      pooka     400:                /* tell waiters & other resources to go unwait themselves */
                    401:                puffs_userdead(pmp);
1.66      pooka     402:                putter_detach(pmp->pmp_pi);
1.26      pooka     403:
                    404:                /*
1.41      pooka     405:                 * Wait until there are no more users for the mount resource.
                    406:                 * Notice that this is hooked against transport_close
                    407:                 * and return from touser.  In an ideal world, it would
                    408:                 * be hooked against final return from all operations.
                    409:                 * But currently it works well enough, since nobody
                    410:                 * does weird blocking voodoo after return from touser().
1.26      pooka     411:                 */
1.41      pooka     412:                while (pmp->pmp_refcount != 0)
                    413:                        cv_wait(&pmp->pmp_refcount_cv, &pmp->pmp_lock);
1.31      pooka     414:                mutex_exit(&pmp->pmp_lock);
1.26      pooka     415:
1.84      pooka     416:                /*
                    417:                 * Release kernel thread now that there is nothing
                    418:                 * it would be wanting to lock.
                    419:                 */
1.99      manu      420:                KASSERT(curlwp != uvm.pagedaemon_lwp);
1.84      pooka     421:                psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP);
1.85      pooka     422:                psopr->psopr_sopreq = PUFFS_SOPREQSYS_EXIT;
1.84      pooka     423:                mutex_enter(&pmp->pmp_sopmtx);
1.86      pooka     424:                if (pmp->pmp_sopthrcount == 0) {
                    425:                        mutex_exit(&pmp->pmp_sopmtx);
                    426:                        kmem_free(psopr, sizeof(*psopr));
                    427:                        mutex_enter(&pmp->pmp_sopmtx);
                    428:                        KASSERT(pmp->pmp_sopthrcount == 0);
                    429:                } else {
                    430:                        TAILQ_INSERT_TAIL(&pmp->pmp_sopreqs,
                    431:                            psopr, psopr_entries);
                    432:                        cv_signal(&pmp->pmp_sopcv);
                    433:                }
1.84      pooka     434:                while (pmp->pmp_sopthrcount > 0)
                    435:                        cv_wait(&pmp->pmp_sopcv, &pmp->pmp_sopmtx);
                    436:                mutex_exit(&pmp->pmp_sopmtx);
                    437:
1.26      pooka     438:                /* free resources now that we hopefully have no waiters left */
1.41      pooka     439:                cv_destroy(&pmp->pmp_unmounting_cv);
                    440:                cv_destroy(&pmp->pmp_refcount_cv);
1.63      pooka     441:                cv_destroy(&pmp->pmp_msg_waiter_cv);
1.84      pooka     442:                cv_destroy(&pmp->pmp_sopcv);
1.31      pooka     443:                mutex_destroy(&pmp->pmp_lock);
1.84      pooka     444:                mutex_destroy(&pmp->pmp_sopmtx);
1.31      pooka     445:
1.70      pooka     446:                kmem_free(pmp->pmp_pnodehash, BUCKETALLOC(pmp->pmp_npnodehash));
                    447:                kmem_free(pmp, sizeof(struct puffs_mount));
1.1       pooka     448:                error = 0;
1.16      pooka     449:        } else {
1.31      pooka     450:                mutex_exit(&pmp->pmp_lock);
1.1       pooka     451:        }
                    452:
                    453:  out:
1.2       pooka     454:        DPRINTF(("puffs_unmount: return %d\n", error));
1.1       pooka     455:        return error;
                    456: }
                    457:
                    458: /*
                    459:  * This doesn't need to travel to userspace
                    460:  */
                    461: int
1.73      pooka     462: puffs_vfsop_root(struct mount *mp, struct vnode **vpp)
1.1       pooka     463: {
1.45      pooka     464:        struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.59      pooka     465:        int rv;
1.1       pooka     466:
1.59      pooka     467:        rv = puffs_cookie2vnode(pmp, pmp->pmp_root_cookie, 1, 1, vpp);
                    468:        KASSERT(rv != PUFFS_NOSUCHCOOKIE);
                    469:        return rv;
1.1       pooka     470: }
                    471:
                    472: int
1.73      pooka     473: puffs_vfsop_statvfs(struct mount *mp, struct statvfs *sbp)
1.1       pooka     474: {
1.63      pooka     475:        PUFFS_MSG_VARS(vfs, statvfs);
1.1       pooka     476:        struct puffs_mount *pmp;
                    477:        int error = 0;
                    478:
                    479:        pmp = MPTOPUFFSMP(mp);
                    480:
                    481:        /*
                    482:         * If we are mounting, it means that the userspace counterpart
                    483:         * is calling mount(2), but mount(2) also calls statvfs.  So
                    484:         * requesting statvfs from userspace would mean a deadlock.
                    485:         * Compensate.
                    486:         */
1.87      pooka     487:        if (__predict_false(pmp->pmp_status == PUFFSTAT_MOUNTING))
1.1       pooka     488:                return EINPROGRESS;
                    489:
1.63      pooka     490:        PUFFS_MSG_ALLOC(vfs, statvfs);
1.69      pooka     491:        puffs_msg_setinfo(park_statvfs, PUFFSOP_VFS, PUFFS_VFS_STATVFS, NULL);
1.1       pooka     492:
1.69      pooka     493:        PUFFS_MSG_ENQUEUEWAIT(pmp, park_statvfs, error);
1.60      pooka     494:        error = checkerr(pmp, error, __func__);
1.63      pooka     495:        statvfs_msg->pvfsr_sb.f_iosize = DEV_BSIZE;
1.10      pooka     496:
1.1       pooka     497:        /*
                    498:         * Try to produce a sensible result even in the event
                    499:         * of userspace error.
                    500:         *
                    501:         * XXX: cache the copy in non-error case
                    502:         */
                    503:        if (!error) {
1.63      pooka     504:                copy_statvfs_info(&statvfs_msg->pvfsr_sb, mp);
                    505:                (void)memcpy(sbp, &statvfs_msg->pvfsr_sb,
1.1       pooka     506:                    sizeof(struct statvfs));
                    507:        } else {
                    508:                copy_statvfs_info(sbp, mp);
                    509:        }
                    510:
1.63      pooka     511:        PUFFS_MSG_RELEASE(statvfs);
1.14      pooka     512:        return error;
1.1       pooka     513: }
                    514:
1.26      pooka     515: static int
1.83      pooka     516: pageflush(struct mount *mp, kauth_cred_t cred, int waitfor)
1.1       pooka     517: {
1.26      pooka     518:        struct puffs_node *pn;
1.74      ad        519:        struct vnode *vp, *mvp;
1.97      manu      520:        int error, rv, fsyncwait;
1.1       pooka     521:
1.18      pooka     522:        error = 0;
1.97      manu      523:        fsyncwait = (waitfor == MNT_WAIT) ? FSYNC_WAIT : 0;
1.18      pooka     524:
1.74      ad        525:        /* Allocate a marker vnode. */
1.98      hannken   526:        mvp = vnalloc(mp);
1.74      ad        527:
1.18      pooka     528:        /*
1.24      pooka     529:         * Sync all cached data from regular vnodes (which are not
                    530:         * currently locked, see below).  After this we call VFS_SYNC
                    531:         * for the fs server, which should handle data and metadata for
                    532:         * all the nodes it knows to exist.
1.18      pooka     533:         */
1.74      ad        534:        mutex_enter(&mntvnode_lock);
1.18      pooka     535:  loop:
1.74      ad        536:        for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
                    537:                vmark(mvp, vp);
                    538:                if (vp->v_mount != mp || vismarker(vp))
                    539:                        continue;
1.18      pooka     540:
1.96      rmind     541:                mutex_enter(vp->v_interlock);
1.26      pooka     542:                pn = VPTOPP(vp);
1.19      pooka     543:                if (vp->v_type != VREG || UVM_OBJ_IS_CLEAN(&vp->v_uobj)) {
1.96      rmind     544:                        mutex_exit(vp->v_interlock);
1.18      pooka     545:                        continue;
                    546:                }
                    547:
1.74      ad        548:                mutex_exit(&mntvnode_lock);
1.21      pooka     549:
                    550:                /*
                    551:                 * Here we try to get a reference to the vnode and to
                    552:                 * lock it.  This is mostly cargo-culted, but I will
                    553:                 * offer an explanation to why I believe this might
                    554:                 * actually do the right thing.
                    555:                 *
                    556:                 * If the vnode is a goner, we quite obviously don't need
                    557:                 * to sync it.
                    558:                 *
                    559:                 * If the vnode was busy, we don't need to sync it because
                    560:                 * this is never called with MNT_WAIT except from
                    561:                 * dounmount(), when we are wait-flushing all the dirty
                    562:                 * vnodes through other routes in any case.  So there,
                    563:                 * sync() doesn't actually sync.  Happy now?
                    564:                 */
1.95      hannken   565:                rv = vget(vp, LK_EXCLUSIVE | LK_NOWAIT);
1.18      pooka     566:                if (rv) {
1.74      ad        567:                        mutex_enter(&mntvnode_lock);
                    568:                        if (rv == ENOENT) {
                    569:                                (void)vunmark(mvp);
1.18      pooka     570:                                goto loop;
1.74      ad        571:                        }
1.18      pooka     572:                        continue;
                    573:                }
                    574:
1.83      pooka     575:                /* hmm.. is the FAF thing entirely sensible? */
                    576:                if (waitfor == MNT_LAZY) {
1.96      rmind     577:                        mutex_enter(vp->v_interlock);
1.83      pooka     578:                        pn->pn_stat |= PNODE_FAF;
1.96      rmind     579:                        mutex_exit(vp->v_interlock);
1.30      pooka     580:                }
1.97      manu      581:                rv = VOP_FSYNC(vp, cred, fsyncwait, 0, 0);
1.83      pooka     582:                if (waitfor == MNT_LAZY) {
1.96      rmind     583:                        mutex_enter(vp->v_interlock);
1.83      pooka     584:                        pn->pn_stat &= ~PNODE_FAF;
1.96      rmind     585:                        mutex_exit(vp->v_interlock);
1.26      pooka     586:                }
1.21      pooka     587:                if (rv)
1.18      pooka     588:                        error = rv;
                    589:                vput(vp);
1.74      ad        590:                mutex_enter(&mntvnode_lock);
1.18      pooka     591:        }
1.74      ad        592:        mutex_exit(&mntvnode_lock);
1.76      pooka     593:        vnfree(mvp);
1.18      pooka     594:
1.26      pooka     595:        return error;
                    596: }
                    597:
                    598: int
1.73      pooka     599: puffs_vfsop_sync(struct mount *mp, int waitfor, struct kauth_cred *cred)
1.26      pooka     600: {
1.63      pooka     601:        PUFFS_MSG_VARS(vfs, sync);
1.62      pooka     602:        struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.26      pooka     603:        int error, rv;
                    604:
1.83      pooka     605:        error = pageflush(mp, cred, waitfor);
1.26      pooka     606:
1.18      pooka     607:        /* sync fs */
1.63      pooka     608:        PUFFS_MSG_ALLOC(vfs, sync);
                    609:        sync_msg->pvfsr_waitfor = waitfor;
                    610:        puffs_credcvt(&sync_msg->pvfsr_cred, cred);
1.69      pooka     611:        puffs_msg_setinfo(park_sync, PUFFSOP_VFS, PUFFS_VFS_SYNC, NULL);
1.1       pooka     612:
1.69      pooka     613:        PUFFS_MSG_ENQUEUEWAIT(pmp, park_sync, rv);
1.62      pooka     614:        rv = checkerr(pmp, rv, __func__);
1.18      pooka     615:        if (rv)
                    616:                error = rv;
1.1       pooka     617:
1.63      pooka     618:        PUFFS_MSG_RELEASE(sync);
1.1       pooka     619:        return error;
                    620: }
                    621:
                    622: int
1.73      pooka     623: puffs_vfsop_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
1.1       pooka     624: {
1.63      pooka     625:        PUFFS_MSG_VARS(vfs, fhtonode);
1.33      pooka     626:        struct puffs_mount *pmp = MPTOPUFFSMP(mp);
                    627:        struct vnode *vp;
1.54      pooka     628:        void *fhdata;
                    629:        size_t argsize, fhlen;
1.33      pooka     630:        int error;
                    631:
1.38      pooka     632:        if (pmp->pmp_args.pa_fhsize == 0)
1.33      pooka     633:                return EOPNOTSUPP;
                    634:
1.54      pooka     635:        if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) {
                    636:                fhlen = fhp->fid_len;
                    637:                fhdata = fhp;
1.39      pooka     638:        } else {
1.54      pooka     639:                fhlen = PUFFS_FROMFHSIZE(fhp->fid_len);
                    640:                fhdata = fhp->fid_data;
                    641:
                    642:                if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) {
                    643:                        if (pmp->pmp_args.pa_fhsize < fhlen)
                    644:                                return EINVAL;
                    645:                } else {
                    646:                        if (pmp->pmp_args.pa_fhsize != fhlen)
                    647:                                return EINVAL;
                    648:                }
1.39      pooka     649:        }
1.33      pooka     650:
1.63      pooka     651:        argsize = sizeof(struct puffs_vfsmsg_fhtonode) + fhlen;
1.75      pooka     652:        puffs_msgmem_alloc(argsize, &park_fhtonode, (void *)&fhtonode_msg, 1);
1.63      pooka     653:        fhtonode_msg->pvfsr_dsize = fhlen;
                    654:        memcpy(fhtonode_msg->pvfsr_data, fhdata, fhlen);
1.69      pooka     655:        puffs_msg_setinfo(park_fhtonode, PUFFSOP_VFS, PUFFS_VFS_FHTOVP, NULL);
1.33      pooka     656:
1.69      pooka     657:        PUFFS_MSG_ENQUEUEWAIT(pmp, park_fhtonode, error);
1.60      pooka     658:        error = checkerr(pmp, error, __func__);
1.33      pooka     659:        if (error)
1.38      pooka     660:                goto out;
1.33      pooka     661:
1.63      pooka     662:        error = puffs_cookie2vnode(pmp, fhtonode_msg->pvfsr_fhcookie, 1,1,&vp);
1.33      pooka     663:        DPRINTF(("puffs_fhtovp: got cookie %p, existing vnode %p\n",
1.63      pooka     664:            fhtonode_msg->pvfsr_fhcookie, vp));
1.59      pooka     665:        if (error == PUFFS_NOSUCHCOOKIE) {
1.63      pooka     666:                error = puffs_getvnode(mp, fhtonode_msg->pvfsr_fhcookie,
                    667:                    fhtonode_msg->pvfsr_vtype, fhtonode_msg->pvfsr_size,
                    668:                    fhtonode_msg->pvfsr_rdev, &vp);
1.33      pooka     669:                if (error)
1.38      pooka     670:                        goto out;
1.33      pooka     671:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.59      pooka     672:        } else if (error) {
                    673:                goto out;
1.33      pooka     674:        }
1.1       pooka     675:
1.33      pooka     676:        *vpp = vp;
1.38      pooka     677:  out:
1.63      pooka     678:        puffs_msgmem_release(park_fhtonode);
1.38      pooka     679:        return error;
1.1       pooka     680: }
                    681:
                    682: int
1.73      pooka     683: puffs_vfsop_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1.1       pooka     684: {
1.63      pooka     685:        PUFFS_MSG_VARS(vfs, nodetofh);
1.33      pooka     686:        struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1.54      pooka     687:        size_t argsize, fhlen;
1.33      pooka     688:        int error;
                    689:
1.38      pooka     690:        if (pmp->pmp_args.pa_fhsize == 0)
1.33      pooka     691:                return EOPNOTSUPP;
                    692:
1.54      pooka     693:        /* if file handles are static len, we can test len immediately */
1.38      pooka     694:        if (((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) == 0)
1.54      pooka     695:            && ((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) == 0)
1.38      pooka     696:            && (PUFFS_FROMFHSIZE(*fh_size) < pmp->pmp_args.pa_fhsize)) {
                    697:                *fh_size = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
1.33      pooka     698:                return E2BIG;
                    699:        }
1.1       pooka     700:
1.54      pooka     701:        if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
                    702:                fhlen = *fh_size;
                    703:        else
                    704:                fhlen = PUFFS_FROMFHSIZE(*fh_size);
                    705:
1.63      pooka     706:        argsize = sizeof(struct puffs_vfsmsg_nodetofh) + fhlen;
1.75      pooka     707:        puffs_msgmem_alloc(argsize, &park_nodetofh, (void *)&nodetofh_msg, 1);
1.63      pooka     708:        nodetofh_msg->pvfsr_fhcookie = VPTOPNC(vp);
                    709:        nodetofh_msg->pvfsr_dsize = fhlen;
1.69      pooka     710:        puffs_msg_setinfo(park_nodetofh, PUFFSOP_VFS, PUFFS_VFS_VPTOFH, NULL);
1.38      pooka     711:
1.69      pooka     712:        PUFFS_MSG_ENQUEUEWAIT(pmp, park_nodetofh, error);
1.60      pooka     713:        error = checkerr(pmp, error, __func__);
1.54      pooka     714:
                    715:        if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
1.63      pooka     716:                fhlen = nodetofh_msg->pvfsr_dsize;
1.54      pooka     717:        else if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC)
1.63      pooka     718:                fhlen = PUFFS_TOFHSIZE(nodetofh_msg->pvfsr_dsize);
1.54      pooka     719:        else
                    720:                fhlen = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
                    721:
1.38      pooka     722:        if (error) {
                    723:                if (error == E2BIG)
1.54      pooka     724:                        *fh_size = fhlen;
1.38      pooka     725:                goto out;
                    726:        }
                    727:
1.54      pooka     728:        if (fhlen > FHANDLE_SIZE_MAX) {
1.69      pooka     729:                puffs_senderr(pmp, PUFFS_ERR_VPTOFH, E2BIG,
1.60      pooka     730:                    "file handle too big", VPTOPNC(vp));
1.58      pooka     731:                error = EPROTO;
1.38      pooka     732:                goto out;
                    733:        }
1.33      pooka     734:
1.54      pooka     735:        if (*fh_size < fhlen) {
                    736:                *fh_size = fhlen;
1.38      pooka     737:                error = E2BIG;
                    738:                goto out;
                    739:        }
1.54      pooka     740:        *fh_size = fhlen;
1.1       pooka     741:
1.38      pooka     742:        if (fhp) {
1.54      pooka     743:                if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) {
1.63      pooka     744:                        memcpy(fhp, nodetofh_msg->pvfsr_data, fhlen);
1.54      pooka     745:                } else {
                    746:                        fhp->fid_len = *fh_size;
1.63      pooka     747:                        memcpy(fhp->fid_data, nodetofh_msg->pvfsr_data,
                    748:                            nodetofh_msg->pvfsr_dsize);
1.54      pooka     749:                }
1.38      pooka     750:        }
1.1       pooka     751:
1.38      pooka     752:  out:
1.63      pooka     753:        puffs_msgmem_release(park_nodetofh);
1.38      pooka     754:        return error;
1.1       pooka     755: }
                    756:
                    757: void
1.82      cegger    758: puffs_vfsop_init(void)
1.1       pooka     759: {
                    760:
1.56      pooka     761:        /* some checks depend on this */
                    762:        KASSERT(VNOVAL == VSIZENOTSET);
                    763:
1.31      pooka     764:        pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0,
                    765:            "puffpnpl", &pool_allocator_nointr, IPL_NONE);
1.100.8.1! riz       766:        pool_init(&puffs_vapool, sizeof(struct vattr), 0, 0, 0,
        !           767:            "puffvapl", &pool_allocator_nointr, IPL_NONE);
1.31      pooka     768:        puffs_msgif_init();
1.1       pooka     769: }
                    770:
                    771: void
1.82      cegger    772: puffs_vfsop_done(void)
1.1       pooka     773: {
                    774:
1.31      pooka     775:        puffs_msgif_destroy();
                    776:        pool_destroy(&puffs_pnpool);
1.100.8.1! riz       777:        pool_destroy(&puffs_vapool);
1.1       pooka     778: }
                    779:
                    780: int
1.73      pooka     781: puffs_vfsop_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ts)
1.1       pooka     782: {
                    783:
                    784:        return EOPNOTSUPP;
                    785: }
                    786:
1.88      pooka     787: int
                    788: puffs_vfsop_extattrctl(struct mount *mp, int cmd, struct vnode *vp,
                    789:        int attrnamespace, const char *attrname)
                    790: {
                    791:        PUFFS_MSG_VARS(vfs, extattrctl);
                    792:        struct puffs_mount *pmp = MPTOPUFFSMP(mp);
                    793:        struct puffs_node *pnp;
                    794:        puffs_cookie_t pnc;
                    795:        int error, flags;
                    796:
                    797:        if (vp) {
                    798:                /* doesn't make sense for puffs servers */
                    799:                if (vp->v_mount != mp)
                    800:                        return EXDEV;
                    801:                pnp = vp->v_data;
                    802:                pnc = pnp->pn_cookie;
                    803:                flags = PUFFS_EXTATTRCTL_HASNODE;
                    804:        } else {
                    805:                pnp = pnc = NULL;
                    806:                flags = 0;
                    807:        }
                    808:
                    809:        PUFFS_MSG_ALLOC(vfs, extattrctl);
                    810:        extattrctl_msg->pvfsr_cmd = cmd;
                    811:        extattrctl_msg->pvfsr_attrnamespace = attrnamespace;
                    812:        extattrctl_msg->pvfsr_flags = flags;
                    813:        if (attrname) {
                    814:                strlcpy(extattrctl_msg->pvfsr_attrname, attrname,
                    815:                    sizeof(extattrctl_msg->pvfsr_attrname));
                    816:                extattrctl_msg->pvfsr_flags |= PUFFS_EXTATTRCTL_HASATTRNAME;
                    817:        }
                    818:        puffs_msg_setinfo(park_extattrctl,
                    819:            PUFFSOP_VFS, PUFFS_VFS_EXTATTRCTL, pnc);
                    820:
                    821:        puffs_msg_enqueue(pmp, park_extattrctl);
                    822:        if (vp) {
                    823:                mutex_enter(&pnp->pn_mtx);
                    824:                puffs_referencenode(pnp);
                    825:                mutex_exit(&pnp->pn_mtx);
1.90      hannken   826:                VOP_UNLOCK(vp);
1.88      pooka     827:        }
                    828:        error = puffs_msg_wait2(pmp, park_extattrctl, pnp, NULL);
                    829:        PUFFS_MSG_RELEASE(extattrctl);
                    830:        if (vp) {
                    831:                puffs_releasenode(pnp);
                    832:        }
                    833:
                    834:        return checkerr(pmp, error, __func__);
                    835: }
                    836:
1.1       pooka     837: const struct vnodeopv_desc * const puffs_vnodeopv_descs[] = {
                    838:        &puffs_vnodeop_opv_desc,
1.3       pooka     839:        &puffs_specop_opv_desc,
1.4       pooka     840:        &puffs_fifoop_opv_desc,
1.12      pooka     841:        &puffs_msgop_opv_desc,
1.1       pooka     842:        NULL,
                    843: };
                    844:
                    845: struct vfsops puffs_vfsops = {
                    846:        MOUNT_PUFFS,
1.48      dsl       847:        sizeof (struct puffs_kargs),
1.73      pooka     848:        puffs_vfsop_mount,              /* mount        */
                    849:        puffs_vfsop_start,              /* start        */
                    850:        puffs_vfsop_unmount,            /* unmount      */
                    851:        puffs_vfsop_root,               /* root         */
                    852:        (void *)eopnotsupp,             /* quotactl     */
                    853:        puffs_vfsop_statvfs,            /* statvfs      */
                    854:        puffs_vfsop_sync,               /* sync         */
                    855:        (void *)eopnotsupp,             /* vget         */
                    856:        puffs_vfsop_fhtovp,             /* fhtovp       */
                    857:        puffs_vfsop_vptofh,             /* vptofh       */
                    858:        puffs_vfsop_init,               /* init         */
                    859:        NULL,                           /* reinit       */
                    860:        puffs_vfsop_done,               /* done         */
                    861:        NULL,                           /* mountroot    */
                    862:        puffs_vfsop_snapshot,           /* snapshot     */
1.88      pooka     863:        puffs_vfsop_extattrctl,         /* extattrctl   */
1.83      pooka     864:        (void *)eopnotsupp,             /* suspendctl   */
1.78      dholland  865:        genfs_renamelock_enter,
                    866:        genfs_renamelock_exit,
1.79      ad        867:        (void *)eopnotsupp,
1.73      pooka     868:        puffs_vnodeopv_descs,           /* vnodeops     */
                    869:        0,                              /* refcount     */
1.1       pooka     870:        { NULL, NULL }
                    871: };
1.80      rumble    872:
                    873: static int
                    874: puffs_modcmd(modcmd_t cmd, void *arg)
                    875: {
                    876:
                    877:        switch (cmd) {
                    878:        case MODULE_CMD_INIT:
                    879:                return vfs_attach(&puffs_vfsops);
                    880:        case MODULE_CMD_FINI:
                    881:                return vfs_detach(&puffs_vfsops);
                    882:        default:
                    883:                return ENOTTY;
                    884:        }
                    885: }

CVSweb <webmaster@jp.NetBSD.org>