[BACK]Return to spec_vnops.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / miscfs / specfs

Annotation of src/sys/miscfs/specfs/spec_vnops.c, Revision 1.132

1.132   ! hannken     1: /*     $NetBSD: spec_vnops.c,v 1.131 2010/08/21 13:19:40 pgoyette Exp $        */
1.112     ad          2:
                      3: /*-
                      4:  * Copyright (c) 2008 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     17:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     18:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     19:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     20:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     21:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     22:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     23:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     24:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     25:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     26:  * POSSIBILITY OF SUCH DAMAGE.
                     27:  */
1.16      cgd        28:
1.1       cgd        29: /*
1.15      mycroft    30:  * Copyright (c) 1989, 1993
                     31:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd        32:  *
                     33:  * Redistribution and use in source and binary forms, with or without
                     34:  * modification, are permitted provided that the following conditions
                     35:  * are met:
                     36:  * 1. Redistributions of source code must retain the above copyright
                     37:  *    notice, this list of conditions and the following disclaimer.
                     38:  * 2. Redistributions in binary form must reproduce the above copyright
                     39:  *    notice, this list of conditions and the following disclaimer in the
                     40:  *    documentation and/or other materials provided with the distribution.
1.69      agc        41:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        42:  *    may be used to endorse or promote products derived from this software
                     43:  *    without specific prior written permission.
                     44:  *
                     45:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     46:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     47:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     48:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     49:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     50:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     51:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     52:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     53:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     54:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     55:  * SUCH DAMAGE.
                     56:  *
1.39      fvdl       57:  *     @(#)spec_vnops.c        8.15 (Berkeley) 7/14/95
1.1       cgd        58:  */
1.60      lukem      59:
                     60: #include <sys/cdefs.h>
1.132   ! hannken    61: __KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.131 2010/08/21 13:19:40 pgoyette Exp $");
1.1       cgd        62:
1.9       mycroft    63: #include <sys/param.h>
                     64: #include <sys/proc.h>
                     65: #include <sys/systm.h>
                     66: #include <sys/kernel.h>
                     67: #include <sys/conf.h>
                     68: #include <sys/buf.h>
                     69: #include <sys/mount.h>
                     70: #include <sys/namei.h>
                     71: #include <sys/vnode.h>
                     72: #include <sys/stat.h>
                     73: #include <sys/errno.h>
                     74: #include <sys/ioctl.h>
1.81      ws         75: #include <sys/poll.h>
1.9       mycroft    76: #include <sys/file.h>
                     77: #include <sys/disklabel.h>
1.35      kleink     78: #include <sys/lockf.h>
1.71      dsl        79: #include <sys/tty.h>
1.87      elad       80: #include <sys/kauth.h>
1.106     hannken    81: #include <sys/fstrans.h>
1.122     haad       82: #include <sys/module.h>
1.28      christos   83:
1.30      mycroft    84: #include <miscfs/genfs/genfs.h>
1.15      mycroft    85: #include <miscfs/specfs/specdev.h>
1.1       cgd        86:
                     87: /* symbolic sleep message strings for devices */
1.37      mycroft    88: const char     devopn[] = "devopn";
                     89: const char     devio[] = "devio";
                     90: const char     devwait[] = "devwait";
                     91: const char     devin[] = "devin";
                     92: const char     devout[] = "devout";
                     93: const char     devioc[] = "devioc";
                     94: const char     devcls[] = "devcls";
1.61      matt       95:
1.112     ad         96: vnode_t                *specfs_hash[SPECHSZ];
1.46      sommerfe   97:
                     98: /*
1.112     ad         99:  * This vnode operations vector is used for special device nodes
                    100:  * created from whole cloth by the kernel.  For the ops vector for
                    101:  * vnodes built from special devices found in a filesystem, see (e.g)
                    102:  * ffs_specop_entries[] in ffs_vnops.c or the equivalent for other
                    103:  * filesystems.
1.46      sommerfe  104:  */
1.1       cgd       105:
1.82      xtraeme   106: int (**spec_vnodeop_p)(void *);
1.53      jdolecek  107: const struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
1.15      mycroft   108:        { &vop_default_desc, vn_default_error },
                    109:        { &vop_lookup_desc, spec_lookup },              /* lookup */
                    110:        { &vop_create_desc, spec_create },              /* create */
                    111:        { &vop_mknod_desc, spec_mknod },                /* mknod */
                    112:        { &vop_open_desc, spec_open },                  /* open */
                    113:        { &vop_close_desc, spec_close },                /* close */
                    114:        { &vop_access_desc, spec_access },              /* access */
                    115:        { &vop_getattr_desc, spec_getattr },            /* getattr */
                    116:        { &vop_setattr_desc, spec_setattr },            /* setattr */
                    117:        { &vop_read_desc, spec_read },                  /* read */
                    118:        { &vop_write_desc, spec_write },                /* write */
1.47      sommerfe  119:        { &vop_fcntl_desc, spec_fcntl },                /* fcntl */
1.15      mycroft   120:        { &vop_ioctl_desc, spec_ioctl },                /* ioctl */
1.32      mycroft   121:        { &vop_poll_desc, spec_poll },                  /* poll */
1.65      jdolecek  122:        { &vop_kqfilter_desc, spec_kqfilter },          /* kqfilter */
1.39      fvdl      123:        { &vop_revoke_desc, spec_revoke },              /* revoke */
1.15      mycroft   124:        { &vop_mmap_desc, spec_mmap },                  /* mmap */
                    125:        { &vop_fsync_desc, spec_fsync },                /* fsync */
                    126:        { &vop_seek_desc, spec_seek },                  /* seek */
                    127:        { &vop_remove_desc, spec_remove },              /* remove */
                    128:        { &vop_link_desc, spec_link },                  /* link */
                    129:        { &vop_rename_desc, spec_rename },              /* rename */
                    130:        { &vop_mkdir_desc, spec_mkdir },                /* mkdir */
                    131:        { &vop_rmdir_desc, spec_rmdir },                /* rmdir */
                    132:        { &vop_symlink_desc, spec_symlink },            /* symlink */
                    133:        { &vop_readdir_desc, spec_readdir },            /* readdir */
                    134:        { &vop_readlink_desc, spec_readlink },          /* readlink */
                    135:        { &vop_abortop_desc, spec_abortop },            /* abortop */
                    136:        { &vop_inactive_desc, spec_inactive },          /* inactive */
                    137:        { &vop_reclaim_desc, spec_reclaim },            /* reclaim */
                    138:        { &vop_lock_desc, spec_lock },                  /* lock */
                    139:        { &vop_unlock_desc, spec_unlock },              /* unlock */
                    140:        { &vop_bmap_desc, spec_bmap },                  /* bmap */
                    141:        { &vop_strategy_desc, spec_strategy },          /* strategy */
                    142:        { &vop_print_desc, spec_print },                /* print */
                    143:        { &vop_islocked_desc, spec_islocked },          /* islocked */
                    144:        { &vop_pathconf_desc, spec_pathconf },          /* pathconf */
                    145:        { &vop_advlock_desc, spec_advlock },            /* advlock */
