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

Annotation of src/sys/fs/puffs/puffs_transport.c, Revision 1.8.10.1

1.8.10.1! reinoud     1: /* $NetBSD: puffs_transport.c,v 1.8 2007/02/16 17:23:59 hannken Exp $ */
1.1       pooka       2:
                      3: /*
1.3       pooka       4:  * Copyright (c) 2006  Antti Kantee.  All Rights Reserved.
1.1       pooka       5:  *
                      6:  * Development of this software was supported by the
1.3       pooka       7:  * Ulla Tuominen Foundation.
1.1       pooka       8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. The name of the company nor the name of the author may be used to
                     18:  *    endorse or promote products derived from this software without specific
                     19:  *    prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
                     22:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     23:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     24:  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     27:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  */
                     33:
1.3       pooka      34: #include <sys/cdefs.h>
1.8.10.1! reinoud    35: __KERNEL_RCSID(0, "$NetBSD: puffs_transport.c,v 1.8 2007/02/16 17:23:59 hannken Exp $");
1.3       pooka      36:
1.1       pooka      37: #include <sys/param.h>
                     38: #include <sys/conf.h>
                     39: #include <sys/file.h>
                     40: #include <sys/filedesc.h>
1.5       pooka      41: #include <sys/fstrans.h>
                     42: #include <sys/kthread.h>
1.1       pooka      43: #include <sys/malloc.h>
1.4       pooka      44: #include <sys/namei.h>
1.1       pooka      45: #include <sys/poll.h>
                     46: #include <sys/socketvar.h>
                     47:
                     48: #include <fs/puffs/puffs_sys.h>
                     49:
1.7       ad         50: #include <miscfs/syncfs/syncfs.h> /* XXX: for syncer_mutex reference */
1.1       pooka      51:
                     52:
                     53: /*
                     54:  * puffs instance structures.  these are always allocated and freed
                     55:  * from the context of the device node / fileop code.
                     56:  */
                     57: struct puffs_instance {
                     58:        pid_t pi_pid;
                     59:        int pi_idx;
                     60:        int pi_fd;
                     61:        struct puffs_mount *pi_pmp;
                     62:        struct selinfo pi_sel;
                     63:
                     64:        TAILQ_ENTRY(puffs_instance) pi_entries;
                     65: };
                     66: #define PMP_EMBRYO ((struct puffs_mount *)-1)  /* before mount */
                     67: #define PMP_DEAD ((struct puffs_mount *)-2)    /* goner        */
                     68:
                     69: static TAILQ_HEAD(, puffs_instance) puffs_ilist
                     70:     = TAILQ_HEAD_INITIALIZER(puffs_ilist);
                     71:
1.8.10.1! reinoud    72: static int get_pi_idx(struct puffs_instance *);
        !            73:
        !            74:
        !            75: /*
        !            76:  * public init / deinit
        !            77:  */
        !            78:
1.1       pooka      79: /* protects both the list and the contents of the list elements */
1.8.10.1! reinoud    80: static kmutex_t pi_mtx;
1.1       pooka      81:
1.8.10.1! reinoud    82: void
        !            83: puffs_transport_init()
        !            84: {
        !            85:
        !            86:        mutex_init(&pi_mtx, MUTEX_DEFAULT, IPL_NONE);
        !            87: }
1.1       pooka      88:
1.8.10.1! reinoud    89: void
        !            90: puffs_transport_destroy()
        !            91: {
        !            92:
        !            93:        mutex_destroy(&pi_mtx);
        !            94: }
