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

1.98.2.8! ad          1: /*     $NetBSD: spec_vnops.c,v 1.98.2.7 2007/08/19 19:24:57 ad Exp $   */
1.16      cgd         2:
1.1       cgd         3: /*
1.15      mycroft     4:  * Copyright (c) 1989, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         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.
1.69      agc        15:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        16:  *    may be used to endorse or promote products derived from this software
                     17:  *    without specific prior written permission.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     29:  * SUCH DAMAGE.
                     30:  *
1.39      fvdl       31:  *     @(#)spec_vnops.c        8.15 (Berkeley) 7/14/95
1.1       cgd        32:  */
1.60      lukem      33:
                     34: #include <sys/cdefs.h>
1.98.2.8! ad         35: __KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.98.2.7 2007/08/19 19:24:57 ad Exp $");
1.1       cgd        36:
1.9       mycroft    37: #include <sys/param.h>
                     38: #include <sys/proc.h>
                     39: #include <sys/systm.h>
                     40: #include <sys/kernel.h>
                     41: #include <sys/conf.h>
                     42: #include <sys/buf.h>
                     43: #include <sys/mount.h>
                     44: #include <sys/namei.h>
                     45: #include <sys/vnode.h>
                     46: #include <sys/stat.h>
                     47: #include <sys/errno.h>
                     48: #include <sys/ioctl.h>
1.81      ws         49: #include <sys/poll.h>
1.9       mycroft    50: #include <sys/file.h>
                     51: #include <sys/disklabel.h>
1.35      kleink     52: #include <sys/lockf.h>
1.71      dsl        53: #include <sys/tty.h>
1.87      elad       54: #include <sys/kauth.h>
1.28      christos   55:
1.30      mycroft    56: #include <miscfs/genfs/genfs.h>
1.15      mycroft    57: #include <miscfs/specfs/specdev.h>
1.1       cgd        58:
                     59: /* symbolic sleep message strings for devices */
1.37      mycroft    60: const char     devopn[] = "devopn";
                     61: const char     devio[] = "devio";
                     62: const char     devwait[] = "devwait";
                     63: const char     devin[] = "devin";
                     64: const char     devout[] = "devout";
                     65: const char     devioc[] = "devioc";
                     66: const char     devcls[] = "devcls";
1.61      matt       67:
                     68: struct vnode   *speclisth[SPECHSZ];
1.46      sommerfe   69:
                     70: /*
                     71:  * This vnode operations vector is used for two things only:
                     72:  * - special device nodes created from whole cloth by the kernel.
                     73:  * - as a temporary vnodeops replacement for vnodes which were found to
                     74:  *     be aliased by callers of checkalias().
                     75:  * For the ops vector for vnodes built from special devices found in a
                     76:  * filesystem, see (e.g) ffs_specop_entries[] in ffs_vnops.c or the
                     77:  * equivalent for other filesystems.
                     78:  */
1.1       cgd        79:
1.82      xtraeme    80: int (**spec_vnodeop_p)(void *);
1.53      jdolecek   81: const struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
1.15      mycroft    82:        { &vop_default_desc, vn_default_error },
                     83:        { &vop_lookup_desc, spec_lookup },              /* lookup */
                     84:        { &vop_create_desc, spec_create },              /* create */
                     85:        { &vop_mknod_desc, spec_mknod },                /* mknod */
                     86:        { &vop_open_desc, spec_open },                  /* open */
                     87:        { &vop_close_desc, spec_close },                /* close */
                     88:        { &vop_access_desc, spec_access },              /* access */
                     89:        { &vop_getattr_desc, spec_getattr },            /* getattr */
                     90:        { &vop_setattr_desc, spec_setattr },            /* setattr */
                     91:        { &vop_read_desc, spec_read },                  /* read */
                     92:        { &vop_write_desc, spec_write },                /* write */