1.28      christos  146:        { &vop_bwrite_desc, spec_bwrite },              /* bwrite */
1.55      chs       147:        { &vop_getpages_desc, spec_getpages },          /* getpages */
                    148:        { &vop_putpages_desc, spec_putpages },          /* putpages */
                    149:        { NULL, NULL }
1.1       cgd       150: };
1.53      jdolecek  151: const struct vnodeopv_desc spec_vnodeop_opv_desc =
1.15      mycroft   152:        { &spec_vnodeop_p, spec_vnodeop_entries };
1.1       cgd       153:
1.127     elad      154: static kauth_listener_t rawio_listener;
                    155:
1.126     elad      156: /* Returns true if vnode is /dev/mem or /dev/kmem. */
                    157: bool
                    158: iskmemvp(struct vnode *vp)
                    159: {
                    160:        return ((vp->v_type == VCHR) && iskmemdev(vp->v_rdev));
                    161: }
                    162:
1.1       cgd       163: /*
1.112     ad        164:  * Returns true if dev is /dev/mem or /dev/kmem.
                    165:  */
                    166: int
                    167: iskmemdev(dev_t dev)
                    168: {
                    169:        /* mem_no is emitted by config(8) to generated devsw.c */
                    170:        extern const int mem_no;
                    171:
                    172:        /* minor 14 is /dev/io on i386 with COMPAT_10 */
                    173:        return (major(dev) == mem_no && (minor(dev) < 2 || minor(dev) == 14));
                    174: }
                    175:
1.127     elad      176: static int
                    177: rawio_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
                    178:     void *arg0, void *arg1, void *arg2, void *arg3)
                    179: {
                    180:        int result;
                    181:
                    182:        result = KAUTH_RESULT_DEFER;
                    183:
                    184:        if ((action != KAUTH_DEVICE_RAWIO_SPEC) &&
                    185:            (action != KAUTH_DEVICE_RAWIO_PASSTHRU))
                    186:                return result;
                    187:
                    188:        /* Access is mandated by permissions. */
                    189:        result = KAUTH_RESULT_ALLOW;
                    190:
                    191:        return result;
                    192: }
                    193:
                    194: void
                    195: spec_init(void)
                    196: {
                    197:
                    198:        rawio_listener = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
                    199:            rawio_listener_cb, NULL);
                    200: }
                    201:
1.112     ad        202: /*
                    203:  * Initialize a vnode that represents a device.
                    204:  */
                    205: void
                    206: spec_node_init(vnode_t *vp, dev_t rdev)
                    207: {
                    208:        specnode_t *sn;
                    209:        specdev_t *sd;
                    210:        vnode_t *vp2;
                    211:        vnode_t **vpp;
                    212:
                    213:        KASSERT(vp->v_type == VBLK || vp->v_type == VCHR);
                    214:        KASSERT(vp->v_specnode == NULL);
                    215:
                    216:        /*
                    217:         * Search the hash table for this device.  If known, add a
                    218:         * reference to the device structure.  If not known, create
                    219:         * a new entry to represent the device.  In all cases add
                    220:         * the vnode to the hash table.
                    221:         */
                    222:        sn = kmem_alloc(sizeof(*sn), KM_SLEEP);
                    223:        if (sn == NULL) {
                    224:                /* XXX */
                    225:                panic("spec_node_init: unable to allocate memory");
                    226:        }
                    227:        sd = kmem_alloc(sizeof(*sd), KM_SLEEP);
                    228:        if (sd == NULL) {
                    229:                /* XXX */
                    230:                panic("spec_node_init: unable to allocate memory");
                    231:        }
1.120     pooka     232:        mutex_enter(&device_lock);
1.112     ad        233:        vpp = &specfs_hash[SPECHASH(rdev)];
                    234:        for (vp2 = *vpp; vp2 != NULL; vp2 = vp2->v_specnext) {
                    235:                KASSERT(vp2->v_specnode != NULL);
                    236:                if (rdev == vp2->v_rdev && vp->v_type == vp2->v_type) {
                    237:                        break;
                    238:                }
                    239:        }
                    240:        if (vp2 == NULL) {
                    241:                /* No existing record, create a new one. */
                    242:                sd->sd_rdev = rdev;
                    243:                sd->sd_mountpoint = NULL;
                    244:                sd->sd_lockf = NULL;
                    245:                sd->sd_refcnt = 1;
                    246:                sd->sd_opencnt = 0;
                    247:                sd->sd_bdevvp = NULL;
                    248:                sn->sn_dev = sd;
                    249:                sd = NULL;
                    250:        } else {
                    251:                /* Use the existing record. */
                    252:                sn->sn_dev = vp2->v_specnode->sn_dev;
                    253:                sn->sn_dev->sd_refcnt++;
                    254:        }
                    255:        /* Insert vnode into the hash chain. */
                    256:        sn->sn_opencnt = 0;
                    257:        sn->sn_rdev = rdev;
                    258:        sn->sn_gone = false;
                    259:        vp->v_specnode = sn;
                    260:        vp->v_specnext = *vpp;
                    261:        *vpp = vp;
1.120     pooka     262:        mutex_exit(&device_lock);
1.112     ad        263:
                    264:        /* Free the record we allocated if unused. */
                    265:        if (sd != NULL) {
                    266:                kmem_free(sd, sizeof(*sd));
                    267:        }
                    268: }
                    269:
                    270: /*
                    271:  * A vnode representing a special device is going away.  Close
                    272:  * the device if the vnode holds it open.
                    273:  */
                    274: void
                    275: spec_node_revoke(vnode_t *vp)
                    276: {
                    277:        specnode_t *sn;
                    278:        specdev_t *sd;
                    279:
                    280:        sn = vp->v_specnode;
                    281:        sd = sn->sn_dev;
                    282:
                    283:        KASSERT(vp->v_type == VBLK || vp->v_type == VCHR);
                    284:        KASSERT(vp->v_specnode != NULL);
                    285:        KASSERT((vp->v_iflag & VI_XLOCK) != 0);
                    286:        KASSERT(sn->sn_gone == false);
                    287:
1.120     pooka     288:        mutex_enter(&device_lock);
1.112     ad        289:        KASSERT(sn->sn_opencnt <= sd->sd_opencnt);
                    290:        if (sn->sn_opencnt != 0) {
                    291:                sd->sd_opencnt -= (sn->sn_opencnt - 1);
                    292:                sn->sn_opencnt = 1;
                    293:                sn->sn_gone = true;
1.120     pooka     294:                mutex_exit(&device_lock);
1.112     ad        295:
                    296:                VOP_CLOSE(vp, FNONBLOCK, NOCRED);
                    297:
1.120     pooka     298:                mutex_enter(&device_lock);
1.112     ad        299:                KASSERT(sn->sn_opencnt == 0);
                    300:        }
1.120     pooka     301:        mutex_exit(&device_lock);
1.112     ad        302: }
                    303:
                    304: /*
                    305:  * A vnode representing a special device is being recycled.
                    306:  * Destroy the specfs component.
                    307:  */
                    308: void
                    309: spec_node_destroy(vnode_t *vp)
                    310: {
                    311:        specnode_t *sn;
                    312:        specdev_t *sd;
                    313:        vnode_t **vpp, *vp2;
                    314:        int refcnt;
                    315:
                    316:        sn = vp->v_specnode;
                    317:        sd = sn->sn_dev;
                    318:
                    319:        KASSERT(vp->v_type == VBLK || vp->v_type == VCHR);
                    320:        KASSERT(vp->v_specnode != NULL);
                    321:        KASSERT(sn->sn_opencnt == 0);
                    322:
1.120     pooka     323:        mutex_enter(&device_lock);
1.112     ad        324:        /* Remove from the hash and destroy the node. */
                    325:        vpp = &specfs_hash[SPECHASH(vp->v_rdev)];
                    326:        for (vp2 = *vpp;; vp2 = vp2->v_specnext) {
                    327:                if (vp2 == NULL) {
                    328:                        panic("spec_node_destroy: corrupt hash");
                    329:                }
                    330:                if (vp2 == vp) {
                    331:                        KASSERT(vp == *vpp);
                    332:                        *vpp = vp->v_specnext;
                    333:                        break;
                    334:                }
                    335:                if (vp2->v_specnext == vp) {
                    336:                        vp2->v_specnext = vp->v_specnext;
                    337:                        break;
                    338:                }
                    339:        }
                    340:        sn = vp->v_specnode;
                    341:        vp->v_specnode = NULL;
                    342:        refcnt = sd->sd_refcnt--;
                    343:        KASSERT(refcnt > 0);
1.120     pooka     344:        mutex_exit(&device_lock);
1.112     ad        345:
                    346:        /* If the device is no longer in use, destroy our record. */
                    347:        if (refcnt == 1) {
                    348:                KASSERT(sd->sd_opencnt == 0);
                    349:                KASSERT(sd->sd_bdevvp == NULL);
                    350:                kmem_free(sd, sizeof(*sd));
                    351:        }
                    352:        kmem_free(sn, sizeof(*sn));
                    353: }
                    354:
                    355: /*
1.1       cgd       356:  * Trivial lookup routine that always fails.
                    357:  */
