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>