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