Annotation of sys/miscfs/specfs/spec_vnops.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: spec_vnops.c,v 1.43 2007/06/18 08:30:07 jasper Exp $ */
! 2: /* $NetBSD: spec_vnops.c,v 1.29 1996/04/22 01:42:38 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1989, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)spec_vnops.c 8.8 (Berkeley) 11/21/94
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/proc.h>
! 37: #include <sys/systm.h>
! 38: #include <sys/kernel.h>
! 39: #include <sys/conf.h>
! 40: #include <sys/buf.h>
! 41: #include <sys/mount.h>
! 42: #include <sys/namei.h>
! 43: #include <sys/vnode.h>
! 44: #include <sys/stat.h>
! 45: #include <sys/errno.h>
! 46: #include <sys/ioctl.h>
! 47: #include <sys/file.h>
! 48: #include <sys/disklabel.h>
! 49: #include <sys/lockf.h>
! 50: #include <sys/poll.h>
! 51:
! 52: #include <miscfs/specfs/specdev.h>
! 53:
! 54: #define v_lastr v_specinfo->si_lastr
! 55:
! 56: struct vnode *speclisth[SPECHSZ];
! 57:
! 58: int (**spec_vnodeop_p)(void *);
! 59: struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
! 60: { &vop_default_desc, vn_default_error },
! 61: { &vop_lookup_desc, spec_lookup }, /* lookup */
! 62: { &vop_create_desc, spec_create }, /* create */
! 63: { &vop_mknod_desc, spec_mknod }, /* mknod */
! 64: { &vop_open_desc, spec_open }, /* open */
! 65: { &vop_close_desc, spec_close }, /* close */
! 66: { &vop_access_desc, spec_access }, /* access */
! 67: { &vop_getattr_desc, spec_getattr }, /* getattr */
! 68: { &vop_setattr_desc, spec_setattr }, /* setattr */
! 69: { &vop_read_desc, spec_read }, /* read */
! 70: { &vop_write_desc, spec_write }, /* write */
! 71: { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
! 72: { &vop_poll_desc, spec_poll }, /* poll */
! 73: { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */
! 74: { &vop_revoke_desc, spec_revoke }, /* revoke */
! 75: { &vop_fsync_desc, spec_fsync }, /* fsync */
! 76: { &vop_remove_desc, spec_remove }, /* remove */
! 77: { &vop_link_desc, spec_link }, /* link */
! 78: { &vop_rename_desc, spec_rename }, /* rename */
! 79: { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
! 80: { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
! 81: { &vop_symlink_desc, spec_symlink }, /* symlink */
! 82: { &vop_readdir_desc, spec_readdir }, /* readdir */
! 83: { &vop_readlink_desc, spec_readlink }, /* readlink */
! 84: { &vop_abortop_desc, spec_abortop }, /* abortop */
! 85: { &vop_inactive_desc, spec_inactive }, /* inactive */
! 86: { &vop_reclaim_desc, spec_reclaim }, /* reclaim */
! 87: { &vop_lock_desc, spec_lock }, /* lock */
! 88: { &vop_unlock_desc, spec_unlock }, /* unlock */
! 89: { &vop_bmap_desc, spec_bmap }, /* bmap */
! 90: { &vop_strategy_desc, spec_strategy }, /* strategy */
! 91: { &vop_print_desc, spec_print }, /* print */
! 92: { &vop_islocked_desc, spec_islocked }, /* islocked */
! 93: { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
! 94: { &vop_advlock_desc, spec_advlock }, /* advlock */
! 95: { &vop_bwrite_desc, spec_bwrite }, /* bwrite */
! 96: { NULL, NULL }
! 97: };
! 98: struct vnodeopv_desc spec_vnodeop_opv_desc =
! 99: { &spec_vnodeop_p, spec_vnodeop_entries };
! 100:
! 101: int
! 102: spec_vnoperate(void *v)
! 103: {
! 104: struct vop_generic_args *ap = v;
! 105:
! 106: return (VOCALL(spec_vnodeop_p, ap->a_desc->vdesc_offset, ap));
! 107: }
! 108:
! 109: /*
! 110: * Trivial lookup routine that always fails.
! 111: */
! 112: int
! 113: spec_lookup(void *v)
! 114: {
! 115: struct vop_lookup_args *ap = v;
! 116:
! 117: *ap->a_vpp = NULL;
! 118: return (ENOTDIR);
! 119: }
! 120:
! 121: /*
! 122: * Open a special file.
! 123: */
! 124: /* ARGSUSED */
! 125: int
! 126: spec_open(void *v)
! 127: {
! 128: struct vop_open_args *ap = v;
! 129: struct proc *p = ap->a_p;
! 130: struct vnode *vp = ap->a_vp;
! 131: struct vnode *bvp;
! 132: dev_t bdev;
! 133: dev_t dev = (dev_t)vp->v_rdev;
! 134: int maj = major(dev);
! 135: int error;
! 136:
! 137: /*
! 138: * Don't allow open if fs is mounted -nodev.
! 139: */
! 140: if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
! 141: return (ENXIO);
! 142:
! 143: switch (vp->v_type) {
! 144:
! 145: case VCHR:
! 146: if ((u_int)maj >= nchrdev)
! 147: return (ENXIO);
! 148: if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) {
! 149: /*
! 150: * When running in very secure mode, do not allow
! 151: * opens for writing of any disk character devices.
! 152: */
! 153: if (securelevel >= 2 && cdevsw[maj].d_type == D_DISK)
! 154: return (EPERM);
! 155: /*
! 156: * When running in secure mode, do not allow opens
! 157: * for writing of /dev/mem, /dev/kmem, or character
! 158: * devices whose corresponding block devices are
! 159: * currently mounted.
! 160: */
! 161: if (securelevel >= 1) {
! 162: if ((bdev = chrtoblk(dev)) != NODEV &&
! 163: vfinddev(bdev, VBLK, &bvp) &&
! 164: bvp->v_usecount > 0 &&
! 165: (error = vfs_mountedon(bvp)))
! 166: return (error);
! 167: if (iskmemdev(dev))
! 168: return (EPERM);
! 169: }
! 170: }
! 171: if (cdevsw[maj].d_type == D_TTY)
! 172: vp->v_flag |= VISTTY;
! 173: if (cdevsw[maj].d_flags & D_CLONE)
! 174: return (spec_open_clone(ap));
! 175: VOP_UNLOCK(vp, 0, p);
! 176: error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p);
! 177: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 178: return (error);
! 179:
! 180: case VBLK:
! 181: if ((u_int)maj >= nblkdev)
! 182: return (ENXIO);
! 183: /*
! 184: * When running in very secure mode, do not allow
! 185: * opens for writing of any disk block devices.
! 186: */
! 187: if (securelevel >= 2 && ap->a_cred != FSCRED &&
! 188: (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK)
! 189: return (EPERM);
! 190: /*
! 191: * Do not allow opens of block devices that are
! 192: * currently mounted.
! 193: */
! 194: if ((error = vfs_mountedon(vp)) != 0)
! 195: return (error);
! 196: return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p));
! 197: case VNON:
! 198: case VLNK:
! 199: case VDIR:
! 200: case VREG:
! 201: case VBAD:
! 202: case VFIFO:
! 203: case VSOCK:
! 204: break;
! 205: }
! 206: return (0);
! 207: }
! 208:
! 209: /*
! 210: * Vnode op for read
! 211: */
! 212: /* ARGSUSED */
! 213: int
! 214: spec_read(void *v)
! 215: {
! 216: struct vop_read_args *ap = v;
! 217: struct vnode *vp = ap->a_vp;
! 218: struct uio *uio = ap->a_uio;
! 219: struct proc *p = uio->uio_procp;
! 220: struct buf *bp;
! 221: daddr64_t bn, nextbn, bscale;
! 222: int bsize;
! 223: struct partinfo dpart;
! 224: int n, on, majordev;
! 225: int (*ioctl)(dev_t, u_long, caddr_t, int, struct proc *);
! 226: int error = 0;
! 227:
! 228: #ifdef DIAGNOSTIC
! 229: if (uio->uio_rw != UIO_READ)
! 230: panic("spec_read mode");
! 231: if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
! 232: panic("spec_read proc");
! 233: #endif
! 234: if (uio->uio_resid == 0)
! 235: return (0);
! 236:
! 237: switch (vp->v_type) {
! 238:
! 239: case VCHR:
! 240: VOP_UNLOCK(vp, 0, p);
! 241: error = (*cdevsw[major(vp->v_rdev)].d_read)
! 242: (vp->v_rdev, uio, ap->a_ioflag);
! 243: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 244: return (error);
! 245:
! 246: case VBLK:
! 247: if (uio->uio_offset < 0)
! 248: return (EINVAL);
! 249: bsize = BLKDEV_IOSIZE;
! 250: if ((majordev = major(vp->v_rdev)) < nblkdev &&
! 251: (ioctl = bdevsw[majordev].d_ioctl) != NULL &&
! 252: (*ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0) {
! 253: u_int32_t frag =
! 254: DISKLABELV1_FFS_FRAG(dpart.part->p_fragblock);
! 255: u_int32_t fsize =
! 256: DISKLABELV1_FFS_FSIZE(dpart.part->p_fragblock);
! 257: if (dpart.part->p_fstype == FS_BSDFFS && frag != 0 &&
! 258: fsize != 0)
! 259: bsize = frag * fsize;
! 260: }
! 261: bscale = btodb(bsize);
! 262: do {
! 263: bn = btodb(uio->uio_offset) & ~(bscale - 1);
! 264: on = uio->uio_offset % bsize;
! 265: n = min((bsize - on), uio->uio_resid);
! 266: if (vp->v_lastr + bscale == bn) {
! 267: nextbn = bn + bscale;
! 268: error = breadn(vp, bn, bsize, &nextbn, &bsize,
! 269: 1, NOCRED, &bp);
! 270: } else
! 271: error = bread(vp, bn, bsize, NOCRED, &bp);
! 272: vp->v_lastr = bn;
! 273: n = min(n, bsize - bp->b_resid);
! 274: if (error) {
! 275: brelse(bp);
! 276: return (error);
! 277: }
! 278: error = uiomove((char *)bp->b_data + on, n, uio);
! 279: brelse(bp);
! 280: } while (error == 0 && uio->uio_resid > 0 && n != 0);
! 281: return (error);
! 282:
! 283: default:
! 284: panic("spec_read type");
! 285: }
! 286: /* NOTREACHED */
! 287: }
! 288:
! 289: int
! 290: spec_inactive(void *v)
! 291: {
! 292: struct vop_inactive_args *ap = v;
! 293:
! 294: VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
! 295: return (0);
! 296: }
! 297:
! 298: /*
! 299: * Vnode op for write
! 300: */
! 301: /* ARGSUSED */
! 302: int
! 303: spec_write(void *v)
! 304: {
! 305: struct vop_write_args *ap = v;
! 306: struct vnode *vp = ap->a_vp;
! 307: struct uio *uio = ap->a_uio;
! 308: struct proc *p = uio->uio_procp;
! 309: struct buf *bp;
! 310: daddr64_t bn, bscale;
! 311: int bsize;
! 312: struct partinfo dpart;
! 313: int n, on, majordev;
! 314: int (*ioctl)(dev_t, u_long, caddr_t, int, struct proc *);
! 315: int error = 0;
! 316:
! 317: #ifdef DIAGNOSTIC
! 318: if (uio->uio_rw != UIO_WRITE)
! 319: panic("spec_write mode");
! 320: if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
! 321: panic("spec_write proc");
! 322: #endif
! 323:
! 324: switch (vp->v_type) {
! 325:
! 326: case VCHR:
! 327: VOP_UNLOCK(vp, 0, p);
! 328: error = (*cdevsw[major(vp->v_rdev)].d_write)
! 329: (vp->v_rdev, uio, ap->a_ioflag);
! 330: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 331: return (error);
! 332:
! 333: case VBLK:
! 334: if (uio->uio_resid == 0)
! 335: return (0);
! 336: if (uio->uio_offset < 0)
! 337: return (EINVAL);
! 338: bsize = BLKDEV_IOSIZE;
! 339: if ((majordev = major(vp->v_rdev)) < nblkdev &&
! 340: (ioctl = bdevsw[majordev].d_ioctl) != NULL &&
! 341: (*ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0) {
! 342: u_int32_t frag =
! 343: DISKLABELV1_FFS_FRAG(dpart.part->p_fragblock);
! 344: u_int32_t fsize =
! 345: DISKLABELV1_FFS_FSIZE(dpart.part->p_fragblock);
! 346: if (dpart.part->p_fstype == FS_BSDFFS && frag != 0 &&
! 347: fsize != 0)
! 348: bsize = frag * fsize;
! 349: }
! 350: bscale = btodb(bsize);
! 351: do {
! 352: bn = btodb(uio->uio_offset) & ~(bscale - 1);
! 353: on = uio->uio_offset % bsize;
! 354: n = min((bsize - on), uio->uio_resid);
! 355: error = bread(vp, bn, bsize, NOCRED, &bp);
! 356: n = min(n, bsize - bp->b_resid);
! 357: if (error) {
! 358: brelse(bp);
! 359: return (error);
! 360: }
! 361: error = uiomove((char *)bp->b_data + on, n, uio);
! 362: if (n + on == bsize)
! 363: bawrite(bp);
! 364: else
! 365: bdwrite(bp);
! 366: } while (error == 0 && uio->uio_resid > 0 && n != 0);
! 367: return (error);
! 368:
! 369: default:
! 370: panic("spec_write type");
! 371: }
! 372: /* NOTREACHED */
! 373: }
! 374:
! 375: /*
! 376: * Device ioctl operation.
! 377: */
! 378: /* ARGSUSED */
! 379: int
! 380: spec_ioctl(void *v)
! 381: {
! 382: struct vop_ioctl_args *ap = v;
! 383: dev_t dev = ap->a_vp->v_rdev;
! 384: int maj = major(dev);
! 385:
! 386: switch (ap->a_vp->v_type) {
! 387:
! 388: case VCHR:
! 389: return ((*cdevsw[maj].d_ioctl)(dev, ap->a_command, ap->a_data,
! 390: ap->a_fflag, ap->a_p));
! 391:
! 392: case VBLK:
! 393: return ((*bdevsw[maj].d_ioctl)(dev, ap->a_command, ap->a_data,
! 394: ap->a_fflag, ap->a_p));
! 395:
! 396: default:
! 397: panic("spec_ioctl");
! 398: /* NOTREACHED */
! 399: }
! 400: }
! 401:
! 402: /* ARGSUSED */
! 403: int
! 404: spec_poll(void *v)
! 405: {
! 406: struct vop_poll_args *ap = v;
! 407: dev_t dev;
! 408:
! 409: switch (ap->a_vp->v_type) {
! 410:
! 411: default:
! 412: return (ap->a_events &
! 413: (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
! 414:
! 415: case VCHR:
! 416: dev = ap->a_vp->v_rdev;
! 417: return (*cdevsw[major(dev)].d_poll)(dev, ap->a_events, ap->a_p);
! 418: }
! 419: }
! 420: /* ARGSUSED */
! 421: int
! 422: spec_kqfilter(void *v)
! 423: {
! 424: struct vop_kqfilter_args *ap = v;
! 425:
! 426: dev_t dev;
! 427:
! 428: dev = ap->a_vp->v_rdev;
! 429: if (cdevsw[major(dev)].d_flags & D_KQFILTER)
! 430: return (*cdevsw[major(dev)].d_kqfilter)(dev, ap->a_kn);
! 431: return (1);
! 432: }
! 433:
! 434: /*
! 435: * Synch buffers associated with a block device
! 436: */
! 437: /* ARGSUSED */
! 438: int
! 439: spec_fsync(void *v)
! 440: {
! 441: struct vop_fsync_args *ap = v;
! 442: struct vnode *vp = ap->a_vp;
! 443: struct buf *bp;
! 444: struct buf *nbp;
! 445: int s;
! 446:
! 447: if (vp->v_type == VCHR)
! 448: return (0);
! 449: /*
! 450: * Flush all dirty buffers associated with a block device.
! 451: */
! 452: loop:
! 453: s = splbio();
! 454: for (bp = LIST_FIRST(&vp->v_dirtyblkhd);
! 455: bp != LIST_END(&vp->v_dirtyblkhd); bp = nbp) {
! 456: nbp = LIST_NEXT(bp, b_vnbufs);
! 457: if ((bp->b_flags & B_BUSY))
! 458: continue;
! 459: if ((bp->b_flags & B_DELWRI) == 0)
! 460: panic("spec_fsync: not dirty");
! 461: bremfree(bp);
! 462: bp->b_flags |= B_BUSY;
! 463: splx(s);
! 464: bawrite(bp);
! 465: goto loop;
! 466: }
! 467: if (ap->a_waitfor == MNT_WAIT) {
! 468: vwaitforio (vp, 0, "spec_fsync", 0);
! 469:
! 470: #ifdef DIAGNOSTIC
! 471: if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
! 472: splx(s);
! 473: vprint("spec_fsync: dirty", vp);
! 474: goto loop;
! 475: }
! 476: #endif
! 477: }
! 478: splx(s);
! 479: return (0);
! 480: }
! 481:
! 482: int
! 483: spec_strategy(void *v)
! 484: {
! 485: struct vop_strategy_args *ap = v;
! 486: struct buf *bp = ap->a_bp;
! 487: int maj = major(bp->b_dev);
! 488:
! 489: if (LIST_FIRST(&bp->b_dep) != NULL)
! 490: buf_start(bp);
! 491:
! 492: (*bdevsw[maj].d_strategy)(bp);
! 493: return (0);
! 494: }
! 495:
! 496: /*
! 497: * This is a noop, simply returning what one has been given.
! 498: */
! 499: int
! 500: spec_bmap(void *v)
! 501: {
! 502: struct vop_bmap_args *ap = v;
! 503:
! 504: if (ap->a_vpp != NULL)
! 505: *ap->a_vpp = ap->a_vp;
! 506: if (ap->a_bnp != NULL)
! 507: *ap->a_bnp = ap->a_bn;
! 508: if (ap->a_runp != NULL)
! 509: *ap->a_runp = 0;
! 510:
! 511: return (0);
! 512: }
! 513:
! 514: /*
! 515: * Device close routine
! 516: */
! 517: /* ARGSUSED */
! 518: int
! 519: spec_close(void *v)
! 520: {
! 521: struct vop_close_args *ap = v;
! 522: struct vnode *vp = ap->a_vp;
! 523: dev_t dev = vp->v_rdev;
! 524: int (*devclose)(dev_t, int, int, struct proc *);
! 525: int mode, error;
! 526:
! 527: switch (vp->v_type) {
! 528:
! 529: case VCHR:
! 530: /*
! 531: * Hack: a tty device that is a controlling terminal
! 532: * has a reference from the session structure.
! 533: * We cannot easily tell that a character device is
! 534: * a controlling terminal, unless it is the closing
! 535: * process' controlling terminal. In that case,
! 536: * if the reference count is 2 (this last descriptor
! 537: * plus the session), release the reference from the session.
! 538: */
! 539: if (vcount(vp) == 2 && ap->a_p &&
! 540: vp == ap->a_p->p_session->s_ttyvp) {
! 541: vrele(vp);
! 542: ap->a_p->p_session->s_ttyvp = NULL;
! 543: }
! 544: /*
! 545: * If the vnode is locked, then we are in the midst
! 546: * of forcably closing the device, otherwise we only
! 547: * close on last reference.
! 548: */
! 549: if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
! 550: return (0);
! 551: if (cdevsw[major(dev)].d_flags & D_CLONE)
! 552: return (spec_close_clone(ap));
! 553: devclose = cdevsw[major(dev)].d_close;
! 554: mode = S_IFCHR;
! 555: break;
! 556:
! 557: case VBLK:
! 558: /*
! 559: * On last close of a block device (that isn't mounted)
! 560: * we must invalidate any in core blocks, so that
! 561: * we can, for instance, change floppy disks. In order to do
! 562: * that, we must lock the vnode. If we are coming from
! 563: * vclean(), the vnode is already locked.
! 564: */
! 565: if (!(vp->v_flag & VXLOCK))
! 566: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
! 567: error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0);
! 568: if (!(vp->v_flag & VXLOCK))
! 569: VOP_UNLOCK(vp, 0, ap->a_p);
! 570: if (error)
! 571: return (error);
! 572: /*
! 573: * We do not want to really close the device if it
! 574: * is still in use unless we are trying to close it
! 575: * forcibly. Since every use (buffer, vnode, swap, cmap)
! 576: * holds a reference to the vnode, and because we mark
! 577: * any other vnodes that alias this device, when the
! 578: * sum of the reference counts on all the aliased
! 579: * vnodes descends to one, we are on last close.
! 580: */
! 581: if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
! 582: return (0);
! 583: devclose = bdevsw[major(dev)].d_close;
! 584: mode = S_IFBLK;
! 585: break;
! 586:
! 587: default:
! 588: panic("spec_close: not special");
! 589: }
! 590:
! 591: return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
! 592: }
! 593:
! 594: /*
! 595: * Print out the contents of a special device vnode.
! 596: */
! 597: int
! 598: spec_print(void *v)
! 599: {
! 600: struct vop_print_args *ap = v;
! 601:
! 602: printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
! 603: minor(ap->a_vp->v_rdev));
! 604: return 0;
! 605: }
! 606:
! 607: /*
! 608: * Return POSIX pathconf information applicable to special devices.
! 609: */
! 610: int
! 611: spec_pathconf(void *v)
! 612: {
! 613: struct vop_pathconf_args *ap = v;
! 614:
! 615: switch (ap->a_name) {
! 616: case _PC_LINK_MAX:
! 617: *ap->a_retval = LINK_MAX;
! 618: return (0);
! 619: case _PC_MAX_CANON:
! 620: *ap->a_retval = MAX_CANON;
! 621: return (0);
! 622: case _PC_MAX_INPUT:
! 623: *ap->a_retval = MAX_INPUT;
! 624: return (0);
! 625: case _PC_PIPE_BUF:
! 626: *ap->a_retval = PIPE_BUF;
! 627: return (0);
! 628: case _PC_CHOWN_RESTRICTED:
! 629: *ap->a_retval = 1;
! 630: return (0);
! 631: case _PC_VDISABLE:
! 632: *ap->a_retval = _POSIX_VDISABLE;
! 633: return (0);
! 634: default:
! 635: return (EINVAL);
! 636: }
! 637: /* NOTREACHED */
! 638: }
! 639:
! 640: /*
! 641: * Special device advisory byte-level locks.
! 642: */
! 643: /* ARGSUSED */
! 644: int
! 645: spec_advlock(void *v)
! 646: {
! 647: struct vop_advlock_args *ap = v;
! 648: struct vnode *vp = ap->a_vp;
! 649:
! 650: return (lf_advlock(&vp->v_speclockf, (off_t)0, ap->a_id,
! 651: ap->a_op, ap->a_fl, ap->a_flags));
! 652: }
! 653:
! 654: /*
! 655: * Special device failed operation
! 656: */
! 657: /*ARGSUSED*/
! 658: int
! 659: spec_ebadf(void *v)
! 660: {
! 661:
! 662: return (EBADF);
! 663: }
! 664:
! 665: /*
! 666: * Special device bad operation
! 667: */
! 668: /*ARGSUSED*/
! 669: int
! 670: spec_badop(void *v)
! 671: {
! 672:
! 673: panic("spec_badop called");
! 674: /* NOTREACHED */
! 675: }
CVSweb