1.21      mycroft    93:        { &vop_lease_desc, spec_lease_check },          /* lease */
1.47      sommerfe   94:        { &vop_fcntl_desc, spec_fcntl },                /* fcntl */
1.15      mycroft    95:        { &vop_ioctl_desc, spec_ioctl },                /* ioctl */
1.32      mycroft    96:        { &vop_poll_desc, spec_poll },                  /* poll */
1.65      jdolecek   97:        { &vop_kqfilter_desc, spec_kqfilter },          /* kqfilter */
1.39      fvdl       98:        { &vop_revoke_desc, spec_revoke },              /* revoke */
1.15      mycroft    99:        { &vop_mmap_desc, spec_mmap },                  /* mmap */
                    100:        { &vop_fsync_desc, spec_fsync },                /* fsync */
                    101:        { &vop_seek_desc, spec_seek },                  /* seek */
                    102:        { &vop_remove_desc, spec_remove },              /* remove */
                    103:        { &vop_link_desc, spec_link },                  /* link */
                    104:        { &vop_rename_desc, spec_rename },              /* rename */
                    105:        { &vop_mkdir_desc, spec_mkdir },                /* mkdir */
                    106:        { &vop_rmdir_desc, spec_rmdir },                /* rmdir */
                    107:        { &vop_symlink_desc, spec_symlink },            /* symlink */
                    108:        { &vop_readdir_desc, spec_readdir },            /* readdir */
                    109:        { &vop_readlink_desc, spec_readlink },          /* readlink */
                    110:        { &vop_abortop_desc, spec_abortop },            /* abortop */
                    111:        { &vop_inactive_desc, spec_inactive },          /* inactive */
                    112:        { &vop_reclaim_desc, spec_reclaim },            /* reclaim */
                    113:        { &vop_lock_desc, spec_lock },                  /* lock */
                    114:        { &vop_unlock_desc, spec_unlock },              /* unlock */
                    115:        { &vop_bmap_desc, spec_bmap },                  /* bmap */
                    116:        { &vop_strategy_desc, spec_strategy },          /* strategy */
                    117:        { &vop_print_desc, spec_print },                /* print */
                    118:        { &vop_islocked_desc, spec_islocked },          /* islocked */
                    119:        { &vop_pathconf_desc, spec_pathconf },          /* pathconf */
                    120:        { &vop_advlock_desc, spec_advlock },            /* advlock */
1.28      christos  121:        { &vop_bwrite_desc, spec_bwrite },              /* bwrite */
1.55      chs       122:        { &vop_getpages_desc, spec_getpages },          /* getpages */
                    123:        { &vop_putpages_desc, spec_putpages },          /* putpages */
                    124:        { NULL, NULL }
1.1       cgd       125: };
1.53      jdolecek  126: const struct vnodeopv_desc spec_vnodeop_opv_desc =
1.15      mycroft   127:        { &spec_vnodeop_p, spec_vnodeop_entries };
1.1       cgd       128:
                    129: /*
                    130:  * Trivial lookup routine that always fails.
                    131:  */
1.4       andrew    132: int
1.28      christos  133: spec_lookup(v)
                    134:        void *v;
                    135: {
1.15      mycroft   136:        struct vop_lookup_args /* {
                    137:                struct vnode *a_dvp;
                    138:                struct vnode **a_vpp;
                    139:                struct componentname *a_cnp;
1.28      christos  140:        } */ *ap = v;
1.1       cgd       141:
1.15      mycroft   142:        *ap->a_vpp = NULL;
1.1       cgd       143:        return (ENOTDIR);
1.66      jdolecek  144: }
                    145:
                    146: /*
                    147:  * Returns true if dev is /dev/mem or /dev/kmem.
                    148:  */
1.96      elad      149: int
1.66      jdolecek  150: iskmemdev(dev_t dev)
                    151: {
                    152:        /* mem_no is emitted by config(8) to generated devsw.c */
                    153:        extern const int mem_no;
                    154:
                    155:        /* minor 14 is /dev/io on i386 with COMPAT_10 */
                    156:        return (major(dev) == mem_no && (minor(dev) < 2 || minor(dev) == 14));
1.1       cgd       157: }
                    158:
                    159: /*
1.15      mycroft   160:  * Open a special file.
1.1       cgd       161:  */
                    162: /* ARGSUSED */
1.28      christos  163: int
                    164: spec_open(v)
                    165:        void *v;
                    166: {
1.15      mycroft   167:        struct vop_open_args /* {
                    168:                struct vnode *a_vp;
                    169:                int  a_mode;
1.87      elad      170:                kauth_cred_t a_cred;
1.85      christos  171:                struct lwp *a_l;
1.28      christos  172:        } */ *ap = v;
1.85      christos  173:        struct lwp *l = ap->a_l;
1.94      elad      174:        struct vnode *vp = ap->a_vp;
                    175:        dev_t dev = (dev_t)vp->v_rdev;
1.1       cgd       176:        int error;
1.55      chs       177:        struct partinfo pi;
1.96      elad      178:        enum kauth_device_req req;
1.1       cgd       179:
1.15      mycroft   180:        /*
                    181:         * Don't allow open if fs is mounted -nodev.
                    182:         */
1.1       cgd       183:        if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
                    184:                return (ENXIO);
                    185:
1.96      elad      186: #define M2K(m) (((m) & FREAD) && ((m) & FWRITE) ? \
                    187:                 KAUTH_REQ_DEVICE_RAWIO_SPEC_RW : \
                    188:                 (m) & FWRITE ? KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE : \
                    189:                 KAUTH_REQ_DEVICE_RAWIO_SPEC_READ)
