1 /*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * $Id: specfs.c,v 1.1 94/10/19 17:09:23 bill Exp Locker: bill $
34 */
35
36 #include "sys/param.h"
37 #include "sys/file.h"
38 #include "sys/mount.h"
39 #include "sys/stat.h"
40 #include "sys/errno.h"
41 #include "sys/ioctl.h"
42 #include "uio.h"
43 #include "proc.h"
44 #include "systm.h"
45 #include "malloc.h"
46 #include "buf.h"
47 #include "modconfig.h"
48
49 #include "vnode.h"
50 #include "namei.h"
51 #include "specdev.h"
52 #include "dkbad.h" /* XXX */
53 #include "disklabel.h"
54
55 #include "prototypes.h"
56
57 /* symbolic sleep message strings for devices */
58 char devopn[] = "devopn";
59 char devio[] = "devio";
60 char devwait[] = "devwait";
61 char devin[] = "devin";
62 char devout[] = "devout";
63 char devioc[] = "devioc";
64 char devcls[] = "devcls";
65
66 struct vnodeops spec_vnodeops = {
67 spec_lookup, /* lookup */
68 spec_create, /* create */
69 spec_mknod, /* mknod */
70 spec_open, /* open */
71 spec_close, /* close */
72 spec_access, /* access */
73 spec_getattr, /* getattr */
74 spec_setattr, /* setattr */
75 spec_read, /* read */
76 spec_write, /* write */
77 spec_ioctl, /* ioctl */
78 spec_select, /* select */
79 spec_mmap, /* mmap */
80 spec_fsync, /* fsync */
81 spec_seek, /* seek */
82 spec_remove, /* remove */
83 spec_link, /* link */
84 spec_rename, /* rename */
85 spec_mkdir, /* mkdir */
86 spec_rmdir, /* rmdir */
87 spec_symlink, /* symlink */
88 spec_readdir, /* readdir */
89 spec_readlink, /* readlink */
90 spec_abortop, /* abortop */
91 spec_inactive, /* inactive */
92 spec_reclaim, /* reclaim */
93 spec_lock, /* lock */
94 spec_unlock, /* unlock */
95 spec_bmap, /* bmap */
96 spec_strategy, /* strategy */
97 spec_print, /* print */
98 spec_islocked, /* islocked */
99 spec_advlock, /* advlock */
100 };
101
102 struct vnode *speclisth[SPECHSZ];
103
104 /* XXX -- belongs in spec_node, spec_vfsops, etc, when moves to ./specfs */
105 /*
106 * Create a vnode for a block device.
107 * Used for root filesystem, argdev, and swap areas.
108 * Also used for memory file system special devices.
109 */
110 int
bdevvp(dev_t dev,struct vnode ** vpp)111 bdevvp(dev_t dev, struct vnode **vpp)
112 {
113 register struct vnode *vp;
114 struct vnode *nvp;
115 int error;
116
117 if (dev == BLK_NODEV)
118 return (0);
119 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
120 if (error) {
121 *vpp = 0;
122 return (error);
123 }
124 vp = nvp;
125 vp->v_type = VBLK;
126 if (nvp = checkalias(vp, dev, (struct mount *)0)) {
127 vput(vp);
128 vp = nvp;
129 }
130 *vpp = vp;
131 return (0);
132 }
133
134 /*
135 * Check to see if the new vnode represents a special device
136 * for which we already have a vnode (either because of
137 * bdevvp() or because of a different vnode representing
138 * the same block device). If such an alias exists, deallocate
139 * the existing contents and return the aliased vnode. The
140 * caller is responsible for filling it with its new contents.
141 */
142 struct vnode *
checkalias(struct vnode * nvp,dev_t nvp_rdev,struct mount * mp)143 checkalias(struct vnode *nvp, dev_t nvp_rdev, struct mount *mp)
144 {
145 struct vnode *vp;
146 struct vnode **vpp;
147
148 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
149 return (NULLVP);
150
151 vpp = &speclisth[SPECHASH(nvp_rdev)];
152 loop:
153 for (vp = *vpp; vp; vp = vp->v_specnext) {
154 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
155 continue;
156 /*
157 * Alias, but not in use, so flush it out.
158 */
159 if (vp->v_usecount == 0) {
160 vgone(vp);
161 goto loop;
162 }
163 if (vget(vp))
164 goto loop;
165 break;
166 }
167 if (vp == NULL || vp->v_tag != VT_NON) {
168 MALLOC(nvp->v_specinfo, struct specinfo *,
169 sizeof(struct specinfo), M_VNODE, M_WAITOK);
170 nvp->v_rdev = nvp_rdev;
171 nvp->v_hashchain = vpp;
172 nvp->v_specnext = *vpp;
173 nvp->v_specflags = 0;
174 *vpp = nvp;
175 if (vp != NULL) {
176 nvp->v_flag |= VALIASED;
177 vp->v_flag |= VALIASED;
178 vput(vp);
179 }
180 return (NULLVP);
181 }
182 VOP_UNLOCK(vp);
183 vclean(vp, 0);
184 vp->v_op = nvp->v_op;
185 vp->v_tag = nvp->v_tag;
186 nvp->v_type = VNON;
187 insmntque(vp, mp);
188 return (vp);
189 }
190
191 void
spec_anonymous(struct vnode * vp)192 spec_anonymous(struct vnode *vp) {
193 vclean(vp, 0);
194 vp->v_op = &spec_vnodeops;
195 insmntque(vp, (struct mount *)0);
196 }
197
198 /* remove any aliases of the device */
199 void
spec_remove_aliases(struct vnode * vp)200 spec_remove_aliases(struct vnode *vp) {
201 struct vnode *vq;
202
203 while (vp->v_flag & VALIASED) {
204 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
205 if (vq->v_rdev != vp->v_rdev ||
206 vq->v_type != vp->v_type || vp == vq)
207 continue;
208 vgone(vq);
209 break;
210 }
211 }
212 }
213
214 /* remove special device vnode from alias list. */
215 void
spec_remove_(struct vnode * vp)216 spec_remove_(struct vnode *vp)
217 {
218 struct vnode *vq, *vx;
219 long count;
220
221 /* remove device */
222 if (*vp->v_hashchain == vp) {
223 *vp->v_hashchain = vp->v_specnext;
224 } else {
225 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
226 if (vq->v_specnext != vp)
227 continue;
228 vq->v_specnext = vp->v_specnext;
229 break;
230 }
231 /* device not found in hash */
232 if (vq == NULL)
233 panic("spec_remove: device");
234 }
235
236 /* remove device's aliases */
237 if (vp->v_flag & VALIASED) {
238 count = 0;
239 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
240 if (vq->v_rdev != vp->v_rdev ||
241 vq->v_type != vp->v_type)
242 continue;
243 count++;
244 vx = vq;
245 }
246 /* device's alias is missing */
247 if (count == 0)
248 panic("spec_remove: alias");
249 if (count == 1)
250 vx->v_flag &= ~VALIASED;
251 vp->v_flag &= ~VALIASED;
252 }
253 FREE(vp->v_specinfo, M_VNODE);
254 vp->v_specinfo = NULL;
255 }
256
257 /* locate a vnode in the special device list by device number and type. */
258 int
spec_find(dev_t dev,enum vtype type,struct vnode ** vpp)259 spec_find(dev_t dev, enum vtype type, struct vnode **vpp)
260 {
261 struct vnode *vp;
262
263 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
264 if (dev != vp->v_rdev || type != vp->v_type)
265 continue;
266 *vpp = vp;
267 return (0);
268 }
269 return (1);
270 }
271
272 /*
273 * Calculate the total number of references to a special device.
274 */
275 int
spec_count(struct vnode * vp)276 spec_count(struct vnode *vp)
277 {
278 struct vnode *vq;
279 int count;
280
281 if ((vp->v_flag & VALIASED) == 0)
282 return (vp->v_usecount);
283 loop:
284 for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
285 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
286 continue;
287 /*
288 * Alias, but not in use, so flush it out.
289 */
290 if (vq->v_usecount == 0) {
291 vgone(vq);
292 goto loop;
293 }
294 count += vq->v_usecount;
295 }
296 return (count);
297 }
298
299 /* Check to see if a filesystem is mounted on a block device. */
300 int
mountedon(struct vnode * vp)301 mountedon(struct vnode *vp)
302 {
303 struct vnode *vq;
304
305 if (vp->v_specflags & SI_MOUNTEDON)
306 return (EBUSY);
307 if (vp->v_flag & VALIASED) {
308 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
309 if (vq->v_rdev != vp->v_rdev ||
310 vq->v_type != vp->v_type)
311 continue;
312 if (vq->v_specflags & SI_MOUNTEDON)
313 return (EBUSY);
314 }
315 }
316 return (0);
317 }
318
319 /* XXX */
320
321 /*
322 * Trivial lookup routine that always fails.
323 */
324 spec_lookup(vp, ndp, p)
325 struct vnode *vp;
326 struct nameidata *ndp;
327 struct proc *p;
328 {
329
330 ndp->ni_dvp = vp;
331 ndp->ni_vp = NULL;
332 return (ENOTDIR);
333 }
334
335 /*
336 * Open a special file: Don't allow open if fs is mounted -nodev,
337 * and don't allow opens of block devices that are currently mounted.
338 * Otherwise, call device driver open function.
339 */
340 /* ARGSUSED */
spec_open(vp,mode,cred,p)341 spec_open(vp, mode, cred, p)
342 register struct vnode *vp;
343 int mode;
344 struct ucred *cred;
345 struct proc *p;
346 {
347 dev_t dev = (dev_t)vp->v_rdev;
348 /* register int maj = major(dev); */
349 int error;
350
351 if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
352 return (ENXIO);
353
354 switch (vp->v_type) {
355
356 case VCHR:
357 /* if ((u_int)maj >= nchrdev)
358 return (ENXIO); */
359 VOP_UNLOCK(vp);
360 error = devif_open(dev, CHRDEV, mode, p);
361 /* error = (*cdevsw[maj].d_open)(dev, mode, S_IFCHR, p);*/
362 VOP_LOCK(vp);
363 return (error);
364
365 case VBLK:
366 /* if ((u_int)maj >= nblkdev)
367 return (ENXIO); */
368 if (error = mountedon(vp))
369 return (error);
370
371 /* if a mount, must be exclusive use and invalidate cache. */
372 if ((mode & FMOUNT) != 0) {
373 if (spec_count(vp) > 1)
374 return (EBUSY);
375 vinvalbuf(vp, 1);
376 }
377
378 return (devif_open(dev, BLKDEV, mode, p));
379 /*return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK, p));*/
380 }
381 return (0);
382 }
383
384 /*
385 * Vnode op for read
386 */
387 /* ARGSUSED */
spec_read(vp,uio,ioflag,cred)388 spec_read(vp, uio, ioflag, cred)
389 register struct vnode *vp;
390 register struct uio *uio;
391 int ioflag;
392 struct ucred *cred;
393 {
394 struct proc *p = uio->uio_procp;
395 struct buf *bp;
396 daddr_t bn;
397 long bsize, bscale;
398 struct partinfo dpart;
399 register int n, on;
400 int error = 0;
401 extern int mem_no;
402
403 #ifdef DIAGNOSTIC
404 if (uio->uio_rw != UIO_READ)
405 panic("spec_read mode");
406 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
407 panic("spec_read proc");
408 #endif
409 if (uio->uio_resid == 0)
410 return (0);
411
412 switch (vp->v_type) {
413
414 case VCHR:
415 /*
416 * Negative offsets allowed only for /dev/kmem
417 */
418 if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
419 return (EINVAL);
420 VOP_UNLOCK(vp);
421 error = devif_read(vp->v_rdev, CHRDEV, uio, ioflag);
422 /*error = (*cdevsw[major(vp->v_rdev)].d_read)
423 (vp->v_rdev, uio, ioflag);*/
424 VOP_LOCK(vp);
425 return (error);
426
427 case VBLK:
428 if (uio->uio_offset < 0)
429 return (EINVAL);
430 bsize = BLKDEV_IOSIZE;
431 if (devif_ioctl(vp->v_rdev, BLKDEV, DIOCGPART,
432 (caddr_t)&dpart, FREAD, p) == 0) {
433 /* if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
434 (caddr_t)&dpart, FREAD, p) == 0) { */
435 if (dpart.part->p_fstype == FS_BSDFFS &&
436 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
437 bsize = dpart.part->p_frag *
438 dpart.part->p_fsize;
439 }
440 bscale = bsize / DEV_BSIZE;
441 do {
442 bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
443 on = uio->uio_offset % bsize;
444 n = min((unsigned)(bsize - on), uio->uio_resid);
445 if (vp->v_lastr + bscale == bn)
446 error = breada(vp, bn, (int)bsize, bn + bscale,
447 (int)bsize, NOCRED, &bp);
448 else
449 error = bread(vp, bn, (int)bsize, NOCRED, &bp);
450 vp->v_lastr = bn;
451 n = min(n, bsize - bp->b_resid);
452 if (error) {
453 brelse(bp);
454 return (error);
455 }
456 error = uiomove(bp->b_un.b_addr + on, n, uio);
457 if (n + on == bsize)
458 bp->b_flags |= B_AGE;
459 brelse(bp);
460 } while (error == 0 && uio->uio_resid > 0 && n != 0);
461 return (error);
462
463 default:
464 panic("spec_read type");
465 }
466 /* NOTREACHED */
467 }
468
469 /*
470 * Vnode op for write
471 */
472 /* ARGSUSED */
spec_write(vp,uio,ioflag,cred)473 spec_write(vp, uio, ioflag, cred)
474 register struct vnode *vp;
475 register struct uio *uio;
476 int ioflag;
477 struct ucred *cred;
478 {
479 struct proc *p = uio->uio_procp;
480 struct buf *bp;
481 daddr_t bn;
482 int bsize, blkmask;
483 struct partinfo dpart;
484 register int n, on;
485 int error = 0;
486 extern int mem_no;
487
488 #ifdef DIAGNOSTIC
489 if (uio->uio_rw != UIO_WRITE)
490 panic("spec_write mode");
491 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
492 panic("spec_write proc");
493 #endif
494
495 switch (vp->v_type) {
496
497 case VCHR:
498 /*
499 * Negative offsets allowed only for /dev/kmem
500 */
501 if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
502 return (EINVAL);
503 VOP_UNLOCK(vp);
504 error = devif_write(vp->v_rdev, CHRDEV, uio, ioflag);
505 /* error = (*cdevsw[major(vp->v_rdev)].d_write)
506 (vp->v_rdev, uio, ioflag); */
507 VOP_LOCK(vp);
508 return (error);
509
510 case VBLK:
511 if (uio->uio_resid == 0)
512 return (0);
513 if (uio->uio_offset < 0)
514 return (EINVAL);
515 bsize = BLKDEV_IOSIZE;
516 if (devif_ioctl(vp->v_rdev, BLKDEV, DIOCGPART,
517 (caddr_t)&dpart, FREAD, p) == 0) {
518 /* if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
519 (caddr_t)&dpart, FREAD, p) == 0) { */
520 if (dpart.part->p_fstype == FS_BSDFFS &&
521 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
522 bsize = dpart.part->p_frag *
523 dpart.part->p_fsize;
524 }
525 blkmask = (bsize / DEV_BSIZE) - 1;
526 do {
527 bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
528 on = uio->uio_offset % bsize;
529 n = min((unsigned)(bsize - on), uio->uio_resid);
530 if (n == bsize)
531 bp = getblk(vp, bn, bsize);
532 else
533 error = bread(vp, bn, bsize, NOCRED, &bp);
534 n = min(n, bsize - bp->b_resid);
535 if (error) {
536 brelse(bp);
537 return (error);
538 }
539 error = uiomove(bp->b_un.b_addr + on, n, uio);
540 if (n + on == bsize) {
541 bp->b_flags |= B_AGE;
542 bawrite(bp);
543 } else
544 bdwrite(bp, vp);
545 } while (error == 0 && uio->uio_resid > 0 && n != 0);
546 return (error);
547
548 default:
549 panic("spec_write type");
550 }
551 /* NOTREACHED */
552 }
553
554 /*
555 * Device ioctl operation.
556 */
557 /* ARGSUSED */
558 spec_ioctl(vp, com, data, fflag, cred, p)
559 struct vnode *vp;
560 int com;
561 caddr_t data;
562 int fflag;
563 struct ucred *cred;
564 struct proc *p;
565 {
566 dev_t dev = vp->v_rdev;
567
568 switch (vp->v_type) {
569
570 case VCHR:
571 return (devif_ioctl(dev, CHRDEV, com, data, fflag, p));
572 /*return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data,
573 fflag, p));*/
574
575 case VBLK:
576 /* internal "ioctl" to sense flags to discover if a tape */
577 /* if (com == 0 && (int)data == B_TAPE)
578 if (bdevsw[major(dev)].d_flags & B_TAPE)
579 return (0);
580 else
581 return (1); */
582 return (devif_ioctl(dev, BLKDEV, com, data, fflag, p));
583 /* return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data,
584 fflag, p)); */
585
586 default:
587 panic("spec_ioctl");
588 /* NOTREACHED */
589 }
590 }
591
592 /* ARGSUSED */
593 spec_select(vp, which, fflags, cred, p)
594 struct vnode *vp;
595 int which, fflags;
596 struct ucred *cred;
597 struct proc *p;
598 {
599 register dev_t dev;
600
601 switch (vp->v_type) {
602
603 default:
604 return (1); /* XXX */
605
606 case VCHR:
607 dev = vp->v_rdev;
608 return (devif_select(dev, CHRDEV, which, p));
609 /* return (*cdevsw[major(dev)].d_select)(dev, which, p);*/
610 }
611 }
612
613 /*
614 * Just call the device strategy routine
615 */
spec_strategy(bp)616 spec_strategy(bp)
617 register struct buf *bp;
618 {
619
620 (void)devif_strategy(BLKDEV, bp);
621 /* (*bdevsw[major(bp->b_dev)].d_strategy)(bp); */
622 return (0);
623 }
624
625 /*
626 * This is a noop, simply returning what one has been given.
627 */
628 spec_bmap(vp, bn, vpp, bnp)
629 struct vnode *vp;
630 daddr_t bn;
631 struct vnode **vpp;
632 daddr_t *bnp;
633 {
634
635 if (vpp != NULL)
636 *vpp = vp;
637 if (bnp != NULL)
638 *bnp = bn;
639 return (0);
640 }
641
642 /*
643 * At the moment we do not do any locking.
644 */
645 /* ARGSUSED */
646 spec_lock(vp)
647 struct vnode *vp;
648 {
649
650 return (0);
651 }
652
653 /* ARGSUSED */
654 spec_unlock(vp)
655 struct vnode *vp;
656 {
657
658 return (0);
659 }
660
661 /*
662 * Device close routine
663 */
664 /* ARGSUSED */
spec_close(vp,flag,cred,p)665 spec_close(vp, flag, cred, p)
666 register struct vnode *vp;
667 int flag;
668 struct ucred *cred;
669 struct proc *p;
670 {
671 dev_t dev = vp->v_rdev;
672 /*int (*devclose) __P((dev_t, int, int, struct proc *));*/
673 devif_type_t typ;
674 int mode;
675
676 switch (vp->v_type) {
677
678 case VCHR:
679 /*
680 * If the vnode is locked, then we are in the midst
681 * of forcably closing the device, otherwise we only
682 * close on last reference.
683 */
684 if (spec_count(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
685 return (0);
686 /* devclose = cdevsw[major(dev)].d_close; */
687 mode = S_IFCHR;
688 typ = CHRDEV;
689 break;
690
691 case VBLK:
692 /*
693 * On last close of a block device (that isn't mounted)
694 * we must invalidate any in core blocks, so that
695 * we can, for instance, change floppy disks.
696 */
697 vflushbuf(vp, 0, 0);
698 if (vinvalbuf(vp, 1))
699 return (0);
700 /*
701 * We do not want to really close the device if it
702 * is still in use unless we are trying to close it
703 * forcibly. Since every use (buffer, vnode, swap, cmap)
704 * holds a reference to the vnode, and because we mark
705 * any other vnodes that alias this device, when the
706 * sum of the reference counts on all the aliased
707 * vnodes descends to one, we are on last close.
708 */
709 if (spec_count(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
710 return (0);
711 /* devclose = bdevsw[major(dev)].d_close; */
712 mode = S_IFBLK;
713 typ = BLKDEV;
714 break;
715
716 default:
717 panic("spec_close: not special");
718 }
719
720 return (devif_close(dev, typ, flag, p));
721 /* return ((*devclose)(dev, flag, mode, p)); */
722 }
723
724 /*
725 * Print out the contents of a special device vnode.
726 */
727 spec_print(vp)
728 struct vnode *vp;
729 {
730
731 printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev),
732 minor(vp->v_rdev));
733 }
734
735 /*
736 * Special device advisory byte-level locks.
737 */
738 /* ARGSUSED */
739 spec_advlock(vp, id, op, fl, flags)
740 struct vnode *vp;
741 caddr_t id;
742 int op;
743 struct flock *fl;
744 int flags;
745 {
746
747 return (EOPNOTSUPP);
748 }
749
750 /*
751 * Special device failed operation
752 */
spec_ebadf()753 spec_ebadf()
754 {
755
756 return (EBADF);
757 }
758
759 /*
760 * Special device bad operation
761 */
spec_badop()762 spec_badop()
763 {
764
765 panic("spec_badop called");
766 /* NOTREACHED */
767 }
768