1.4       andrew    358: int
1.104     pooka     359: spec_lookup(void *v)
1.28      christos  360: {
1.15      mycroft   361:        struct vop_lookup_args /* {
                    362:                struct vnode *a_dvp;
                    363:                struct vnode **a_vpp;
                    364:                struct componentname *a_cnp;
1.28      christos  365:        } */ *ap = v;
1.1       cgd       366:
1.15      mycroft   367:        *ap->a_vpp = NULL;
1.1       cgd       368:        return (ENOTDIR);
1.66      jdolecek  369: }
                    370:
                    371: /*
1.15      mycroft   372:  * Open a special file.
1.1       cgd       373:  */
                    374: /* ARGSUSED */
1.28      christos  375: int
1.104     pooka     376: spec_open(void *v)
1.28      christos  377: {
1.15      mycroft   378:        struct vop_open_args /* {
                    379:                struct vnode *a_vp;
                    380:                int  a_mode;
1.87      elad      381:                kauth_cred_t a_cred;
1.28      christos  382:        } */ *ap = v;
1.112     ad        383:        struct lwp *l;
                    384:        struct vnode *vp;
                    385:        dev_t dev;
1.1       cgd       386:        int error;
1.55      chs       387:        struct partinfo pi;
1.96      elad      388:        enum kauth_device_req req;
1.112     ad        389:        specnode_t *sn;
                    390:        specdev_t *sd;
                    391:
1.122     haad      392:        u_int gen;
                    393:        const char *name;
                    394:
1.112     ad        395:        l = curlwp;
                    396:        vp = ap->a_vp;
                    397:        dev = vp->v_rdev;
                    398:        sn = vp->v_specnode;
                    399:        sd = sn->sn_dev;
1.122     haad      400:        name = NULL;
                    401:        gen = 0;
                    402:
1.15      mycroft   403:        /*
                    404:         * Don't allow open if fs is mounted -nodev.
                    405:         */
1.1       cgd       406:        if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
                    407:                return (ENXIO);
                    408:
1.112     ad        409:        switch (ap->a_mode & (FREAD | FWRITE)) {
                    410:        case FREAD | FWRITE:
                    411:                req = KAUTH_REQ_DEVICE_RAWIO_SPEC_RW;
                    412:                break;
                    413:        case FWRITE:
                    414:                req = KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE;
                    415:                break;
                    416:        default:
                    417:                req = KAUTH_REQ_DEVICE_RAWIO_SPEC_READ;
                    418:                break;
                    419:        }
1.89      elad      420:
1.1       cgd       421:        switch (vp->v_type) {
                    422:        case VCHR:
1.96      elad      423:                error = kauth_authorize_device_spec(ap->a_cred, req, vp);
1.112     ad        424:                if (error != 0)
1.96      elad      425:                        return (error);
1.89      elad      426:
1.112     ad        427:                /*
                    428:                 * Character devices can accept opens from multiple
                    429:                 * vnodes.
                    430:                 */
1.120     pooka     431:                mutex_enter(&device_lock);
1.112     ad        432:                if (sn->sn_gone) {
1.120     pooka     433:                        mutex_exit(&device_lock);
1.112     ad        434:                        return (EBADF);
                    435:                }
                    436:                sd->sd_opencnt++;
                    437:                sn->sn_opencnt++;
1.120     pooka     438:                mutex_exit(&device_lock);
1.100     ad        439:                if (cdev_type(dev) == D_TTY)
1.108     ad        440:                        vp->v_vflag |= VV_ISTTY;
1.130     hannken   441:                VOP_UNLOCK(vp);
1.122     haad      442:                do {
1.125     tsutsui   443:                        const struct cdevsw *cdev;
                    444:
1.122     haad      445:                        gen = module_gen;
                    446:                        error = cdev_open(dev, ap->a_mode, S_IFCHR, l);
                    447:                        if (error != ENXIO)
                    448:                                break;
                    449:
1.125     tsutsui   450:                        /* Check if we already have a valid driver */
                    451:                        mutex_enter(&device_lock);
                    452:                        cdev = cdevsw_lookup(dev);
                    453:                        mutex_exit(&device_lock);
                    454:                        if (cdev != NULL)
                    455:                                break;
                    456:
1.122     haad      457:                        /* Get device name from devsw_conv array */
                    458:                        if ((name = cdevsw_getname(major(dev))) == NULL)
                    459:                                break;
                    460:
                    461:                        /* Try to autoload device module */
1.129     ahoka     462:                        (void) module_autoload(name, MODULE_CLASS_DRIVER);
1.122     haad      463:                } while (gen != module_gen);
                    464:
1.39      fvdl      465:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.70      dsl       466:                break;
1.1       cgd       467:
                    468:        case VBLK:
1.96      elad      469:                error = kauth_authorize_device_spec(ap->a_cred, req, vp);
1.112     ad        470:                if (error != 0)
1.96      elad      471:                        return (error);
1.112     ad        472:
                    473:                /*
                    474:                 * For block devices, permit only one open.  The buffer
                    475:                 * cache cannot remain self-consistent with multiple
                    476:                 * vnodes holding a block device open.
                    477:                 */
1.120     pooka     478:                mutex_enter(&device_lock);
1.112     ad        479:                if (sn->sn_gone) {
1.120     pooka     480:                        mutex_exit(&device_lock);
1.112     ad        481:                        return (EBADF);
                    482:                }
                    483:                if (sd->sd_opencnt != 0) {
1.120     pooka     484:                        mutex_exit(&device_lock);
1.112     ad        485:                        return EBUSY;
                    486:                }
                    487:                sn->sn_opencnt = 1;
                    488:                sd->sd_opencnt = 1;
                    489:                sd->sd_bdevvp = vp;
1.120     pooka     490:                mutex_exit(&device_lock);
1.122     haad      491:                do {
1.125     tsutsui   492:                        const struct bdevsw *bdev;
                    493:
1.122     haad      494:                        gen = module_gen;
                    495:                        error = bdev_open(dev, ap->a_mode, S_IFBLK, l);
                    496:                        if (error != ENXIO)
                    497:                                break;
                    498:
1.125     tsutsui   499:                        /* Check if we already have a valid driver */
                    500:                        mutex_enter(&device_lock);
                    501:                        bdev = bdevsw_lookup(dev);
                    502:                        mutex_exit(&device_lock);
                    503:                        if (bdev != NULL)
                    504:                                break;
                    505:
1.122     haad      506:                        /* Get device name from devsw_conv array */
                    507:                        if ((name = bdevsw_getname(major(dev))) == NULL)
                    508:                                break;
                    509:
1.130     hannken   510:                        VOP_UNLOCK(vp);
1.122     haad      511:
                    512:                         /* Try to autoload device module */
                    513:                        (void) module_autoload(name, MODULE_CLASS_DRIVER);
                    514:
                    515:                        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    516:                } while (gen != module_gen);
1.112     ad        517:
1.70      dsl       518:                break;
1.55      chs       519:
1.28      christos  520:        case VNON:
                    521:        case VLNK:
                    522:        case VDIR:
                    523:        case VREG:
                    524:        case VBAD:
                    525:        case VFIFO:
                    526:        case VSOCK:
1.70      dsl       527:        default:
                    528:                return 0;
1.1       cgd       529:        }
1.70      dsl       530:
1.120     pooka     531:        mutex_enter(&device_lock);
1.112     ad        532:        if (sn->sn_gone) {
                    533:                if (error == 0)
                    534:                        error = EBADF;
                    535:        } else if (error != 0) {
                    536:                sd->sd_opencnt--;
                    537:                sn->sn_opencnt--;
1.115     hannken   538:                if (vp->v_type == VBLK)
                    539:                        sd->sd_bdevvp = NULL;
                    540:
1.112     ad        541:        }
1.120     pooka     542:        mutex_exit(&device_lock);
1.89      elad      543:
1.112     ad        544:        if (cdev_type(dev) != D_DISK || error != 0)
1.70      dsl       545:                return error;
1.112     ad        546:
1.100     ad        547:        if (vp->v_type == VCHR)
                    548:                error = cdev_ioctl(vp->v_rdev, DIOCGPART, &pi, FREAD, curlwp);
                    549:        else
                    550:                error = bdev_ioctl(vp->v_rdev, DIOCGPART, &pi, FREAD, curlwp);
                    551:        if (error == 0)
1.99      yamt      552:                uvm_vnp_setsize(vp,
                    553:                    (voff_t)pi.disklab->d_secsize * pi.part->p_size);
1.70      dsl       554:        return 0;
1.1       cgd       555: }
                    556:
                    557: /*
                    558:  * Vnode op for read
                    559:  */
                    560: /* ARGSUSED */
