Annotation of src/sys/miscfs/specfs/spec_vnops.c, Revision 1.118
1.118 ! ad 1: /* $NetBSD: spec_vnops.c,v 1.117 2008/04/28 20:24:08 martin 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.118 ! ad 61: __KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.117 2008/04/28 20:24:08 martin 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.28 christos 82:
1.30 mycroft 83: #include <miscfs/genfs/genfs.h>
1.15 mycroft 84: #include <miscfs/specfs/specdev.h>
1.1 cgd 85:
86: /* symbolic sleep message strings for devices */
1.37 mycroft 87: const char devopn[] = "devopn";
88: const char devio[] = "devio";
89: const char devwait[] = "devwait";
90: const char devin[] = "devin";
91: const char devout[] = "devout";
92: const char devioc[] = "devioc";
93: const char devcls[] = "devcls";
1.61 matt 94:
1.112 ad 95: vnode_t *specfs_hash[SPECHSZ];
96: kmutex_t specfs_lock;
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:
154: /*
1.112 ad 155: * Returns true if dev is /dev/mem or /dev/kmem.
156: */
157: int
158: iskmemdev(dev_t dev)
159: {
160: /* mem_no is emitted by config(8) to generated devsw.c */
161: extern const int mem_no;
162:
163: /* minor 14 is /dev/io on i386 with COMPAT_10 */
164: return (major(dev) == mem_no && (minor(dev) < 2 || minor(dev) == 14));
165: }
166:
167: /*
168: * Initialize a vnode that represents a device.
169: */
170: void
171: spec_node_init(vnode_t *vp, dev_t rdev)
172: {
173: specnode_t *sn;
174: specdev_t *sd;
175: vnode_t *vp2;
176: vnode_t **vpp;
177:
178: KASSERT(vp->v_type == VBLK || vp->v_type == VCHR);
179: KASSERT(vp->v_specnode == NULL);
180:
181: /*
182: * Search the hash table for this device. If known, add a
183: * reference to the device structure. If not known, create
184: * a new entry to represent the device. In all cases add
185: * the vnode to the hash table.
186: */
187: sn = kmem_alloc(sizeof(*sn), KM_SLEEP);
188: if (sn == NULL) {
189: /* XXX */
190: panic("spec_node_init: unable to allocate memory");
191: }
192: sd = kmem_alloc(sizeof(*sd), KM_SLEEP);
193: if (sd == NULL) {
194: /* XXX */
195: panic("spec_node_init: unable to allocate memory");
196: }
197: mutex_enter(&specfs_lock);
198: vpp = &specfs_hash[SPECHASH(rdev)];
199: for (vp2 = *vpp; vp2 != NULL; vp2 = vp2->v_specnext) {
200: KASSERT(vp2->v_specnode != NULL);
201: if (rdev == vp2->v_rdev && vp->v_type == vp2->v_type) {
202: break;
203: }
204: }
205: if (vp2 == NULL) {
206: /* No existing record, create a new one. */
207: sd->sd_rdev = rdev;
208: sd->sd_mountpoint = NULL;
209: sd->sd_lockf = NULL;
210: sd->sd_refcnt = 1;
211: sd->sd_opencnt = 0;
212: sd->sd_bdevvp = NULL;
213: sn->sn_dev = sd;
214: sd = NULL;
215: } else {
216: /* Use the existing record. */
217: sn->sn_dev = vp2->v_specnode->sn_dev;
218: sn->sn_dev->sd_refcnt++;
219: }
220: /* Insert vnode into the hash chain. */
221: sn->sn_opencnt = 0;
222: sn->sn_rdev = rdev;
223: sn->sn_gone = false;
224: vp->v_specnode = sn;
225: vp->v_specnext = *vpp;
226: *vpp = vp;
227: mutex_exit(&specfs_lock);
228:
229: /* Free the record we allocated if unused. */
230: if (sd != NULL) {
231: kmem_free(sd, sizeof(*sd));
232: }
233: }
234:
235: /*
236: * A vnode representing a special device is going away. Close
237: * the device if the vnode holds it open.
238: */
239: void
240: spec_node_revoke(vnode_t *vp)
241: {
242: specnode_t *sn;
243: specdev_t *sd;
244:
245: sn = vp->v_specnode;
246: sd = sn->sn_dev;
247:
248: KASSERT(vp->v_type == VBLK || vp->v_type == VCHR);
249: KASSERT(vp->v_specnode != NULL);
250: KASSERT((vp->v_iflag & VI_XLOCK) != 0);
251: KASSERT(sn->sn_gone == false);
252:
253: mutex_enter(&specfs_lock);
254: KASSERT(sn->sn_opencnt <= sd->sd_opencnt);
255: if (sn->sn_opencnt != 0) {
256: sd->sd_opencnt -= (sn->sn_opencnt - 1);
257: sn->sn_opencnt = 1;
258: sn->sn_gone = true;
259: mutex_exit(&specfs_lock);
260:
261: VOP_CLOSE(vp, FNONBLOCK, NOCRED);
262:
263: mutex_enter(&specfs_lock);
264: KASSERT(sn->sn_opencnt == 0);
265: }
266: mutex_exit(&specfs_lock);
267: }
268:
269: /*
270: * A vnode representing a special device is being recycled.
271: * Destroy the specfs component.
272: */
273: void
274: spec_node_destroy(vnode_t *vp)
275: {
276: specnode_t *sn;
277: specdev_t *sd;
278: vnode_t **vpp, *vp2;
279: int refcnt;
280:
281: sn = vp->v_specnode;
282: sd = sn->sn_dev;
283:
284: KASSERT(vp->v_type == VBLK || vp->v_type == VCHR);
285: KASSERT(vp->v_specnode != NULL);
286: KASSERT(sn->sn_opencnt == 0);
287:
288: mutex_enter(&specfs_lock);
289: /* Remove from the hash and destroy the node. */
290: vpp = &specfs_hash[SPECHASH(vp->v_rdev)];
291: for (vp2 = *vpp;; vp2 = vp2->v_specnext) {
292: if (vp2 == NULL) {
293: panic("spec_node_destroy: corrupt hash");
294: }
295: if (vp2 == vp) {
296: KASSERT(vp == *vpp);
297: *vpp = vp->v_specnext;
298: break;
299: }
300: if (vp2->v_specnext == vp) {
301: vp2->v_specnext = vp->v_specnext;
302: break;
303: }
304: }
305: sn = vp->v_specnode;
306: vp->v_specnode = NULL;
307: refcnt = sd->sd_refcnt--;
308: KASSERT(refcnt > 0);
309: mutex_exit(&specfs_lock);
310:
311: /* If the device is no longer in use, destroy our record. */
312: if (refcnt == 1) {
313: KASSERT(sd->sd_opencnt == 0);
314: KASSERT(sd->sd_bdevvp == NULL);
315: kmem_free(sd, sizeof(*sd));
316: }
317: kmem_free(sn, sizeof(*sn));
318: }
319:
320: /*
1.1 cgd 321: * Trivial lookup routine that always fails.
322: */
1.4 andrew 323: int
1.104 pooka 324: spec_lookup(void *v)
1.28 christos 325: {
1.15 mycroft 326: struct vop_lookup_args /* {
327: struct vnode *a_dvp;
328: struct vnode **a_vpp;
329: struct componentname *a_cnp;
1.28 christos 330: } */ *ap = v;
1.1 cgd 331:
1.15 mycroft 332: *ap->a_vpp = NULL;
1.1 cgd 333: return (ENOTDIR);
1.66 jdolecek 334: }
335:
336: /*
1.15 mycroft 337: * Open a special file.
1.1 cgd 338: */
339: /* ARGSUSED */
1.28 christos 340: int
1.104 pooka 341: spec_open(void *v)
1.28 christos 342: {
1.15 mycroft 343: struct vop_open_args /* {
344: struct vnode *a_vp;
345: int a_mode;
1.87 elad 346: kauth_cred_t a_cred;
1.28 christos 347: } */ *ap = v;
1.112 ad 348: struct lwp *l;
349: struct vnode *vp;
350: dev_t dev;
1.1 cgd 351: int error;
1.55 chs 352: struct partinfo pi;
1.96 elad 353: enum kauth_device_req req;
1.112 ad 354: specnode_t *sn;
355: specdev_t *sd;
356:
357: l = curlwp;
358: vp = ap->a_vp;
359: dev = vp->v_rdev;
360: sn = vp->v_specnode;
361: sd = sn->sn_dev;
1.1 cgd 362:
1.15 mycroft 363: /*
364: * Don't allow open if fs is mounted -nodev.
365: */
1.1 cgd 366: if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
367: return (ENXIO);
368:
1.112 ad 369: switch (ap->a_mode & (FREAD | FWRITE)) {
370: case FREAD | FWRITE:
371: req = KAUTH_REQ_DEVICE_RAWIO_SPEC_RW;
372: break;
373: case FWRITE:
374: req = KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE;
375: break;
376: default:
377: req = KAUTH_REQ_DEVICE_RAWIO_SPEC_READ;
378: break;
379: }
1.89 elad 380:
1.1 cgd 381: switch (vp->v_type) {
382: case VCHR:
1.96 elad 383: error = kauth_authorize_device_spec(ap->a_cred, req, vp);
1.112 ad 384: if (error != 0)
1.96 elad 385: return (error);
1.89 elad 386:
1.112 ad 387: /*
388: * Character devices can accept opens from multiple
389: * vnodes.
390: */
391: mutex_enter(&specfs_lock);
392: if (sn->sn_gone) {
393: mutex_exit(&specfs_lock);
394: return (EBADF);
395: }
396: sd->sd_opencnt++;
397: sn->sn_opencnt++;
398: mutex_exit(&specfs_lock);
1.100 ad 399: if (cdev_type(dev) == D_TTY)
1.108 ad 400: vp->v_vflag |= VV_ISTTY;
1.39 fvdl 401: VOP_UNLOCK(vp, 0);
1.100 ad 402: error = cdev_open(dev, ap->a_mode, S_IFCHR, l);
1.39 fvdl 403: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.70 dsl 404: break;
1.1 cgd 405:
406: case VBLK:
1.96 elad 407: error = kauth_authorize_device_spec(ap->a_cred, req, vp);
1.112 ad 408: if (error != 0)
1.96 elad 409: return (error);
1.112 ad 410:
411: /*
412: * For block devices, permit only one open. The buffer
413: * cache cannot remain self-consistent with multiple
414: * vnodes holding a block device open.
415: */
416: mutex_enter(&specfs_lock);
417: if (sn->sn_gone) {
418: mutex_exit(&specfs_lock);
419: return (EBADF);
420: }
421: if (sd->sd_opencnt != 0) {
422: mutex_exit(&specfs_lock);
423: return EBUSY;
424: }
425: sn->sn_opencnt = 1;
426: sd->sd_opencnt = 1;
427: sd->sd_bdevvp = vp;
428: mutex_exit(&specfs_lock);
429:
1.100 ad 430: error = bdev_open(dev, ap->a_mode, S_IFBLK, l);
1.70 dsl 431: break;
1.55 chs 432:
1.28 christos 433: case VNON:
434: case VLNK:
435: case VDIR:
436: case VREG:
437: case VBAD:
438: case VFIFO:
439: case VSOCK:
1.70 dsl 440: default:
441: return 0;
1.1 cgd 442: }
1.70 dsl 443:
1.112 ad 444: mutex_enter(&specfs_lock);
445: if (sn->sn_gone) {
446: if (error == 0)
447: error = EBADF;
448: } else if (error != 0) {
449: sd->sd_opencnt--;
450: sn->sn_opencnt--;
1.115 hannken 451: if (vp->v_type == VBLK)
452: sd->sd_bdevvp = NULL;
453:
1.112 ad 454: }
455: mutex_exit(&specfs_lock);
1.89 elad 456:
1.112 ad 457: if (cdev_type(dev) != D_DISK || error != 0)
1.70 dsl 458: return error;
1.112 ad 459:
1.100 ad 460: if (vp->v_type == VCHR)
461: error = cdev_ioctl(vp->v_rdev, DIOCGPART, &pi, FREAD, curlwp);
462: else
463: error = bdev_ioctl(vp->v_rdev, DIOCGPART, &pi, FREAD, curlwp);
464: if (error == 0)
1.99 yamt 465: uvm_vnp_setsize(vp,
466: (voff_t)pi.disklab->d_secsize * pi.part->p_size);
1.70 dsl 467: return 0;
1.1 cgd 468: }
469:
470: /*
471: * Vnode op for read
472: */
473: /* ARGSUSED */
1.28 christos 474: int
1.104 pooka 475: spec_read(void *v)
1.28 christos 476: {
1.15 mycroft 477: struct vop_read_args /* {
478: struct vnode *a_vp;
479: struct uio *a_uio;
480: int a_ioflag;
1.87 elad 481: kauth_cred_t a_cred;
1.28 christos 482: } */ *ap = v;
1.48 augustss 483: struct vnode *vp = ap->a_vp;
484: struct uio *uio = ap->a_uio;
1.86 yamt 485: struct lwp *l = curlwp;
1.56 chs 486: struct buf *bp;
1.57 chs 487: daddr_t bn;
1.59 chs 488: int bsize, bscale;
1.56 chs 489: struct partinfo dpart;
1.64 gehenna 490: int n, on;
1.1 cgd 491: int error = 0;
492:
493: #ifdef DIAGNOSTIC
494: if (uio->uio_rw != UIO_READ)
495: panic("spec_read mode");
1.86 yamt 496: if (&uio->uio_vmspace->vm_map != kernel_map &&
497: uio->uio_vmspace != curproc->p_vmspace)
1.1 cgd 498: panic("spec_read proc");
499: #endif
500: if (uio->uio_resid == 0)
501: return (0);
502:
1.56 chs 503: switch (vp->v_type) {
504:
505: case VCHR:
1.39 fvdl 506: VOP_UNLOCK(vp, 0);
1.100 ad 507: error = cdev_read(vp->v_rdev, uio, ap->a_ioflag);
1.58 chs 508: vn_lock(vp, LK_SHARED | LK_RETRY);
1.1 cgd 509: return (error);
510:
1.56 chs 511: case VBLK:
1.112 ad 512: KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp);
1.56 chs 513: if (uio->uio_offset < 0)
514: return (EINVAL);
515: bsize = BLKDEV_IOSIZE;
1.100 ad 516: if (bdev_ioctl(vp->v_rdev, DIOCGPART, &dpart, FREAD, l) == 0) {
1.56 chs 517: if (dpart.part->p_fstype == FS_BSDFFS &&
518: dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
519: bsize = dpart.part->p_frag *
520: dpart.part->p_fsize;
521: }
1.59 chs 522: bscale = bsize >> DEV_BSHIFT;
1.56 chs 523: do {
1.59 chs 524: bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1);
1.56 chs 525: on = uio->uio_offset % bsize;
526: n = min((unsigned)(bsize - on), uio->uio_resid);
1.57 chs 527: error = bread(vp, bn, bsize, NOCRED, &bp);
1.56 chs 528: n = min(n, bsize - bp->b_resid);
529: if (error) {
1.107 ad 530: brelse(bp, 0);
1.56 chs 531: return (error);
532: }
533: error = uiomove((char *)bp->b_data + on, n, uio);
1.107 ad 534: brelse(bp, 0);
1.56 chs 535: } while (error == 0 && uio->uio_resid > 0 && n != 0);
536: return (error);
537:
538: default:
539: panic("spec_read type");
1.1 cgd 540: }
1.56 chs 541: /* NOTREACHED */
1.1 cgd 542: }
543:
544: /*
545: * Vnode op for write
546: */
547: /* ARGSUSED */
1.28 christos 548: int
1.104 pooka 549: spec_write(void *v)
1.28 christos 550: {
1.15 mycroft 551: struct vop_write_args /* {
552: struct vnode *a_vp;
553: struct uio *a_uio;
554: int a_ioflag;
1.87 elad 555: kauth_cred_t a_cred;
1.28 christos 556: } */ *ap = v;
1.48 augustss 557: struct vnode *vp = ap->a_vp;
558: struct uio *uio = ap->a_uio;
1.86 yamt 559: struct lwp *l = curlwp;
1.56 chs 560: struct buf *bp;
561: daddr_t bn;
1.59 chs 562: int bsize, bscale;
1.56 chs 563: struct partinfo dpart;
1.64 gehenna 564: int n, on;
1.1 cgd 565: int error = 0;
566:
567: #ifdef DIAGNOSTIC
568: if (uio->uio_rw != UIO_WRITE)
569: panic("spec_write mode");
1.86 yamt 570: if (&uio->uio_vmspace->vm_map != kernel_map &&
571: uio->uio_vmspace != curproc->p_vmspace)
1.1 cgd 572: panic("spec_write proc");
573: #endif
574:
1.56 chs 575: switch (vp->v_type) {
576:
577: case VCHR:
1.39 fvdl 578: VOP_UNLOCK(vp, 0);
1.100 ad 579: error = cdev_write(vp->v_rdev, uio, ap->a_ioflag);
1.39 fvdl 580: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.1 cgd 581: return (error);
1.56 chs 582:
583: case VBLK:
1.112 ad 584: KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp);
1.56 chs 585: if (uio->uio_resid == 0)
586: return (0);
587: if (uio->uio_offset < 0)
588: return (EINVAL);
589: bsize = BLKDEV_IOSIZE;
1.100 ad 590: if (bdev_ioctl(vp->v_rdev, DIOCGPART, &dpart, FREAD, l) == 0) {
1.56 chs 591: if (dpart.part->p_fstype == FS_BSDFFS &&
592: dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
593: bsize = dpart.part->p_frag *
594: dpart.part->p_fsize;
595: }
1.59 chs 596: bscale = bsize >> DEV_BSHIFT;
1.56 chs 597: do {
1.59 chs 598: bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1);
1.56 chs 599: on = uio->uio_offset % bsize;
600: n = min((unsigned)(bsize - on), uio->uio_resid);
601: if (n == bsize)
602: bp = getblk(vp, bn, bsize, 0, 0);
603: else
604: error = bread(vp, bn, bsize, NOCRED, &bp);
605: if (error) {
1.107 ad 606: brelse(bp, 0);
1.56 chs 607: return (error);
608: }
609: n = min(n, bsize - bp->b_resid);
610: error = uiomove((char *)bp->b_data + on, n, uio);
611: if (error)
1.107 ad 612: brelse(bp, 0);
1.56 chs 613: else {
614: if (n + on == bsize)
615: bawrite(bp);
616: else
617: bdwrite(bp);
1.107 ad 618: error = bp->b_error;
1.56 chs 619: }
620: } while (error == 0 && uio->uio_resid > 0 && n != 0);
621: return (error);
622:
623: default:
624: panic("spec_write type");
1.55 chs 625: }
1.56 chs 626: /* NOTREACHED */
1.1 cgd 627: }
628:
629: /*
630: * Device ioctl operation.
631: */
632: /* ARGSUSED */
1.28 christos 633: int
1.104 pooka 634: spec_ioctl(void *v)
1.28 christos 635: {
1.15 mycroft 636: struct vop_ioctl_args /* {
637: struct vnode *a_vp;
1.19 cgd 638: u_long a_command;
1.78 jrf 639: void *a_data;
1.15 mycroft 640: int a_fflag;
1.87 elad 641: kauth_cred_t a_cred;
1.28 christos 642: } */ *ap = v;
1.83 chs 643: struct vnode *vp;
644: dev_t dev;
1.1 cgd 645:
1.83 chs 646: /*
647: * Extract all the info we need from the vnode, taking care to
648: * avoid a race with VOP_REVOKE().
649: */
650:
651: vp = ap->a_vp;
652: dev = NODEV;
1.111 ad 653: mutex_enter(&vp->v_interlock);
1.112 ad 654: if ((vp->v_iflag & VI_XLOCK) == 0 && vp->v_specnode) {
1.83 chs 655: dev = vp->v_rdev;
656: }
1.111 ad 657: mutex_exit(&vp->v_interlock);
1.83 chs 658: if (dev == NODEV) {
659: return ENXIO;
660: }
661:
662: switch (vp->v_type) {
1.1 cgd 663:
664: case VCHR:
1.100 ad 665: return cdev_ioctl(dev, ap->a_command, ap->a_data,
1.109 pooka 666: ap->a_fflag, curlwp);
1.1 cgd 667:
668: case VBLK:
1.112 ad 669: KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp);
1.100 ad 670: return bdev_ioctl(dev, ap->a_command, ap->a_data,
1.109 pooka 671: ap->a_fflag, curlwp);
1.1 cgd 672:
673: default:
674: panic("spec_ioctl");
675: /* NOTREACHED */
676: }
677: }
678:
679: /* ARGSUSED */
1.28 christos 680: int
1.104 pooka 681: spec_poll(void *v)
1.28 christos 682: {
1.32 mycroft 683: struct vop_poll_args /* {
1.15 mycroft 684: struct vnode *a_vp;
1.32 mycroft 685: int a_events;
1.28 christos 686: } */ *ap = v;
1.91 jld 687: struct vnode *vp;
1.48 augustss 688: dev_t dev;
1.1 cgd 689:
1.91 jld 690: /*
691: * Extract all the info we need from the vnode, taking care to
692: * avoid a race with VOP_REVOKE().
693: */
694:
695: vp = ap->a_vp;
696: dev = NODEV;
1.111 ad 697: mutex_enter(&vp->v_interlock);
1.112 ad 698: if ((vp->v_iflag & VI_XLOCK) == 0 && vp->v_specnode) {
1.91 jld 699: dev = vp->v_rdev;
700: }
1.111 ad 701: mutex_exit(&vp->v_interlock);
1.91 jld 702: if (dev == NODEV) {
1.92 jld 703: return POLLERR;
1.91 jld 704: }
705:
706: switch (vp->v_type) {
1.1 cgd 707:
708: case VCHR:
1.109 pooka 709: return cdev_poll(dev, ap->a_events, curlwp);
1.30 mycroft 710:
711: default:
1.32 mycroft 712: return (genfs_poll(v));
1.15 mycroft 713: }
714: }
1.65 jdolecek 715:
716: /* ARGSUSED */
717: int
1.104 pooka 718: spec_kqfilter(void *v)
1.65 jdolecek 719: {
720: struct vop_kqfilter_args /* {
721: struct vnode *a_vp;
722: struct proc *a_kn;
723: } */ *ap = v;
724: dev_t dev;
725:
726: switch (ap->a_vp->v_type) {
727:
728: case VCHR:
729: dev = ap->a_vp->v_rdev;
1.100 ad 730: return cdev_kqfilter(dev, ap->a_kn);
1.65 jdolecek 731: default:
732: /*
733: * Block devices don't support kqfilter, and refuse it
734: * for any other files (like those vflush()ed) too.
735: */
736: return (EOPNOTSUPP);
737: }
738: }
739:
1.15 mycroft 740: /*
1.101 pooka 741: * Allow mapping of only D_DISK. This is called only for VBLK.
742: */
743: int
1.104 pooka 744: spec_mmap(void *v)
1.101 pooka 745: {
746: struct vop_mmap_args /* {
747: struct vnode *a_vp;
1.102 pooka 748: vm_prot_t a_prot;
1.101 pooka 749: kauth_cred_t a_cred;
750: } */ *ap = v;
751: struct vnode *vp = ap->a_vp;
752:
753: KASSERT(vp->v_type == VBLK);
754: if (bdev_type(vp->v_rdev) != D_DISK)
755: return EINVAL;
756:
757: return 0;
758: }
759:
760: /*
1.15 mycroft 761: * Synch buffers associated with a block device
762: */
763: /* ARGSUSED */
764: int
1.104 pooka 765: spec_fsync(void *v)
1.28 christos 766: {
1.15 mycroft 767: struct vop_fsync_args /* {
768: struct vnode *a_vp;
1.87 elad 769: kauth_cred_t a_cred;
1.40 kleink 770: int a_flags;
1.50 fvdl 771: off_t offlo;
772: off_t offhi;
1.28 christos 773: } */ *ap = v;
1.48 augustss 774: struct vnode *vp = ap->a_vp;
1.118 ! ad 775: struct mount *mp;
! 776: int error;
1.15 mycroft 777:
1.112 ad 778: if (vp->v_type == VBLK) {
1.118 ! ad 779: if ((mp = vp->v_specmountpoint) != NULL) {
! 780: error = VFS_FSYNC(mp, vp, ap->a_flags | FSYNC_VFS);
! 781: if (error != EOPNOTSUPP)
! 782: return error;
! 783: }
1.40 kleink 784: vflushbuf(vp, (ap->a_flags & FSYNC_WAIT) != 0);
1.112 ad 785: }
1.15 mycroft 786: return (0);
1.1 cgd 787: }
788:
789: /*
790: * Just call the device strategy routine
791: */
1.28 christos 792: int
1.104 pooka 793: spec_strategy(void *v)
1.28 christos 794: {
1.15 mycroft 795: struct vop_strategy_args /* {
1.76 hannken 796: struct vnode *a_vp;
1.15 mycroft 797: struct buf *a_bp;
1.28 christos 798: } */ *ap = v;
1.76 hannken 799: struct vnode *vp = ap->a_vp;
800: struct buf *bp = ap->a_bp;
1.106 hannken 801: int error;
1.1 cgd 802:
1.112 ad 803: KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp);
804:
1.79 hannken 805: error = 0;
1.76 hannken 806: bp->b_dev = vp->v_rdev;
1.45 fvdl 807: if (!(bp->b_flags & B_READ) &&
1.105 pooka 808: (LIST_FIRST(&bp->b_dep)) != NULL && bioopsp)
809: bioopsp->io_start(bp);
1.77 hannken 810:
1.106 hannken 811: if (!(bp->b_flags & B_READ))
1.110 hannken 812: error = fscow_run(bp, false);
1.77 hannken 813:
1.79 hannken 814: if (error) {
815: bp->b_error = error;
816: biodone(bp);
817: return (error);
818: }
819:
1.100 ad 820: bdev_strategy(bp);
1.76 hannken 821:
1.1 cgd 822: return (0);
823: }
824:
1.39 fvdl 825: int
1.104 pooka 826: spec_inactive(void *v)
1.39 fvdl 827: {
828: struct vop_inactive_args /* {
829: struct vnode *a_vp;
1.85 christos 830: struct proc *a_l;
1.39 fvdl 831: } */ *ap = v;
832:
833: VOP_UNLOCK(ap->a_vp, 0);
834: return (0);
835: }
836:
1.1 cgd 837: /*
838: * This is a noop, simply returning what one has been given.
839: */
1.28 christos 840: int
1.104 pooka 841: spec_bmap(void *v)
1.28 christos 842: {
1.15 mycroft 843: struct vop_bmap_args /* {
844: struct vnode *a_vp;
845: daddr_t a_bn;
846: struct vnode **a_vpp;
847: daddr_t *a_bnp;
1.39 fvdl 848: int *a_runp;
1.28 christos 849: } */ *ap = v;
1.1 cgd 850:
1.15 mycroft 851: if (ap->a_vpp != NULL)
852: *ap->a_vpp = ap->a_vp;
853: if (ap->a_bnp != NULL)
854: *ap->a_bnp = ap->a_bn;
1.39 fvdl 855: if (ap->a_runp != NULL)
1.55 chs 856: *ap->a_runp = (MAXBSIZE >> DEV_BSHIFT) - 1;
1.1 cgd 857: return (0);
858: }
859:
860: /*
861: * Device close routine
862: */
863: /* ARGSUSED */
1.28 christos 864: int
1.104 pooka 865: spec_close(void *v)
1.28 christos 866: {
1.15 mycroft 867: struct vop_close_args /* {
868: struct vnode *a_vp;
869: int a_fflag;
1.87 elad 870: kauth_cred_t a_cred;
1.28 christos 871: } */ *ap = v;
1.48 augustss 872: struct vnode *vp = ap->a_vp;
1.71 dsl 873: struct session *sess;
1.1 cgd 874: dev_t dev = vp->v_rdev;
1.112 ad 875: int mode, error, flags, flags1, count;
876: specnode_t *sn;
877: specdev_t *sd;
1.44 wrstuden 878:
1.108 ad 879: flags = vp->v_iflag;
1.112 ad 880: sn = vp->v_specnode;
881: sd = sn->sn_dev;
1.1 cgd 882:
883: switch (vp->v_type) {
884:
885: case VCHR:
1.11 cgd 886: /*
887: * Hack: a tty device that is a controlling terminal
1.112 ad 888: * has a reference from the session structure. We
889: * cannot easily tell that a character device is a
890: * controlling terminal, unless it is the closing
891: * process' controlling terminal. In that case, if the
892: * open count is 1 release the reference from the
893: * session. Also, remove the link from the tty back to
894: * the session and pgrp.
895: *
896: * XXX V. fishy.
1.11 cgd 897: */
1.116 ad 898: mutex_enter(proc_lock);
1.112 ad 899: sess = curlwp->l_proc->p_session;
900: if (sn->sn_opencnt == 1 && vp == sess->s_ttyvp) {
901: mutex_spin_enter(&tty_lock);
1.71 dsl 902: sess->s_ttyvp = NULL;
1.72 pk 903: if (sess->s_ttyp->t_session != NULL) {
904: sess->s_ttyp->t_pgrp = NULL;
905: sess->s_ttyp->t_session = NULL;
1.112 ad 906: mutex_spin_exit(&tty_lock);
907: SESSRELE(sess);
1.116 ad 908: mutex_exit(proc_lock);
1.100 ad 909: } else {
1.112 ad 910: mutex_spin_exit(&tty_lock);
1.100 ad 911: if (sess->s_ttyp->t_pgrp != NULL)
912: panic("spec_close: spurious pgrp ref");
1.116 ad 913: mutex_exit(proc_lock);
1.100 ad 914: }
1.11 cgd 915: vrele(vp);
1.100 ad 916: } else
1.116 ad 917: mutex_exit(proc_lock);
1.100 ad 918:
1.1 cgd 919: /*
920: * If the vnode is locked, then we are in the midst
921: * of forcably closing the device, otherwise we only
922: * close on last reference.
923: */
924: mode = S_IFCHR;
925: break;
926:
927: case VBLK:
1.112 ad 928: KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp);
1.1 cgd 929: /*
930: * On last close of a block device (that isn't mounted)
931: * we must invalidate any in core blocks, so that
932: * we can, for instance, change floppy disks.
933: */
1.109 pooka 934: error = vinvalbuf(vp, V_SAVE, ap->a_cred, curlwp, 0, 0);
1.28 christos 935: if (error)
1.15 mycroft 936: return (error);
1.1 cgd 937: /*
938: * We do not want to really close the device if it
939: * is still in use unless we are trying to close it
940: * forcibly. Since every use (buffer, vnode, swap, cmap)
941: * holds a reference to the vnode, and because we mark
942: * any other vnodes that alias this device, when the
943: * sum of the reference counts on all the aliased
944: * vnodes descends to one, we are on last close.
945: */
946: mode = S_IFBLK;
947: break;
1.5 cgd 948:
1.1 cgd 949: default:
950: panic("spec_close: not special");
951: }
952:
1.112 ad 953: mutex_enter(&specfs_lock);
954: sn->sn_opencnt--;
955: count = --sd->sd_opencnt;
956: if (vp->v_type == VBLK)
957: sd->sd_bdevvp = NULL;
958: mutex_exit(&specfs_lock);
959:
960: if (count != 0)
961: return 0;
962:
1.44 wrstuden 963: flags1 = ap->a_fflag;
964:
965: /*
1.108 ad 966: * if VI_XLOCK is set, then we're going away soon, so make this
1.44 wrstuden 967: * non-blocking. Also ensures that we won't wedge in vn_lock below.
968: */
1.108 ad 969: if (flags & VI_XLOCK)
1.44 wrstuden 970: flags1 |= FNONBLOCK;
971:
972: /*
1.62 wiz 973: * If we're able to block, release the vnode lock & reacquire. We
1.72 pk 974: * might end up sleeping for someone else who wants our queues. They
1.108 ad 975: * won't get them if we hold the vnode locked. Also, if VI_XLOCK is
1.100 ad 976: * set, don't release the lock as we won't be able to regain it.
1.44 wrstuden 977: */
978: if (!(flags1 & FNONBLOCK))
979: VOP_UNLOCK(vp, 0);
980:
1.100 ad 981: if (vp->v_type == VBLK)
1.109 pooka 982: error = bdev_close(dev, flags1, mode, curlwp);
1.64 gehenna 983: else
1.109 pooka 984: error = cdev_close(dev, flags1, mode, curlwp);
1.44 wrstuden 985:
986: if (!(flags1 & FNONBLOCK))
987: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
988:
989: return (error);
1.1 cgd 990: }
991:
992: /*
993: * Print out the contents of a special device vnode.
994: */
1.28 christos 995: int
1.104 pooka 996: spec_print(void *v)
1.28 christos 997: {
1.15 mycroft 998: struct vop_print_args /* {
999: struct vnode *a_vp;
1.28 christos 1000: } */ *ap = v;
1.15 mycroft 1001:
1.112 ad 1002: printf("dev %d, %d\n", major(ap->a_vp->v_rdev),
1.33 christos 1003: minor(ap->a_vp->v_rdev));
1.28 christos 1004: return 0;
1.15 mycroft 1005: }
1006:
1007: /*
1008: * Return POSIX pathconf information applicable to special devices.
1009: */
1.28 christos 1010: int
1.104 pooka 1011: spec_pathconf(void *v)
1.28 christos 1012: {
1.15 mycroft 1013: struct vop_pathconf_args /* {
1014: struct vnode *a_vp;
1015: int a_name;
1.18 cgd 1016: register_t *a_retval;
1.28 christos 1017: } */ *ap = v;
1.1 cgd 1018:
1.15 mycroft 1019: switch (ap->a_name) {
1020: case _PC_LINK_MAX:
1021: *ap->a_retval = LINK_MAX;
1022: return (0);
1023: case _PC_MAX_CANON:
1024: *ap->a_retval = MAX_CANON;
1025: return (0);
1026: case _PC_MAX_INPUT:
1027: *ap->a_retval = MAX_INPUT;
1028: return (0);
1029: case _PC_PIPE_BUF:
1030: *ap->a_retval = PIPE_BUF;
1031: return (0);
1032: case _PC_CHOWN_RESTRICTED:
1033: *ap->a_retval = 1;
1034: return (0);
1035: case _PC_VDISABLE:
1036: *ap->a_retval = _POSIX_VDISABLE;
1.41 kleink 1037: return (0);
1038: case _PC_SYNC_IO:
1039: *ap->a_retval = 1;
1.15 mycroft 1040: return (0);
1041: default:
1042: return (EINVAL);
1043: }
1.1 cgd 1044: /* NOTREACHED */
1.35 kleink 1045: }
1046:
1.80 perry 1047: /*
1.35 kleink 1048: * Advisory record locking support.
1049: */
1050: int
1.104 pooka 1051: spec_advlock(void *v)
1.35 kleink 1052: {
1053: struct vop_advlock_args /* {
1054: struct vnode *a_vp;
1.78 jrf 1055: void *a_id;
1.35 kleink 1056: int a_op;
1057: struct flock *a_fl;
1058: int a_flags;
1059: } */ *ap = v;
1.48 augustss 1060: struct vnode *vp = ap->a_vp;
1.35 kleink 1061:
1.49 jdolecek 1062: return lf_advlock(ap, &vp->v_speclockf, (off_t)0);
1.1 cgd 1063: }
CVSweb <webmaster@jp.NetBSD.org>