xref: /csrg-svn/sys/miscfs/specfs/spec_vnops.c (revision 47540)
137486Smckusick /*
237486Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337486Smckusick  * All rights reserved.
437486Smckusick  *
544443Sbostic  * %sccs.include.redist.c%
637486Smckusick  *
7*47540Skarels  *	@(#)spec_vnops.c	7.31 (Berkeley) 03/17/91
837486Smckusick  */
937486Smckusick 
1037486Smckusick #include "param.h"
1137486Smckusick #include "systm.h"
1237725Smckusick #include "user.h"
1337725Smckusick #include "kernel.h"
1437486Smckusick #include "conf.h"
1537486Smckusick #include "buf.h"
1639365Smckusick #include "mount.h"
1737486Smckusick #include "vnode.h"
1840652Smckusick #include "specdev.h"
1939432Smckusick #include "stat.h"
2037486Smckusick #include "errno.h"
2139614Smckusick #include "ioctl.h"
2239614Smckusick #include "file.h"
2339614Smckusick #include "disklabel.h"
2437486Smckusick 
2540707Skarels /* symbolic sleep message strings for devices */
2640707Skarels char	devopn[] = "devopn";
2740707Skarels char	devio[] = "devio";
2840707Skarels char	devwait[] = "devwait";
2940707Skarels char	devin[] = "devin";
3040707Skarels char	devout[] = "devout";
3140707Skarels char	devioc[] = "devioc";
3240707Skarels char	devcls[] = "devcls";
3340707Skarels 
3439446Smckusick int	spec_lookup(),
3539446Smckusick 	spec_open(),
3639446Smckusick 	spec_read(),
3739446Smckusick 	spec_write(),
3839446Smckusick 	spec_strategy(),
3939666Smckusick 	spec_bmap(),
4039446Smckusick 	spec_ioctl(),
4139446Smckusick 	spec_select(),
4239446Smckusick 	spec_lock(),
4339446Smckusick 	spec_unlock(),
4439446Smckusick 	spec_close(),
4539666Smckusick 	spec_print(),
4646196Smckusick 	spec_advlock(),
4739507Smckusick 	spec_ebadf(),
48*47540Skarels 	spec_badop();
4937486Smckusick 
50*47540Skarels int	nullop();
51*47540Skarels 
5239446Smckusick struct vnodeops spec_vnodeops = {
5339507Smckusick 	spec_lookup,		/* lookup */
5439507Smckusick 	spec_badop,		/* create */
5539507Smckusick 	spec_badop,		/* mknod */
5639507Smckusick 	spec_open,		/* open */
5739507Smckusick 	spec_close,		/* close */
5839507Smckusick 	spec_ebadf,		/* access */
5939507Smckusick 	spec_ebadf,		/* getattr */
6039507Smckusick 	spec_ebadf,		/* setattr */
6139507Smckusick 	spec_read,		/* read */
6239507Smckusick 	spec_write,		/* write */
6339507Smckusick 	spec_ioctl,		/* ioctl */
6439507Smckusick 	spec_select,		/* select */
6539507Smckusick 	spec_badop,		/* mmap */
66*47540Skarels 	nullop,			/* fsync */
6739507Smckusick 	spec_badop,		/* seek */
6839507Smckusick 	spec_badop,		/* remove */
6939507Smckusick 	spec_badop,		/* link */
7039507Smckusick 	spec_badop,		/* rename */
7139507Smckusick 	spec_badop,		/* mkdir */
7239507Smckusick 	spec_badop,		/* rmdir */
7339507Smckusick 	spec_badop,		/* symlink */
7439507Smckusick 	spec_badop,		/* readdir */
7539507Smckusick 	spec_badop,		/* readlink */
7639507Smckusick 	spec_badop,		/* abortop */
77*47540Skarels 	nullop,			/* inactive */
78*47540Skarels 	nullop,			/* reclaim */
7939507Smckusick 	spec_lock,		/* lock */
8039507Smckusick 	spec_unlock,		/* unlock */
8139666Smckusick 	spec_bmap,		/* bmap */
8239507Smckusick 	spec_strategy,		/* strategy */
8339666Smckusick 	spec_print,		/* print */
84*47540Skarels 	nullop,			/* islocked */
8546196Smckusick 	spec_advlock,		/* advlock */
8637486Smckusick };
8737486Smckusick 
8837486Smckusick /*
8939292Smckusick  * Trivial lookup routine that always fails.
9039292Smckusick  */
9139446Smckusick spec_lookup(vp, ndp)
9239292Smckusick 	struct vnode *vp;
9339292Smckusick 	struct nameidata *ndp;
9439292Smckusick {
9539292Smckusick 
9639292Smckusick 	ndp->ni_dvp = vp;
9739292Smckusick 	ndp->ni_vp = NULL;
9839292Smckusick 	return (ENOTDIR);
9939292Smckusick }
10039292Smckusick 
10139292Smckusick /*
10237486Smckusick  * Open called to allow handler
10337486Smckusick  * of special files to initialize and
10437486Smckusick  * validate before actual IO.
10537486Smckusick  */
10637725Smckusick /* ARGSUSED */
10739446Smckusick spec_open(vp, mode, cred)
10837486Smckusick 	register struct vnode *vp;
10937486Smckusick 	int mode;
11037486Smckusick 	struct ucred *cred;
11137486Smckusick {
112*47540Skarels 	struct proc *p = curproc;		/* XXX */
11337486Smckusick 	dev_t dev = (dev_t)vp->v_rdev;
11437486Smckusick 	register int maj = major(dev);
11540375Smckusick 	int error;
11637486Smckusick 
11741400Smckusick 	if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
11839365Smckusick 		return (ENXIO);
11939365Smckusick 
12037486Smckusick 	switch (vp->v_type) {
12137486Smckusick 
12237486Smckusick 	case VCHR:
12337486Smckusick 		if ((u_int)maj >= nchrdev)
12437486Smckusick 			return (ENXIO);
125*47540Skarels 		return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR, p));
12637486Smckusick 
12737486Smckusick 	case VBLK:
12837486Smckusick 		if ((u_int)maj >= nblkdev)
12937486Smckusick 			return (ENXIO);
13040375Smckusick 		if (error = mountedon(vp))
13140375Smckusick 			return (error);
132*47540Skarels 		return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK, p));
13337486Smckusick 	}
13437486Smckusick 	return (0);
13537486Smckusick }
13637486Smckusick 
13737486Smckusick /*
13837486Smckusick  * Vnode op for read
13937486Smckusick  */
14041961Smckusick /* ARGSUSED */
14139588Smckusick spec_read(vp, uio, ioflag, cred)
14237486Smckusick 	register struct vnode *vp;
14339614Smckusick 	register struct uio *uio;
14437486Smckusick 	int ioflag;
14537486Smckusick 	struct ucred *cred;
14637486Smckusick {
147*47540Skarels 	struct proc *p = curproc;		/* XXX */
14839614Smckusick 	struct buf *bp;
14939614Smckusick 	daddr_t bn;
15039614Smckusick 	long bsize, bscale;
15139614Smckusick 	struct partinfo dpart;
15239614Smckusick 	register int n, on;
15339614Smckusick 	int error = 0;
15439588Smckusick 	extern int mem_no;
15537486Smckusick 
15639588Smckusick 	if (uio->uio_rw != UIO_READ)
15739588Smckusick 		panic("spec_read mode");
15839588Smckusick 	if (uio->uio_resid == 0)
15939588Smckusick 		return (0);
16039588Smckusick 
16139588Smckusick 	switch (vp->v_type) {
16239588Smckusick 
16339588Smckusick 	case VCHR:
16439588Smckusick 		/*
16539588Smckusick 		 * Negative offsets allowed only for /dev/kmem
16639588Smckusick 		 */
16739588Smckusick 		if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
16839588Smckusick 			return (EINVAL);
16939588Smckusick 		VOP_UNLOCK(vp);
17039588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_read)
171*47540Skarels 			(vp->v_rdev, uio, ioflag, p);
17237725Smckusick 		VOP_LOCK(vp);
17339588Smckusick 		return (error);
17439588Smckusick 
17539588Smckusick 	case VBLK:
17639588Smckusick 		if (uio->uio_offset < 0)
17739588Smckusick 			return (EINVAL);
17839614Smckusick 		bsize = BLKDEV_IOSIZE;
17939614Smckusick 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
180*47540Skarels 		    (caddr_t)&dpart, FREAD, p) == 0) {
18139614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
18239614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
18339614Smckusick 				bsize = dpart.part->p_frag *
18439614Smckusick 				    dpart.part->p_fsize;
18539614Smckusick 		}
18639614Smckusick 		bscale = bsize / DEV_BSIZE;
18739614Smckusick 		do {
18839614Smckusick 			bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
18939614Smckusick 			on = uio->uio_offset % bsize;
19039614Smckusick 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
19139614Smckusick 			if (vp->v_lastr + bscale == bn)
19239614Smckusick 				error = breada(vp, bn, (int)bsize, bn + bscale,
19339614Smckusick 					(int)bsize, NOCRED, &bp);
19439614Smckusick 			else
19539614Smckusick 				error = bread(vp, bn, (int)bsize, NOCRED, &bp);
19639614Smckusick 			vp->v_lastr = bn;
19739614Smckusick 			n = MIN(n, bsize - bp->b_resid);
19839614Smckusick 			if (error) {
19939614Smckusick 				brelse(bp);
20039614Smckusick 				return (error);
20139614Smckusick 			}
20239614Smckusick 			error = uiomove(bp->b_un.b_addr + on, n, uio);
20339614Smckusick 			if (n + on == bsize)
20439614Smckusick 				bp->b_flags |= B_AGE;
20539614Smckusick 			brelse(bp);
20639614Smckusick 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
20739614Smckusick 		return (error);
20839588Smckusick 
20939588Smckusick 	default:
21039588Smckusick 		panic("spec_read type");
21139588Smckusick 	}
21239588Smckusick 	/* NOTREACHED */
21337486Smckusick }
21437486Smckusick 
21537486Smckusick /*
21637486Smckusick  * Vnode op for write
21737486Smckusick  */
21841961Smckusick /* ARGSUSED */
21939588Smckusick spec_write(vp, uio, ioflag, cred)
22037486Smckusick 	register struct vnode *vp;
22139614Smckusick 	register struct uio *uio;
22237486Smckusick 	int ioflag;
22337486Smckusick 	struct ucred *cred;
22437486Smckusick {
225*47540Skarels 	struct proc *p = curproc;		/* XXX */
22639614Smckusick 	struct buf *bp;
22739614Smckusick 	daddr_t bn;
22839614Smckusick 	int bsize, blkmask;
22939614Smckusick 	struct partinfo dpart;
23045731Smckusick 	register int n, on;
23145731Smckusick 	int error = 0;
23239588Smckusick 	extern int mem_no;
23337486Smckusick 
23439588Smckusick 	if (uio->uio_rw != UIO_WRITE)
23539588Smckusick 		panic("spec_write mode");
23639588Smckusick 
23739588Smckusick 	switch (vp->v_type) {
23839588Smckusick 
23939588Smckusick 	case VCHR:
24039588Smckusick 		/*
24139588Smckusick 		 * Negative offsets allowed only for /dev/kmem
24239588Smckusick 		 */
24339588Smckusick 		if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
24439588Smckusick 			return (EINVAL);
24539588Smckusick 		VOP_UNLOCK(vp);
24639588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_write)
247*47540Skarels 			(vp->v_rdev, uio, ioflag, p);
24837725Smckusick 		VOP_LOCK(vp);
24939588Smckusick 		return (error);
25039588Smckusick 
25139588Smckusick 	case VBLK:
25239588Smckusick 		if (uio->uio_resid == 0)
25339588Smckusick 			return (0);
25439588Smckusick 		if (uio->uio_offset < 0)
25539588Smckusick 			return (EINVAL);
25639614Smckusick 		bsize = BLKDEV_IOSIZE;
25739614Smckusick 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
258*47540Skarels 		    (caddr_t)&dpart, FREAD, p) == 0) {
25939614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
26039614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
26139614Smckusick 				bsize = dpart.part->p_frag *
26239614Smckusick 				    dpart.part->p_fsize;
26339614Smckusick 		}
26439614Smckusick 		blkmask = (bsize / DEV_BSIZE) - 1;
26539614Smckusick 		do {
26639614Smckusick 			bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
26739614Smckusick 			on = uio->uio_offset % bsize;
26839614Smckusick 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
26939614Smckusick 			if (n == bsize)
27039614Smckusick 				bp = getblk(vp, bn, bsize);
27139614Smckusick 			else
27239614Smckusick 				error = bread(vp, bn, bsize, NOCRED, &bp);
27339614Smckusick 			n = MIN(n, bsize - bp->b_resid);
27439614Smckusick 			if (error) {
27539614Smckusick 				brelse(bp);
27639614Smckusick 				return (error);
27739614Smckusick 			}
27839614Smckusick 			error = uiomove(bp->b_un.b_addr + on, n, uio);
27939614Smckusick 			if (n + on == bsize) {
28039614Smckusick 				bp->b_flags |= B_AGE;
28139614Smckusick 				bawrite(bp);
28239614Smckusick 			} else
28339614Smckusick 				bdwrite(bp);
28439614Smckusick 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
28539614Smckusick 		return (error);
28639588Smckusick 
28739588Smckusick 	default:
28839588Smckusick 		panic("spec_write type");
28939588Smckusick 	}
29039588Smckusick 	/* NOTREACHED */
29137486Smckusick }
29237486Smckusick 
29337486Smckusick /*
29437486Smckusick  * Device ioctl operation.
29537486Smckusick  */
29637725Smckusick /* ARGSUSED */
29739446Smckusick spec_ioctl(vp, com, data, fflag, cred)
29837486Smckusick 	struct vnode *vp;
29939666Smckusick 	int com;
30037486Smckusick 	caddr_t data;
30137486Smckusick 	int fflag;
30237486Smckusick 	struct ucred *cred;
30337486Smckusick {
304*47540Skarels 	struct proc *p = curproc;		/* XXX */
30537725Smckusick 	dev_t dev = vp->v_rdev;
30637486Smckusick 
30737486Smckusick 	switch (vp->v_type) {
30837486Smckusick 
30937486Smckusick 	case VCHR:
310*47540Skarels 		return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data,
311*47540Skarels 		    fflag, p));
31237486Smckusick 
31337486Smckusick 	case VBLK:
31439666Smckusick 		if (com == 0 && (int)data == B_TAPE)
31539666Smckusick 			if (bdevsw[major(dev)].d_flags & B_TAPE)
31639666Smckusick 				return (0);
31739666Smckusick 			else
31839666Smckusick 				return (1);
319*47540Skarels 		return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data,
320*47540Skarels 		   fflag, p));
32137486Smckusick 
32237486Smckusick 	default:
32339446Smckusick 		panic("spec_ioctl");
32437486Smckusick 		/* NOTREACHED */
32537486Smckusick 	}
32637486Smckusick }
32737486Smckusick 
32837725Smckusick /* ARGSUSED */
32940189Smckusick spec_select(vp, which, fflags, cred)
33037486Smckusick 	struct vnode *vp;
33140189Smckusick 	int which, fflags;
33237486Smckusick 	struct ucred *cred;
33337486Smckusick {
334*47540Skarels 	struct proc *p = curproc;		/* XXX */
33537486Smckusick 	register dev_t dev;
33637486Smckusick 
33737486Smckusick 	switch (vp->v_type) {
33837486Smckusick 
33937486Smckusick 	default:
34037486Smckusick 		return (1);		/* XXX */
34137486Smckusick 
34237486Smckusick 	case VCHR:
34337725Smckusick 		dev = vp->v_rdev;
344*47540Skarels 		return (*cdevsw[major(dev)].d_select)(dev, which, p);
34537486Smckusick 	}
34637486Smckusick }
34737486Smckusick 
34837486Smckusick /*
34937486Smckusick  * Just call the device strategy routine
35037486Smckusick  */
35139446Smckusick spec_strategy(bp)
35237486Smckusick 	register struct buf *bp;
35337486Smckusick {
35439666Smckusick 
35537486Smckusick 	(*bdevsw[major(bp->b_dev)].d_strategy)(bp);
35637486Smckusick 	return (0);
35737486Smckusick }
35837486Smckusick 
35939432Smckusick /*
36039666Smckusick  * This is a noop, simply returning what one has been given.
36139666Smckusick  */
36239666Smckusick spec_bmap(vp, bn, vpp, bnp)
36339666Smckusick 	struct vnode *vp;
36439666Smckusick 	daddr_t bn;
36539666Smckusick 	struct vnode **vpp;
36639666Smckusick 	daddr_t *bnp;
36739666Smckusick {
36839666Smckusick 
36939666Smckusick 	if (vpp != NULL)
37039666Smckusick 		*vpp = vp;
37139666Smckusick 	if (bnp != NULL)
37239666Smckusick 		*bnp = bn;
37339666Smckusick 	return (0);
37439666Smckusick }
37539666Smckusick 
37639666Smckusick /*
37739432Smckusick  * At the moment we do not do any locking.
37839432Smckusick  */
37939489Smckusick /* ARGSUSED */
38039446Smckusick spec_lock(vp)
38137486Smckusick 	struct vnode *vp;
38237486Smckusick {
38337486Smckusick 
38437486Smckusick 	return (0);
38537486Smckusick }
38637486Smckusick 
38739489Smckusick /* ARGSUSED */
38839446Smckusick spec_unlock(vp)
38937486Smckusick 	struct vnode *vp;
39037486Smckusick {
39137486Smckusick 
39237486Smckusick 	return (0);
39337486Smckusick }
39437486Smckusick 
39537486Smckusick /*
39637486Smckusick  * Device close routine
39737486Smckusick  */
39837725Smckusick /* ARGSUSED */
39939446Smckusick spec_close(vp, flag, cred)
40037725Smckusick 	register struct vnode *vp;
40137486Smckusick 	int flag;
40237486Smckusick 	struct ucred *cred;
40337486Smckusick {
404*47540Skarels 	struct proc *p = curproc;		/* XXX */
40537486Smckusick 	dev_t dev = vp->v_rdev;
40637725Smckusick 	int (*cfunc)();
40740707Skarels 	int mode;
40837486Smckusick 
40937725Smckusick 	switch (vp->v_type) {
41037725Smckusick 
41137725Smckusick 	case VCHR:
41239485Smckusick 		/*
41339485Smckusick 		 * If the vnode is locked, then we are in the midst
41439485Smckusick 		 * of forcably closing the device, otherwise we only
41539485Smckusick 		 * close on last reference.
41639485Smckusick 		 */
41739630Smckusick 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
41837725Smckusick 			return (0);
41937725Smckusick 		cfunc = cdevsw[major(dev)].d_close;
42039432Smckusick 		mode = S_IFCHR;
42137725Smckusick 		break;
42237725Smckusick 
42337725Smckusick 	case VBLK:
42437725Smckusick 		/*
42537725Smckusick 		 * On last close of a block device (that isn't mounted)
42637725Smckusick 		 * we must invalidate any in core blocks, so that
42737725Smckusick 		 * we can, for instance, change floppy disks.
42837725Smckusick 		 */
42939666Smckusick 		vflushbuf(vp, 0);
43039666Smckusick 		if (vinvalbuf(vp, 1))
43138613Smckusick 			return (0);
43237725Smckusick 		/*
43339485Smckusick 		 * We do not want to really close the device if it
43439485Smckusick 		 * is still in use unless we are trying to close it
43539485Smckusick 		 * forcibly. Since every use (buffer, vnode, swap, cmap)
43639630Smckusick 		 * holds a reference to the vnode, and because we mark
43739630Smckusick 		 * any other vnodes that alias this device, when the
43839630Smckusick 		 * sum of the reference counts on all the aliased
43939630Smckusick 		 * vnodes descends to one, we are on last close.
44037725Smckusick 		 */
44139630Smckusick 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
44237725Smckusick 			return (0);
44337725Smckusick 		cfunc = bdevsw[major(dev)].d_close;
44439432Smckusick 		mode = S_IFBLK;
44537725Smckusick 		break;
44637725Smckusick 
44737725Smckusick 	default:
44839446Smckusick 		panic("spec_close: not special");
44937725Smckusick 	}
45037725Smckusick 
451*47540Skarels 	return ((*cfunc)(dev, flag, mode, p));
45237486Smckusick }
45337486Smckusick 
45437486Smckusick /*
45539666Smckusick  * Print out the contents of a special device vnode.
45639666Smckusick  */
45739666Smckusick spec_print(vp)
45839666Smckusick 	struct vnode *vp;
45939666Smckusick {
46039666Smckusick 
46139666Smckusick 	printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev),
46239666Smckusick 		minor(vp->v_rdev));
46339666Smckusick }
46439666Smckusick 
46539666Smckusick /*
46646196Smckusick  * Special device advisory byte-level locks.
46746196Smckusick  */
46846196Smckusick spec_advlock(vp, id, op, fl, flags)
46946196Smckusick 	struct vnode *vp;
47046196Smckusick 	caddr_t id;
47146196Smckusick 	int op;
47246196Smckusick 	struct flock *fl;
47346196Smckusick 	int flags;
47446196Smckusick {
47546196Smckusick 
47646196Smckusick 	return (EOPNOTSUPP);
47746196Smckusick }
47846196Smckusick 
47946196Smckusick /*
48039507Smckusick  * Special device failed operation
48137486Smckusick  */
48239507Smckusick spec_ebadf()
48339507Smckusick {
48439507Smckusick 
48539507Smckusick 	return (EBADF);
48639507Smckusick }
48739507Smckusick 
48839507Smckusick /*
48939507Smckusick  * Special device bad operation
49039507Smckusick  */
49139446Smckusick spec_badop()
49237486Smckusick {
49337486Smckusick 
49439446Smckusick 	panic("spec_badop called");
49539292Smckusick 	/* NOTREACHED */
49637486Smckusick }
497