1.89      elad      190:
1.1       cgd       191:        switch (vp->v_type) {
                    192:
                    193:        case VCHR:
1.96      elad      194:                req = M2K(ap->a_mode);
                    195:                error = kauth_authorize_device_spec(ap->a_cred, req, vp);
                    196:                if (error)
                    197:                        return (error);
1.89      elad      198:
1.98.2.3  ad        199:                if (cdev_type(dev) == D_TTY)
1.98.2.6  ad        200:                        vp->v_vflag |= VV_ISTTY;
1.39      fvdl      201:                VOP_UNLOCK(vp, 0);
1.98.2.3  ad        202:                error = cdev_open(dev, ap->a_mode, S_IFCHR, l);
1.39      fvdl      203:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.98.2.3  ad        204:                if (cdev_type(dev) != D_DISK)
1.70      dsl       205:                        return error;
                    206:                break;
1.1       cgd       207:
                    208:        case VBLK:
1.96      elad      209:                req = M2K(ap->a_mode);
                    210:                error = kauth_authorize_device_spec(ap->a_cred, req, vp);
                    211:                if (error)
                    212:                        return (error);
1.98.2.3  ad        213:                error = bdev_open(dev, ap->a_mode, S_IFBLK, l);
1.70      dsl       214:                break;
1.55      chs       215:
1.28      christos  216:        case VNON:
                    217:        case VLNK:
                    218:        case VDIR:
                    219:        case VREG:
                    220:        case VBAD:
                    221:        case VFIFO:
                    222:        case VSOCK:
1.70      dsl       223:        default:
                    224:                return 0;
1.1       cgd       225:        }
1.70      dsl       226:
1.89      elad      227: #undef M2K
                    228:
1.70      dsl       229:        if (error)
                    230:                return error;
1.98.2.3  ad        231:        if (vp->v_type == VCHR)
                    232:                error = cdev_ioctl(vp->v_rdev, DIOCGPART, &pi, FREAD, curlwp);
                    233:        else
                    234:                error = bdev_ioctl(vp->v_rdev, DIOCGPART, &pi, FREAD, curlwp);
                    235:        if (error == 0)
1.98.2.5  ad        236:                uvm_vnp_setsize(vp,
                    237:                    (voff_t)pi.disklab->d_secsize * pi.part->p_size);
1.70      dsl       238:        return 0;
1.1       cgd       239: }
                    240:
                    241: /*
                    242:  * Vnode op for read
                    243:  */
                    244: /* ARGSUSED */
1.28      christos  245: int
                    246: spec_read(v)
                    247:        void *v;
                    248: {
1.15      mycroft   249:        struct vop_read_args /* {
                    250:                struct vnode *a_vp;
                    251:                struct uio *a_uio;
                    252:                int  a_ioflag;
1.87      elad      253:                kauth_cred_t a_cred;
1.28      christos  254:        } */ *ap = v;
1.48      augustss  255:        struct vnode *vp = ap->a_vp;
                    256:        struct uio *uio = ap->a_uio;
1.86      yamt      257:        struct lwp *l = curlwp;
1.56      chs       258:        struct buf *bp;
1.57      chs       259:        daddr_t bn;
1.59      chs       260:        int bsize, bscale;
1.56      chs       261:        struct partinfo dpart;
1.64      gehenna   262:        int n, on;
1.1       cgd       263:        int error = 0;
                    264:
                    265: #ifdef DIAGNOSTIC
                    266:        if (uio->uio_rw != UIO_READ)
                    267:                panic("spec_read mode");
1.86      yamt      268:        if (&uio->uio_vmspace->vm_map != kernel_map &&
                    269:            uio->uio_vmspace != curproc->p_vmspace)
1.1       cgd       270:                panic("spec_read proc");
                    271: #endif
                    272:        if (uio->uio_resid == 0)
                    273:                return (0);
                    274:
1.56      chs       275:        switch (vp->v_type) {
                    276:
                    277:        case VCHR:
1.39      fvdl      278:                VOP_UNLOCK(vp, 0);
1.98.2.3  ad        279:                error = cdev_read(vp->v_rdev, uio, ap->a_ioflag);
1.58      chs       280:                vn_lock(vp, LK_SHARED | LK_RETRY);
1.1       cgd       281:                return (error);
                    282:
1.56      chs       283:        case VBLK:
                    284:                if (uio->uio_offset < 0)
                    285:                        return (EINVAL);
                    286:                bsize = BLKDEV_IOSIZE;
1.98.2.3  ad        287:                if (bdev_ioctl(vp->v_rdev, DIOCGPART, &dpart, FREAD, l) == 0) {
1.56      chs       288:                        if (dpart.part->p_fstype == FS_BSDFFS &&
                    289:                            dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
                    290:                                bsize = dpart.part->p_frag *
                    291:                                    dpart.part->p_fsize;
                    292:                }
1.59      chs       293:                bscale = bsize >> DEV_BSHIFT;
1.56      chs       294:                do {
1.59      chs       295:                        bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1);
1.56      chs       296:                        on = uio->uio_offset % bsize;
                    297:                        n = min((unsigned)(bsize - on), uio->uio_resid);
1.57      chs       298:                        error = bread(vp, bn, bsize, NOCRED, &bp);
1.56      chs       299:                        n = min(n, bsize - bp->b_resid);
                    300:                        if (error) {
1.98.2.4  ad        301:                                brelse(bp, 0);
1.56      chs       302:                                return (error);
                    303:                        }
                    304:                        error = uiomove((char *)bp->b_data + on, n, uio);
1.98.2.4  ad        305:                        brelse(bp, 0);
1.56      chs       306:                } while (error == 0 && uio->uio_resid > 0 && n != 0);
                    307:                return (error);
                    308:
                    309:        default:
                    310:                panic("spec_read type");
1.1       cgd       311:        }
1.56      chs       312:        /* NOTREACHED */
1.1       cgd       313: }
                    314:
                    315: /*
                    316:  * Vnode op for write
                    317:  */
                    318: /* ARGSUSED */
