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