1.28      christos  561: int
1.104     pooka     562: spec_read(void *v)
1.28      christos  563: {
1.15      mycroft   564:        struct vop_read_args /* {
                    565:                struct vnode *a_vp;
                    566:                struct uio *a_uio;
                    567:                int  a_ioflag;
1.87      elad      568:                kauth_cred_t a_cred;
1.28      christos  569:        } */ *ap = v;
1.48      augustss  570:        struct vnode *vp = ap->a_vp;
                    571:        struct uio *uio = ap->a_uio;
1.86      yamt      572:        struct lwp *l = curlwp;
1.56      chs       573:        struct buf *bp;
1.57      chs       574:        daddr_t bn;
1.59      chs       575:        int bsize, bscale;
1.56      chs       576:        struct partinfo dpart;
1.64      gehenna   577:        int n, on;
1.1       cgd       578:        int error = 0;
                    579:
                    580: #ifdef DIAGNOSTIC
                    581:        if (uio->uio_rw != UIO_READ)
                    582:                panic("spec_read mode");
1.86      yamt      583:        if (&uio->uio_vmspace->vm_map != kernel_map &&
                    584:            uio->uio_vmspace != curproc->p_vmspace)
1.1       cgd       585:                panic("spec_read proc");
                    586: #endif
                    587:        if (uio->uio_resid == 0)
                    588:                return (0);
                    589:
1.56      chs       590:        switch (vp->v_type) {
                    591:
                    592:        case VCHR:
1.130     hannken   593:                VOP_UNLOCK(vp);
1.100     ad        594:                error = cdev_read(vp->v_rdev, uio, ap->a_ioflag);
1.58      chs       595:                vn_lock(vp, LK_SHARED | LK_RETRY);
1.1       cgd       596:                return (error);
                    597:
1.56      chs       598:        case VBLK:
1.112     ad        599:                KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp);
1.56      chs       600:                if (uio->uio_offset < 0)
                    601:                        return (EINVAL);
                    602:                bsize = BLKDEV_IOSIZE;
1.100     ad        603:                if (bdev_ioctl(vp->v_rdev, DIOCGPART, &dpart, FREAD, l) == 0) {
1.56      chs       604:                        if (dpart.part->p_fstype == FS_BSDFFS &&
                    605:                            dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
                    606:                                bsize = dpart.part->p_frag *
                    607:                                    dpart.part->p_fsize;
                    608:                }
1.59      chs       609:                bscale = bsize >> DEV_BSHIFT;
1.56      chs       610:                do {
1.59      chs       611:                        bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1);
1.56      chs       612:                        on = uio->uio_offset % bsize;
                    613:                        n = min((unsigned)(bsize - on), uio->uio_resid);
1.119     hannken   614:                        error = bread(vp, bn, bsize, NOCRED, 0, &bp);
1.56      chs       615:                        n = min(n, bsize - bp->b_resid);
                    616:                        if (error) {
1.107     ad        617:                                brelse(bp, 0);
1.56      chs       618:                                return (error);
                    619:                        }
                    620:                        error = uiomove((char *)bp->b_data + on, n, uio);
1.107     ad        621:                        brelse(bp, 0);
1.56      chs       622:                } while (error == 0 && uio->uio_resid > 0 && n != 0);
                    623:                return (error);
                    624:
                    625:        default:
                    626:                panic("spec_read type");
1.1       cgd       627:        }
1.56      chs       628:        /* NOTREACHED */
1.1       cgd       629: }
                    630:
                    631: /*
                    632:  * Vnode op for write
                    633:  */
                    634: /* ARGSUSED */