1.28      christos  319: int
                    320: spec_write(v)
                    321:        void *v;
                    322: {
1.15      mycroft   323:        struct vop_write_args /* {
                    324:                struct vnode *a_vp;
                    325:                struct uio *a_uio;
                    326:                int  a_ioflag;
1.87      elad      327:                kauth_cred_t a_cred;
1.28      christos  328:        } */ *ap = v;
1.48      augustss  329:        struct vnode *vp = ap->a_vp;
                    330:        struct uio *uio = ap->a_uio;
1.86      yamt      331:        struct lwp *l = curlwp;
1.56      chs       332:        struct buf *bp;
                    333:        daddr_t bn;
1.59      chs       334:        int bsize, bscale;
1.56      chs       335:        struct partinfo dpart;
1.64      gehenna   336:        int n, on;
1.1       cgd       337:        int error = 0;
                    338:
                    339: #ifdef DIAGNOSTIC
                    340:        if (uio->uio_rw != UIO_WRITE)
                    341:                panic("spec_write mode");
1.86      yamt      342:        if (&uio->uio_vmspace->vm_map != kernel_map &&
                    343:            uio->uio_vmspace != curproc->p_vmspace)
1.1       cgd       344:                panic("spec_write proc");
                    345: #endif
                    346:
1.56      chs       347:        switch (vp->v_type) {
                    348:
                    349:        case VCHR:
1.39      fvdl      350:                VOP_UNLOCK(vp, 0);
1.98.2.3  ad        351:                error = cdev_write(vp->v_rdev, uio, ap->a_ioflag);
1.39      fvdl      352:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.1       cgd       353:                return (error);
1.56      chs       354:
                    355:        case VBLK:
                    356:                if (uio->uio_resid == 0)
                    357:                        return (0);
                    358:                if (uio->uio_offset < 0)
                    359:                        return (EINVAL);
                    360:                bsize = BLKDEV_IOSIZE;
1.98.2.3  ad        361:                if (bdev_ioctl(vp->v_rdev, DIOCGPART, &dpart, FREAD, l) == 0) {
1.56      chs       362:                        if (dpart.part->p_fstype == FS_BSDFFS &&
                    363:                            dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
                    364:                                bsize = dpart.part->p_frag *
                    365:                                    dpart.part->p_fsize;
                    366:                }
1.59      chs       367:                bscale = bsize >> DEV_BSHIFT;
1.56      chs       368:                do {
1.59      chs       369:                        bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1);
1.56      chs       370:                        on = uio->uio_offset % bsize;
                    371:                        n = min((unsigned)(bsize - on), uio->uio_resid);
                    372:                        if (n == bsize)
                    373:                                bp = getblk(vp, bn, bsize, 0, 0);
                    374:                        else
                    375:                                error = bread(vp, bn, bsize, NOCRED, &bp);
                    376:                        if (error) {
1.98.2.4  ad        377:                                brelse(bp, 0);
1.56      chs       378:                                return (error);
                    379:                        }
                    380:                        n = min(n, bsize - bp->b_resid);
                    381:                        error = uiomove((char *)bp->b_data + on, n, uio);
                    382:                        if (error)
1.98.2.4  ad        383:                                brelse(bp, 0);
1.56      chs       384:                        else {
                    385:                                if (n + on == bsize)
                    386:                                        bawrite(bp);
                    387:                                else
                    388:                                        bdwrite(bp);
1.98.2.7  ad        389:                                error = bp->b_error;
1.56      chs       390:                        }
                    391:                } while (error == 0 && uio->uio_resid > 0 && n != 0);
                    392:                return (error);
                    393:
                    394:        default:
                    395:                panic("spec_write type");
1.55      chs       396:        }
1.56      chs       397:        /* NOTREACHED */
1.1       cgd       398: }
                    399:
                    400: /*
                    401:  * Device ioctl operation.
                    402:  */
                    403: /* ARGSUSED */