1.1       pooka      95:
                     96: /*
                     97:  * fd routines, for cloner
                     98:  */
                     99: static int puffs_fop_read(struct file *, off_t *, struct uio *,
                    100:                          kauth_cred_t, int);
                    101: static int puffs_fop_write(struct file *, off_t *, struct uio *,
                    102:                           kauth_cred_t, int);
                    103: static int puffs_fop_ioctl(struct file*, u_long, void *, struct lwp *);
                    104: static int puffs_fop_poll(struct file *, int, struct lwp *);
                    105: static int puffs_fop_close(struct file *, struct lwp *);
                    106: static int puffs_fop_kqfilter(struct file *, struct knote *);
                    107:
                    108:
                    109: static const struct fileops puffs_fileops = {
                    110:        puffs_fop_read,
                    111:        puffs_fop_write,
                    112:        puffs_fop_ioctl,
                    113:        fnullop_fcntl,
                    114:        puffs_fop_poll,
                    115:        fbadop_stat,
                    116:        puffs_fop_close,
                    117:        puffs_fop_kqfilter
                    118: };
                    119:
                    120: static int
                    121: puffs_fop_read(struct file *fp, off_t *off, struct uio *uio,
                    122:        kauth_cred_t cred, int flags)
                    123: {
                    124:
                    125:        return ENODEV;
                    126: }
                    127:
                    128: static int
                    129: puffs_fop_write(struct file *fp, off_t *off, struct uio *uio,
                    130:        kauth_cred_t cred, int flags)
                    131: {
                    132:
                    133:        return ENODEV;
                    134: }
                    135:
                    136: /*
                    137:  * Poll query interface.  The question is only if an event
                    138:  * can be read from us (and by read I mean ioctl... ugh).
                    139:  */
                    140: #define PUFFPOLL_EVSET (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)
                    141: static int
                    142: puffs_fop_poll(struct file *fp, int events, struct lwp *l)
                    143: {
                    144:        struct puffs_mount *pmp = FPTOPMP(fp);
                    145:        int revents;
                    146:
                    147:        if (pmp == PMP_EMBRYO || pmp == PMP_DEAD) {
                    148:                printf("puffs_fop_ioctl: puffs %p, not mounted\n", pmp);
                    149:                return ENOENT;
                    150:        }
                    151:
                    152:        revents = events & (POLLOUT | POLLWRNORM | POLLWRBAND);
                    153:        if ((events & PUFFPOLL_EVSET) == 0)
                    154:                return revents;
                    155:
                    156:        /* check queue */
1.8.10.1! reinoud   157:        mutex_enter(&pmp->pmp_lock);
1.1       pooka     158:        if (!TAILQ_EMPTY(&pmp->pmp_req_touser))
                    159:                revents |= PUFFPOLL_EVSET;
                    160:        else
                    161:                selrecord(l, pmp->pmp_sel);
1.8.10.1! reinoud   162:        mutex_exit(&pmp->pmp_lock);
1.1       pooka     163:
                    164:        return revents;
                    165: }
                    166:
                    167: /*
                    168:  * device close = forced unmount.
                    169:  *
                    170:  * unmounting is a frightfully complex operation to avoid races
                    171:  */
                    172: static int
                    173: puffs_fop_close(struct file *fp, struct lwp *l)
                    174: {
                    175:        struct puffs_instance *pi;
                    176:        struct puffs_mount *pmp;
                    177:        struct mount *mp;
1.2       pooka     178:        int gone, rv;
1.1       pooka     179:
                    180:        DPRINTF(("puffs_fop_close: device closed, force filesystem unmount\n"));
                    181:
1.2       pooka     182:  restart:
1.8.10.1! reinoud   183:        mutex_enter(&pi_mtx);
1.1       pooka     184:        pmp = FPTOPMP(fp);
                    185:        /*
                    186:         * First check if the fs was never mounted.  In that case
                    187:         * remove the instance from the list.  If mount is attempted later,
                    188:         * it will simply fail.
                    189:         */
                    190:        if (pmp == PMP_EMBRYO) {
                    191:                pi = FPTOPI(fp);
                    192:                TAILQ_REMOVE(&puffs_ilist, pi, pi_entries);
1.8.10.1! reinoud   193:                mutex_exit(&pi_mtx);
1.1       pooka     194:                FREE(pi, M_PUFFS);
1.2       pooka     195:
                    196:                DPRINTF(("puffs_fop_close: pmp associated with fp %p was "
                    197:                    "embryonic\n", fp));
                    198:
1.1       pooka     199:                return 0;
                    200:        }
                    201:
                    202:        /*
                    203:         * Next, analyze unmount was called and the instance is dead.
                    204:         * In this case we can just free the structure and go home, it
                    205:         * was removed from the list by puffs_nukebypmp().
                    206:         */
                    207:        if (pmp == PMP_DEAD) {
                    208:                /* would be nice, but don't have a reference to it ... */
                    209:                /* KASSERT(pmp_status == PUFFSTAT_DYING); */
1.8.10.1! reinoud   210:                mutex_exit(&pi_mtx);
1.2       pooka     211:
                    212:                DPRINTF(("puffs_fop_close: pmp associated with fp %p was "
                    213:                    "dead\n", fp));
                    214:
1.3       pooka     215:                goto out;
1.1       pooka     216:        }
                    217:
                    218:        /*
                    219:         * So we have a reference.  Proceed to unwrap the file system.
                    220:         */
                    221:        mp = PMPTOMP(pmp);
1.8.10.1! reinoud   222:        mutex_exit(&pi_mtx);
        !           223:        mutex_enter(&pmp->pmp_lock);
1.1       pooka     224:
                    225:        /*
                    226:         * Free the waiting callers before proceeding any further.
                    227:         * The syncer might be jogging around in this file system
                    228:         * currently.  If we allow it to go to the userspace of no
                    229:         * return while trying to get the syncer lock, well ...
                    230:         * synclk: I feel happy, I feel fine.
                    231:         * lockmgr: You're not fooling anyone, you know.
                    232:         */
                    233:        puffs_userdead(pmp);
                    234:
                    235:        /*
1.2       pooka     236:         * Make sure someone from puffs_unmount() isn't currently in
                    237:         * userspace.  If we don't take this precautionary step,
                    238:         * they might notice that the mountpoint has disappeared
                    239:         * from under them once they return.  Especially note that we
                    240:         * cannot simply test for an unmounter before calling
                    241:         * dounmount(), since it might be possible that that particular
                    242:         * invocation of unmount was called without MNT_FORCE.  Here we
                    243:         * *must* make sure unmount succeeds.  Also, restart is necessary
                    244:         * since pmp isn't locked.  We might end up with PMP_DEAD after
                    245:         * restart and exit from there.
                    246:         */
                    247:        if (pmp->pmp_unmounting) {
1.8.10.1! reinoud   248:                cv_wait(&pmp->pmp_unmounting_cv, &pmp->pmp_lock);
        !           249: #if 0
1.2       pooka     250:                ltsleep(&pmp->pmp_unmounting, PNORELOCK | PVFS, "puffsum",
                    251:                    0, &pmp->pmp_lock);
1.8.10.1! reinoud   252: #endif
        !           253:                mutex_exit(&pmp->pmp_lock);
1.2       pooka     254:                DPRINTF(("puffs_fop_close: unmount was in progress for pmp %p, "
                    255:                    "restart\n", pmp));
                    256:                goto restart;
                    257:        }
                    258:
                    259:        /*
1.5       pooka     260:         * Check that suspend isn't running.  Issues here:
                    261:         * + we cannot nuke the mountpoint while suspend is running
                    262:         *   because we risk nuking it from under us (as usual... does
                    263:         *   anyone see a pattern forming?)
                    264:         * + we must have userdead or the suspend thread might deadlock.
                    265:         *   this has been done above
                    266:         * + this DOES NOT solve the problem with the regular unmount path.
                    267:         *   however, it is way way way way less likely a problem.
                    268:         *   perhaps vfs_busy() in vfs_suspend() would help?
                    269:         */
                    270:        if (pmp->pmp_suspend) {
1.8.10.1! reinoud   271:                cv_wait(&pmp->pmp_suspend_cv, &pmp->pmp_lock);
        !           272: #if 0
1.5       pooka     273:                ltsleep(&pmp->pmp_suspend, PNORELOCK | PVFS, "puffsusum",
                    274:                    0, &pmp->pmp_lock);
1.8.10.1! reinoud   275: #endif
        !           276:                mutex_exit(&pmp->pmp_lock);
1.5       pooka     277:                DPRINTF(("puffs_fop_close: suspend was in progress for pmp %p, "
                    278:                    "restart\n", pmp));
                    279:                goto restart;
                    280:        }
1.8.10.1! reinoud   281:        mutex_exit(&pmp->pmp_lock);
1.5       pooka     282:
                    283:        /*
1.1       pooka     284:         * Detach from VFS.  First do necessary XXX-dance (from
                    285:         * sys_unmount() & other callers of dounmount()
                    286:         *
                    287:         * XXX Freeze syncer.  Must do this before locking the
                    288:         * mount point.  See dounmount() for details.
                    289:         *
                    290:         * XXX2: take a reference to the mountpoint before starting to
1.7       ad        291:         * wait for syncer_mutex.  Otherwise the mointpoint can be
1.1       pooka     292:         * wiped out while we wait.
                    293:         */
                    294:        simple_lock(&mp->mnt_slock);
                    295:        mp->mnt_wcnt++;
                    296:        simple_unlock(&mp->mnt_slock);
                    297:
1.7       ad        298:        mutex_enter(&syncer_mutex);
1.1       pooka     299:
                    300:        simple_lock(&mp->mnt_slock);
                    301:        mp->mnt_wcnt--;
                    302:        if (mp->mnt_wcnt == 0)
                    303:                wakeup(&mp->mnt_wcnt);
                    304:        gone = mp->mnt_iflag & IMNT_GONE;
                    305:        simple_unlock(&mp->mnt_slock);
                    306:        if (gone) {
1.7       ad        307:                mutex_exit(&syncer_mutex);
1.3       pooka     308:                goto out;
1.1       pooka     309:        }
                    310:
                    311:        /*
                    312:         * microscopic race condition here (although not with the current
                    313:         * kernel), but can't really fix it without starting a crusade
                    314:         * against vfs_busy(), so let it be, let it be, let it be
                    315:         */
                    316:
                    317:        /*
                    318:         * The only way vfs_busy() will fail for us is if the filesystem
                    319:         * is already a goner.
                    320:         * XXX: skating on the thin ice of modern calling conventions ...
                    321:         */
                    322:        if (vfs_busy(mp, 0, 0)) {
1.7       ad        323:                mutex_exit(&syncer_mutex);
1.3       pooka     324:                goto out;
1.1       pooka     325:        }
                    326:
1.3       pooka     327:        /*
                    328:         * Once we have the mount point, unmount() can't interfere..
                    329:         * or at least in theory it shouldn't.  dounmount() reentracy
                    330:         * might require some visiting at some point.
                    331:         */
1.2       pooka     332:        rv = dounmount(mp, MNT_FORCE, l);
1.3       pooka     333:        KASSERT(rv == 0);
                    334:
                    335:  out:
                    336:        /*
                    337:         * Finally, release the instance information.  It was already
                    338:         * removed from the list by puffs_nukebypmp() and we know it's
                    339:         * dead, so no need to lock.
                    340:         */
                    341:        pi = FPTOPI(fp);
                    342:        FREE(pi, M_PUFFS);
1.1       pooka     343:
                    344:        return 0;
                    345: }
                    346:
                    347: static int
