xref: /386bsd/usr/src/kernel/kern/fs/specfs.c (revision dc8b130e)
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