1.28      christos  635: int
1.104     pooka     636: spec_write(void *v)
1.28      christos  637: {
1.15      mycroft   638:        struct vop_write_args /* {
                    639:                struct vnode *a_vp;
                    640:                struct uio *a_uio;
                    641:                int  a_ioflag;
1.87      elad      642:                kauth_cred_t a_cred;
1.28      christos  643:        } */ *ap = v;
1.48      augustss  644:        struct vnode *vp = ap->a_vp;
                    645:        struct uio *uio = ap->a_uio;
1.86      yamt      646:        struct lwp *l = curlwp;
1.56      chs       647:        struct buf *bp;
                    648:        daddr_t bn;
1.59      chs       649:        int bsize, bscale;
1.56      chs       650:        struct partinfo dpart;
1.64      gehenna   651:        int n, on;
1.1       cgd       652:        int error = 0;
                    653:
                    654: #ifdef DIAGNOSTIC
                    655:        if (uio->uio_rw != UIO_WRITE)
                    656:                panic("spec_write mode");
1.86      yamt      657:        if (&uio->uio_vmspace->vm_map != kernel_map &&
                    658:            uio->uio_vmspace != curproc->p_vmspace)
1.1       cgd       659:                panic("spec_write proc");
                    660: #endif
                    661:
1.56      chs       662:        switch (vp->v_type) {
                    663:
                    664:        case VCHR:
1.130     hannken   665:                VOP_UNLOCK(vp);
1.100     ad        666:                error = cdev_write(vp->v_rdev, uio, ap->a_ioflag);
1.39      fvdl      667:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.1       cgd       668:                return (error);
1.56      chs       669:
                    670:        case VBLK:
1.112     ad        671:                KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp);
1.56      chs       672:                if (uio->uio_resid == 0)
                    673:                        return (0);
                    674:                if (uio->uio_offset < 0)
                    675:                        return (EINVAL);
                    676:                bsize = BLKDEV_IOSIZE;
1.100     ad        677:                if (bdev_ioctl(vp->v_rdev, DIOCGPART, &dpart, FREAD, l) == 0) {
1.56      chs       678:                        if (dpart.part->p_fstype == FS_BSDFFS &&
                    679:                            dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
                    680:                                bsize = dpart.part->p_frag *
                    681:                                    dpart.part->p_fsize;
                    682:                }
1.59      chs       683:                bscale = bsize >> DEV_BSHIFT;
1.56      chs       684:                do {
1.59      chs       685:                        bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1);
1.56      chs       686:                        on = uio->uio_offset % bsize;
                    687:                        n = min((unsigned)(bsize - on), uio->uio_resid);
                    688:                        if (n == bsize)
                    689:                                bp = getblk(vp, bn, bsize, 0, 0);
                    690:                        else
1.119     hannken   691:                                error = bread(vp, bn, bsize, NOCRED,
                    692:                                    B_MODIFY, &bp);
1.56      chs       693:                        if (error) {
1.107     ad        694:                                brelse(bp, 0);
1.56      chs       695:                                return (error);
                    696:                        }
                    697:                        n = min(n, bsize - bp->b_resid);
                    698:                        error = uiomove((char *)bp->b_data + on, n, uio);
                    699:                        if (error)
1.107     ad        700:                                brelse(bp, 0);
1.56      chs       701:                        else {
                    702:                                if (n + on == bsize)
                    703:                                        bawrite(bp);
                    704:                                else
                    705:                                        bdwrite(bp);
1.107     ad        706:                                error = bp->b_error;
1.56      chs       707:                        }
                    708:                } while (error == 0 && uio->uio_resid > 0 && n != 0);
                    709:                return (error);
                    710:
                    711:        default:
                    712:                panic("spec_write type");
1.55      chs       713:        }
1.56      chs       714:        /* NOTREACHED */
1.1       cgd       715: }
                    716:
                    717: /*
                    718:  * Device ioctl operation.
                    719:  */
                    720: /* ARGSUSED */
