xref: /csrg-svn/sys/miscfs/specfs/spec_vnops.c (revision 68411)
137486Smckusick /*
268234Spendry  * Copyright (c) 1989, 1993, 1995
363247Sbostic  *	The Regents of the University of California.  All rights reserved.
437486Smckusick  *
544443Sbostic  * %sccs.include.redist.c%
637486Smckusick  *
7*68411Smckusick  *	@(#)spec_vnops.c	8.12 (Berkeley) 02/22/95
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 */
4160391Smckusick 	{ &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 */
4660391Smckusick 	{ &vop_read_desc, spec_read },			/* read */
4753542Sheideman 	{ &vop_write_desc, spec_write },		/* write */
4867650Smckusick 	{ &vop_lease_desc, spec_lease_check },		/* lease */
4953542Sheideman 	{ &vop_ioctl_desc, spec_ioctl },		/* ioctl */
5053542Sheideman 	{ &vop_select_desc, spec_select },		/* select */
51*68411Smckusick 	{ &vop_revoke_desc, spec_revoke },		/* revoke */
5260391Smckusick 	{ &vop_mmap_desc, spec_mmap },			/* mmap */
5353542Sheideman 	{ &vop_fsync_desc, spec_fsync },		/* fsync */
5460391Smckusick 	{ &vop_seek_desc, spec_seek },			/* seek */
5553542Sheideman 	{ &vop_remove_desc, spec_remove },		/* remove */
5660391Smckusick 	{ &vop_link_desc, spec_link },			/* link */
5753542Sheideman 	{ &vop_rename_desc, spec_rename },		/* rename */
5853542Sheideman 	{ &vop_mkdir_desc, spec_mkdir },		/* mkdir */
5953542Sheideman 	{ &vop_rmdir_desc, spec_rmdir },		/* rmdir */
6053542Sheideman 	{ &vop_symlink_desc, spec_symlink },		/* symlink */
6153542Sheideman 	{ &vop_readdir_desc, spec_readdir },		/* readdir */
6253542Sheideman 	{ &vop_readlink_desc, spec_readlink },		/* readlink */
6353542Sheideman 	{ &vop_abortop_desc, spec_abortop },		/* abortop */
6453542Sheideman 	{ &vop_inactive_desc, spec_inactive },		/* inactive */
6553542Sheideman 	{ &vop_reclaim_desc, spec_reclaim },		/* reclaim */
6660391Smckusick 	{ &vop_lock_desc, spec_lock },			/* lock */
6753542Sheideman 	{ &vop_unlock_desc, spec_unlock },		/* unlock */
6860391Smckusick 	{ &vop_bmap_desc, spec_bmap },			/* bmap */
6953542Sheideman 	{ &vop_strategy_desc, spec_strategy },		/* strategy */
7053542Sheideman 	{ &vop_print_desc, spec_print },		/* print */
7153542Sheideman 	{ &vop_islocked_desc, spec_islocked },		/* islocked */
7260391Smckusick 	{ &vop_pathconf_desc, spec_pathconf },		/* pathconf */
7353542Sheideman 	{ &vop_advlock_desc, spec_advlock },		/* advlock */
7453542Sheideman 	{ &vop_blkatoff_desc, spec_blkatoff },		/* blkatoff */
7553542Sheideman 	{ &vop_valloc_desc, spec_valloc },		/* valloc */
7653542Sheideman 	{ &vop_vfree_desc, spec_vfree },		/* vfree */
7753542Sheideman 	{ &vop_truncate_desc, spec_truncate },		/* truncate */
7853542Sheideman 	{ &vop_update_desc, spec_update },		/* update */
7953542Sheideman 	{ &vop_bwrite_desc, spec_bwrite },		/* bwrite */
8053542Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
8137486Smckusick };
8253542Sheideman struct vnodeopv_desc spec_vnodeop_opv_desc =
8353542Sheideman 	{ &spec_vnodeop_p, spec_vnodeop_entries };
8437486Smckusick 
8537486Smckusick /*
8639292Smckusick  * Trivial lookup routine that always fails.
8739292Smckusick  */
8852320Sheideman int
8954439Smckusick spec_lookup(ap)
9054439Smckusick 	struct vop_lookup_args /* {
9154439Smckusick 		struct vnode *a_dvp;
9254439Smckusick 		struct vnode **a_vpp;
9354439Smckusick 		struct componentname *a_cnp;
9454439Smckusick 	} */ *ap;
9539292Smckusick {
9639292Smckusick 
9753597Sheideman 	*ap->a_vpp = NULL;
9839292Smckusick 	return (ENOTDIR);
9939292Smckusick }
10039292Smckusick 
10139292Smckusick /*
10259486Smckusick  * Open a special file.
10337486Smckusick  */
10437725Smckusick /* ARGSUSED */
10554439Smckusick spec_open(ap)
10654439Smckusick 	struct vop_open_args /* {
10754439Smckusick 		struct vnode *a_vp;
10854439Smckusick 		int  a_mode;
10954439Smckusick 		struct ucred *a_cred;
11054439Smckusick 		struct proc *a_p;
11154439Smckusick 	} */ *ap;
11237486Smckusick {
11359486Smckusick 	struct vnode *bvp, *vp = ap->a_vp;
11459486Smckusick 	dev_t bdev, dev = (dev_t)vp->v_rdev;
11537486Smckusick 	register int maj = major(dev);
11640375Smckusick 	int error;
11737486Smckusick 
11859486Smckusick 	/*
11959486Smckusick 	 * Don't allow open if fs is mounted -nodev.
12059486Smckusick 	 */
12153863Sheideman 	if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
12239365Smckusick 		return (ENXIO);
12339365Smckusick 
12453863Sheideman 	switch (vp->v_type) {
12537486Smckusick 
12637486Smckusick 	case VCHR:
12737486Smckusick 		if ((u_int)maj >= nchrdev)
12837486Smckusick 			return (ENXIO);
12959486Smckusick 		if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) {
13059486Smckusick 			/*
13159486Smckusick 			 * When running in very secure mode, do not allow
13259486Smckusick 			 * opens for writing of any disk character devices.
13359486Smckusick 			 */
13468129Smckusick 			if (securelevel >= 2 && cdevsw[maj].d_type == D_DISK)
13559486Smckusick 				return (EPERM);
13659486Smckusick 			/*
13759486Smckusick 			 * When running in secure mode, do not allow opens
13859486Smckusick 			 * for writing of /dev/mem, /dev/kmem, or character
13959486Smckusick 			 * devices whose corresponding block devices are
14059486Smckusick 			 * currently mounted.
14159486Smckusick 			 */
14259486Smckusick 			if (securelevel >= 1) {
14359486Smckusick 				if ((bdev = chrtoblk(dev)) != NODEV &&
14459486Smckusick 				    vfinddev(bdev, VBLK, &bvp) &&
14559486Smckusick 				    bvp->v_usecount > 0 &&
14665671Shibler 				    (error = vfs_mountedon(bvp)))
14759486Smckusick 					return (error);
14859486Smckusick 				if (iskmemdev(dev))
14959486Smckusick 					return (EPERM);
15059486Smckusick 			}
15159486Smckusick 		}
15268129Smckusick 		if (cdevsw[maj].d_type == D_TTY)
15367951Smckusick 			vp->v_flag |= VISTTY;
15453863Sheideman 		VOP_UNLOCK(vp);
15553597Sheideman 		error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p);
15653863Sheideman 		VOP_LOCK(vp);
15749944Smckusick 		return (error);
15837486Smckusick 
15937486Smckusick 	case VBLK:
16037486Smckusick 		if ((u_int)maj >= nblkdev)
16137486Smckusick 			return (ENXIO);
16259486Smckusick 		/*
16359486Smckusick 		 * When running in very secure mode, do not allow
16459486Smckusick 		 * opens for writing of any disk block devices.
16559486Smckusick 		 */
16659486Smckusick 		if (securelevel >= 2 && ap->a_cred != FSCRED &&
16768129Smckusick 		    (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK)
16859486Smckusick 			return (EPERM);
16959486Smckusick 		/*
17059486Smckusick 		 * Do not allow opens of block devices that are
17159486Smckusick 		 * currently mounted.
17259486Smckusick 		 */
17365671Shibler 		if (error = vfs_mountedon(vp))
17440375Smckusick 			return (error);
17553597Sheideman 		return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p));
17637486Smckusick 	}
17737486Smckusick 	return (0);
17837486Smckusick }
17937486Smckusick 
18037486Smckusick /*
18137486Smckusick  * Vnode op for read
18237486Smckusick  */
18341961Smckusick /* ARGSUSED */
18454439Smckusick spec_read(ap)
18554439Smckusick 	struct vop_read_args /* {
18654439Smckusick 		struct vnode *a_vp;
18754439Smckusick 		struct uio *a_uio;
18854439Smckusick 		int  a_ioflag;
18954439Smckusick 		struct ucred *a_cred;
19054439Smckusick 	} */ *ap;
19137486Smckusick {
19253863Sheideman 	register struct vnode *vp = ap->a_vp;
19353863Sheideman 	register struct uio *uio = ap->a_uio;
19453863Sheideman  	struct proc *p = uio->uio_procp;
19539614Smckusick 	struct buf *bp;
19652321Smckusick 	daddr_t bn, nextbn;
19739614Smckusick 	long bsize, bscale;
19839614Smckusick 	struct partinfo dpart;
19965532Smckusick 	int n, on, majordev, (*ioctl)();
20039614Smckusick 	int error = 0;
20165532Smckusick 	dev_t dev;
20237486Smckusick 
20348015Smckusick #ifdef DIAGNOSTIC
20453863Sheideman 	if (uio->uio_rw != UIO_READ)
20539588Smckusick 		panic("spec_read mode");
20653863Sheideman 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
20748015Smckusick 		panic("spec_read proc");
20848015Smckusick #endif
20953863Sheideman 	if (uio->uio_resid == 0)
21039588Smckusick 		return (0);
21139588Smckusick 
21253863Sheideman 	switch (vp->v_type) {
21339588Smckusick 
21439588Smckusick 	case VCHR:
21553863Sheideman 		VOP_UNLOCK(vp);
21653863Sheideman 		error = (*cdevsw[major(vp->v_rdev)].d_read)
21753863Sheideman 			(vp->v_rdev, uio, ap->a_ioflag);
21853863Sheideman 		VOP_LOCK(vp);
21939588Smckusick 		return (error);
22039588Smckusick 
22139588Smckusick 	case VBLK:
22253863Sheideman 		if (uio->uio_offset < 0)
22339588Smckusick 			return (EINVAL);
22439614Smckusick 		bsize = BLKDEV_IOSIZE;
22565532Smckusick 		dev = vp->v_rdev;
22665532Smckusick 		if ((majordev = major(dev)) < nblkdev &&
22765532Smckusick 		    (ioctl = bdevsw[majordev].d_ioctl) != NULL &&
22865532Smckusick 		    (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 &&
22965532Smckusick 		    dpart.part->p_fstype == FS_BSDFFS &&
23065532Smckusick 		    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
23165532Smckusick 			bsize = dpart.part->p_frag * dpart.part->p_fsize;
23239614Smckusick 		bscale = bsize / DEV_BSIZE;
23339614Smckusick 		do {
23453863Sheideman 			bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
23553863Sheideman 			on = uio->uio_offset % bsize;
23655059Spendry 			n = min((unsigned)(bsize - on), uio->uio_resid);
23753863Sheideman 			if (vp->v_lastr + bscale == bn) {
23852321Smckusick 				nextbn = bn + bscale;
23953863Sheideman 				error = breadn(vp, bn, (int)bsize, &nextbn,
24052321Smckusick 					(int *)&bsize, 1, NOCRED, &bp);
24152321Smckusick 			} else
24253863Sheideman 				error = bread(vp, bn, (int)bsize, NOCRED, &bp);
24353863Sheideman 			vp->v_lastr = bn;
24455059Spendry 			n = min(n, bsize - bp->b_resid);
24539614Smckusick 			if (error) {
24639614Smckusick 				brelse(bp);
24739614Smckusick 				return (error);
24839614Smckusick 			}
24964551Sbostic 			error = uiomove((char *)bp->b_data + on, n, uio);
25039614Smckusick 			if (n + on == bsize)
25139614Smckusick 				bp->b_flags |= B_AGE;
25239614Smckusick 			brelse(bp);
25353863Sheideman 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
25439614Smckusick 		return (error);
25539588Smckusick 
25639588Smckusick 	default:
25739588Smckusick 		panic("spec_read type");
25839588Smckusick 	}
25939588Smckusick 	/* NOTREACHED */
26037486Smckusick }
26137486Smckusick 
26237486Smckusick /*
26337486Smckusick  * Vnode op for write
26437486Smckusick  */
26541961Smckusick /* ARGSUSED */
26654439Smckusick spec_write(ap)
26754439Smckusick 	struct vop_write_args /* {
26854439Smckusick 		struct vnode *a_vp;
26954439Smckusick 		struct uio *a_uio;
27054439Smckusick 		int  a_ioflag;
27154439Smckusick 		struct ucred *a_cred;
27254439Smckusick 	} */ *ap;
27337486Smckusick {
27453863Sheideman 	register struct vnode *vp = ap->a_vp;
27553863Sheideman 	register struct uio *uio = ap->a_uio;
27653863Sheideman 	struct proc *p = uio->uio_procp;
27739614Smckusick 	struct buf *bp;
27839614Smckusick 	daddr_t bn;
27939614Smckusick 	int bsize, blkmask;
28039614Smckusick 	struct partinfo dpart;
28145731Smckusick 	register int n, on;
28245731Smckusick 	int error = 0;
28337486Smckusick 
28448015Smckusick #ifdef DIAGNOSTIC
28553863Sheideman 	if (uio->uio_rw != UIO_WRITE)
28639588Smckusick 		panic("spec_write mode");
28753863Sheideman 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
28848015Smckusick 		panic("spec_write proc");
28948015Smckusick #endif
29039588Smckusick 
29153863Sheideman 	switch (vp->v_type) {
29239588Smckusick 
29339588Smckusick 	case VCHR:
29453863Sheideman 		VOP_UNLOCK(vp);
29553863Sheideman 		error = (*cdevsw[major(vp->v_rdev)].d_write)
29653863Sheideman 			(vp->v_rdev, uio, ap->a_ioflag);
29753863Sheideman 		VOP_LOCK(vp);
29839588Smckusick 		return (error);
29939588Smckusick 
30039588Smckusick 	case VBLK:
30153863Sheideman 		if (uio->uio_resid == 0)
30239588Smckusick 			return (0);
30353863Sheideman 		if (uio->uio_offset < 0)
30439588Smckusick 			return (EINVAL);
30539614Smckusick 		bsize = BLKDEV_IOSIZE;
30653863Sheideman 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
30747540Skarels 		    (caddr_t)&dpart, FREAD, p) == 0) {
30839614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
30939614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
31039614Smckusick 				bsize = dpart.part->p_frag *
31139614Smckusick 				    dpart.part->p_fsize;
31239614Smckusick 		}
31339614Smckusick 		blkmask = (bsize / DEV_BSIZE) - 1;
31439614Smckusick 		do {
31553863Sheideman 			bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
31653863Sheideman 			on = uio->uio_offset % bsize;
31755059Spendry 			n = min((unsigned)(bsize - on), uio->uio_resid);
31839614Smckusick 			if (n == bsize)
31957798Smckusick 				bp = getblk(vp, bn, bsize, 0, 0);
32039614Smckusick 			else
32153863Sheideman 				error = bread(vp, bn, bsize, NOCRED, &bp);
32255059Spendry 			n = min(n, bsize - bp->b_resid);
32339614Smckusick 			if (error) {
32439614Smckusick 				brelse(bp);
32539614Smckusick 				return (error);
32639614Smckusick 			}
32764551Sbostic 			error = uiomove((char *)bp->b_data + on, n, uio);
32839614Smckusick 			if (n + on == bsize) {
32939614Smckusick 				bp->b_flags |= B_AGE;
33039614Smckusick 				bawrite(bp);
33139614Smckusick 			} else
33239614Smckusick 				bdwrite(bp);
33353863Sheideman 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
33439614Smckusick 		return (error);
33539588Smckusick 
33639588Smckusick 	default:
33739588Smckusick 		panic("spec_write type");
33839588Smckusick 	}
33939588Smckusick 	/* NOTREACHED */
34037486Smckusick }
34137486Smckusick 
34237486Smckusick /*
34337486Smckusick  * Device ioctl operation.
34437486Smckusick  */
34537725Smckusick /* ARGSUSED */
34654439Smckusick spec_ioctl(ap)
34754439Smckusick 	struct vop_ioctl_args /* {
34854439Smckusick 		struct vnode *a_vp;
34954439Smckusick 		int  a_command;
35054439Smckusick 		caddr_t  a_data;
35154439Smckusick 		int  a_fflag;
35254439Smckusick 		struct ucred *a_cred;
35354439Smckusick 		struct proc *a_p;
35454439Smckusick 	} */ *ap;
35537486Smckusick {
35653597Sheideman 	dev_t dev = ap->a_vp->v_rdev;
35737486Smckusick 
35853597Sheideman 	switch (ap->a_vp->v_type) {
35937486Smckusick 
36037486Smckusick 	case VCHR:
36153597Sheideman 		return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
36253597Sheideman 		    ap->a_fflag, ap->a_p));
36337486Smckusick 
36437486Smckusick 	case VBLK:
36553597Sheideman 		if (ap->a_command == 0 && (int)ap->a_data == B_TAPE)
36668129Smckusick 			if (bdevsw[major(dev)].d_type == D_TAPE)
36739666Smckusick 				return (0);
36839666Smckusick 			else
36939666Smckusick 				return (1);
37053597Sheideman 		return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
37153597Sheideman 		   ap->a_fflag, ap->a_p));
37237486Smckusick 
37337486Smckusick 	default:
37439446Smckusick 		panic("spec_ioctl");
37537486Smckusick 		/* NOTREACHED */
37637486Smckusick 	}
37737486Smckusick }
37837486Smckusick 
37937725Smckusick /* ARGSUSED */
38054439Smckusick spec_select(ap)
38154439Smckusick 	struct vop_select_args /* {
38254439Smckusick 		struct vnode *a_vp;
38354439Smckusick 		int  a_which;
38454439Smckusick 		int  a_fflags;
38554439Smckusick 		struct ucred *a_cred;
38654439Smckusick 		struct proc *a_p;
38754439Smckusick 	} */ *ap;
38837486Smckusick {
38937486Smckusick 	register dev_t dev;
39037486Smckusick 
39153597Sheideman 	switch (ap->a_vp->v_type) {
39237486Smckusick 
39337486Smckusick 	default:
39437486Smckusick 		return (1);		/* XXX */
39537486Smckusick 
39637486Smckusick 	case VCHR:
39753597Sheideman 		dev = ap->a_vp->v_rdev;
39853597Sheideman 		return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p);
39937486Smckusick 	}
40037486Smckusick }
40154439Smckusick /*
40254439Smckusick  * Synch buffers associated with a block device
40354439Smckusick  */
40454439Smckusick /* ARGSUSED */
40554439Smckusick int
40654439Smckusick spec_fsync(ap)
40754439Smckusick 	struct vop_fsync_args /* {
40854439Smckusick 		struct vnode *a_vp;
40954439Smckusick 		struct ucred *a_cred;
41054439Smckusick 		int  a_waitfor;
41154439Smckusick 		struct proc *a_p;
41254439Smckusick 	} */ *ap;
41354439Smckusick {
41454439Smckusick 	register struct vnode *vp = ap->a_vp;
41554439Smckusick 	register struct buf *bp;
41654439Smckusick 	struct buf *nbp;
41756548Smckusick 	int s;
41837486Smckusick 
41954439Smckusick 	if (vp->v_type == VCHR)
42054439Smckusick 		return (0);
42154439Smckusick 	/*
42254439Smckusick 	 * Flush all dirty buffers associated with a block device.
42354439Smckusick 	 */
42454439Smckusick loop:
42554439Smckusick 	s = splbio();
42665246Smckusick 	for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
42765246Smckusick 		nbp = bp->b_vnbufs.le_next;
42854439Smckusick 		if ((bp->b_flags & B_BUSY))
42954439Smckusick 			continue;
43054439Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
43154439Smckusick 			panic("spec_fsync: not dirty");
43254439Smckusick 		bremfree(bp);
43354439Smckusick 		bp->b_flags |= B_BUSY;
43454439Smckusick 		splx(s);
43556548Smckusick 		bawrite(bp);
43654439Smckusick 		goto loop;
43754439Smckusick 	}
43854439Smckusick 	if (ap->a_waitfor == MNT_WAIT) {
43954439Smckusick 		while (vp->v_numoutput) {
44054439Smckusick 			vp->v_flag |= VBWAIT;
44154439Smckusick 			sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
44254439Smckusick 		}
44354439Smckusick #ifdef DIAGNOSTIC
44465246Smckusick 		if (vp->v_dirtyblkhd.lh_first) {
44554439Smckusick 			vprint("spec_fsync: dirty", vp);
44654439Smckusick 			goto loop;
44754439Smckusick 		}
44854439Smckusick #endif
44954439Smckusick 	}
45054439Smckusick 	splx(s);
45156548Smckusick 	return (0);
45254439Smckusick }
45354439Smckusick 
45437486Smckusick /*
45537486Smckusick  * Just call the device strategy routine
45637486Smckusick  */
45754439Smckusick spec_strategy(ap)
45854439Smckusick 	struct vop_strategy_args /* {
45954439Smckusick 		struct buf *a_bp;
46054439Smckusick 	} */ *ap;
46137486Smckusick {
46239666Smckusick 
46353597Sheideman 	(*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp);
46437486Smckusick 	return (0);
46537486Smckusick }
46637486Smckusick 
46739432Smckusick /*
46839666Smckusick  * This is a noop, simply returning what one has been given.
46939666Smckusick  */
47054439Smckusick spec_bmap(ap)
47154439Smckusick 	struct vop_bmap_args /* {
47254439Smckusick 		struct vnode *a_vp;
47354439Smckusick 		daddr_t  a_bn;
47454439Smckusick 		struct vnode **a_vpp;
47554439Smckusick 		daddr_t *a_bnp;
47668234Spendry 		int *a_runp;
47754439Smckusick 	} */ *ap;
47839666Smckusick {
47939666Smckusick 
48053597Sheideman 	if (ap->a_vpp != NULL)
48153597Sheideman 		*ap->a_vpp = ap->a_vp;
48253597Sheideman 	if (ap->a_bnp != NULL)
48353597Sheideman 		*ap->a_bnp = ap->a_bn;
48468231Spendry 	if (ap->a_runp != NULL)
48568231Spendry 		*ap->a_runp = 0;
48639666Smckusick 	return (0);
48739666Smckusick }
48839666Smckusick 
48939666Smckusick /*
49039432Smckusick  * At the moment we do not do any locking.
49139432Smckusick  */
49239489Smckusick /* ARGSUSED */
49354439Smckusick spec_lock(ap)
49454439Smckusick 	struct vop_lock_args /* {
49554439Smckusick 		struct vnode *a_vp;
49654439Smckusick 	} */ *ap;
49737486Smckusick {
49837486Smckusick 
49937486Smckusick 	return (0);
50037486Smckusick }
50137486Smckusick 
50239489Smckusick /* ARGSUSED */
50354439Smckusick spec_unlock(ap)
50454439Smckusick 	struct vop_unlock_args /* {
50554439Smckusick 		struct vnode *a_vp;
50654439Smckusick 	} */ *ap;
50737486Smckusick {
50837486Smckusick 
50937486Smckusick 	return (0);
51037486Smckusick }
51137486Smckusick 
51237486Smckusick /*
51337486Smckusick  * Device close routine
51437486Smckusick  */
51537725Smckusick /* ARGSUSED */
51654439Smckusick spec_close(ap)
51754439Smckusick 	struct vop_close_args /* {
51854439Smckusick 		struct vnode *a_vp;
51954439Smckusick 		int  a_fflag;
52054439Smckusick 		struct ucred *a_cred;
52154439Smckusick 		struct proc *a_p;
52254439Smckusick 	} */ *ap;
52337486Smckusick {
52453863Sheideman 	register struct vnode *vp = ap->a_vp;
52553863Sheideman 	dev_t dev = vp->v_rdev;
52649273Skarels 	int (*devclose) __P((dev_t, int, int, struct proc *));
52754439Smckusick 	int mode, error;
52837486Smckusick 
52953863Sheideman 	switch (vp->v_type) {
53037725Smckusick 
53137725Smckusick 	case VCHR:
53239485Smckusick 		/*
53360498Smckusick 		 * Hack: a tty device that is a controlling terminal
53460498Smckusick 		 * has a reference from the session structure.
53560498Smckusick 		 * We cannot easily tell that a character device is
53660498Smckusick 		 * a controlling terminal, unless it is the closing
53760498Smckusick 		 * process' controlling terminal.  In that case,
53860498Smckusick 		 * if the reference count is 2 (this last descriptor
53960498Smckusick 		 * plus the session), release the reference from the session.
54060498Smckusick 		 */
54160527Smckusick 		if (vcount(vp) == 2 && ap->a_p &&
54260527Smckusick 		    vp == ap->a_p->p_session->s_ttyvp) {
54360498Smckusick 			vrele(vp);
54460498Smckusick 			ap->a_p->p_session->s_ttyvp = NULL;
54560498Smckusick 		}
54660498Smckusick 		/*
54739485Smckusick 		 * If the vnode is locked, then we are in the midst
54839485Smckusick 		 * of forcably closing the device, otherwise we only
54939485Smckusick 		 * close on last reference.
55039485Smckusick 		 */
55153863Sheideman 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
55237725Smckusick 			return (0);
55349273Skarels 		devclose = cdevsw[major(dev)].d_close;
55439432Smckusick 		mode = S_IFCHR;
55537725Smckusick 		break;
55637725Smckusick 
55737725Smckusick 	case VBLK:
55837725Smckusick 		/*
55937725Smckusick 		 * On last close of a block device (that isn't mounted)
56037725Smckusick 		 * we must invalidate any in core blocks, so that
56137725Smckusick 		 * we can, for instance, change floppy disks.
56237725Smckusick 		 */
56366739Spendry 		if (error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0))
56454439Smckusick 			return (error);
56537725Smckusick 		/*
56639485Smckusick 		 * We do not want to really close the device if it
56739485Smckusick 		 * is still in use unless we are trying to close it
56839485Smckusick 		 * forcibly. Since every use (buffer, vnode, swap, cmap)
56939630Smckusick 		 * holds a reference to the vnode, and because we mark
57039630Smckusick 		 * any other vnodes that alias this device, when the
57139630Smckusick 		 * sum of the reference counts on all the aliased
57239630Smckusick 		 * vnodes descends to one, we are on last close.
57337725Smckusick 		 */
57453863Sheideman 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
57537725Smckusick 			return (0);
57649273Skarels 		devclose = bdevsw[major(dev)].d_close;
57739432Smckusick 		mode = S_IFBLK;
57837725Smckusick 		break;
57937725Smckusick 
58037725Smckusick 	default:
58139446Smckusick 		panic("spec_close: not special");
58237725Smckusick 	}
58337725Smckusick 
58453597Sheideman 	return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
58537486Smckusick }
58637486Smckusick 
58737486Smckusick /*
58839666Smckusick  * Print out the contents of a special device vnode.
58939666Smckusick  */
59054439Smckusick spec_print(ap)
59154439Smckusick 	struct vop_print_args /* {
59254439Smckusick 		struct vnode *a_vp;
59354439Smckusick 	} */ *ap;
59439666Smckusick {
59539666Smckusick 
59653597Sheideman 	printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
59753597Sheideman 		minor(ap->a_vp->v_rdev));
59839666Smckusick }
59939666Smckusick 
60039666Smckusick /*
60160391Smckusick  * Return POSIX pathconf information applicable to special devices.
60260391Smckusick  */
60360391Smckusick spec_pathconf(ap)
60460391Smckusick 	struct vop_pathconf_args /* {
60560391Smckusick 		struct vnode *a_vp;
60660391Smckusick 		int a_name;
60760391Smckusick 		int *a_retval;
60860391Smckusick 	} */ *ap;
60960391Smckusick {
61060391Smckusick 
61160391Smckusick 	switch (ap->a_name) {
61260391Smckusick 	case _PC_LINK_MAX:
61360391Smckusick 		*ap->a_retval = LINK_MAX;
61460391Smckusick 		return (0);
61560391Smckusick 	case _PC_MAX_CANON:
61660391Smckusick 		*ap->a_retval = MAX_CANON;
61760391Smckusick 		return (0);
61860391Smckusick 	case _PC_MAX_INPUT:
61960391Smckusick 		*ap->a_retval = MAX_INPUT;
62060391Smckusick 		return (0);
62160391Smckusick 	case _PC_PIPE_BUF:
62260391Smckusick 		*ap->a_retval = PIPE_BUF;
62360391Smckusick 		return (0);
62460391Smckusick 	case _PC_CHOWN_RESTRICTED:
62560391Smckusick 		*ap->a_retval = 1;
62660391Smckusick 		return (0);
62760391Smckusick 	case _PC_VDISABLE:
62860391Smckusick 		*ap->a_retval = _POSIX_VDISABLE;
62960391Smckusick 		return (0);
63060391Smckusick 	default:
63160391Smckusick 		return (EINVAL);
63260391Smckusick 	}
63360391Smckusick 	/* NOTREACHED */
63460391Smckusick }
63560391Smckusick 
63660391Smckusick /*
63746196Smckusick  * Special device advisory byte-level locks.
63846196Smckusick  */
63948015Smckusick /* ARGSUSED */
64054439Smckusick spec_advlock(ap)
64154439Smckusick 	struct vop_advlock_args /* {
64254439Smckusick 		struct vnode *a_vp;
64354439Smckusick 		caddr_t  a_id;
64454439Smckusick 		int  a_op;
64554439Smckusick 		struct flock *a_fl;
64654439Smckusick 		int  a_flags;
64754439Smckusick 	} */ *ap;
64846196Smckusick {
64946196Smckusick 
65046196Smckusick 	return (EOPNOTSUPP);
65146196Smckusick }
65246196Smckusick 
65346196Smckusick /*
65439507Smckusick  * Special device failed operation
65537486Smckusick  */
65639507Smckusick spec_ebadf()
65739507Smckusick {
65839507Smckusick 
65939507Smckusick 	return (EBADF);
66039507Smckusick }
66139507Smckusick 
66239507Smckusick /*
66339507Smckusick  * Special device bad operation
66439507Smckusick  */
66539446Smckusick spec_badop()
66637486Smckusick {
66737486Smckusick 
66839446Smckusick 	panic("spec_badop called");
66939292Smckusick 	/* NOTREACHED */
67037486Smckusick }
671