1.28      christos  404: int
                    405: spec_ioctl(v)
                    406:        void *v;
                    407: {
1.15      mycroft   408:        struct vop_ioctl_args /* {
                    409:                struct vnode *a_vp;
1.19      cgd       410:                u_long a_command;
1.78      jrf       411:                void  *a_data;
1.15      mycroft   412:                int  a_fflag;
1.87      elad      413:                kauth_cred_t a_cred;
1.85      christos  414:                struct lwp *a_l;
1.28      christos  415:        } */ *ap = v;
1.83      chs       416:        struct vnode *vp;
                    417:        dev_t dev;
1.1       cgd       418:
1.83      chs       419:        /*
                    420:         * Extract all the info we need from the vnode, taking care to
                    421:         * avoid a race with VOP_REVOKE().
                    422:         */
                    423:
                    424:        vp = ap->a_vp;
                    425:        dev = NODEV;
1.98.2.1  ad        426:        mutex_enter(&vp->v_interlock);
1.98.2.6  ad        427:        if ((vp->v_iflag & VI_XLOCK) == 0 && vp->v_specinfo) {
1.83      chs       428:                dev = vp->v_rdev;
                    429:        }
1.98.2.1  ad        430:        mutex_exit(&vp->v_interlock);
1.83      chs       431:        if (dev == NODEV) {
                    432:                return ENXIO;
                    433:        }
                    434:
                    435:        switch (vp->v_type) {
1.1       cgd       436:
                    437:        case VCHR:
1.98.2.3  ad        438:                return cdev_ioctl(dev, ap->a_command, ap->a_data,
                    439:                    ap->a_fflag, ap->a_l);
1.1       cgd       440:
                    441:        case VBLK:
1.42      thorpej   442:                if (ap->a_command == 0 && (long)ap->a_data == B_TAPE) {
1.98.2.3  ad        443:                        if (bdev_type(dev) == D_TAPE)
1.1       cgd       444:                                return (0);
                    445:                        else
                    446:                                return (1);
1.42      thorpej   447:                }
1.98.2.3  ad        448:                return bdev_ioctl(dev, ap->a_command, ap->a_data,
                    449:                   ap->a_fflag, ap->a_l);
1.1       cgd       450:
                    451:        default:
                    452:                panic("spec_ioctl");
                    453:                /* NOTREACHED */
                    454:        }
                    455: }
                    456:
                    457: /* ARGSUSED */
1.28      christos  458: int
1.32      mycroft   459: spec_poll(v)
1.28      christos  460:        void *v;
                    461: {
1.32      mycroft   462:        struct vop_poll_args /* {
1.15      mycroft   463:                struct vnode *a_vp;
1.32      mycroft   464:                int a_events;
1.85      christos  465:                struct lwp *a_l;
1.28      christos  466:        } */ *ap = v;
1.91      jld       467:        struct vnode *vp;
1.48      augustss  468:        dev_t dev;
1.1       cgd       469:
1.91      jld       470:        /*
                    471:         * Extract all the info we need from the vnode, taking care to
                    472:         * avoid a race with VOP_REVOKE().
                    473:         */
                    474:
                    475:        vp = ap->a_vp;
                    476:        dev = NODEV;
1.98.2.1  ad        477:        mutex_enter(&vp->v_interlock);
1.98.2.6  ad        478:        if ((vp->v_iflag & VI_XLOCK) == 0 && vp->v_specinfo) {
1.91      jld       479:                dev = vp->v_rdev;
                    480:        }
1.98.2.1  ad        481:        mutex_exit(&vp->v_interlock);
1.91      jld       482:        if (dev == NODEV) {
1.92      jld       483:                return POLLERR;
1.91      jld       484:        }
                    485:
                    486:        switch (vp->v_type) {
1.1       cgd       487:
                    488:        case VCHR:
1.98.2.3  ad        489:                return cdev_poll(dev, ap->a_events, ap->a_l);
1.30      mycroft   490:
                    491:        default:
1.32      mycroft   492:                return (genfs_poll(v));
1.15      mycroft   493:        }
                    494: }
1.65      jdolecek  495:
                    496: /* ARGSUSED */
                    497: int
                    498: spec_kqfilter(v)
                    499:        void *v;
                    500: {
                    501:        struct vop_kqfilter_args /* {
                    502:                struct vnode    *a_vp;
                    503:                struct proc     *a_kn;
                    504:        } */ *ap = v;
                    505:        dev_t dev;
                    506:
                    507:        switch (ap->a_vp->v_type) {
                    508:
                    509:        case VCHR:
                    510:                dev = ap->a_vp->v_rdev;
1.98.2.3  ad        511:                return cdev_kqfilter(dev, ap->a_kn);
1.65      jdolecek  512:        default:
                    513:                /*
                    514:                 * Block devices don't support kqfilter, and refuse it
                    515:                 * for any other files (like those vflush()ed) too.
                    516:                 */
                    517:                return (EOPNOTSUPP);
                    518:        }
                    519: }
                    520:
1.15      mycroft   521: /*
                    522:  * Synch buffers associated with a block device
                    523:  */
                    524: /* ARGSUSED */
                    525: int
1.28      christos  526: spec_fsync(v)
                    527:        void *v;
                    528: {
1.15      mycroft   529:        struct vop_fsync_args /* {
                    530:                struct vnode *a_vp;
1.87      elad      531:                kauth_cred_t a_cred;
1.40      kleink    532:                int  a_flags;
1.50      fvdl      533:                off_t offlo;
                    534:                off_t offhi;
1.85      christos  535:                struct lwp *a_l;
1.28      christos  536:        } */ *ap = v;
1.48      augustss  537:        struct vnode *vp = ap->a_vp;
1.15      mycroft   538:
1.30      mycroft   539:        if (vp->v_type == VBLK)
1.40      kleink    540:                vflushbuf(vp, (ap->a_flags & FSYNC_WAIT) != 0);
1.15      mycroft   541:        return (0);
1.1       cgd       542: }
                    543:
                    544: /*
                    545:  * Just call the device strategy routine
                    546:  */
1.28      christos  547: int
                    548: spec_strategy(v)
                    549:        void *v;
                    550: {
1.15      mycroft   551:        struct vop_strategy_args /* {
1.76      hannken   552:                struct vnode *a_vp;
1.15      mycroft   553:                struct buf *a_bp;
1.28      christos  554:        } */ *ap = v;
1.76      hannken   555:        struct vnode *vp = ap->a_vp;
                    556:        struct buf *bp = ap->a_bp;
1.98.2.1  ad        557:        int error;
1.77      hannken   558:        struct spec_cow_entry *e;
1.1       cgd       559:
1.79      hannken   560:        error = 0;
1.76      hannken   561:        bp->b_dev = vp->v_rdev;
1.98.2.8! ad        562:        if (!(bp->b_flags & B_READ) && bioops != NULL)
        !           563:                (*bioops->io_start)(bp);
1.77      hannken   564:
                    565:        if (!(bp->b_flags & B_READ) && !SLIST_EMPTY(&vp->v_spec_cow_head)) {
1.98.2.1  ad        566:                mutex_enter(&vp->v_spec_cow_lock);
1.77      hannken   567:                while (vp->v_spec_cow_req > 0)
1.98.2.1  ad        568:                        mtsleep(&vp->v_spec_cow_req, PRIBIO, "cowlist", 0,
                    569:                            &vp->v_spec_cow_lock);
1.77      hannken   570:                vp->v_spec_cow_count++;
1.98.2.1  ad        571:                mutex_exit(&vp->v_spec_cow_lock);
1.77      hannken   572:
1.79      hannken   573:                SLIST_FOREACH(e, &vp->v_spec_cow_head, ce_list) {
                    574:                        if ((error = (*e->ce_func)(e->ce_cookie, bp)) != 0)
                    575:                                break;
                    576:                }
1.77      hannken   577:
1.98.2.1  ad        578:                mutex_enter(&vp->v_spec_cow_lock);
1.77      hannken   579:                vp->v_spec_cow_count--;
                    580:                if (vp->v_spec_cow_req && vp->v_spec_cow_count == 0)
                    581:                        wakeup(&vp->v_spec_cow_req);
1.98.2.1  ad        582:                mutex_exit(&vp->v_spec_cow_lock);
1.77      hannken   583:        }
                    584:
1.79      hannken   585:        if (error) {
1.98.2.7  ad        586:                bp->b_error = error;
                    587:                bp->b_resid = bp->b_bcount;
                    588:                biodone(bp);
1.79      hannken   589:                return (error);
                    590:        }
                    591:
1.98.2.3  ad        592:        bdev_strategy(bp);
1.76      hannken   593:
1.1       cgd       594:        return (0);
                    595: }
                    596:
1.39      fvdl      597: int
                    598: spec_inactive(v)
                    599:        void *v;
                    600: {
                    601:        struct vop_inactive_args /* {
                    602:                struct vnode *a_vp;
1.85      christos  603:                struct proc *a_l;
1.39      fvdl      604:        } */ *ap = v;
                    605:
                    606:        VOP_UNLOCK(ap->a_vp, 0);
                    607:        return (0);
                    608: }
                    609:
1.1       cgd       610: /*
                    611:  * This is a noop, simply returning what one has been given.
                    612:  */
