xref: /csrg-svn/sys/miscfs/specfs/spec_vnops.c (revision 57798)
137486Smckusick /*
237486Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337486Smckusick  * All rights reserved.
437486Smckusick  *
544443Sbostic  * %sccs.include.redist.c%
637486Smckusick  *
7*57798Smckusick  *	@(#)spec_vnops.c	7.52 (Berkeley) 02/02/93
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/stat.h>
2051457Sbostic #include <sys/errno.h>
2151457Sbostic #include <sys/ioctl.h>
2251457Sbostic #include <sys/file.h>
2351457Sbostic #include <sys/disklabel.h>
2455028Smckusick #include <miscfs/specfs/specdev.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 
3553542Sheideman int (**spec_vnodeop_p)();
3653542Sheideman struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
3753542Sheideman 	{ &vop_default_desc, vn_default_error },
3853542Sheideman 	{ &vop_lookup_desc, spec_lookup },		/* lookup */
3953542Sheideman 	{ &vop_create_desc, spec_create },		/* create */
4053542Sheideman 	{ &vop_mknod_desc, spec_mknod },		/* mknod */
4153542Sheideman 	{ &vop_open_desc, spec_open },		/* open */
4253542Sheideman 	{ &vop_close_desc, spec_close },		/* close */
4353542Sheideman 	{ &vop_access_desc, spec_access },		/* access */
4453542Sheideman 	{ &vop_getattr_desc, spec_getattr },		/* getattr */
4553542Sheideman 	{ &vop_setattr_desc, spec_setattr },		/* setattr */
4653542Sheideman 	{ &vop_read_desc, spec_read },		/* read */
4753542Sheideman 	{ &vop_write_desc, spec_write },		/* write */
4853542Sheideman 	{ &vop_ioctl_desc, spec_ioctl },		/* ioctl */
4953542Sheideman 	{ &vop_select_desc, spec_select },		/* select */
5053542Sheideman 	{ &vop_mmap_desc, spec_mmap },		/* mmap */
5153542Sheideman 	{ &vop_fsync_desc, spec_fsync },		/* fsync */
5253542Sheideman 	{ &vop_seek_desc, spec_seek },		/* seek */
5353542Sheideman 	{ &vop_remove_desc, spec_remove },		/* remove */
5453542Sheideman 	{ &vop_link_desc, spec_link },		/* link */
5553542Sheideman 	{ &vop_rename_desc, spec_rename },		/* rename */
5653542Sheideman 	{ &vop_mkdir_desc, spec_mkdir },		/* mkdir */
5753542Sheideman 	{ &vop_rmdir_desc, spec_rmdir },		/* rmdir */
5853542Sheideman 	{ &vop_symlink_desc, spec_symlink },		/* symlink */
5953542Sheideman 	{ &vop_readdir_desc, spec_readdir },		/* readdir */
6053542Sheideman 	{ &vop_readlink_desc, spec_readlink },		/* readlink */
6153542Sheideman 	{ &vop_abortop_desc, spec_abortop },		/* abortop */
6253542Sheideman 	{ &vop_inactive_desc, spec_inactive },		/* inactive */
6353542Sheideman 	{ &vop_reclaim_desc, spec_reclaim },		/* reclaim */
6453542Sheideman 	{ &vop_lock_desc, spec_lock },		/* lock */
6553542Sheideman 	{ &vop_unlock_desc, spec_unlock },		/* unlock */
6653542Sheideman 	{ &vop_bmap_desc, spec_bmap },		/* bmap */
6753542Sheideman 	{ &vop_strategy_desc, spec_strategy },		/* strategy */
6853542Sheideman 	{ &vop_print_desc, spec_print },		/* print */
6953542Sheideman 	{ &vop_islocked_desc, spec_islocked },		/* islocked */
7053542Sheideman 	{ &vop_advlock_desc, spec_advlock },		/* advlock */
7153542Sheideman 	{ &vop_blkatoff_desc, spec_blkatoff },		/* blkatoff */
7253542Sheideman 	{ &vop_valloc_desc, spec_valloc },		/* valloc */
7353542Sheideman 	{ &vop_vfree_desc, spec_vfree },		/* vfree */
7453542Sheideman 	{ &vop_truncate_desc, spec_truncate },		/* truncate */
7553542Sheideman 	{ &vop_update_desc, spec_update },		/* update */
7653542Sheideman 	{ &vop_bwrite_desc, spec_bwrite },		/* bwrite */
7753542Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
7837486Smckusick };
7953542Sheideman struct vnodeopv_desc spec_vnodeop_opv_desc =
8053542Sheideman 	{ &spec_vnodeop_p, spec_vnodeop_entries };
8137486Smckusick 
8237486Smckusick /*
8339292Smckusick  * Trivial lookup routine that always fails.
8439292Smckusick  */
8552320Sheideman int
8654439Smckusick spec_lookup(ap)
8754439Smckusick 	struct vop_lookup_args /* {
8854439Smckusick 		struct vnode *a_dvp;
8954439Smckusick 		struct vnode **a_vpp;
9054439Smckusick 		struct componentname *a_cnp;
9154439Smckusick 	} */ *ap;
9239292Smckusick {
9339292Smckusick 
9453597Sheideman 	*ap->a_vpp = NULL;
9539292Smckusick 	return (ENOTDIR);
9639292Smckusick }
9739292Smckusick 
9839292Smckusick /*
9949273Skarels  * Open a special file: Don't allow open if fs is mounted -nodev,
10049273Skarels  * and don't allow opens of block devices that are currently mounted.
10149273Skarels  * Otherwise, call device driver open function.
10237486Smckusick  */
10337725Smckusick /* ARGSUSED */
10454439Smckusick spec_open(ap)
10554439Smckusick 	struct vop_open_args /* {
10654439Smckusick 		struct vnode *a_vp;
10754439Smckusick 		int  a_mode;
10854439Smckusick 		struct ucred *a_cred;
10954439Smckusick 		struct proc *a_p;
11054439Smckusick 	} */ *ap;
11137486Smckusick {
11253863Sheideman 	register struct vnode *vp = ap->a_vp;
11353863Sheideman 	dev_t dev = (dev_t)vp->v_rdev;
11437486Smckusick 	register int maj = major(dev);
11540375Smckusick 	int error;
11637486Smckusick 
11753863Sheideman 	if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
11839365Smckusick 		return (ENXIO);
11939365Smckusick 
12053863Sheideman 	switch (vp->v_type) {
12137486Smckusick 
12237486Smckusick 	case VCHR:
12337486Smckusick 		if ((u_int)maj >= nchrdev)
12437486Smckusick 			return (ENXIO);
12553863Sheideman 		VOP_UNLOCK(vp);
12653597Sheideman 		error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p);
12753863Sheideman 		VOP_LOCK(vp);
12849944Smckusick 		return (error);
12937486Smckusick 
13037486Smckusick 	case VBLK:
13137486Smckusick 		if ((u_int)maj >= nblkdev)
13237486Smckusick 			return (ENXIO);
13353863Sheideman 		if (error = ufs_mountedon(vp))
13440375Smckusick 			return (error);
13553597Sheideman 		return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p));
13637486Smckusick 	}
13737486Smckusick 	return (0);
13837486Smckusick }
13937486Smckusick 
14037486Smckusick /*
14137486Smckusick  * Vnode op for read
14237486Smckusick  */
14341961Smckusick /* ARGSUSED */
14454439Smckusick spec_read(ap)
14554439Smckusick 	struct vop_read_args /* {
14654439Smckusick 		struct vnode *a_vp;
14754439Smckusick 		struct uio *a_uio;
14854439Smckusick 		int  a_ioflag;
14954439Smckusick 		struct ucred *a_cred;
15054439Smckusick 	} */ *ap;
15137486Smckusick {
15253863Sheideman 	register struct vnode *vp = ap->a_vp;
15353863Sheideman 	register struct uio *uio = ap->a_uio;
15453863Sheideman  	struct proc *p = uio->uio_procp;
15539614Smckusick 	struct buf *bp;
15652321Smckusick 	daddr_t bn, nextbn;
15739614Smckusick 	long bsize, bscale;
15839614Smckusick 	struct partinfo dpart;
15939614Smckusick 	register int n, on;
16039614Smckusick 	int error = 0;
16137486Smckusick 
16248015Smckusick #ifdef DIAGNOSTIC
16353863Sheideman 	if (uio->uio_rw != UIO_READ)
16439588Smckusick 		panic("spec_read mode");
16553863Sheideman 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
16648015Smckusick 		panic("spec_read proc");
16748015Smckusick #endif
16853863Sheideman 	if (uio->uio_resid == 0)
16939588Smckusick 		return (0);
17039588Smckusick 
17153863Sheideman 	switch (vp->v_type) {
17239588Smckusick 
17339588Smckusick 	case VCHR:
17453863Sheideman 		VOP_UNLOCK(vp);
17553863Sheideman 		error = (*cdevsw[major(vp->v_rdev)].d_read)
17653863Sheideman 			(vp->v_rdev, uio, ap->a_ioflag);
17753863Sheideman 		VOP_LOCK(vp);
17839588Smckusick 		return (error);
17939588Smckusick 
18039588Smckusick 	case VBLK:
18153863Sheideman 		if (uio->uio_offset < 0)
18239588Smckusick 			return (EINVAL);
18339614Smckusick 		bsize = BLKDEV_IOSIZE;
18453863Sheideman 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
18547540Skarels 		    (caddr_t)&dpart, FREAD, p) == 0) {
18639614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
18739614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
18839614Smckusick 				bsize = dpart.part->p_frag *
18939614Smckusick 				    dpart.part->p_fsize;
19039614Smckusick 		}
19139614Smckusick 		bscale = bsize / DEV_BSIZE;
19239614Smckusick 		do {
19353863Sheideman 			bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
19453863Sheideman 			on = uio->uio_offset % bsize;
19555059Spendry 			n = min((unsigned)(bsize - on), uio->uio_resid);
19653863Sheideman 			if (vp->v_lastr + bscale == bn) {
19752321Smckusick 				nextbn = bn + bscale;
19853863Sheideman 				error = breadn(vp, bn, (int)bsize, &nextbn,
19952321Smckusick 					(int *)&bsize, 1, NOCRED, &bp);
20052321Smckusick 			} else
20153863Sheideman 				error = bread(vp, bn, (int)bsize, NOCRED, &bp);
20253863Sheideman 			vp->v_lastr = bn;
20355059Spendry 			n = min(n, bsize - bp->b_resid);
20439614Smckusick 			if (error) {
20539614Smckusick 				brelse(bp);
20639614Smckusick 				return (error);
20739614Smckusick 			}
20853863Sheideman 			error = uiomove(bp->b_un.b_addr + on, n, uio);
20939614Smckusick 			if (n + on == bsize)
21039614Smckusick 				bp->b_flags |= B_AGE;
21139614Smckusick 			brelse(bp);
21253863Sheideman 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
21339614Smckusick 		return (error);
21439588Smckusick 
21539588Smckusick 	default:
21639588Smckusick 		panic("spec_read type");
21739588Smckusick 	}
21839588Smckusick 	/* NOTREACHED */
21937486Smckusick }
22037486Smckusick 
22137486Smckusick /*
22237486Smckusick  * Vnode op for write
22337486Smckusick  */
22441961Smckusick /* ARGSUSED */
22554439Smckusick spec_write(ap)
22654439Smckusick 	struct vop_write_args /* {
22754439Smckusick 		struct vnode *a_vp;
22854439Smckusick 		struct uio *a_uio;
22954439Smckusick 		int  a_ioflag;
23054439Smckusick 		struct ucred *a_cred;
23154439Smckusick 	} */ *ap;
23237486Smckusick {
23353863Sheideman 	register struct vnode *vp = ap->a_vp;
23453863Sheideman 	register struct uio *uio = ap->a_uio;
23553863Sheideman 	struct proc *p = uio->uio_procp;
23639614Smckusick 	struct buf *bp;
23739614Smckusick 	daddr_t bn;
23839614Smckusick 	int bsize, blkmask;
23939614Smckusick 	struct partinfo dpart;
24045731Smckusick 	register int n, on;
24145731Smckusick 	int error = 0;
24237486Smckusick 
24348015Smckusick #ifdef DIAGNOSTIC
24453863Sheideman 	if (uio->uio_rw != UIO_WRITE)
24539588Smckusick 		panic("spec_write mode");
24653863Sheideman 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
24748015Smckusick 		panic("spec_write proc");
24848015Smckusick #endif
24939588Smckusick 
25053863Sheideman 	switch (vp->v_type) {
25139588Smckusick 
25239588Smckusick 	case VCHR:
25353863Sheideman 		VOP_UNLOCK(vp);
25453863Sheideman 		error = (*cdevsw[major(vp->v_rdev)].d_write)
25553863Sheideman 			(vp->v_rdev, uio, ap->a_ioflag);
25653863Sheideman 		VOP_LOCK(vp);
25739588Smckusick 		return (error);
25839588Smckusick 
25939588Smckusick 	case VBLK:
26053863Sheideman 		if (uio->uio_resid == 0)
26139588Smckusick 			return (0);
26253863Sheideman 		if (uio->uio_offset < 0)
26339588Smckusick 			return (EINVAL);
26439614Smckusick 		bsize = BLKDEV_IOSIZE;
26553863Sheideman 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
26647540Skarels 		    (caddr_t)&dpart, FREAD, p) == 0) {
26739614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
26839614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
26939614Smckusick 				bsize = dpart.part->p_frag *
27039614Smckusick 				    dpart.part->p_fsize;
27139614Smckusick 		}
27239614Smckusick 		blkmask = (bsize / DEV_BSIZE) - 1;
27339614Smckusick 		do {
27453863Sheideman 			bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
27553863Sheideman 			on = uio->uio_offset % bsize;
27655059Spendry 			n = min((unsigned)(bsize - on), uio->uio_resid);
27739614Smckusick 			if (n == bsize)
278*57798Smckusick 				bp = getblk(vp, bn, bsize, 0, 0);
27939614Smckusick 			else
28053863Sheideman 				error = bread(vp, bn, bsize, NOCRED, &bp);
28155059Spendry 			n = min(n, bsize - bp->b_resid);
28239614Smckusick 			if (error) {
28339614Smckusick 				brelse(bp);
28439614Smckusick 				return (error);
28539614Smckusick 			}
28653863Sheideman 			error = uiomove(bp->b_un.b_addr + on, n, uio);
28739614Smckusick 			if (n + on == bsize) {
28839614Smckusick 				bp->b_flags |= B_AGE;
28939614Smckusick 				bawrite(bp);
29039614Smckusick 			} else
29139614Smckusick 				bdwrite(bp);
29253863Sheideman 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
29339614Smckusick 		return (error);
29439588Smckusick 
29539588Smckusick 	default:
29639588Smckusick 		panic("spec_write type");
29739588Smckusick 	}
29839588Smckusick 	/* NOTREACHED */
29937486Smckusick }
30037486Smckusick 
30137486Smckusick /*
30237486Smckusick  * Device ioctl operation.
30337486Smckusick  */
30437725Smckusick /* ARGSUSED */
30554439Smckusick spec_ioctl(ap)
30654439Smckusick 	struct vop_ioctl_args /* {
30754439Smckusick 		struct vnode *a_vp;
30854439Smckusick 		int  a_command;
30954439Smckusick 		caddr_t  a_data;
31054439Smckusick 		int  a_fflag;
31154439Smckusick 		struct ucred *a_cred;
31254439Smckusick 		struct proc *a_p;
31354439Smckusick 	} */ *ap;
31437486Smckusick {
31553597Sheideman 	dev_t dev = ap->a_vp->v_rdev;
31637486Smckusick 
31753597Sheideman 	switch (ap->a_vp->v_type) {
31837486Smckusick 
31937486Smckusick 	case VCHR:
32053597Sheideman 		return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
32153597Sheideman 		    ap->a_fflag, ap->a_p));
32237486Smckusick 
32337486Smckusick 	case VBLK:
32453597Sheideman 		if (ap->a_command == 0 && (int)ap->a_data == B_TAPE)
32539666Smckusick 			if (bdevsw[major(dev)].d_flags & B_TAPE)
32639666Smckusick 				return (0);
32739666Smckusick 			else
32839666Smckusick 				return (1);
32953597Sheideman 		return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
33053597Sheideman 		   ap->a_fflag, ap->a_p));
33137486Smckusick 
33237486Smckusick 	default:
33339446Smckusick 		panic("spec_ioctl");
33437486Smckusick 		/* NOTREACHED */
33537486Smckusick 	}
33637486Smckusick }
33737486Smckusick 
33837725Smckusick /* ARGSUSED */
33954439Smckusick spec_select(ap)
34054439Smckusick 	struct vop_select_args /* {
34154439Smckusick 		struct vnode *a_vp;
34254439Smckusick 		int  a_which;
34354439Smckusick 		int  a_fflags;
34454439Smckusick 		struct ucred *a_cred;
34554439Smckusick 		struct proc *a_p;
34654439Smckusick 	} */ *ap;
34737486Smckusick {
34837486Smckusick 	register dev_t dev;
34937486Smckusick 
35053597Sheideman 	switch (ap->a_vp->v_type) {
35137486Smckusick 
35237486Smckusick 	default:
35337486Smckusick 		return (1);		/* XXX */
35437486Smckusick 
35537486Smckusick 	case VCHR:
35653597Sheideman 		dev = ap->a_vp->v_rdev;
35753597Sheideman 		return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p);
35837486Smckusick 	}
35937486Smckusick }
36054439Smckusick /*
36154439Smckusick  * Synch buffers associated with a block device
36254439Smckusick  */
36354439Smckusick /* ARGSUSED */
36454439Smckusick int
36554439Smckusick spec_fsync(ap)
36654439Smckusick 	struct vop_fsync_args /* {
36754439Smckusick 		struct vnode *a_vp;
36854439Smckusick 		struct ucred *a_cred;
36954439Smckusick 		int  a_waitfor;
37054439Smckusick 		struct proc *a_p;
37154439Smckusick 	} */ *ap;
37254439Smckusick {
37354439Smckusick 	register struct vnode *vp = ap->a_vp;
37454439Smckusick 	register struct buf *bp;
37554439Smckusick 	struct buf *nbp;
37656548Smckusick 	int s;
37737486Smckusick 
37854439Smckusick 	if (vp->v_type == VCHR)
37954439Smckusick 		return (0);
38054439Smckusick 	/*
38154439Smckusick 	 * Flush all dirty buffers associated with a block device.
38254439Smckusick 	 */
38354439Smckusick loop:
38454439Smckusick 	s = splbio();
38556471Smckusick 	for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) {
38656471Smckusick 		nbp = bp->b_vnbufs.qe_next;
38754439Smckusick 		if ((bp->b_flags & B_BUSY))
38854439Smckusick 			continue;
38954439Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
39054439Smckusick 			panic("spec_fsync: not dirty");
39154439Smckusick 		bremfree(bp);
39254439Smckusick 		bp->b_flags |= B_BUSY;
39354439Smckusick 		splx(s);
39456548Smckusick 		bawrite(bp);
39554439Smckusick 		goto loop;
39654439Smckusick 	}
39754439Smckusick 	if (ap->a_waitfor == MNT_WAIT) {
39854439Smckusick 		while (vp->v_numoutput) {
39954439Smckusick 			vp->v_flag |= VBWAIT;
40054439Smckusick 			sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
40154439Smckusick 		}
40254439Smckusick #ifdef DIAGNOSTIC
40356471Smckusick 		if (vp->v_dirtyblkhd.le_next) {
40454439Smckusick 			vprint("spec_fsync: dirty", vp);
40554439Smckusick 			goto loop;
40654439Smckusick 		}
40754439Smckusick #endif
40854439Smckusick 	}
40954439Smckusick 	splx(s);
41056548Smckusick 	return (0);
41154439Smckusick }
41254439Smckusick 
41337486Smckusick /*
41437486Smckusick  * Just call the device strategy routine
41537486Smckusick  */
41654439Smckusick spec_strategy(ap)
41754439Smckusick 	struct vop_strategy_args /* {
41854439Smckusick 		struct buf *a_bp;
41954439Smckusick 	} */ *ap;
42037486Smckusick {
42139666Smckusick 
42253597Sheideman 	(*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp);
42337486Smckusick 	return (0);
42437486Smckusick }
42537486Smckusick 
42639432Smckusick /*
42739666Smckusick  * This is a noop, simply returning what one has been given.
42839666Smckusick  */
42954439Smckusick spec_bmap(ap)
43054439Smckusick 	struct vop_bmap_args /* {
43154439Smckusick 		struct vnode *a_vp;
43254439Smckusick 		daddr_t  a_bn;
43354439Smckusick 		struct vnode **a_vpp;
43454439Smckusick 		daddr_t *a_bnp;
43554439Smckusick 	} */ *ap;
43639666Smckusick {
43739666Smckusick 
43853597Sheideman 	if (ap->a_vpp != NULL)
43953597Sheideman 		*ap->a_vpp = ap->a_vp;
44053597Sheideman 	if (ap->a_bnp != NULL)
44153597Sheideman 		*ap->a_bnp = ap->a_bn;
44239666Smckusick 	return (0);
44339666Smckusick }
44439666Smckusick 
44539666Smckusick /*
44639432Smckusick  * At the moment we do not do any locking.
44739432Smckusick  */
44839489Smckusick /* ARGSUSED */
44954439Smckusick spec_lock(ap)
45054439Smckusick 	struct vop_lock_args /* {
45154439Smckusick 		struct vnode *a_vp;
45254439Smckusick 	} */ *ap;
45337486Smckusick {
45437486Smckusick 
45537486Smckusick 	return (0);
45637486Smckusick }
45737486Smckusick 
45839489Smckusick /* ARGSUSED */
45954439Smckusick spec_unlock(ap)
46054439Smckusick 	struct vop_unlock_args /* {
46154439Smckusick 		struct vnode *a_vp;
46254439Smckusick 	} */ *ap;
46337486Smckusick {
46437486Smckusick 
46537486Smckusick 	return (0);
46637486Smckusick }
46737486Smckusick 
46837486Smckusick /*
46937486Smckusick  * Device close routine
47037486Smckusick  */
47137725Smckusick /* ARGSUSED */
47254439Smckusick spec_close(ap)
47354439Smckusick 	struct vop_close_args /* {
47454439Smckusick 		struct vnode *a_vp;
47554439Smckusick 		int  a_fflag;
47654439Smckusick 		struct ucred *a_cred;
47754439Smckusick 		struct proc *a_p;
47854439Smckusick 	} */ *ap;
47937486Smckusick {
48053863Sheideman 	register struct vnode *vp = ap->a_vp;
48153863Sheideman 	dev_t dev = vp->v_rdev;
48249273Skarels 	int (*devclose) __P((dev_t, int, int, struct proc *));
48354439Smckusick 	int mode, error;
48437486Smckusick 
48553863Sheideman 	switch (vp->v_type) {
48637725Smckusick 
48737725Smckusick 	case VCHR:
48839485Smckusick 		/*
48939485Smckusick 		 * If the vnode is locked, then we are in the midst
49039485Smckusick 		 * of forcably closing the device, otherwise we only
49139485Smckusick 		 * close on last reference.
49239485Smckusick 		 */
49353863Sheideman 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
49437725Smckusick 			return (0);
49549273Skarels 		devclose = cdevsw[major(dev)].d_close;
49639432Smckusick 		mode = S_IFCHR;
49737725Smckusick 		break;
49837725Smckusick 
49937725Smckusick 	case VBLK:
50037725Smckusick 		/*
50137725Smckusick 		 * On last close of a block device (that isn't mounted)
50237725Smckusick 		 * we must invalidate any in core blocks, so that
50337725Smckusick 		 * we can, for instance, change floppy disks.
50437725Smckusick 		 */
505*57798Smckusick 		if (error = vinvalbuf(vp, 1, ap->a_cred, ap->a_p, 0, 0))
50654439Smckusick 			return (error);
50737725Smckusick 		/*
50839485Smckusick 		 * We do not want to really close the device if it
50939485Smckusick 		 * is still in use unless we are trying to close it
51039485Smckusick 		 * forcibly. Since every use (buffer, vnode, swap, cmap)
51139630Smckusick 		 * holds a reference to the vnode, and because we mark
51239630Smckusick 		 * any other vnodes that alias this device, when the
51339630Smckusick 		 * sum of the reference counts on all the aliased
51439630Smckusick 		 * vnodes descends to one, we are on last close.
51537725Smckusick 		 */
51653863Sheideman 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
51737725Smckusick 			return (0);
51849273Skarels 		devclose = bdevsw[major(dev)].d_close;
51939432Smckusick 		mode = S_IFBLK;
52037725Smckusick 		break;
52137725Smckusick 
52237725Smckusick 	default:
52339446Smckusick 		panic("spec_close: not special");
52437725Smckusick 	}
52537725Smckusick 
52653597Sheideman 	return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
52737486Smckusick }
52837486Smckusick 
52937486Smckusick /*
53039666Smckusick  * Print out the contents of a special device vnode.
53139666Smckusick  */
53254439Smckusick spec_print(ap)
53354439Smckusick 	struct vop_print_args /* {
53454439Smckusick 		struct vnode *a_vp;
53554439Smckusick 	} */ *ap;
53639666Smckusick {
53739666Smckusick 
53853597Sheideman 	printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
53953597Sheideman 		minor(ap->a_vp->v_rdev));
54039666Smckusick }
54139666Smckusick 
54239666Smckusick /*
54346196Smckusick  * Special device advisory byte-level locks.
54446196Smckusick  */
54548015Smckusick /* ARGSUSED */
54654439Smckusick spec_advlock(ap)
54754439Smckusick 	struct vop_advlock_args /* {
54854439Smckusick 		struct vnode *a_vp;
54954439Smckusick 		caddr_t  a_id;
55054439Smckusick 		int  a_op;
55154439Smckusick 		struct flock *a_fl;
55254439Smckusick 		int  a_flags;
55354439Smckusick 	} */ *ap;
55446196Smckusick {
55546196Smckusick 
55646196Smckusick 	return (EOPNOTSUPP);
55746196Smckusick }
55846196Smckusick 
55946196Smckusick /*
56039507Smckusick  * Special device failed operation
56137486Smckusick  */
56239507Smckusick spec_ebadf()
56339507Smckusick {
56439507Smckusick 
56539507Smckusick 	return (EBADF);
56639507Smckusick }
56739507Smckusick 
56839507Smckusick /*
56939507Smckusick  * Special device bad operation
57039507Smckusick  */
57139446Smckusick spec_badop()
57237486Smckusick {
57337486Smckusick 
57439446Smckusick 	panic("spec_badop called");
57539292Smckusick 	/* NOTREACHED */
57637486Smckusick }
577