1.28      christos  721: int
1.104     pooka     722: spec_ioctl(void *v)
1.28      christos  723: {
1.15      mycroft   724:        struct vop_ioctl_args /* {
                    725:                struct vnode *a_vp;
1.19      cgd       726:                u_long a_command;
1.78      jrf       727:                void  *a_data;
1.15      mycroft   728:                int  a_fflag;
1.87      elad      729:                kauth_cred_t a_cred;
1.28      christos  730:        } */ *ap = v;
1.83      chs       731:        struct vnode *vp;
                    732:        dev_t dev;
1.1       cgd       733:
1.83      chs       734:        /*
                    735:         * Extract all the info we need from the vnode, taking care to
                    736:         * avoid a race with VOP_REVOKE().
                    737:         */
                    738:
                    739:        vp = ap->a_vp;
                    740:        dev = NODEV;
1.111     ad        741:        mutex_enter(&vp->v_interlock);
1.112     ad        742:        if ((vp->v_iflag & VI_XLOCK) == 0 && vp->v_specnode) {
1.83      chs       743:                dev = vp->v_rdev;
                    744:        }
1.111     ad        745:        mutex_exit(&vp->v_interlock);
1.83      chs       746:        if (dev == NODEV) {
                    747:                return ENXIO;
                    748:        }
                    749:
                    750:        switch (vp->v_type) {
1.1       cgd       751:
                    752:        case VCHR:
1.100     ad        753:                return cdev_ioctl(dev, ap->a_command, ap->a_data,
1.109     pooka     754:                    ap->a_fflag, curlwp);
1.1       cgd       755:
                    756:        case VBLK:
1.112     ad        757:                KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp);
1.100     ad        758:                return bdev_ioctl(dev, ap->a_command, ap->a_data,
1.109     pooka     759:                   ap->a_fflag, curlwp);
1.1       cgd       760:
                    761:        default:
                    762:                panic("spec_ioctl");
                    763:                /* NOTREACHED */
                    764:        }
                    765: }
                    766:
                    767: /* ARGSUSED */
1.28      christos  768: int
1.104     pooka     769: spec_poll(void *v)
1.28      christos  770: {
1.32      mycroft   771:        struct vop_poll_args /* {
1.15      mycroft   772:                struct vnode *a_vp;
1.32      mycroft   773:                int a_events;
1.28      christos  774:        } */ *ap = v;
1.91      jld       775:        struct vnode *vp;
1.48      augustss  776:        dev_t dev;
1.1       cgd       777:
1.91      jld       778:        /*
                    779:         * Extract all the info we need from the vnode, taking care to
                    780:         * avoid a race with VOP_REVOKE().
                    781:         */
                    782:
                    783:        vp = ap->a_vp;
                    784:        dev = NODEV;
1.111     ad        785:        mutex_enter(&vp->v_interlock);
1.112     ad        786:        if ((vp->v_iflag & VI_XLOCK) == 0 && vp->v_specnode) {
1.91      jld       787:                dev = vp->v_rdev;
                    788:        }
1.111     ad        789:        mutex_exit(&vp->v_interlock);
1.91      jld       790:        if (dev == NODEV) {
1.92      jld       791:                return POLLERR;
1.91      jld       792:        }
                    793:
                    794:        switch (vp->v_type) {
1.1       cgd       795:
                    796:        case VCHR:
1.109     pooka     797:                return cdev_poll(dev, ap->a_events, curlwp);
1.30      mycroft   798:
                    799:        default:
1.32      mycroft   800:                return (genfs_poll(v));
1.15      mycroft   801:        }
                    802: }
1.65      jdolecek  803:
                    804: /* ARGSUSED */
                    805: int
1.104     pooka     806: spec_kqfilter(void *v)
1.65      jdolecek  807: {
                    808:        struct vop_kqfilter_args /* {
                    809:                struct vnode    *a_vp;
                    810:                struct proc     *a_kn;
                    811:        } */ *ap = v;
                    812:        dev_t dev;
                    813:
                    814:        switch (ap->a_vp->v_type) {
                    815:
                    816:        case VCHR:
                    817:                dev = ap->a_vp->v_rdev;
1.100     ad        818:                return cdev_kqfilter(dev, ap->a_kn);
1.65      jdolecek  819:        default:
                    820:                /*
                    821:                 * Block devices don't support kqfilter, and refuse it
                    822:                 * for any other files (like those vflush()ed) too.
                    823:                 */
                    824:                return (EOPNOTSUPP);
                    825:        }
                    826: }
                    827:
1.15      mycroft   828: /*
1.101     pooka     829:  * Allow mapping of only D_DISK.  This is called only for VBLK.
                    830:  */
                    831: int
1.104     pooka     832: spec_mmap(void *v)
1.101     pooka     833: {
                    834:        struct vop_mmap_args /* {
                    835:                struct vnode *a_vp;
1.102     pooka     836:                vm_prot_t a_prot;
1.101     pooka     837:                kauth_cred_t a_cred;
                    838:        } */ *ap = v;
                    839:        struct vnode *vp = ap->a_vp;
                    840:
                    841:        KASSERT(vp->v_type == VBLK);
                    842:        if (bdev_type(vp->v_rdev) != D_DISK)
                    843:                return EINVAL;
                    844:
                    845:        return 0;
                    846: }
                    847:
                    848: /*
1.15      mycroft   849:  * Synch buffers associated with a block device
                    850:  */
                    851: /* ARGSUSED */
                    852: int
1.104     pooka     853: spec_fsync(void *v)
1.28      christos  854: {
1.15      mycroft   855:        struct vop_fsync_args /* {
                    856:                struct vnode *a_vp;
1.87      elad      857:                kauth_cred_t a_cred;
1.40      kleink    858:                int  a_flags;
1.50      fvdl      859:                off_t offlo;
                    860:                off_t offhi;
1.28      christos  861:        } */ *ap = v;
1.48      augustss  862:        struct vnode *vp = ap->a_vp;
1.118     ad        863:        struct mount *mp;
                    864:        int error;
1.15      mycroft   865:
1.112     ad        866:        if (vp->v_type == VBLK) {
1.118     ad        867:                if ((mp = vp->v_specmountpoint) != NULL) {
                    868:                        error = VFS_FSYNC(mp, vp, ap->a_flags | FSYNC_VFS);
                    869:                        if (error != EOPNOTSUPP)
                    870:                                return error;
                    871:                }
1.132   ! hannken   872:                return vflushbuf(vp, (ap->a_flags & FSYNC_WAIT) != 0);
1.112     ad        873:        }
1.15      mycroft   874:        return (0);
1.1       cgd       875: }
                    876:
                    877: /*
                    878:  * Just call the device strategy routine
                    879:  */