1.28      christos  613: int
                    614: spec_bmap(v)
                    615:        void *v;
                    616: {
1.15      mycroft   617:        struct vop_bmap_args /* {
                    618:                struct vnode *a_vp;
                    619:                daddr_t  a_bn;
                    620:                struct vnode **a_vpp;
                    621:                daddr_t *a_bnp;
1.39      fvdl      622:                int *a_runp;
1.28      christos  623:        } */ *ap = v;
1.1       cgd       624:
1.15      mycroft   625:        if (ap->a_vpp != NULL)
                    626:                *ap->a_vpp = ap->a_vp;
                    627:        if (ap->a_bnp != NULL)
                    628:                *ap->a_bnp = ap->a_bn;
1.39      fvdl      629:        if (ap->a_runp != NULL)
1.55      chs       630:                *ap->a_runp = (MAXBSIZE >> DEV_BSHIFT) - 1;
1.1       cgd       631:        return (0);
                    632: }
                    633:
                    634: /*
                    635:  * Device close routine
                    636:  */
                    637: /* ARGSUSED */
1.28      christos  638: int
                    639: spec_close(v)
                    640:        void *v;
                    641: {
1.15      mycroft   642:        struct vop_close_args /* {
                    643:                struct vnode *a_vp;
                    644:                int  a_fflag;
1.87      elad      645:                kauth_cred_t a_cred;
1.85      christos  646:                struct lwp *a_l;
1.28      christos  647:        } */ *ap = v;
1.48      augustss  648:        struct vnode *vp = ap->a_vp;
1.71      dsl       649:        struct session *sess;
1.1       cgd       650:        dev_t dev = vp->v_rdev;
1.44      wrstuden  651:        int mode, error, count, flags, flags1;
                    652:
1.54      thorpej   653:        count = vcount(vp);
1.98.2.6  ad        654:        flags = vp->v_iflag;
1.1       cgd       655:
                    656:        switch (vp->v_type) {
                    657:
                    658:        case VCHR:
1.11      cgd       659:                /*
                    660:                 * Hack: a tty device that is a controlling terminal
                    661:                 * has a reference from the session structure.
                    662:                 * We cannot easily tell that a character device is
                    663:                 * a controlling terminal, unless it is the closing
                    664:                 * process' controlling terminal.  In that case,
                    665:                 * if the reference count is 2 (this last descriptor
                    666:                 * plus the session), release the reference from the session.
1.71      dsl       667:                 * Also remove the link from the tty back to the session
                    668:                 * and pgrp - due to the way consoles are handled we cannot
                    669:                 * guarantee that the vrele() will do the final close on the
                    670:                 * actual tty device.
1.11      cgd       671:                 */
1.98.2.2  ad        672:                mutex_enter(&proclist_lock);
1.85      christos  673:                if (count == 2 && ap->a_l &&
                    674:                    vp == (sess = ap->a_l->l_proc->p_session)->s_ttyvp) {
1.71      dsl       675:                        sess->s_ttyvp = NULL;
1.72      pk        676:                        if (sess->s_ttyp->t_session != NULL) {
                    677:                                sess->s_ttyp->t_pgrp = NULL;
                    678:                                sess->s_ttyp->t_session = NULL;
1.98.2.2  ad        679:                                mutex_exit(&proclist_lock);
1.72      pk        680:                                SESSRELE(sess);
1.98.2.2  ad        681:                        } else {
                    682:                                if (sess->s_ttyp->t_pgrp != NULL)
                    683:                                        panic("spec_close: spurious pgrp ref");
                    684:                                mutex_exit(&proclist_lock);
                    685:                        }
1.11      cgd       686:                        vrele(vp);
1.44      wrstuden  687:                        count--;
1.98.2.2  ad        688:                } else
                    689:                        mutex_exit(&proclist_lock);
                    690:
1.1       cgd       691:                /*
                    692:                 * If the vnode is locked, then we are in the midst
                    693:                 * of forcably closing the device, otherwise we only
                    694:                 * close on last reference.
                    695:                 */
1.98.2.6  ad        696:                if (count > 1 && (flags & VI_XLOCK) == 0)
1.1       cgd       697:                        return (0);
                    698:                mode = S_IFCHR;
                    699:                break;
                    700:
                    701:        case VBLK:
                    702:                /*
                    703:                 * On last close of a block device (that isn't mounted)
                    704:                 * we must invalidate any in core blocks, so that
                    705:                 * we can, for instance, change floppy disks.
                    706:                 */
1.85      christos  707:                error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_l, 0, 0);
1.28      christos  708:                if (error)
1.15      mycroft   709:                        return (error);
1.1       cgd       710:                /*
                    711:                 * We do not want to really close the device if it
                    712:                 * is still in use unless we are trying to close it
                    713:                 * forcibly. Since every use (buffer, vnode, swap, cmap)
                    714:                 * holds a reference to the vnode, and because we mark
                    715:                 * any other vnodes that alias this device, when the
                    716:                 * sum of the reference counts on all the aliased
                    717:                 * vnodes descends to one, we are on last close.
                    718:                 */
1.98.2.6  ad        719:                if (count > 1 && (flags & VI_XLOCK) == 0)
1.1       cgd       720:                        return (0);
                    721:                mode = S_IFBLK;
                    722:                break;
1.5       cgd       723:
1.1       cgd       724:        default:
                    725:                panic("spec_close: not special");
                    726:        }
                    727:
1.44      wrstuden  728:        flags1 = ap->a_fflag;
                    729:
                    730:        /*
1.98.2.6  ad        731:         * if VI_XLOCK is set, then we're going away soon, so make this
1.44      wrstuden  732:         * non-blocking. Also ensures that we won't wedge in vn_lock below.
                    733:         */
1.98.2.6  ad        734:        if (flags & VI_XLOCK)
1.44      wrstuden  735:                flags1 |= FNONBLOCK;
                    736:
                    737:        /*
1.62      wiz       738:         * If we're able to block, release the vnode lock & reacquire. We
1.72      pk        739:         * might end up sleeping for someone else who wants our queues. They
1.98.2.6  ad        740:         * won't get them if we hold the vnode locked. Also, if VI_XLOCK is
                    741:         * set, don't release the lock as we won't be able to regain it.
1.44      wrstuden  742:         */
                    743:        if (!(flags1 & FNONBLOCK))
                    744:                VOP_UNLOCK(vp, 0);
                    745:
1.98.2.3  ad        746:        if (vp->v_type == VBLK)
                    747:                error = bdev_close(dev, flags1, mode, ap->a_l);
1.64      gehenna   748:        else
1.98.2.3  ad        749:                error = cdev_close(dev, flags1, mode, ap->a_l);
1.44      wrstuden  750:
                    751:        if (!(flags1 & FNONBLOCK))
                    752:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    753:
                    754:        return (error);
1.1       cgd       755: }
                    756:
                    757: /*
                    758:  * Print out the contents of a special device vnode.
                    759:  */
1.28      christos  760: int
                    761: spec_print(v)
                    762:        void *v;
                    763: {
1.15      mycroft   764:        struct vop_print_args /* {
                    765:                struct vnode *a_vp;
1.28      christos  766:        } */ *ap = v;
1.15      mycroft   767:
1.34      christos  768:        printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
1.33      christos  769:            minor(ap->a_vp->v_rdev));
1.28      christos  770:        return 0;
1.15      mycroft   771: }
                    772:
                    773: /*
                    774:  * Return POSIX pathconf information applicable to special devices.
                    775:  */
1.28      christos  776: int
                    777: spec_pathconf(v)
                    778:        void *v;
                    779: {
1.15      mycroft   780:        struct vop_pathconf_args /* {
                    781:                struct vnode *a_vp;
                    782:                int a_name;
1.18      cgd       783:                register_t *a_retval;
1.28      christos  784:        } */ *ap = v;
1.1       cgd       785:
1.15      mycroft   786:        switch (ap->a_name) {
                    787:        case _PC_LINK_MAX:
                    788:                *ap->a_retval = LINK_MAX;
                    789:                return (0);
                    790:        case _PC_MAX_CANON:
                    791:                *ap->a_retval = MAX_CANON;
                    792:                return (0);
                    793:        case _PC_MAX_INPUT:
                    794:                *ap->a_retval = MAX_INPUT;
                    795:                return (0);
                    796:        case _PC_PIPE_BUF:
                    797:                *ap->a_retval = PIPE_BUF;
                    798:                return (0);
                    799:        case _PC_CHOWN_RESTRICTED:
                    800:                *ap->a_retval = 1;
                    801:                return (0);
                    802:        case _PC_VDISABLE:
                    803:                *ap->a_retval = _POSIX_VDISABLE;
1.41      kleink    804:                return (0);
                    805:        case _PC_SYNC_IO:
                    806:                *ap->a_retval = 1;
1.15      mycroft   807:                return (0);
                    808:        default:
                    809:                return (EINVAL);
                    810:        }
1.1       cgd       811:        /* NOTREACHED */
1.35      kleink    812: }
                    813:
1.80      perry     814: /*
1.35      kleink    815:  * Advisory record locking support.
                    816:  */
                    817: int
                    818: spec_advlock(v)
                    819:        void *v;
                    820: {
                    821:        struct vop_advlock_args /* {
                    822:                struct vnode *a_vp;
1.78      jrf       823:                void *a_id;
1.35      kleink    824:                int a_op;
                    825:                struct flock *a_fl;
                    826:                int a_flags;
                    827:        } */ *ap = v;
1.48      augustss  828:        struct vnode *vp = ap->a_vp;
1.35      kleink    829:
1.49      jdolecek  830:        return lf_advlock(ap, &vp->v_speclockf, (off_t)0);
1.1       cgd       831: }

CVSweb <webmaster@jp.NetBSD.org>