1.4       pooka     348: puffs_flush(struct puffs_mount *pmp, struct puffs_flush *pf)
                    349: {
                    350:        struct vnode *vp;
                    351:        int rv;
                    352:
                    353:        /* XXX: slurry */
                    354:        if (pf->pf_op == PUFFS_INVAL_NAMECACHE_ALL) {
                    355:                cache_purgevfs(PMPTOMP(pmp));
                    356:                return 0;
                    357:        }
                    358:
                    359:        rv = 0;
                    360:
                    361:        /*
                    362:         * Get vnode, don't lock it.  Namecache is protected by its own lock
                    363:         * and we have a reference to protect against premature harvesting.
                    364:         *
                    365:         * The node we want here might be locked and the op is in
                    366:         * userspace waiting for us to complete ==> deadlock.  Another
                    367:         * reason we need to eventually bump locking to userspace, as we
                    368:         * will need to lock the node if we wish to do flushes.
                    369:         */
                    370:        vp = puffs_pnode2vnode(pmp, pf->pf_cookie, 0);
                    371:        if (vp == NULL)
                    372:                return ENOENT;
                    373:
                    374:        switch (pf->pf_op) {
                    375: #if 0
                    376:        /* not quite ready, yet */
                    377:        case PUFFS_INVAL_NAMECACHE_NODE:
                    378:        struct componentname *pf_cn;
                    379:        char *name;
                    380:                /* get comfortab^Wcomponentname */
                    381:                MALLOC(pf_cn, struct componentname *,
                    382:                    sizeof(struct componentname), M_PUFFS, M_WAITOK | M_ZERO);
                    383:                memset(pf_cn, 0, sizeof(struct componentname));
                    384:                break;
                    385:
                    386: #endif
                    387:        case PUFFS_INVAL_NAMECACHE_DIR:
                    388:                cache_purge1(vp, NULL, PURGE_CHILDREN);
                    389:                break;
                    390:
1.8.10.1! reinoud   391: #if 0
        !           392:        case PUFFS_INVAL_PAGECACHE_NODE_RANGE:
        !           393:                simple_lock(&vp->v_uobj.vmobjlock);
        !           394:                /* XXX: validate args? */
        !           395:                rv = VOP_PUTPAGES(vp, pf->pf_start, pf->pf_end, PGO_FREE);
        !           396:                break;
        !           397: #endif
        !           398:
        !           399:        case PUFFS_INVAL_PAGECACHE_NODE:
        !           400:                simple_lock(&vp->v_uobj.vmobjlock);
        !           401:                rv = VOP_PUTPAGES(vp, 0, 0, PGO_FREE | PGO_ALLPAGES);
        !           402:                break;
        !           403:
1.4       pooka     404:        default:
                    405:                rv = EINVAL;
                    406:        }
                    407:
                    408:        vrele(vp);
                    409:
                    410:        return rv;
                    411: }
                    412:
1.5       pooka     413: static void
                    414: dosuspendresume(void *arg)
                    415: {
                    416:        struct puffs_mount *pmp = arg;
                    417:        struct mount *mp;
                    418:        int rv;
                    419:
                    420:        mp = PMPTOMP(pmp);
                    421:        /*
                    422:         * XXX?  does this really do any good or is it just
                    423:         * paranoid stupidity?  or stupid paranoia?
                    424:         */
                    425:        if (mp->mnt_iflag & IMNT_UNMOUNT) {
                    426:                printf("puffs dosuspendresume(): detected suspend on "
                    427:                    "unmounting fs\n");
                    428:                goto out;
                    429:        }
                    430:
                    431:        /* do the dance */
                    432:        rv = vfs_suspend(PMPTOMP(pmp), 0);
                    433:        if (rv == 0)
                    434:                vfs_resume(PMPTOMP(pmp));
                    435:
1.8.10.1! reinoud   436:        mutex_enter(&pmp->pmp_lock);
1.5       pooka     437:        KASSERT(pmp->pmp_suspend);
                    438:        pmp->pmp_suspend = 0;
1.8.10.1! reinoud   439:        cv_broadcast(&pmp->pmp_suspend_cv);
        !           440:        mutex_exit(&pmp->pmp_lock);
1.5       pooka     441:
                    442:  out:
                    443:        kthread_exit(0);
                    444: }
                    445:
1.4       pooka     446: static int
1.1       pooka     447: puffs_fop_ioctl(struct file *fp, u_long cmd, void *data, struct lwp *l)
                    448: {
1.6       pooka     449:        struct puffs_mount *pmp = FPTOPMP(fp);
1.1       pooka     450:        int rv;
                    451:
                    452:        if (pmp == PMP_EMBRYO || pmp == PMP_DEAD) {
                    453:                printf("puffs_fop_ioctl: puffs %p, not mounted\n", pmp);
                    454:                return ENOENT;
                    455:        }
                    456:
                    457:        switch (cmd) {
                    458:        case PUFFSGETOP:
                    459:                rv = puffs_getop(pmp, data, fp->f_flag & FNONBLOCK);
                    460:                break;
                    461:
                    462:        case PUFFSPUTOP:
                    463:                rv =  puffs_putop(pmp, data);
                    464:                break;
                    465:
                    466: #if 0 /* bitrot */
                    467:        case PUFFSSIZEOP:
                    468:                rv = puffssizeop(pmp, data);
                    469:                break;
                    470: #endif
                    471:
                    472:        case PUFFSSTARTOP:
                    473:                rv = puffs_start2(pmp, data);
                    474:                break;
                    475:
1.4       pooka     476:        case PUFFSFLUSHOP:
                    477:                rv = puffs_flush(pmp, data);
                    478:                break;
                    479:
1.5       pooka     480:        case PUFFSSUSPENDOP:
                    481:                rv = 0;
1.8.10.1! reinoud   482:                mutex_enter(&pmp->pmp_lock);
1.5       pooka     483:                if (pmp->pmp_suspend || pmp->pmp_status != PUFFSTAT_RUNNING)
                    484:                        rv = EBUSY;
                    485:                else
                    486:                        pmp->pmp_suspend = 1;
1.8.10.1! reinoud   487:                mutex_exit(&pmp->pmp_lock);
1.5       pooka     488:                if (rv)
                    489:                        break;
                    490:                rv = kthread_create1(dosuspendresume, pmp, NULL, "puffsusp");
                    491:                break;
                    492:
1.1       pooka     493:        /* already done in sys_ioctl() */
                    494:        case FIONBIO:
                    495:                rv = 0;
                    496:                break;
                    497:
                    498:        default:
                    499:                rv = EINVAL;
                    500:                break;
                    501:        }
                    502:
                    503:        return rv;
                    504: }
                    505:
                    506: /* kqueue stuff */
                    507:
                    508: static void
                    509: filt_puffsdetach(struct knote *kn)
                    510: {
                    511:        struct puffs_instance *pi = kn->kn_hook;
                    512:
1.8.10.1! reinoud   513:        mutex_enter(&pi_mtx);
1.1       pooka     514:        SLIST_REMOVE(&pi->pi_sel.sel_klist, kn, knote, kn_selnext);
1.8.10.1! reinoud   515:        mutex_exit(&pi_mtx);
1.1       pooka     516: }
                    517:
                    518: static int
                    519: filt_puffsioctl(struct knote *kn, long hint)
                    520: {
                    521:        struct puffs_instance *pi = kn->kn_hook;
                    522:        struct puffs_mount *pmp;
                    523:        int error;
                    524:
                    525:        error = 0;
1.8.10.1! reinoud   526:        mutex_enter(&pi_mtx);
1.1       pooka     527:        pmp = pi->pi_pmp;
                    528:        if (pmp == PMP_EMBRYO || pmp == PMP_DEAD)
                    529:                error = 1;
1.8.10.1! reinoud   530:        mutex_exit(&pi_mtx);
1.1       pooka     531:        if (error)
                    532:                return 0;
                    533:
1.8.10.1! reinoud   534:        mutex_enter(&pmp->pmp_lock);
        !           535:        kn->kn_data = pmp->pmp_req_waiters;
        !           536:        mutex_exit(&pmp->pmp_lock);
1.1       pooka     537:
                    538:        return kn->kn_data != 0;
                    539: }
                    540:
                    541: static const struct filterops puffsioctl_filtops =
                    542:        { 1, NULL, filt_puffsdetach, filt_puffsioctl };
                    543:
                    544: static int
                    545: puffs_fop_kqfilter(struct file *fp, struct knote *kn)
                    546: {
                    547:        struct puffs_instance *pi = fp->f_data;
                    548:        struct klist *klist;
                    549:
                    550:        if (kn->kn_filter != EVFILT_READ)
                    551:                return 1;
                    552:
                    553:        klist = &pi->pi_sel.sel_klist;
                    554:        kn->kn_fop = &puffsioctl_filtops;
                    555:        kn->kn_hook = pi;
                    556:
1.8.10.1! reinoud   557:        mutex_enter(&pi_mtx);
1.1       pooka     558:        SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1.8.10.1! reinoud   559:        mutex_exit(&pi_mtx);
1.1       pooka     560:
                    561:        return 0;
                    562: }
                    563:
                    564:
                    565: /*
                    566:  * Device routines
                    567:  */
                    568:
                    569: dev_type_open(puffscdopen);
                    570: dev_type_close(puffscdclose);
                    571: dev_type_ioctl(puffscdioctl);
                    572:
                    573: /* dev */
                    574: const struct cdevsw puffs_cdevsw = {
                    575:        puffscdopen,    puffscdclose,   noread,         nowrite,
                    576:        noioctl,        nostop,         notty,          nopoll,
                    577:        nommap,         nokqfilter,     D_OTHER
                    578: };
                    579: int
                    580: puffscdopen(dev_t dev, int flags, int fmt, struct lwp *l)
                    581: {
                    582:        struct puffs_instance *pi;
                    583:        struct file *fp;
                    584:        int error, fd, idx;
                    585:
                    586:        /*
                    587:         * XXX: decide on some security model and check permissions
                    588:         */
                    589:
                    590:        if (minor(dev) != PUFFS_CLONER)
                    591:                return ENXIO;
                    592:
                    593:        if ((error = falloc(l, &fp, &fd)) != 0)
                    594:                return error;
                    595:
                    596:        MALLOC(pi, struct puffs_instance *, sizeof(struct puffs_instance),
                    597:            M_PUFFS, M_WAITOK | M_ZERO);
                    598:
1.8.10.1! reinoud   599:        mutex_enter(&pi_mtx);
1.1       pooka     600:        idx = get_pi_idx(pi);
                    601:        if (idx == PUFFS_CLONER) {
1.8.10.1! reinoud   602:                mutex_exit(&pi_mtx);
1.1       pooka     603:                FREE(pi, M_PUFFS);
                    604:                FILE_UNUSE(fp, l);
                    605:                ffree(fp);
                    606:                return EBUSY;
                    607:        }
                    608:
                    609:        pi->pi_pid = l->l_proc->p_pid;
                    610:        pi->pi_idx = idx;
1.8.10.1! reinoud   611:        mutex_exit(&pi_mtx);
1.1       pooka     612:
                    613:        DPRINTF(("puffscdopen: registered embryonic pmp for pid: %d\n",
                    614:            pi->pi_pid));
                    615:
                    616:        return fdclone(l, fp, fd, FREAD|FWRITE, &puffs_fileops, pi);
                    617: }
                    618:
                    619: int
                    620: puffscdclose(dev_t dev, int flags, int fmt, struct lwp *l)
                    621: {
                    622:
                    623:        panic("puffscdclose impossible\n");
                    624:
                    625:        return 0;
                    626: }
                    627:
                    628:
                    629: /*
                    630:  * Set puffs_mount -pointer.  Called from puffs_mount(), which is the
                    631:  * earliest place that knows about this.
                    632:  *
                    633:  * We only want to make sure that the caller had the right to open the
                    634:  * device, we don't so much care about which context it gets in case
                    635:  * the same process opened multiple (since they are equal at this point).
                    636:  */
                    637: int
                    638: puffs_setpmp(pid_t pid, int fd, struct puffs_mount *pmp)
                    639: {
                    640:        struct puffs_instance *pi;
                    641:        int rv = 1;
                    642:
1.8.10.1! reinoud   643:        mutex_enter(&pi_mtx);
1.1       pooka     644:        TAILQ_FOREACH(pi, &puffs_ilist, pi_entries) {
                    645:                if (pi->pi_pid == pid && pi->pi_pmp == PMP_EMBRYO) {
                    646:                        pi->pi_pmp = pmp;
                    647:                        pi->pi_fd = fd;
                    648:                        pmp->pmp_sel = &pi->pi_sel;
                    649:                        rv = 0;
                    650:                        break;
                    651:                    }
                    652:        }
1.8.10.1! reinoud   653:        mutex_exit(&pi_mtx);
1.1       pooka     654:
                    655:        return rv;
                    656: }
                    657:
                    658: /*
                    659:  * Remove mount point from list of instances.  Called from unmount.
                    660:  */
                    661: void
                    662: puffs_nukebypmp(struct puffs_mount *pmp)
                    663: {
                    664:        struct puffs_instance *pi;
                    665:
1.8.10.1! reinoud   666:        mutex_enter(&pi_mtx);
1.1       pooka     667:        TAILQ_FOREACH(pi, &puffs_ilist, pi_entries) {
                    668:                if (pi->pi_pmp == pmp) {
                    669:                        TAILQ_REMOVE(&puffs_ilist, pi, pi_entries);
                    670:                        break;
                    671:                }
                    672:        }
                    673:        if (pi)
                    674:                pi->pi_pmp = PMP_DEAD;
                    675:
                    676: #ifdef DIAGNOSTIC
                    677:        else
                    678:                panic("puffs_nukebypmp: invalid puffs_mount\n");
                    679: #endif /* DIAGNOSTIC */
                    680:
1.8.10.1! reinoud   681:        mutex_exit(&pi_mtx);
1.1       pooka     682:
                    683:        DPRINTF(("puffs_nukebypmp: nuked %p\n", pi));
                    684: }
                    685:
                    686: /* search sorted list of instances for free minor, sorted insert arg */
                    687: static int
                    688: get_pi_idx(struct puffs_instance *pi_i)
                    689: {
                    690:        struct puffs_instance *pi;
                    691:        int i;
                    692:
                    693:        i = 0;
                    694:        TAILQ_FOREACH(pi, &puffs_ilist, pi_entries) {
                    695:                if (i == PUFFS_CLONER)
                    696:                        return PUFFS_CLONER;
                    697:                if (i != pi->pi_idx)
                    698:                        break;
                    699:                i++;
                    700:        }
                    701:
                    702:        pi_i->pi_pmp = PMP_EMBRYO;
                    703:
                    704:        if (pi == NULL)
                    705:                TAILQ_INSERT_TAIL(&puffs_ilist, pi_i, pi_entries);
                    706:        else
                    707:                TAILQ_INSERT_BEFORE(pi, pi_i, pi_entries);
                    708:
                    709:        return i;
                    710: }

CVSweb <webmaster@jp.NetBSD.org>