xref: /csrg-svn/sys/miscfs/specfs/spec_vnops.c (revision 54439)
137486Smckusick /*
237486Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337486Smckusick  * All rights reserved.
437486Smckusick  *
544443Sbostic  * %sccs.include.redist.c%
637486Smckusick  *
7*54439Smckusick  *	@(#)spec_vnops.c	7.46 (Berkeley) 06/25/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 
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_vget_desc, spec_vget },		/* vget */
7353542Sheideman 	{ &vop_valloc_desc, spec_valloc },		/* valloc */
7453542Sheideman 	{ &vop_vfree_desc, spec_vfree },		/* vfree */
7553542Sheideman 	{ &vop_truncate_desc, spec_truncate },		/* truncate */
7653542Sheideman 	{ &vop_update_desc, spec_update },		/* update */
7753542Sheideman 	{ &vop_bwrite_desc, spec_bwrite },		/* bwrite */
7853542Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
7937486Smckusick };
8053542Sheideman struct vnodeopv_desc spec_vnodeop_opv_desc =
8153542Sheideman 	{ &spec_vnodeop_p, spec_vnodeop_entries };
8237486Smckusick 
8337486Smckusick /*
8439292Smckusick  * Trivial lookup routine that always fails.
8539292Smckusick  */
8652320Sheideman int
87*54439Smckusick spec_lookup(ap)
88*54439Smckusick 	struct vop_lookup_args /* {
89*54439Smckusick 		struct vnode *a_dvp;
90*54439Smckusick 		struct vnode **a_vpp;
91*54439Smckusick 		struct componentname *a_cnp;
92*54439Smckusick 	} */ *ap;
9339292Smckusick {
9439292Smckusick 
9553597Sheideman 	*ap->a_vpp = NULL;
9639292Smckusick 	return (ENOTDIR);
9739292Smckusick }
9839292Smckusick 
9939292Smckusick /*
10049273Skarels  * Open a special file: Don't allow open if fs is mounted -nodev,
10149273Skarels  * and don't allow opens of block devices that are currently mounted.
10249273Skarels  * Otherwise, call device driver open function.
10337486Smckusick  */
10437725Smckusick /* ARGSUSED */
105*54439Smckusick spec_open(ap)
106*54439Smckusick 	struct vop_open_args /* {
107*54439Smckusick 		struct vnode *a_vp;
108*54439Smckusick 		int  a_mode;
109*54439Smckusick 		struct ucred *a_cred;
110*54439Smckusick 		struct proc *a_p;
111*54439Smckusick 	} */ *ap;
11237486Smckusick {
11353542Sheideman 	USES_VOP_LOCK;
11453542Sheideman 	USES_VOP_UNLOCK;
11553863Sheideman 	register struct vnode *vp = ap->a_vp;
11653863Sheideman 	dev_t dev = (dev_t)vp->v_rdev;
11737486Smckusick 	register int maj = major(dev);
11840375Smckusick 	int error;
11937486Smckusick 
12053863Sheideman 	if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
12139365Smckusick 		return (ENXIO);
12239365Smckusick 
12353863Sheideman 	switch (vp->v_type) {
12437486Smckusick 
12537486Smckusick 	case VCHR:
12637486Smckusick 		if ((u_int)maj >= nchrdev)
12737486Smckusick 			return (ENXIO);
12853863Sheideman 		VOP_UNLOCK(vp);
12953597Sheideman 		error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p);
13053863Sheideman 		VOP_LOCK(vp);
13149944Smckusick 		return (error);
13237486Smckusick 
13337486Smckusick 	case VBLK:
13437486Smckusick 		if ((u_int)maj >= nblkdev)
13537486Smckusick 			return (ENXIO);
13653863Sheideman 		if (error = ufs_mountedon(vp))
13740375Smckusick 			return (error);
13853597Sheideman 		return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p));
13937486Smckusick 	}
14037486Smckusick 	return (0);
14137486Smckusick }
14237486Smckusick 
14337486Smckusick /*
14437486Smckusick  * Vnode op for read
14537486Smckusick  */
14641961Smckusick /* ARGSUSED */
147*54439Smckusick spec_read(ap)
148*54439Smckusick 	struct vop_read_args /* {
149*54439Smckusick 		struct vnode *a_vp;
150*54439Smckusick 		struct uio *a_uio;
151*54439Smckusick 		int  a_ioflag;
152*54439Smckusick 		struct ucred *a_cred;
153*54439Smckusick 	} */ *ap;
15437486Smckusick {
15553542Sheideman 	USES_VOP_LOCK;
15653542Sheideman 	USES_VOP_UNLOCK;
15753863Sheideman 	register struct vnode *vp = ap->a_vp;
15853863Sheideman 	register struct uio *uio = ap->a_uio;
15953863Sheideman  	struct proc *p = uio->uio_procp;
16039614Smckusick 	struct buf *bp;
16152321Smckusick 	daddr_t bn, nextbn;
16239614Smckusick 	long bsize, bscale;
16339614Smckusick 	struct partinfo dpart;
16439614Smckusick 	register int n, on;
16539614Smckusick 	int error = 0;
16637486Smckusick 
16748015Smckusick #ifdef DIAGNOSTIC
16853863Sheideman 	if (uio->uio_rw != UIO_READ)
16939588Smckusick 		panic("spec_read mode");
17053863Sheideman 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
17148015Smckusick 		panic("spec_read proc");
17248015Smckusick #endif
17353863Sheideman 	if (uio->uio_resid == 0)
17439588Smckusick 		return (0);
17539588Smckusick 
17653863Sheideman 	switch (vp->v_type) {
17739588Smckusick 
17839588Smckusick 	case VCHR:
17953863Sheideman 		VOP_UNLOCK(vp);
18053863Sheideman 		error = (*cdevsw[major(vp->v_rdev)].d_read)
18153863Sheideman 			(vp->v_rdev, uio, ap->a_ioflag);
18253863Sheideman 		VOP_LOCK(vp);
18339588Smckusick 		return (error);
18439588Smckusick 
18539588Smckusick 	case VBLK:
18653863Sheideman 		if (uio->uio_offset < 0)
18739588Smckusick 			return (EINVAL);
18839614Smckusick 		bsize = BLKDEV_IOSIZE;
18953863Sheideman 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
19047540Skarels 		    (caddr_t)&dpart, FREAD, p) == 0) {
19139614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
19239614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
19339614Smckusick 				bsize = dpart.part->p_frag *
19439614Smckusick 				    dpart.part->p_fsize;
19539614Smckusick 		}
19639614Smckusick 		bscale = bsize / DEV_BSIZE;
19739614Smckusick 		do {
19853863Sheideman 			bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
19953863Sheideman 			on = uio->uio_offset % bsize;
20053863Sheideman 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
20153863Sheideman 			if (vp->v_lastr + bscale == bn) {
20252321Smckusick 				nextbn = bn + bscale;
20353863Sheideman 				error = breadn(vp, bn, (int)bsize, &nextbn,
20452321Smckusick 					(int *)&bsize, 1, NOCRED, &bp);
20552321Smckusick 			} else
20653863Sheideman 				error = bread(vp, bn, (int)bsize, NOCRED, &bp);
20753863Sheideman 			vp->v_lastr = bn;
20839614Smckusick 			n = MIN(n, bsize - bp->b_resid);
20939614Smckusick 			if (error) {
21039614Smckusick 				brelse(bp);
21139614Smckusick 				return (error);
21239614Smckusick 			}
21353863Sheideman 			error = uiomove(bp->b_un.b_addr + on, n, uio);
21439614Smckusick 			if (n + on == bsize)
21539614Smckusick 				bp->b_flags |= B_AGE;
21639614Smckusick 			brelse(bp);
21753863Sheideman 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
21839614Smckusick 		return (error);
21939588Smckusick 
22039588Smckusick 	default:
22139588Smckusick 		panic("spec_read type");
22239588Smckusick 	}
22339588Smckusick 	/* NOTREACHED */
22437486Smckusick }
22537486Smckusick 
22637486Smckusick /*
22737486Smckusick  * Vnode op for write
22837486Smckusick  */
22941961Smckusick /* ARGSUSED */
230*54439Smckusick spec_write(ap)
231*54439Smckusick 	struct vop_write_args /* {
232*54439Smckusick 		struct vnode *a_vp;
233*54439Smckusick 		struct uio *a_uio;
234*54439Smckusick 		int  a_ioflag;
235*54439Smckusick 		struct ucred *a_cred;
236*54439Smckusick 	} */ *ap;
23737486Smckusick {
23853542Sheideman 	USES_VOP_LOCK;
23953542Sheideman 	USES_VOP_UNLOCK;
24053863Sheideman 	register struct vnode *vp = ap->a_vp;
24153863Sheideman 	register struct uio *uio = ap->a_uio;
24253863Sheideman 	struct proc *p = uio->uio_procp;
24339614Smckusick 	struct buf *bp;
24439614Smckusick 	daddr_t bn;
24539614Smckusick 	int bsize, blkmask;
24639614Smckusick 	struct partinfo dpart;
24745731Smckusick 	register int n, on;
24845731Smckusick 	int error = 0;
24937486Smckusick 
25048015Smckusick #ifdef DIAGNOSTIC
25153863Sheideman 	if (uio->uio_rw != UIO_WRITE)
25239588Smckusick 		panic("spec_write mode");
25353863Sheideman 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
25448015Smckusick 		panic("spec_write proc");
25548015Smckusick #endif
25639588Smckusick 
25753863Sheideman 	switch (vp->v_type) {
25839588Smckusick 
25939588Smckusick 	case VCHR:
26053863Sheideman 		VOP_UNLOCK(vp);
26153863Sheideman 		error = (*cdevsw[major(vp->v_rdev)].d_write)
26253863Sheideman 			(vp->v_rdev, uio, ap->a_ioflag);
26353863Sheideman 		VOP_LOCK(vp);
26439588Smckusick 		return (error);
26539588Smckusick 
26639588Smckusick 	case VBLK:
26753863Sheideman 		if (uio->uio_resid == 0)
26839588Smckusick 			return (0);
26953863Sheideman 		if (uio->uio_offset < 0)
27039588Smckusick 			return (EINVAL);
27139614Smckusick 		bsize = BLKDEV_IOSIZE;
27253863Sheideman 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
27347540Skarels 		    (caddr_t)&dpart, FREAD, p) == 0) {
27439614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
27539614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
27639614Smckusick 				bsize = dpart.part->p_frag *
27739614Smckusick 				    dpart.part->p_fsize;
27839614Smckusick 		}
27939614Smckusick 		blkmask = (bsize / DEV_BSIZE) - 1;
28039614Smckusick 		do {
28153863Sheideman 			bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
28253863Sheideman 			on = uio->uio_offset % bsize;
28353863Sheideman 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
28439614Smckusick 			if (n == bsize)
28553863Sheideman 				bp = getblk(vp, bn, bsize);
28639614Smckusick 			else
28753863Sheideman 				error = bread(vp, bn, bsize, NOCRED, &bp);
28839614Smckusick 			n = MIN(n, bsize - bp->b_resid);
28939614Smckusick 			if (error) {
29039614Smckusick 				brelse(bp);
29139614Smckusick 				return (error);
29239614Smckusick 			}
29353863Sheideman 			error = uiomove(bp->b_un.b_addr + on, n, uio);
29439614Smckusick 			if (n + on == bsize) {
29539614Smckusick 				bp->b_flags |= B_AGE;
29639614Smckusick 				bawrite(bp);
29739614Smckusick 			} else
29839614Smckusick 				bdwrite(bp);
29953863Sheideman 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
30039614Smckusick 		return (error);
30139588Smckusick 
30239588Smckusick 	default:
30339588Smckusick 		panic("spec_write type");
30439588Smckusick 	}
30539588Smckusick 	/* NOTREACHED */
30637486Smckusick }
30737486Smckusick 
30837486Smckusick /*
30937486Smckusick  * Device ioctl operation.
31037486Smckusick  */
31137725Smckusick /* ARGSUSED */
312*54439Smckusick spec_ioctl(ap)
313*54439Smckusick 	struct vop_ioctl_args /* {
314*54439Smckusick 		struct vnode *a_vp;
315*54439Smckusick 		int  a_command;
316*54439Smckusick 		caddr_t  a_data;
317*54439Smckusick 		int  a_fflag;
318*54439Smckusick 		struct ucred *a_cred;
319*54439Smckusick 		struct proc *a_p;
320*54439Smckusick 	} */ *ap;
32137486Smckusick {
32253597Sheideman 	dev_t dev = ap->a_vp->v_rdev;
32337486Smckusick 
32453597Sheideman 	switch (ap->a_vp->v_type) {
32537486Smckusick 
32637486Smckusick 	case VCHR:
32753597Sheideman 		return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
32853597Sheideman 		    ap->a_fflag, ap->a_p));
32937486Smckusick 
33037486Smckusick 	case VBLK:
33153597Sheideman 		if (ap->a_command == 0 && (int)ap->a_data == B_TAPE)
33239666Smckusick 			if (bdevsw[major(dev)].d_flags & B_TAPE)
33339666Smckusick 				return (0);
33439666Smckusick 			else
33539666Smckusick 				return (1);
33653597Sheideman 		return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
33753597Sheideman 		   ap->a_fflag, ap->a_p));
33837486Smckusick 
33937486Smckusick 	default:
34039446Smckusick 		panic("spec_ioctl");
34137486Smckusick 		/* NOTREACHED */
34237486Smckusick 	}
34337486Smckusick }
34437486Smckusick 
34537725Smckusick /* ARGSUSED */
346*54439Smckusick spec_select(ap)
347*54439Smckusick 	struct vop_select_args /* {
348*54439Smckusick 		struct vnode *a_vp;
349*54439Smckusick 		int  a_which;
350*54439Smckusick 		int  a_fflags;
351*54439Smckusick 		struct ucred *a_cred;
352*54439Smckusick 		struct proc *a_p;
353*54439Smckusick 	} */ *ap;
35437486Smckusick {
35537486Smckusick 	register dev_t dev;
35637486Smckusick 
35753597Sheideman 	switch (ap->a_vp->v_type) {
35837486Smckusick 
35937486Smckusick 	default:
36037486Smckusick 		return (1);		/* XXX */
36137486Smckusick 
36237486Smckusick 	case VCHR:
36353597Sheideman 		dev = ap->a_vp->v_rdev;
36453597Sheideman 		return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p);
36537486Smckusick 	}
36637486Smckusick }
367*54439Smckusick /*
368*54439Smckusick  * Synch buffers associated with a block device
369*54439Smckusick  */
370*54439Smckusick /* ARGSUSED */
371*54439Smckusick int
372*54439Smckusick spec_fsync(ap)
373*54439Smckusick 	struct vop_fsync_args /* {
374*54439Smckusick 		struct vnode *a_vp;
375*54439Smckusick 		struct ucred *a_cred;
376*54439Smckusick 		int  a_waitfor;
377*54439Smckusick 		struct proc *a_p;
378*54439Smckusick 	} */ *ap;
379*54439Smckusick {
380*54439Smckusick 	register struct vnode *vp = ap->a_vp;
381*54439Smckusick 	register struct buf *bp;
382*54439Smckusick 	struct buf *nbp;
383*54439Smckusick 	int s, error, allerror = 0;
38437486Smckusick 
385*54439Smckusick 	if (vp->v_type == VCHR)
386*54439Smckusick 		return (0);
387*54439Smckusick 	/*
388*54439Smckusick 	 * Flush all dirty buffers associated with a block device.
389*54439Smckusick 	 */
390*54439Smckusick loop:
391*54439Smckusick 	s = splbio();
392*54439Smckusick 	for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
393*54439Smckusick 		nbp = bp->b_blockf;
394*54439Smckusick 		if ((bp->b_flags & B_BUSY))
395*54439Smckusick 			continue;
396*54439Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
397*54439Smckusick 			panic("spec_fsync: not dirty");
398*54439Smckusick 		bremfree(bp);
399*54439Smckusick 		bp->b_flags |= B_BUSY;
400*54439Smckusick 		splx(s);
401*54439Smckusick 		if (error = bawrite(bp))
402*54439Smckusick 			allerror = error;
403*54439Smckusick 		goto loop;
404*54439Smckusick 	}
405*54439Smckusick 	if (ap->a_waitfor == MNT_WAIT) {
406*54439Smckusick 		while (vp->v_numoutput) {
407*54439Smckusick 			vp->v_flag |= VBWAIT;
408*54439Smckusick 			sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
409*54439Smckusick 		}
410*54439Smckusick #ifdef DIAGNOSTIC
411*54439Smckusick 		if (vp->v_dirtyblkhd) {
412*54439Smckusick 			vprint("spec_fsync: dirty", vp);
413*54439Smckusick 			goto loop;
414*54439Smckusick 		}
415*54439Smckusick #endif
416*54439Smckusick 	}
417*54439Smckusick 	splx(s);
418*54439Smckusick 	return (allerror);
419*54439Smckusick }
420*54439Smckusick 
42137486Smckusick /*
42237486Smckusick  * Just call the device strategy routine
42337486Smckusick  */
424*54439Smckusick spec_strategy(ap)
425*54439Smckusick 	struct vop_strategy_args /* {
426*54439Smckusick 		struct buf *a_bp;
427*54439Smckusick 	} */ *ap;
42837486Smckusick {
42939666Smckusick 
43053597Sheideman 	(*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp);
43137486Smckusick 	return (0);
43237486Smckusick }
43337486Smckusick 
43439432Smckusick /*
43539666Smckusick  * This is a noop, simply returning what one has been given.
43639666Smckusick  */
437*54439Smckusick spec_bmap(ap)
438*54439Smckusick 	struct vop_bmap_args /* {
439*54439Smckusick 		struct vnode *a_vp;
440*54439Smckusick 		daddr_t  a_bn;
441*54439Smckusick 		struct vnode **a_vpp;
442*54439Smckusick 		daddr_t *a_bnp;
443*54439Smckusick 	} */ *ap;
44439666Smckusick {
44539666Smckusick 
44653597Sheideman 	if (ap->a_vpp != NULL)
44753597Sheideman 		*ap->a_vpp = ap->a_vp;
44853597Sheideman 	if (ap->a_bnp != NULL)
44953597Sheideman 		*ap->a_bnp = ap->a_bn;
45039666Smckusick 	return (0);
45139666Smckusick }
45239666Smckusick 
45339666Smckusick /*
45439432Smckusick  * At the moment we do not do any locking.
45539432Smckusick  */
45639489Smckusick /* ARGSUSED */
457*54439Smckusick spec_lock(ap)
458*54439Smckusick 	struct vop_lock_args /* {
459*54439Smckusick 		struct vnode *a_vp;
460*54439Smckusick 	} */ *ap;
46137486Smckusick {
46237486Smckusick 
46337486Smckusick 	return (0);
46437486Smckusick }
46537486Smckusick 
46639489Smckusick /* ARGSUSED */
467*54439Smckusick spec_unlock(ap)
468*54439Smckusick 	struct vop_unlock_args /* {
469*54439Smckusick 		struct vnode *a_vp;
470*54439Smckusick 	} */ *ap;
47137486Smckusick {
47237486Smckusick 
47337486Smckusick 	return (0);
47437486Smckusick }
47537486Smckusick 
47637486Smckusick /*
47737486Smckusick  * Device close routine
47837486Smckusick  */
47937725Smckusick /* ARGSUSED */
480*54439Smckusick spec_close(ap)
481*54439Smckusick 	struct vop_close_args /* {
482*54439Smckusick 		struct vnode *a_vp;
483*54439Smckusick 		int  a_fflag;
484*54439Smckusick 		struct ucred *a_cred;
485*54439Smckusick 		struct proc *a_p;
486*54439Smckusick 	} */ *ap;
48737486Smckusick {
48853863Sheideman 	register struct vnode *vp = ap->a_vp;
48953863Sheideman 	dev_t dev = vp->v_rdev;
49049273Skarels 	int (*devclose) __P((dev_t, int, int, struct proc *));
491*54439Smckusick 	int mode, error;
49237486Smckusick 
49353863Sheideman 	switch (vp->v_type) {
49437725Smckusick 
49537725Smckusick 	case VCHR:
49639485Smckusick 		/*
49739485Smckusick 		 * If the vnode is locked, then we are in the midst
49839485Smckusick 		 * of forcably closing the device, otherwise we only
49939485Smckusick 		 * close on last reference.
50039485Smckusick 		 */
50153863Sheideman 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
50237725Smckusick 			return (0);
50349273Skarels 		devclose = cdevsw[major(dev)].d_close;
50439432Smckusick 		mode = S_IFCHR;
50537725Smckusick 		break;
50637725Smckusick 
50737725Smckusick 	case VBLK:
50837725Smckusick 		/*
50937725Smckusick 		 * On last close of a block device (that isn't mounted)
51037725Smckusick 		 * we must invalidate any in core blocks, so that
51137725Smckusick 		 * we can, for instance, change floppy disks.
51237725Smckusick 		 */
513*54439Smckusick 		if (error = vinvalbuf(vp, 1, ap->a_cred, ap->a_p))
514*54439Smckusick 			return (error);
51537725Smckusick 		/*
51639485Smckusick 		 * We do not want to really close the device if it
51739485Smckusick 		 * is still in use unless we are trying to close it
51839485Smckusick 		 * forcibly. Since every use (buffer, vnode, swap, cmap)
51939630Smckusick 		 * holds a reference to the vnode, and because we mark
52039630Smckusick 		 * any other vnodes that alias this device, when the
52139630Smckusick 		 * sum of the reference counts on all the aliased
52239630Smckusick 		 * vnodes descends to one, we are on last close.
52337725Smckusick 		 */
52453863Sheideman 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
52537725Smckusick 			return (0);
52649273Skarels 		devclose = bdevsw[major(dev)].d_close;
52739432Smckusick 		mode = S_IFBLK;
52837725Smckusick 		break;
52937725Smckusick 
53037725Smckusick 	default:
53139446Smckusick 		panic("spec_close: not special");
53237725Smckusick 	}
53337725Smckusick 
53453597Sheideman 	return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
53537486Smckusick }
53637486Smckusick 
53737486Smckusick /*
53839666Smckusick  * Print out the contents of a special device vnode.
53939666Smckusick  */
540*54439Smckusick spec_print(ap)
541*54439Smckusick 	struct vop_print_args /* {
542*54439Smckusick 		struct vnode *a_vp;
543*54439Smckusick 	} */ *ap;
54439666Smckusick {
54539666Smckusick 
54653597Sheideman 	printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
54753597Sheideman 		minor(ap->a_vp->v_rdev));
54839666Smckusick }
54939666Smckusick 
55039666Smckusick /*
55146196Smckusick  * Special device advisory byte-level locks.
55246196Smckusick  */
55348015Smckusick /* ARGSUSED */
554*54439Smckusick spec_advlock(ap)
555*54439Smckusick 	struct vop_advlock_args /* {
556*54439Smckusick 		struct vnode *a_vp;
557*54439Smckusick 		caddr_t  a_id;
558*54439Smckusick 		int  a_op;
559*54439Smckusick 		struct flock *a_fl;
560*54439Smckusick 		int  a_flags;
561*54439Smckusick 	} */ *ap;
56246196Smckusick {
56346196Smckusick 
56446196Smckusick 	return (EOPNOTSUPP);
56546196Smckusick }
56646196Smckusick 
56746196Smckusick /*
56839507Smckusick  * Special device failed operation
56937486Smckusick  */
57039507Smckusick spec_ebadf()
57139507Smckusick {
57239507Smckusick 
57339507Smckusick 	return (EBADF);
57439507Smckusick }
57539507Smckusick 
57639507Smckusick /*
57739507Smckusick  * Special device bad operation
57839507Smckusick  */
57939446Smckusick spec_badop()
58037486Smckusick {
58137486Smckusick 
58239446Smckusick 	panic("spec_badop called");
58339292Smckusick 	/* NOTREACHED */
58437486Smckusick }
585