xref: /csrg-svn/sys/miscfs/specfs/spec_vnops.c (revision 53542)
137486Smckusick /*
237486Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337486Smckusick  * All rights reserved.
437486Smckusick  *
544443Sbostic  * %sccs.include.redist.c%
637486Smckusick  *
7*53542Sheideman  *	@(#)spec_vnops.c	7.43 (Berkeley) 05/14/92
837486Smckusick  */
937486Smckusick 
1051457Sbostic #include <sys/param.h>
1151457Sbostic #include <sys/proc.h>
1251457Sbostic #include <sys/systm.h>
1351457Sbostic #include <sys/kernel.h>
1451457Sbostic #include <sys/conf.h>
1551457Sbostic #include <sys/buf.h>
1651457Sbostic #include <sys/mount.h>
1751457Sbostic #include <sys/namei.h>
1851457Sbostic #include <sys/vnode.h>
1951457Sbostic #include <sys/specdev.h>
2051457Sbostic #include <sys/stat.h>
2151457Sbostic #include <sys/errno.h>
2251457Sbostic #include <sys/ioctl.h>
2351457Sbostic #include <sys/file.h>
2451457Sbostic #include <sys/disklabel.h>
2537486Smckusick 
2640707Skarels /* symbolic sleep message strings for devices */
2740707Skarels char	devopn[] = "devopn";
2840707Skarels char	devio[] = "devio";
2940707Skarels char	devwait[] = "devwait";
3040707Skarels char	devin[] = "devin";
3140707Skarels char	devout[] = "devout";
3240707Skarels char	devioc[] = "devioc";
3340707Skarels char	devcls[] = "devcls";
3440707Skarels 
35*53542Sheideman int (**spec_vnodeop_p)();
36*53542Sheideman struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
37*53542Sheideman 	{ &vop_default_desc, vn_default_error },
38*53542Sheideman 	{ &vop_lookup_desc, spec_lookup },		/* lookup */
39*53542Sheideman 	{ &vop_create_desc, spec_create },		/* create */
40*53542Sheideman 	{ &vop_mknod_desc, spec_mknod },		/* mknod */
41*53542Sheideman 	{ &vop_open_desc, spec_open },		/* open */
42*53542Sheideman 	{ &vop_close_desc, spec_close },		/* close */
43*53542Sheideman 	{ &vop_access_desc, spec_access },		/* access */
44*53542Sheideman 	{ &vop_getattr_desc, spec_getattr },		/* getattr */
45*53542Sheideman 	{ &vop_setattr_desc, spec_setattr },		/* setattr */
46*53542Sheideman 	{ &vop_read_desc, spec_read },		/* read */
47*53542Sheideman 	{ &vop_write_desc, spec_write },		/* write */
48*53542Sheideman 	{ &vop_ioctl_desc, spec_ioctl },		/* ioctl */
49*53542Sheideman 	{ &vop_select_desc, spec_select },		/* select */
50*53542Sheideman 	{ &vop_mmap_desc, spec_mmap },		/* mmap */
51*53542Sheideman 	{ &vop_fsync_desc, spec_fsync },		/* fsync */
52*53542Sheideman 	{ &vop_seek_desc, spec_seek },		/* seek */
53*53542Sheideman 	{ &vop_remove_desc, spec_remove },		/* remove */
54*53542Sheideman 	{ &vop_link_desc, spec_link },		/* link */
55*53542Sheideman 	{ &vop_rename_desc, spec_rename },		/* rename */
56*53542Sheideman 	{ &vop_mkdir_desc, spec_mkdir },		/* mkdir */
57*53542Sheideman 	{ &vop_rmdir_desc, spec_rmdir },		/* rmdir */
58*53542Sheideman 	{ &vop_symlink_desc, spec_symlink },		/* symlink */
59*53542Sheideman 	{ &vop_readdir_desc, spec_readdir },		/* readdir */
60*53542Sheideman 	{ &vop_readlink_desc, spec_readlink },		/* readlink */
61*53542Sheideman 	{ &vop_abortop_desc, spec_abortop },		/* abortop */
62*53542Sheideman 	{ &vop_inactive_desc, spec_inactive },		/* inactive */
63*53542Sheideman 	{ &vop_reclaim_desc, spec_reclaim },		/* reclaim */
64*53542Sheideman 	{ &vop_lock_desc, spec_lock },		/* lock */
65*53542Sheideman 	{ &vop_unlock_desc, spec_unlock },		/* unlock */
66*53542Sheideman 	{ &vop_bmap_desc, spec_bmap },		/* bmap */
67*53542Sheideman 	{ &vop_strategy_desc, spec_strategy },		/* strategy */
68*53542Sheideman 	{ &vop_print_desc, spec_print },		/* print */
69*53542Sheideman 	{ &vop_islocked_desc, spec_islocked },		/* islocked */
70*53542Sheideman 	{ &vop_advlock_desc, spec_advlock },		/* advlock */
71*53542Sheideman 	{ &vop_blkatoff_desc, spec_blkatoff },		/* blkatoff */
72*53542Sheideman 	{ &vop_vget_desc, spec_vget },		/* vget */
73*53542Sheideman 	{ &vop_valloc_desc, spec_valloc },		/* valloc */
74*53542Sheideman 	{ &vop_vfree_desc, spec_vfree },		/* vfree */
75*53542Sheideman 	{ &vop_truncate_desc, spec_truncate },		/* truncate */
76*53542Sheideman 	{ &vop_update_desc, spec_update },		/* update */
77*53542Sheideman 	{ &vop_bwrite_desc, spec_bwrite },		/* bwrite */
78*53542Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
7937486Smckusick };
80*53542Sheideman struct vnodeopv_desc spec_vnodeop_opv_desc =
81*53542Sheideman 	{ &spec_vnodeop_p, spec_vnodeop_entries };
8237486Smckusick 
8337486Smckusick /*
8439292Smckusick  * Trivial lookup routine that always fails.
8539292Smckusick  */
8652320Sheideman int
87*53542Sheideman spec_lookup (ap)
88*53542Sheideman 	struct vop_lookup_args *ap;
89*53542Sheideman #define dvp (ap->a_dvp)
90*53542Sheideman #define vpp (ap->a_vpp)
91*53542Sheideman #define cnp (ap->a_cnp)
9239292Smckusick {
9339292Smckusick 
9452320Sheideman 	*vpp = NULL;
9539292Smckusick 	return (ENOTDIR);
9639292Smckusick }
97*53542Sheideman #undef dvp
98*53542Sheideman #undef vpp
99*53542Sheideman #undef cnp
10039292Smckusick 
10139292Smckusick /*
10249273Skarels  * Open a special file: Don't allow open if fs is mounted -nodev,
10349273Skarels  * and don't allow opens of block devices that are currently mounted.
10449273Skarels  * Otherwise, call device driver open function.
10537486Smckusick  */
10637725Smckusick /* ARGSUSED */
107*53542Sheideman spec_open (ap)
108*53542Sheideman 	struct vop_open_args *ap;
109*53542Sheideman #define vp (ap->a_vp)
110*53542Sheideman #define mode (ap->a_mode)
111*53542Sheideman #define cred (ap->a_cred)
112*53542Sheideman #define p (ap->a_p)
11337486Smckusick {
114*53542Sheideman 	USES_VOP_LOCK;
115*53542Sheideman 	USES_VOP_UNLOCK;
11637486Smckusick 	dev_t dev = (dev_t)vp->v_rdev;
11737486Smckusick 	register int maj = major(dev);
11840375Smckusick 	int error;
11937486Smckusick 
12041400Smckusick 	if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
12139365Smckusick 		return (ENXIO);
12239365Smckusick 
12337486Smckusick 	switch (vp->v_type) {
12437486Smckusick 
12537486Smckusick 	case VCHR:
12637486Smckusick 		if ((u_int)maj >= nchrdev)
12737486Smckusick 			return (ENXIO);
12849944Smckusick 		VOP_UNLOCK(vp);
12949944Smckusick 		error = (*cdevsw[maj].d_open)(dev, mode, S_IFCHR, p);
13049944Smckusick 		VOP_LOCK(vp);
13149944Smckusick 		return (error);
13237486Smckusick 
13337486Smckusick 	case VBLK:
13437486Smckusick 		if ((u_int)maj >= nblkdev)
13537486Smckusick 			return (ENXIO);
13651457Sbostic 		if (error = ufs_mountedon(vp))
13740375Smckusick 			return (error);
13847540Skarels 		return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK, p));
13937486Smckusick 	}
14037486Smckusick 	return (0);
14137486Smckusick }
142*53542Sheideman #undef vp
143*53542Sheideman #undef mode
144*53542Sheideman #undef cred
145*53542Sheideman #undef p
14637486Smckusick 
14737486Smckusick /*
14837486Smckusick  * Vnode op for read
14937486Smckusick  */
15041961Smckusick /* ARGSUSED */
151*53542Sheideman spec_read (ap)
152*53542Sheideman 	struct vop_read_args *ap;
153*53542Sheideman #define vp (ap->a_vp)
154*53542Sheideman #define uio (ap->a_uio)
155*53542Sheideman #define ioflag (ap->a_ioflag)
156*53542Sheideman #define cred (ap->a_cred)
15737486Smckusick {
158*53542Sheideman 	USES_VOP_LOCK;
159*53542Sheideman 	USES_VOP_UNLOCK;
16048015Smckusick 	struct proc *p = uio->uio_procp;
16139614Smckusick 	struct buf *bp;
16252321Smckusick 	daddr_t bn, nextbn;
16339614Smckusick 	long bsize, bscale;
16439614Smckusick 	struct partinfo dpart;
16539614Smckusick 	register int n, on;
16639614Smckusick 	int error = 0;
16737486Smckusick 
16848015Smckusick #ifdef DIAGNOSTIC
16939588Smckusick 	if (uio->uio_rw != UIO_READ)
17039588Smckusick 		panic("spec_read mode");
17148015Smckusick 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
17248015Smckusick 		panic("spec_read proc");
17348015Smckusick #endif
17439588Smckusick 	if (uio->uio_resid == 0)
17539588Smckusick 		return (0);
17639588Smckusick 
17739588Smckusick 	switch (vp->v_type) {
17839588Smckusick 
17939588Smckusick 	case VCHR:
18039588Smckusick 		VOP_UNLOCK(vp);
18139588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_read)
18249121Skarels 			(vp->v_rdev, uio, ioflag);
18337725Smckusick 		VOP_LOCK(vp);
18439588Smckusick 		return (error);
18539588Smckusick 
18639588Smckusick 	case VBLK:
18739588Smckusick 		if (uio->uio_offset < 0)
18839588Smckusick 			return (EINVAL);
18939614Smckusick 		bsize = BLKDEV_IOSIZE;
19039614Smckusick 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
19147540Skarels 		    (caddr_t)&dpart, FREAD, p) == 0) {
19239614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
19339614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
19439614Smckusick 				bsize = dpart.part->p_frag *
19539614Smckusick 				    dpart.part->p_fsize;
19639614Smckusick 		}
19739614Smckusick 		bscale = bsize / DEV_BSIZE;
19839614Smckusick 		do {
19939614Smckusick 			bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
20039614Smckusick 			on = uio->uio_offset % bsize;
20139614Smckusick 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
20252321Smckusick 			if (vp->v_lastr + bscale == bn) {
20352321Smckusick 				nextbn = bn + bscale;
20452321Smckusick 				error = breadn(vp, bn, (int)bsize, &nextbn,
20552321Smckusick 					(int *)&bsize, 1, NOCRED, &bp);
20652321Smckusick 			} else
20739614Smckusick 				error = bread(vp, bn, (int)bsize, NOCRED, &bp);
20839614Smckusick 			vp->v_lastr = bn;
20939614Smckusick 			n = MIN(n, bsize - bp->b_resid);
21039614Smckusick 			if (error) {
21139614Smckusick 				brelse(bp);
21239614Smckusick 				return (error);
21339614Smckusick 			}
21439614Smckusick 			error = uiomove(bp->b_un.b_addr + on, n, uio);
21539614Smckusick 			if (n + on == bsize)
21639614Smckusick 				bp->b_flags |= B_AGE;
21739614Smckusick 			brelse(bp);
21839614Smckusick 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
21939614Smckusick 		return (error);
22039588Smckusick 
22139588Smckusick 	default:
22239588Smckusick 		panic("spec_read type");
22339588Smckusick 	}
22439588Smckusick 	/* NOTREACHED */
22537486Smckusick }
226*53542Sheideman #undef vp
227*53542Sheideman #undef uio
228*53542Sheideman #undef ioflag
229*53542Sheideman #undef cred
23037486Smckusick 
23137486Smckusick /*
23237486Smckusick  * Vnode op for write
23337486Smckusick  */
23441961Smckusick /* ARGSUSED */
235*53542Sheideman spec_write (ap)
236*53542Sheideman 	struct vop_write_args *ap;
237*53542Sheideman #define vp (ap->a_vp)
238*53542Sheideman #define uio (ap->a_uio)
239*53542Sheideman #define ioflag (ap->a_ioflag)
240*53542Sheideman #define cred (ap->a_cred)
24137486Smckusick {
242*53542Sheideman 	USES_VOP_LOCK;
243*53542Sheideman 	USES_VOP_UNLOCK;
24448015Smckusick 	struct proc *p = uio->uio_procp;
24539614Smckusick 	struct buf *bp;
24639614Smckusick 	daddr_t bn;
24739614Smckusick 	int bsize, blkmask;
24839614Smckusick 	struct partinfo dpart;
24945731Smckusick 	register int n, on;
25045731Smckusick 	int error = 0;
25137486Smckusick 
25248015Smckusick #ifdef DIAGNOSTIC
25339588Smckusick 	if (uio->uio_rw != UIO_WRITE)
25439588Smckusick 		panic("spec_write mode");
25548015Smckusick 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
25648015Smckusick 		panic("spec_write proc");
25748015Smckusick #endif
25839588Smckusick 
25939588Smckusick 	switch (vp->v_type) {
26039588Smckusick 
26139588Smckusick 	case VCHR:
26239588Smckusick 		VOP_UNLOCK(vp);
26339588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_write)
26449121Skarels 			(vp->v_rdev, uio, ioflag);
26537725Smckusick 		VOP_LOCK(vp);
26639588Smckusick 		return (error);
26739588Smckusick 
26839588Smckusick 	case VBLK:
26939588Smckusick 		if (uio->uio_resid == 0)
27039588Smckusick 			return (0);
27139588Smckusick 		if (uio->uio_offset < 0)
27239588Smckusick 			return (EINVAL);
27339614Smckusick 		bsize = BLKDEV_IOSIZE;
27439614Smckusick 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
27547540Skarels 		    (caddr_t)&dpart, FREAD, p) == 0) {
27639614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
27739614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
27839614Smckusick 				bsize = dpart.part->p_frag *
27939614Smckusick 				    dpart.part->p_fsize;
28039614Smckusick 		}
28139614Smckusick 		blkmask = (bsize / DEV_BSIZE) - 1;
28239614Smckusick 		do {
28339614Smckusick 			bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
28439614Smckusick 			on = uio->uio_offset % bsize;
28539614Smckusick 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
28639614Smckusick 			if (n == bsize)
28739614Smckusick 				bp = getblk(vp, bn, bsize);
28839614Smckusick 			else
28939614Smckusick 				error = bread(vp, bn, bsize, NOCRED, &bp);
29039614Smckusick 			n = MIN(n, bsize - bp->b_resid);
29139614Smckusick 			if (error) {
29239614Smckusick 				brelse(bp);
29339614Smckusick 				return (error);
29439614Smckusick 			}
29539614Smckusick 			error = uiomove(bp->b_un.b_addr + on, n, uio);
29639614Smckusick 			if (n + on == bsize) {
29739614Smckusick 				bp->b_flags |= B_AGE;
29839614Smckusick 				bawrite(bp);
29939614Smckusick 			} else
30039614Smckusick 				bdwrite(bp);
30139614Smckusick 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
30239614Smckusick 		return (error);
30339588Smckusick 
30439588Smckusick 	default:
30539588Smckusick 		panic("spec_write type");
30639588Smckusick 	}
30739588Smckusick 	/* NOTREACHED */
30837486Smckusick }
309*53542Sheideman #undef vp
310*53542Sheideman #undef uio
311*53542Sheideman #undef ioflag
312*53542Sheideman #undef cred
31337486Smckusick 
31437486Smckusick /*
31537486Smckusick  * Device ioctl operation.
31637486Smckusick  */
31737725Smckusick /* ARGSUSED */
318*53542Sheideman spec_ioctl (ap)
319*53542Sheideman 	struct vop_ioctl_args *ap;
320*53542Sheideman #define vp (ap->a_vp)
321*53542Sheideman #define com (ap->a_command)
322*53542Sheideman #define data (ap->a_data)
323*53542Sheideman #define fflag (ap->a_fflag)
324*53542Sheideman #define cred (ap->a_cred)
325*53542Sheideman #define p (ap->a_p)
32637486Smckusick {
32737725Smckusick 	dev_t dev = vp->v_rdev;
32837486Smckusick 
32937486Smckusick 	switch (vp->v_type) {
33037486Smckusick 
33137486Smckusick 	case VCHR:
33247540Skarels 		return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data,
33347540Skarels 		    fflag, p));
33437486Smckusick 
33537486Smckusick 	case VBLK:
33639666Smckusick 		if (com == 0 && (int)data == B_TAPE)
33739666Smckusick 			if (bdevsw[major(dev)].d_flags & B_TAPE)
33839666Smckusick 				return (0);
33939666Smckusick 			else
34039666Smckusick 				return (1);
34147540Skarels 		return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data,
34247540Skarels 		   fflag, p));
34337486Smckusick 
34437486Smckusick 	default:
34539446Smckusick 		panic("spec_ioctl");
34637486Smckusick 		/* NOTREACHED */
34737486Smckusick 	}
34837486Smckusick }
349*53542Sheideman #undef vp
350*53542Sheideman #undef com
351*53542Sheideman #undef data
352*53542Sheideman #undef fflag
353*53542Sheideman #undef cred
354*53542Sheideman #undef p
35537486Smckusick 
35637725Smckusick /* ARGSUSED */
357*53542Sheideman spec_select (ap)
358*53542Sheideman 	struct vop_select_args *ap;
359*53542Sheideman #define vp (ap->a_vp)
360*53542Sheideman #define which (ap->a_which)
361*53542Sheideman #define fflags (ap->a_fflags)
362*53542Sheideman #define cred (ap->a_cred)
363*53542Sheideman #define p (ap->a_p)
36437486Smckusick {
36537486Smckusick 	register dev_t dev;
36637486Smckusick 
36737486Smckusick 	switch (vp->v_type) {
36837486Smckusick 
36937486Smckusick 	default:
37037486Smckusick 		return (1);		/* XXX */
37137486Smckusick 
37237486Smckusick 	case VCHR:
37337725Smckusick 		dev = vp->v_rdev;
37447540Skarels 		return (*cdevsw[major(dev)].d_select)(dev, which, p);
37537486Smckusick 	}
37637486Smckusick }
377*53542Sheideman #undef vp
378*53542Sheideman #undef which
379*53542Sheideman #undef fflags
380*53542Sheideman #undef cred
381*53542Sheideman #undef p
38237486Smckusick 
38337486Smckusick /*
38437486Smckusick  * Just call the device strategy routine
38537486Smckusick  */
386*53542Sheideman spec_strategy (ap)
387*53542Sheideman 	struct vop_strategy_args *ap;
388*53542Sheideman #define bp (ap->a_bp)
38937486Smckusick {
39039666Smckusick 
39137486Smckusick 	(*bdevsw[major(bp->b_dev)].d_strategy)(bp);
39237486Smckusick 	return (0);
39337486Smckusick }
394*53542Sheideman #undef bp
39537486Smckusick 
39639432Smckusick /*
39739666Smckusick  * This is a noop, simply returning what one has been given.
39839666Smckusick  */
399*53542Sheideman spec_bmap (ap)
400*53542Sheideman 	struct vop_bmap_args *ap;
401*53542Sheideman #define vp (ap->a_vp)
402*53542Sheideman #define bn (ap->a_bn)
403*53542Sheideman #define vpp (ap->a_vpp)
404*53542Sheideman #define bnp (ap->a_bnp)
40539666Smckusick {
40639666Smckusick 
40739666Smckusick 	if (vpp != NULL)
40839666Smckusick 		*vpp = vp;
40939666Smckusick 	if (bnp != NULL)
41039666Smckusick 		*bnp = bn;
41139666Smckusick 	return (0);
41239666Smckusick }
413*53542Sheideman #undef vp
414*53542Sheideman #undef bn
415*53542Sheideman #undef vpp
416*53542Sheideman #undef bnp
41739666Smckusick 
41839666Smckusick /*
41939432Smckusick  * At the moment we do not do any locking.
42039432Smckusick  */
42139489Smckusick /* ARGSUSED */
422*53542Sheideman spec_lock (ap)
423*53542Sheideman 	struct vop_lock_args *ap;
424*53542Sheideman #define vp (ap->a_vp)
42537486Smckusick {
42637486Smckusick 
42737486Smckusick 	return (0);
42837486Smckusick }
429*53542Sheideman #undef vp
43037486Smckusick 
43139489Smckusick /* ARGSUSED */
432*53542Sheideman spec_unlock (ap)
433*53542Sheideman 	struct vop_unlock_args *ap;
434*53542Sheideman #define vp (ap->a_vp)
43537486Smckusick {
43637486Smckusick 
43737486Smckusick 	return (0);
43837486Smckusick }
439*53542Sheideman #undef vp
44037486Smckusick 
44137486Smckusick /*
44237486Smckusick  * Device close routine
44337486Smckusick  */
44437725Smckusick /* ARGSUSED */
445*53542Sheideman spec_close (ap)
446*53542Sheideman 	struct vop_close_args *ap;
447*53542Sheideman #define vp (ap->a_vp)
448*53542Sheideman #define flag (ap->a_fflag)
449*53542Sheideman #define cred (ap->a_cred)
450*53542Sheideman #define p (ap->a_p)
45137486Smckusick {
45237486Smckusick 	dev_t dev = vp->v_rdev;
45349273Skarels 	int (*devclose) __P((dev_t, int, int, struct proc *));
45440707Skarels 	int mode;
45537486Smckusick 
45637725Smckusick 	switch (vp->v_type) {
45737725Smckusick 
45837725Smckusick 	case VCHR:
45939485Smckusick 		/*
46039485Smckusick 		 * If the vnode is locked, then we are in the midst
46139485Smckusick 		 * of forcably closing the device, otherwise we only
46239485Smckusick 		 * close on last reference.
46339485Smckusick 		 */
46439630Smckusick 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
46537725Smckusick 			return (0);
46649273Skarels 		devclose = cdevsw[major(dev)].d_close;
46739432Smckusick 		mode = S_IFCHR;
46837725Smckusick 		break;
46937725Smckusick 
47037725Smckusick 	case VBLK:
47137725Smckusick 		/*
47237725Smckusick 		 * On last close of a block device (that isn't mounted)
47337725Smckusick 		 * we must invalidate any in core blocks, so that
47437725Smckusick 		 * we can, for instance, change floppy disks.
47537725Smckusick 		 */
47639666Smckusick 		vflushbuf(vp, 0);
47739666Smckusick 		if (vinvalbuf(vp, 1))
47838613Smckusick 			return (0);
47937725Smckusick 		/*
48039485Smckusick 		 * We do not want to really close the device if it
48139485Smckusick 		 * is still in use unless we are trying to close it
48239485Smckusick 		 * forcibly. Since every use (buffer, vnode, swap, cmap)
48339630Smckusick 		 * holds a reference to the vnode, and because we mark
48439630Smckusick 		 * any other vnodes that alias this device, when the
48539630Smckusick 		 * sum of the reference counts on all the aliased
48639630Smckusick 		 * vnodes descends to one, we are on last close.
48737725Smckusick 		 */
48839630Smckusick 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
48937725Smckusick 			return (0);
49049273Skarels 		devclose = bdevsw[major(dev)].d_close;
49139432Smckusick 		mode = S_IFBLK;
49237725Smckusick 		break;
49337725Smckusick 
49437725Smckusick 	default:
49539446Smckusick 		panic("spec_close: not special");
49637725Smckusick 	}
49737725Smckusick 
49849273Skarels 	return ((*devclose)(dev, flag, mode, p));
49937486Smckusick }
500*53542Sheideman #undef vp
501*53542Sheideman #undef flag
502*53542Sheideman #undef cred
503*53542Sheideman #undef p
50437486Smckusick 
50537486Smckusick /*
50639666Smckusick  * Print out the contents of a special device vnode.
50739666Smckusick  */
508*53542Sheideman spec_print (ap)
509*53542Sheideman 	struct vop_print_args *ap;
510*53542Sheideman #define vp (ap->a_vp)
51139666Smckusick {
51239666Smckusick 
51339666Smckusick 	printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev),
51439666Smckusick 		minor(vp->v_rdev));
51539666Smckusick }
516*53542Sheideman #undef vp
51739666Smckusick 
51839666Smckusick /*
51946196Smckusick  * Special device advisory byte-level locks.
52046196Smckusick  */
52148015Smckusick /* ARGSUSED */
522*53542Sheideman spec_advlock (ap)
523*53542Sheideman 	struct vop_advlock_args *ap;
524*53542Sheideman #define vp (ap->a_vp)
525*53542Sheideman #define id (ap->a_id)
526*53542Sheideman #define op (ap->a_op)
527*53542Sheideman #define fl (ap->a_fl)
528*53542Sheideman #define flags (ap->a_flags)
52946196Smckusick {
53046196Smckusick 
53146196Smckusick 	return (EOPNOTSUPP);
53246196Smckusick }
533*53542Sheideman #undef vp
534*53542Sheideman #undef id
535*53542Sheideman #undef op
536*53542Sheideman #undef fl
537*53542Sheideman #undef flags
53846196Smckusick 
53946196Smckusick /*
54039507Smckusick  * Special device failed operation
54137486Smckusick  */
54239507Smckusick spec_ebadf()
54339507Smckusick {
54439507Smckusick 
54539507Smckusick 	return (EBADF);
54639507Smckusick }
54739507Smckusick 
54839507Smckusick /*
54939507Smckusick  * Special device bad operation
55039507Smckusick  */
55139446Smckusick spec_badop()
55237486Smckusick {
55337486Smckusick 
55439446Smckusick 	panic("spec_badop called");
55539292Smckusick 	/* NOTREACHED */
55637486Smckusick }
557