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