1.28      christos  880: int
1.104     pooka     881: spec_strategy(void *v)
1.28      christos  882: {
1.15      mycroft   883:        struct vop_strategy_args /* {
1.76      hannken   884:                struct vnode *a_vp;
1.15      mycroft   885:                struct buf *a_bp;
1.28      christos  886:        } */ *ap = v;
1.76      hannken   887:        struct vnode *vp = ap->a_vp;
                    888:        struct buf *bp = ap->a_bp;
1.106     hannken   889:        int error;
1.1       cgd       890:
1.112     ad        891:        KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp);
                    892:
1.79      hannken   893:        error = 0;
1.76      hannken   894:        bp->b_dev = vp->v_rdev;
1.77      hannken   895:
1.106     hannken   896:        if (!(bp->b_flags & B_READ))
1.110     hannken   897:                error = fscow_run(bp, false);
1.77      hannken   898:
1.79      hannken   899:        if (error) {
                    900:                bp->b_error = error;
                    901:                biodone(bp);
                    902:                return (error);
                    903:        }
                    904:
1.100     ad        905:        bdev_strategy(bp);
1.76      hannken   906:
1.1       cgd       907:        return (0);
                    908: }
                    909:
1.39      fvdl      910: int
1.104     pooka     911: spec_inactive(void *v)
1.39      fvdl      912: {
                    913:        struct vop_inactive_args /* {
                    914:                struct vnode *a_vp;
1.85      christos  915:                struct proc *a_l;
1.39      fvdl      916:        } */ *ap = v;
                    917:
1.130     hannken   918:        VOP_UNLOCK(ap->a_vp);
1.39      fvdl      919:        return (0);
                    920: }
                    921:
1.1       cgd       922: /*
                    923:  * This is a noop, simply returning what one has been given.
                    924:  */
1.28      christos  925: int
1.104     pooka     926: spec_bmap(void *v)
1.28      christos  927: {
1.15      mycroft   928:        struct vop_bmap_args /* {
                    929:                struct vnode *a_vp;
                    930:                daddr_t  a_bn;
                    931:                struct vnode **a_vpp;
                    932:                daddr_t *a_bnp;
1.39      fvdl      933:                int *a_runp;
1.28      christos  934:        } */ *ap = v;
1.1       cgd       935:
1.15      mycroft   936:        if (ap->a_vpp != NULL)
                    937:                *ap->a_vpp = ap->a_vp;
                    938:        if (ap->a_bnp != NULL)
                    939:                *ap->a_bnp = ap->a_bn;
1.39      fvdl      940:        if (ap->a_runp != NULL)
1.55      chs       941:                *ap->a_runp = (MAXBSIZE >> DEV_BSHIFT) - 1;
1.1       cgd       942:        return (0);
                    943: }
                    944:
                    945: /*
                    946:  * Device close routine
                    947:  */
                    948: /* ARGSUSED */
1.28      christos  949: int
1.104     pooka     950: spec_close(void *v)
1.28      christos  951: {
1.15      mycroft   952:        struct vop_close_args /* {
                    953:                struct vnode *a_vp;
                    954:                int  a_fflag;
1.87      elad      955:                kauth_cred_t a_cred;
1.28      christos  956:        } */ *ap = v;
1.48      augustss  957:        struct vnode *vp = ap->a_vp;
1.71      dsl       958:        struct session *sess;
1.1       cgd       959:        dev_t dev = vp->v_rdev;
1.112     ad        960:        int mode, error, flags, flags1, count;
                    961:        specnode_t *sn;
                    962:        specdev_t *sd;
1.44      wrstuden  963:
1.108     ad        964:        flags = vp->v_iflag;
1.112     ad        965:        sn = vp->v_specnode;
                    966:        sd = sn->sn_dev;
1.1       cgd       967:
                    968:        switch (vp->v_type) {
                    969:
                    970:        case VCHR:
1.11      cgd       971:                /*
                    972:                 * Hack: a tty device that is a controlling terminal
1.112     ad        973:                 * has a reference from the session structure.  We
                    974:                 * cannot easily tell that a character device is a
                    975:                 * controlling terminal, unless it is the closing
                    976:                 * process' controlling terminal.  In that case, if the
                    977:                 * open count is 1 release the reference from the
                    978:                 * session.  Also, remove the link from the tty back to
                    979:                 * the session and pgrp.
                    980:                 *
                    981:                 * XXX V. fishy.
1.11      cgd       982:                 */
1.116     ad        983:                mutex_enter(proc_lock);
1.112     ad        984:                sess = curlwp->l_proc->p_session;
                    985:                if (sn->sn_opencnt == 1 && vp == sess->s_ttyvp) {
                    986:                        mutex_spin_enter(&tty_lock);
1.71      dsl       987:                        sess->s_ttyvp = NULL;
1.72      pk        988:                        if (sess->s_ttyp->t_session != NULL) {
                    989:                                sess->s_ttyp->t_pgrp = NULL;
                    990:                                sess->s_ttyp->t_session = NULL;
1.112     ad        991:                                mutex_spin_exit(&tty_lock);
1.124     rmind     992:                                /* Releases proc_lock. */
                    993:                                proc_sessrele(sess);
1.100     ad        994:                        } else {
1.112     ad        995:                                mutex_spin_exit(&tty_lock);
1.100     ad        996:                                if (sess->s_ttyp->t_pgrp != NULL)
                    997:                                        panic("spec_close: spurious pgrp ref");
1.116     ad        998:                                mutex_exit(proc_lock);
1.100     ad        999:                        }
1.11      cgd      1000:                        vrele(vp);
1.100     ad       1001:                } else
1.116     ad       1002:                        mutex_exit(proc_lock);
1.100     ad       1003:
1.1       cgd      1004:                /*
                   1005:                 * If the vnode is locked, then we are in the midst
                   1006:                 * of forcably closing the device, otherwise we only
                   1007:                 * close on last reference.
                   1008:                 */
                   1009:                mode = S_IFCHR;
                   1010:                break;
                   1011:
                   1012:        case VBLK:
1.112     ad       1013:                KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp);
1.1       cgd      1014:                /*
                   1015:                 * On last close of a block device (that isn't mounted)
                   1016:                 * we must invalidate any in core blocks, so that
                   1017:                 * we can, for instance, change floppy disks.
                   1018:                 */
1.109     pooka    1019:                error = vinvalbuf(vp, V_SAVE, ap->a_cred, curlwp, 0, 0);
1.28      christos 1020:                if (error)
1.15      mycroft  1021:                        return (error);
1.1       cgd      1022:                /*
                   1023:                 * We do not want to really close the device if it
                   1024:                 * is still in use unless we are trying to close it
                   1025:                 * forcibly. Since every use (buffer, vnode, swap, cmap)
                   1026:                 * holds a reference to the vnode, and because we mark
                   1027:                 * any other vnodes that alias this device, when the
                   1028:                 * sum of the reference counts on all the aliased
                   1029:                 * vnodes descends to one, we are on last close.
                   1030:                 */
                   1031:                mode = S_IFBLK;
                   1032:                break;
1.5       cgd      1033:
1.1       cgd      1034:        default:
                   1035:                panic("spec_close: not special");
                   1036:        }
                   1037:
1.120     pooka    1038:        mutex_enter(&device_lock);
1.112     ad       1039:        sn->sn_opencnt--;
                   1040:        count = --sd->sd_opencnt;
                   1041:        if (vp->v_type == VBLK)
                   1042:                sd->sd_bdevvp = NULL;
1.120     pooka    1043:        mutex_exit(&device_lock);
1.112     ad       1044:
                   1045:        if (count != 0)
                   1046:                return 0;
                   1047:
1.44      wrstuden 1048:        flags1 = ap->a_fflag;
                   1049:
                   1050:        /*
1.108     ad       1051:         * if VI_XLOCK is set, then we're going away soon, so make this
1.44      wrstuden 1052:         * non-blocking. Also ensures that we won't wedge in vn_lock below.
                   1053:         */
1.108     ad       1054:        if (flags & VI_XLOCK)
1.44      wrstuden 1055:                flags1 |= FNONBLOCK;
                   1056:
                   1057:        /*
1.62      wiz      1058:         * If we're able to block, release the vnode lock & reacquire. We
1.72      pk       1059:         * might end up sleeping for someone else who wants our queues. They
1.108     ad       1060:         * won't get them if we hold the vnode locked. Also, if VI_XLOCK is
1.100     ad       1061:         * set, don't release the lock as we won't be able to regain it.
1.44      wrstuden 1062:         */
                   1063:        if (!(flags1 & FNONBLOCK))
1.130     hannken  1064:                VOP_UNLOCK(vp);
1.44      wrstuden 1065:
1.100     ad       1066:        if (vp->v_type == VBLK)
1.109     pooka    1067:                error = bdev_close(dev, flags1, mode, curlwp);
1.64      gehenna  1068:        else
1.109     pooka    1069:                error = cdev_close(dev, flags1, mode, curlwp);
1.44      wrstuden 1070:
                   1071:        if (!(flags1 & FNONBLOCK))
                   1072:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                   1073:
                   1074:        return (error);
1.1       cgd      1075: }
                   1076:
                   1077: /*
                   1078:  * Print out the contents of a special device vnode.
                   1079:  */
1.28      christos 1080: int
1.104     pooka    1081: spec_print(void *v)
1.28      christos 1082: {
1.15      mycroft  1083:        struct vop_print_args /* {
                   1084:                struct vnode *a_vp;
1.28      christos 1085:        } */ *ap = v;
1.15      mycroft  1086:
1.121     christos 1087:        printf("dev %llu, %llu\n", (unsigned long long)major(ap->a_vp->v_rdev),
                   1088:            (unsigned long long)minor(ap->a_vp->v_rdev));
1.28      christos 1089:        return 0;
1.15      mycroft  1090: }
                   1091:
                   1092: /*
                   1093:  * Return POSIX pathconf information applicable to special devices.
                   1094:  */
1.28      christos 1095: int
1.104     pooka    1096: spec_pathconf(void *v)
1.28      christos 1097: {
1.15      mycroft  1098:        struct vop_pathconf_args /* {
                   1099:                struct vnode *a_vp;
                   1100:                int a_name;
1.18      cgd      1101:                register_t *a_retval;
1.28      christos 1102:        } */ *ap = v;
1.1       cgd      1103:
1.15      mycroft  1104:        switch (ap->a_name) {
                   1105:        case _PC_LINK_MAX:
                   1106:                *ap->a_retval = LINK_MAX;
                   1107:                return (0);
                   1108:        case _PC_MAX_CANON:
                   1109:                *ap->a_retval = MAX_CANON;
                   1110:                return (0);
                   1111:        case _PC_MAX_INPUT:
                   1112:                *ap->a_retval = MAX_INPUT;
                   1113:                return (0);
                   1114:        case _PC_PIPE_BUF:
                   1115:                *ap->a_retval = PIPE_BUF;
                   1116:                return (0);
                   1117:        case _PC_CHOWN_RESTRICTED:
                   1118:                *ap->a_retval = 1;
                   1119:                return (0);
                   1120:        case _PC_VDISABLE:
                   1121:                *ap->a_retval = _POSIX_VDISABLE;
1.41      kleink   1122:                return (0);
                   1123:        case _PC_SYNC_IO:
                   1124:                *ap->a_retval = 1;
1.15      mycroft  1125:                return (0);
                   1126:        default:
                   1127:                return (EINVAL);
                   1128:        }
1.1       cgd      1129:        /* NOTREACHED */
1.35      kleink   1130: }
                   1131:
1.80      perry    1132: /*
1.35      kleink   1133:  * Advisory record locking support.
                   1134:  */
                   1135: int
1.104     pooka    1136: spec_advlock(void *v)
1.35      kleink   1137: {
                   1138:        struct vop_advlock_args /* {
                   1139:                struct vnode *a_vp;
1.78      jrf      1140:                void *a_id;
1.35      kleink   1141:                int a_op;
                   1142:                struct flock *a_fl;
                   1143:                int a_flags;
                   1144:        } */ *ap = v;
1.48      augustss 1145:        struct vnode *vp = ap->a_vp;
1.35      kleink   1146:
1.49      jdolecek 1147:        return lf_advlock(ap, &vp->v_speclockf, (off_t)0);
1.1       cgd      1148: }

CVSweb <webmaster@jp.NetBSD.org>