Line data Source code
1 : /* $OpenBSD: spec_vnops.c,v 1.95 2018/07/07 15:41:25 visa Exp $ */
2 : /* $NetBSD: spec_vnops.c,v 1.29 1996/04/22 01:42:38 christos Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1989, 1993
6 : * The Regents of the University of California. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : * 3. Neither the name of the University nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : *
32 : * @(#)spec_vnops.c 8.8 (Berkeley) 11/21/94
33 : */
34 :
35 : #include <sys/param.h>
36 : #include <sys/proc.h>
37 : #include <sys/systm.h>
38 : #include <sys/kernel.h>
39 : #include <sys/conf.h>
40 : #include <sys/buf.h>
41 : #include <sys/mount.h>
42 : #include <sys/namei.h>
43 : #include <sys/vnode.h>
44 : #include <sys/lock.h>
45 : #include <sys/stat.h>
46 : #include <sys/errno.h>
47 : #include <sys/ioctl.h>
48 : #include <sys/fcntl.h>
49 : #include <sys/disklabel.h>
50 : #include <sys/lockf.h>
51 : #include <sys/poll.h>
52 : #include <sys/dkio.h>
53 : #include <sys/malloc.h>
54 : #include <sys/specdev.h>
55 : #include <sys/unistd.h>
56 :
57 : #include <uvm/uvm_extern.h>
58 :
59 : #define v_lastr v_specinfo->si_lastr
60 :
61 : int spec_open_clone(struct vop_open_args *);
62 : int spec_close_clone(struct vop_close_args *);
63 :
64 : struct vnode *speclisth[SPECHSZ];
65 :
66 : struct vops spec_vops = {
67 : .vop_lookup = vop_generic_lookup,
68 : .vop_create = spec_badop,
69 : .vop_mknod = spec_badop,
70 : .vop_open = spec_open,
71 : .vop_close = spec_close,
72 : .vop_access = spec_access,
73 : .vop_getattr = spec_getattr,
74 : .vop_setattr = spec_setattr,
75 : .vop_read = spec_read,
76 : .vop_write = spec_write,
77 : .vop_ioctl = spec_ioctl,
78 : .vop_poll = spec_poll,
79 : .vop_kqfilter = spec_kqfilter,
80 : .vop_revoke = vop_generic_revoke,
81 : .vop_fsync = spec_fsync,
82 : .vop_remove = spec_badop,
83 : .vop_link = spec_badop,
84 : .vop_rename = spec_badop,
85 : .vop_mkdir = spec_badop,
86 : .vop_rmdir = spec_badop,
87 : .vop_symlink = spec_badop,
88 : .vop_readdir = spec_badop,
89 : .vop_readlink = spec_badop,
90 : .vop_abortop = spec_badop,
91 : .vop_inactive = spec_inactive,
92 : .vop_reclaim = nullop,
93 : .vop_lock = vop_generic_lock,
94 : .vop_unlock = vop_generic_unlock,
95 : .vop_islocked = vop_generic_islocked,
96 : .vop_bmap = vop_generic_bmap,
97 : .vop_strategy = spec_strategy,
98 : .vop_print = spec_print,
99 : .vop_pathconf = spec_pathconf,
100 : .vop_advlock = spec_advlock,
101 : .vop_bwrite = vop_generic_bwrite,
102 : };
103 :
104 : /*
105 : * Open a special file.
106 : */
107 : int
108 0 : spec_open(void *v)
109 : {
110 0 : struct vop_open_args *ap = v;
111 0 : struct proc *p = ap->a_p;
112 0 : struct vnode *vp = ap->a_vp;
113 0 : struct vnode *bvp;
114 : dev_t bdev;
115 0 : dev_t dev = (dev_t)vp->v_rdev;
116 0 : int maj = major(dev);
117 : int error;
118 :
119 : /*
120 : * Don't allow open if fs is mounted -nodev.
121 : */
122 0 : if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
123 0 : return (ENXIO);
124 :
125 0 : switch (vp->v_type) {
126 :
127 : case VCHR:
128 0 : if ((u_int)maj >= nchrdev)
129 0 : return (ENXIO);
130 0 : if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) {
131 : /*
132 : * When running in very secure mode, do not allow
133 : * opens for writing of any disk character devices.
134 : */
135 0 : if (securelevel >= 2 && cdevsw[maj].d_type == D_DISK)
136 0 : return (EPERM);
137 : /*
138 : * When running in secure mode, do not allow opens
139 : * for writing of /dev/mem, /dev/kmem, or character
140 : * devices whose corresponding block devices are
141 : * currently mounted.
142 : */
143 0 : if (securelevel >= 1) {
144 0 : if ((bdev = chrtoblk(dev)) != NODEV &&
145 0 : vfinddev(bdev, VBLK, &bvp) &&
146 0 : bvp->v_usecount > 0 &&
147 0 : (error = vfs_mountedon(bvp)))
148 0 : return (error);
149 0 : if (iskmemdev(dev))
150 0 : return (EPERM);
151 : }
152 : }
153 0 : if (cdevsw[maj].d_type == D_TTY)
154 0 : vp->v_flag |= VISTTY;
155 0 : if (cdevsw[maj].d_flags & D_CLONE)
156 0 : return (spec_open_clone(ap));
157 0 : VOP_UNLOCK(vp);
158 0 : error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, p);
159 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
160 0 : return (error);
161 :
162 : case VBLK:
163 0 : if ((u_int)maj >= nblkdev)
164 0 : return (ENXIO);
165 : /*
166 : * When running in very secure mode, do not allow
167 : * opens for writing of any disk block devices.
168 : */
169 0 : if (securelevel >= 2 && ap->a_cred != FSCRED &&
170 0 : (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK)
171 0 : return (EPERM);
172 : /*
173 : * Do not allow opens of block devices that are
174 : * currently mounted.
175 : */
176 0 : if ((error = vfs_mountedon(vp)) != 0)
177 0 : return (error);
178 0 : return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, p));
179 : case VNON:
180 : case VLNK:
181 : case VDIR:
182 : case VREG:
183 : case VBAD:
184 : case VFIFO:
185 : case VSOCK:
186 : break;
187 : }
188 0 : return (0);
189 0 : }
190 :
191 : /*
192 : * Vnode op for read
193 : */
194 : int
195 0 : spec_read(void *v)
196 : {
197 0 : struct vop_read_args *ap = v;
198 0 : struct vnode *vp = ap->a_vp;
199 0 : struct uio *uio = ap->a_uio;
200 0 : struct proc *p = uio->uio_procp;
201 0 : struct buf *bp;
202 0 : daddr_t bn, nextbn, bscale;
203 0 : int bsize;
204 0 : struct partinfo dpart;
205 : size_t n;
206 : int on, majordev;
207 : int (*ioctl)(dev_t, u_long, caddr_t, int, struct proc *);
208 : int error = 0;
209 :
210 : #ifdef DIAGNOSTIC
211 0 : if (uio->uio_rw != UIO_READ)
212 0 : panic("spec_read mode");
213 0 : if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
214 0 : panic("spec_read proc");
215 : #endif
216 0 : if (uio->uio_resid == 0)
217 0 : return (0);
218 :
219 0 : switch (vp->v_type) {
220 :
221 : case VCHR:
222 0 : VOP_UNLOCK(vp);
223 0 : error = (*cdevsw[major(vp->v_rdev)].d_read)
224 0 : (vp->v_rdev, uio, ap->a_ioflag);
225 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
226 0 : return (error);
227 :
228 : case VBLK:
229 0 : if (uio->uio_offset < 0)
230 0 : return (EINVAL);
231 0 : bsize = BLKDEV_IOSIZE;
232 0 : if ((majordev = major(vp->v_rdev)) < nblkdev &&
233 0 : (ioctl = bdevsw[majordev].d_ioctl) != NULL &&
234 0 : (*ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0) {
235 : u_int32_t frag =
236 0 : DISKLABELV1_FFS_FRAG(dpart.part->p_fragblock);
237 : u_int32_t fsize =
238 0 : DISKLABELV1_FFS_FSIZE(dpart.part->p_fragblock);
239 0 : if (dpart.part->p_fstype == FS_BSDFFS && frag != 0 &&
240 0 : fsize != 0)
241 0 : bsize = frag * fsize;
242 0 : }
243 0 : bscale = btodb(bsize);
244 0 : do {
245 0 : bn = btodb(uio->uio_offset) & ~(bscale - 1);
246 0 : on = uio->uio_offset % bsize;
247 0 : n = ulmin((bsize - on), uio->uio_resid);
248 0 : if (vp->v_lastr + bscale == bn) {
249 0 : nextbn = bn + bscale;
250 0 : error = breadn(vp, bn, bsize, &nextbn, &bsize,
251 : 1, &bp);
252 0 : } else
253 0 : error = bread(vp, bn, bsize, &bp);
254 0 : vp->v_lastr = bn;
255 0 : n = ulmin(n, bsize - bp->b_resid);
256 0 : if (error) {
257 0 : brelse(bp);
258 0 : return (error);
259 : }
260 0 : error = uiomove((char *)bp->b_data + on, n, uio);
261 0 : brelse(bp);
262 0 : } while (error == 0 && uio->uio_resid > 0 && n != 0);
263 0 : return (error);
264 :
265 : default:
266 0 : panic("spec_read type");
267 : }
268 : /* NOTREACHED */
269 0 : }
270 :
271 : int
272 0 : spec_inactive(void *v)
273 : {
274 0 : struct vop_inactive_args *ap = v;
275 :
276 0 : VOP_UNLOCK(ap->a_vp);
277 0 : return (0);
278 : }
279 :
280 : /*
281 : * Vnode op for write
282 : */
283 : int
284 0 : spec_write(void *v)
285 : {
286 0 : struct vop_write_args *ap = v;
287 0 : struct vnode *vp = ap->a_vp;
288 0 : struct uio *uio = ap->a_uio;
289 0 : struct proc *p = uio->uio_procp;
290 0 : struct buf *bp;
291 : daddr_t bn, bscale;
292 : int bsize;
293 0 : struct partinfo dpart;
294 : size_t n;
295 : int on, majordev;
296 : int (*ioctl)(dev_t, u_long, caddr_t, int, struct proc *);
297 : int error = 0;
298 :
299 : #ifdef DIAGNOSTIC
300 0 : if (uio->uio_rw != UIO_WRITE)
301 0 : panic("spec_write mode");
302 0 : if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
303 0 : panic("spec_write proc");
304 : #endif
305 :
306 0 : switch (vp->v_type) {
307 :
308 : case VCHR:
309 0 : VOP_UNLOCK(vp);
310 0 : error = (*cdevsw[major(vp->v_rdev)].d_write)
311 0 : (vp->v_rdev, uio, ap->a_ioflag);
312 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
313 0 : return (error);
314 :
315 : case VBLK:
316 0 : if (uio->uio_resid == 0)
317 0 : return (0);
318 0 : if (uio->uio_offset < 0)
319 0 : return (EINVAL);
320 : bsize = BLKDEV_IOSIZE;
321 0 : if ((majordev = major(vp->v_rdev)) < nblkdev &&
322 0 : (ioctl = bdevsw[majordev].d_ioctl) != NULL &&
323 0 : (*ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0) {
324 : u_int32_t frag =
325 0 : DISKLABELV1_FFS_FRAG(dpart.part->p_fragblock);
326 : u_int32_t fsize =
327 0 : DISKLABELV1_FFS_FSIZE(dpart.part->p_fragblock);
328 0 : if (dpart.part->p_fstype == FS_BSDFFS && frag != 0 &&
329 0 : fsize != 0)
330 0 : bsize = frag * fsize;
331 0 : }
332 0 : bscale = btodb(bsize);
333 0 : do {
334 0 : bn = btodb(uio->uio_offset) & ~(bscale - 1);
335 0 : on = uio->uio_offset % bsize;
336 0 : n = ulmin((bsize - on), uio->uio_resid);
337 0 : error = bread(vp, bn, bsize, &bp);
338 0 : n = ulmin(n, bsize - bp->b_resid);
339 0 : if (error) {
340 0 : brelse(bp);
341 0 : return (error);
342 : }
343 0 : error = uiomove((char *)bp->b_data + on, n, uio);
344 0 : if (n + on == bsize)
345 0 : bawrite(bp);
346 : else
347 0 : bdwrite(bp);
348 0 : } while (error == 0 && uio->uio_resid > 0 && n != 0);
349 0 : return (error);
350 :
351 : default:
352 0 : panic("spec_write type");
353 : }
354 : /* NOTREACHED */
355 0 : }
356 :
357 : /*
358 : * Device ioctl operation.
359 : */
360 : int
361 0 : spec_ioctl(void *v)
362 : {
363 0 : struct vop_ioctl_args *ap = v;
364 0 : dev_t dev = ap->a_vp->v_rdev;
365 0 : int maj = major(dev);
366 :
367 0 : switch (ap->a_vp->v_type) {
368 :
369 : case VCHR:
370 0 : return ((*cdevsw[maj].d_ioctl)(dev, ap->a_command, ap->a_data,
371 0 : ap->a_fflag, ap->a_p));
372 :
373 : case VBLK:
374 0 : return ((*bdevsw[maj].d_ioctl)(dev, ap->a_command, ap->a_data,
375 0 : ap->a_fflag, ap->a_p));
376 :
377 : default:
378 0 : panic("spec_ioctl");
379 : /* NOTREACHED */
380 : }
381 0 : }
382 :
383 : int
384 0 : spec_poll(void *v)
385 : {
386 0 : struct vop_poll_args *ap = v;
387 : dev_t dev;
388 :
389 0 : switch (ap->a_vp->v_type) {
390 :
391 : default:
392 0 : return (ap->a_events &
393 : (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
394 :
395 : case VCHR:
396 0 : dev = ap->a_vp->v_rdev;
397 0 : return (*cdevsw[major(dev)].d_poll)(dev, ap->a_events, ap->a_p);
398 : }
399 0 : }
400 : int
401 0 : spec_kqfilter(void *v)
402 : {
403 0 : struct vop_kqfilter_args *ap = v;
404 :
405 : dev_t dev;
406 :
407 0 : dev = ap->a_vp->v_rdev;
408 0 : if (cdevsw[major(dev)].d_kqfilter)
409 0 : return (*cdevsw[major(dev)].d_kqfilter)(dev, ap->a_kn);
410 0 : return (EOPNOTSUPP);
411 0 : }
412 :
413 : /*
414 : * Synch buffers associated with a block device
415 : */
416 : int
417 0 : spec_fsync(void *v)
418 : {
419 0 : struct vop_fsync_args *ap = v;
420 0 : struct vnode *vp = ap->a_vp;
421 : struct buf *bp;
422 : struct buf *nbp;
423 : int s;
424 :
425 0 : if (vp->v_type == VCHR)
426 0 : return (0);
427 : /*
428 : * Flush all dirty buffers associated with a block device.
429 : */
430 : loop:
431 0 : s = splbio();
432 0 : LIST_FOREACH_SAFE(bp, &vp->v_dirtyblkhd, b_vnbufs, nbp) {
433 0 : if ((bp->b_flags & B_BUSY))
434 : continue;
435 0 : if ((bp->b_flags & B_DELWRI) == 0)
436 0 : panic("spec_fsync: not dirty");
437 0 : bremfree(bp);
438 0 : buf_acquire(bp);
439 0 : splx(s);
440 0 : bawrite(bp);
441 0 : goto loop;
442 : }
443 0 : if (ap->a_waitfor == MNT_WAIT) {
444 0 : vwaitforio (vp, 0, "spec_fsync", 0);
445 :
446 : #ifdef DIAGNOSTIC
447 0 : if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
448 0 : splx(s);
449 0 : vprint("spec_fsync: dirty", vp);
450 0 : goto loop;
451 : }
452 : #endif
453 : }
454 0 : splx(s);
455 0 : return (0);
456 0 : }
457 :
458 : int
459 0 : spec_strategy(void *v)
460 : {
461 0 : struct vop_strategy_args *ap = v;
462 0 : struct buf *bp = ap->a_bp;
463 0 : int maj = major(bp->b_dev);
464 :
465 0 : if (LIST_FIRST(&bp->b_dep) != NULL)
466 0 : buf_start(bp);
467 :
468 0 : (*bdevsw[maj].d_strategy)(bp);
469 0 : return (0);
470 : }
471 :
472 : /*
473 : * Device close routine
474 : */
475 : int
476 0 : spec_close(void *v)
477 : {
478 0 : struct vop_close_args *ap = v;
479 0 : struct proc *p = ap->a_p;
480 0 : struct vnode *vp = ap->a_vp;
481 0 : dev_t dev = vp->v_rdev;
482 : int (*devclose)(dev_t, int, int, struct proc *);
483 : int mode, relock, error;
484 :
485 0 : switch (vp->v_type) {
486 :
487 : case VCHR:
488 : /*
489 : * Hack: a tty device that is a controlling terminal
490 : * has a reference from the session structure.
491 : * We cannot easily tell that a character device is
492 : * a controlling terminal, unless it is the closing
493 : * process' controlling terminal. In that case,
494 : * if the reference count is 2 (this last descriptor
495 : * plus the session), release the reference from the session.
496 : */
497 0 : if (vcount(vp) == 2 && p != NULL && p->p_p->ps_pgrp &&
498 0 : vp == p->p_p->ps_pgrp->pg_session->s_ttyvp) {
499 0 : vrele(vp);
500 0 : p->p_p->ps_pgrp->pg_session->s_ttyvp = NULL;
501 0 : }
502 0 : if (cdevsw[major(dev)].d_flags & D_CLONE)
503 0 : return (spec_close_clone(ap));
504 : /*
505 : * If the vnode is locked, then we are in the midst
506 : * of forcably closing the device, otherwise we only
507 : * close on last reference.
508 : */
509 0 : if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
510 0 : return (0);
511 0 : devclose = cdevsw[major(dev)].d_close;
512 : mode = S_IFCHR;
513 0 : break;
514 :
515 : case VBLK:
516 : /*
517 : * On last close of a block device (that isn't mounted)
518 : * we must invalidate any in core blocks, so that
519 : * we can, for instance, change floppy disks. In order to do
520 : * that, we must lock the vnode. If we are coming from
521 : * vclean(), the vnode is already locked.
522 : */
523 0 : if (!(vp->v_flag & VXLOCK))
524 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
525 0 : error = vinvalbuf(vp, V_SAVE, ap->a_cred, p, 0, 0);
526 0 : if (!(vp->v_flag & VXLOCK))
527 0 : VOP_UNLOCK(vp);
528 0 : if (error)
529 0 : return (error);
530 : /*
531 : * We do not want to really close the device if it
532 : * is still in use unless we are trying to close it
533 : * forcibly. Since every use (buffer, vnode, swap, cmap)
534 : * holds a reference to the vnode, and because we mark
535 : * any other vnodes that alias this device, when the
536 : * sum of the reference counts on all the aliased
537 : * vnodes descends to one, we are on last close.
538 : */
539 0 : if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
540 0 : return (0);
541 0 : devclose = bdevsw[major(dev)].d_close;
542 : mode = S_IFBLK;
543 0 : break;
544 :
545 : default:
546 0 : panic("spec_close: not special");
547 : }
548 :
549 : /* release lock if held and this isn't coming from vclean() */
550 0 : relock = VOP_ISLOCKED(vp) && !(vp->v_flag & VXLOCK);
551 0 : if (relock)
552 0 : VOP_UNLOCK(vp);
553 0 : error = (*devclose)(dev, ap->a_fflag, mode, p);
554 0 : if (relock)
555 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
556 0 : return (error);
557 0 : }
558 :
559 : int
560 0 : spec_getattr(void *v)
561 : {
562 0 : struct vop_getattr_args *ap = v;
563 0 : struct vnode *vp = ap->a_vp;
564 : int error;
565 :
566 0 : if (!(vp->v_flag & VCLONE))
567 0 : return (EBADF);
568 :
569 0 : vn_lock(vp->v_specparent, LK_EXCLUSIVE|LK_RETRY);
570 0 : error = VOP_GETATTR(vp->v_specparent, ap->a_vap, ap->a_cred, ap->a_p);
571 0 : VOP_UNLOCK(vp->v_specparent);
572 :
573 0 : return (error);
574 0 : }
575 :
576 : int
577 0 : spec_setattr(void *v)
578 : {
579 0 : struct vop_getattr_args *ap = v;
580 0 : struct proc *p = ap->a_p;
581 0 : struct vnode *vp = ap->a_vp;
582 : int error;
583 :
584 0 : if (!(vp->v_flag & VCLONE))
585 0 : return (EBADF);
586 :
587 0 : vn_lock(vp->v_specparent, LK_EXCLUSIVE|LK_RETRY);
588 0 : error = VOP_SETATTR(vp->v_specparent, ap->a_vap, ap->a_cred, p);
589 0 : VOP_UNLOCK(vp->v_specparent);
590 :
591 0 : return (error);
592 0 : }
593 :
594 : int
595 0 : spec_access(void *v)
596 : {
597 0 : struct vop_access_args *ap = v;
598 0 : struct vnode *vp = ap->a_vp;
599 : int error;
600 :
601 0 : if (!(vp->v_flag & VCLONE))
602 0 : return (EBADF);
603 :
604 0 : vn_lock(vp->v_specparent, LK_EXCLUSIVE|LK_RETRY);
605 0 : error = VOP_ACCESS(vp->v_specparent, ap->a_mode, ap->a_cred, ap->a_p);
606 0 : VOP_UNLOCK(vp->v_specparent);
607 :
608 0 : return (error);
609 0 : }
610 :
611 : /*
612 : * Print out the contents of a special device vnode.
613 : */
614 : int
615 0 : spec_print(void *v)
616 : {
617 0 : struct vop_print_args *ap = v;
618 :
619 0 : printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
620 0 : minor(ap->a_vp->v_rdev));
621 0 : return 0;
622 : }
623 :
624 : /*
625 : * Return POSIX pathconf information applicable to special devices.
626 : */
627 : int
628 0 : spec_pathconf(void *v)
629 : {
630 0 : struct vop_pathconf_args *ap = v;
631 : int error = 0;
632 :
633 0 : switch (ap->a_name) {
634 : case _PC_LINK_MAX:
635 0 : *ap->a_retval = LINK_MAX;
636 0 : break;
637 : case _PC_MAX_CANON:
638 0 : *ap->a_retval = MAX_CANON;
639 0 : break;
640 : case _PC_MAX_INPUT:
641 0 : *ap->a_retval = MAX_INPUT;
642 0 : break;
643 : case _PC_CHOWN_RESTRICTED:
644 0 : *ap->a_retval = 1;
645 0 : break;
646 : case _PC_VDISABLE:
647 0 : *ap->a_retval = _POSIX_VDISABLE;
648 0 : break;
649 : case _PC_TIMESTAMP_RESOLUTION:
650 0 : *ap->a_retval = 1;
651 0 : break;
652 : default:
653 : error = EINVAL;
654 0 : break;
655 : }
656 :
657 0 : return (error);
658 : }
659 :
660 : /*
661 : * Special device advisory byte-level locks.
662 : */
663 : int
664 0 : spec_advlock(void *v)
665 : {
666 0 : struct vop_advlock_args *ap = v;
667 0 : struct vnode *vp = ap->a_vp;
668 :
669 0 : return (lf_advlock(&vp->v_speclockf, (off_t)0, ap->a_id,
670 0 : ap->a_op, ap->a_fl, ap->a_flags));
671 : }
672 :
673 : /*
674 : * Special device bad operation
675 : */
676 : int
677 0 : spec_badop(void *v)
678 : {
679 :
680 0 : panic("spec_badop called");
681 : /* NOTREACHED */
682 : }
683 :
684 : /*
685 : * Copyright (c) 2006 Pedro Martelletto <pedro@ambientworks.net>
686 : * Copyright (c) 2006 Thordur Bjornsson <thib@openbsd.org>
687 : *
688 : * Permission to use, copy, modify, and distribute this software for any
689 : * purpose with or without fee is hereby granted, provided that the above
690 : * copyright notice and this permission notice appear in all copies.
691 : *
692 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
693 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
694 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
695 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
696 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
697 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
698 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
699 : */
700 :
701 : #ifdef CLONE_DEBUG
702 : #define DNPRINTF(m...) do { printf(m); } while (0)
703 : #else
704 : #define DNPRINTF(m...) /* nothing */
705 : #endif
706 :
707 : int
708 0 : spec_open_clone(struct vop_open_args *ap)
709 : {
710 0 : struct vnode *cvp, *vp = ap->a_vp;
711 : struct cloneinfo *cip;
712 : int error, i;
713 :
714 : DNPRINTF("cloning vnode\n");
715 :
716 0 : if (minor(vp->v_rdev) >= (1 << CLONE_SHIFT))
717 0 : return (ENXIO);
718 :
719 0 : for (i = 1; i < CLONE_MAPSZ * NBBY; i++)
720 0 : if (isclr(vp->v_specbitmap, i)) {
721 0 : setbit(vp->v_specbitmap, i);
722 0 : break;
723 : }
724 :
725 0 : if (i == CLONE_MAPSZ * NBBY)
726 0 : return (EBUSY); /* too many open instances */
727 :
728 0 : error = cdevvp(makedev(major(vp->v_rdev),
729 : (i << CLONE_SHIFT) | minor(vp->v_rdev)), &cvp);
730 0 : if (error) {
731 0 : clrbit(vp->v_specbitmap, i);
732 0 : return (error); /* out of vnodes */
733 : }
734 :
735 0 : VOP_UNLOCK(vp);
736 :
737 0 : error = cdevsw[major(vp->v_rdev)].d_open(cvp->v_rdev, ap->a_mode,
738 0 : S_IFCHR, ap->a_p);
739 :
740 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
741 :
742 0 : if (error) {
743 0 : vput(cvp);
744 0 : clrbit(vp->v_specbitmap, i);
745 0 : return (error); /* device open failed */
746 : }
747 :
748 0 : cvp->v_flag |= VCLONE;
749 :
750 0 : cip = malloc(sizeof(struct cloneinfo), M_TEMP, M_WAITOK);
751 0 : cip->ci_data = vp->v_data;
752 0 : cip->ci_vp = cvp;
753 :
754 0 : cvp->v_specparent = vp;
755 0 : vp->v_flag |= VCLONED;
756 0 : vp->v_data = cip;
757 :
758 : DNPRINTF("clone of vnode %p is vnode %p\n", vp, cvp);
759 :
760 0 : return (0); /* device cloned */
761 0 : }
762 :
763 : int
764 0 : spec_close_clone(struct vop_close_args *ap)
765 : {
766 0 : struct vnode *pvp, *vp = ap->a_vp;
767 : int error;
768 :
769 0 : error = cdevsw[major(vp->v_rdev)].d_close(vp->v_rdev, ap->a_fflag,
770 0 : S_IFCHR, ap->a_p);
771 0 : if (error)
772 0 : return (error); /* device close failed */
773 :
774 0 : pvp = vp->v_specparent; /* get parent device */
775 0 : clrbit(pvp->v_specbitmap, minor(vp->v_rdev) >> CLONE_SHIFT);
776 0 : vrele(pvp);
777 :
778 0 : return (0); /* clone closed */
779 0 : }
|