xref: /csrg-svn/sys/miscfs/specfs/spec_vnops.c (revision 49944)
137486Smckusick /*
237486Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337486Smckusick  * All rights reserved.
437486Smckusick  *
544443Sbostic  * %sccs.include.redist.c%
637486Smckusick  *
7*49944Smckusick  *	@(#)spec_vnops.c	7.37 (Berkeley) 05/30/91
837486Smckusick  */
937486Smckusick 
1037486Smckusick #include "param.h"
1147649Skarels #include "proc.h"
1237486Smckusick #include "systm.h"
1337725Smckusick #include "kernel.h"
1437486Smckusick #include "conf.h"
1537486Smckusick #include "buf.h"
1639365Smckusick #include "mount.h"
1748015Smckusick #include "namei.h"
1837486Smckusick #include "vnode.h"
1940652Smckusick #include "specdev.h"
2039432Smckusick #include "stat.h"
2137486Smckusick #include "errno.h"
2239614Smckusick #include "ioctl.h"
2339614Smckusick #include "file.h"
2439614Smckusick #include "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 
3539446Smckusick struct vnodeops spec_vnodeops = {
3639507Smckusick 	spec_lookup,		/* lookup */
3748015Smckusick 	spec_create,		/* create */
3848015Smckusick 	spec_mknod,		/* mknod */
3939507Smckusick 	spec_open,		/* open */
4039507Smckusick 	spec_close,		/* close */
4148015Smckusick 	spec_access,		/* access */
4248015Smckusick 	spec_getattr,		/* getattr */
4348015Smckusick 	spec_setattr,		/* setattr */
4439507Smckusick 	spec_read,		/* read */
4539507Smckusick 	spec_write,		/* write */
4639507Smckusick 	spec_ioctl,		/* ioctl */
4739507Smckusick 	spec_select,		/* select */
4848015Smckusick 	spec_mmap,		/* mmap */
4948015Smckusick 	spec_fsync,		/* fsync */
5048015Smckusick 	spec_seek,		/* seek */
5148015Smckusick 	spec_remove,		/* remove */
5248015Smckusick 	spec_link,		/* link */
5348015Smckusick 	spec_rename,		/* rename */
5448015Smckusick 	spec_mkdir,		/* mkdir */
5548015Smckusick 	spec_rmdir,		/* rmdir */
5648015Smckusick 	spec_symlink,		/* symlink */
5748015Smckusick 	spec_readdir,		/* readdir */
5848015Smckusick 	spec_readlink,		/* readlink */
5948015Smckusick 	spec_abortop,		/* abortop */
6048015Smckusick 	spec_inactive,		/* inactive */
6148015Smckusick 	spec_reclaim,		/* reclaim */
6239507Smckusick 	spec_lock,		/* lock */
6339507Smckusick 	spec_unlock,		/* unlock */
6439666Smckusick 	spec_bmap,		/* bmap */
6539507Smckusick 	spec_strategy,		/* strategy */
6639666Smckusick 	spec_print,		/* print */
6748015Smckusick 	spec_islocked,		/* islocked */
6846196Smckusick 	spec_advlock,		/* advlock */
6937486Smckusick };
7037486Smckusick 
7137486Smckusick /*
7239292Smckusick  * Trivial lookup routine that always fails.
7339292Smckusick  */
7448015Smckusick spec_lookup(vp, ndp, p)
7539292Smckusick 	struct vnode *vp;
7639292Smckusick 	struct nameidata *ndp;
7748015Smckusick 	struct proc *p;
7839292Smckusick {
7939292Smckusick 
8039292Smckusick 	ndp->ni_dvp = vp;
8139292Smckusick 	ndp->ni_vp = NULL;
8239292Smckusick 	return (ENOTDIR);
8339292Smckusick }
8439292Smckusick 
8539292Smckusick /*
8649273Skarels  * Open a special file: Don't allow open if fs is mounted -nodev,
8749273Skarels  * and don't allow opens of block devices that are currently mounted.
8849273Skarels  * Otherwise, call device driver open function.
8937486Smckusick  */
9037725Smckusick /* ARGSUSED */
9148015Smckusick spec_open(vp, mode, cred, p)
9237486Smckusick 	register struct vnode *vp;
9337486Smckusick 	int mode;
9437486Smckusick 	struct ucred *cred;
9548015Smckusick 	struct proc *p;
9637486Smckusick {
9737486Smckusick 	dev_t dev = (dev_t)vp->v_rdev;
9837486Smckusick 	register int maj = major(dev);
9940375Smckusick 	int error;
10037486Smckusick 
10141400Smckusick 	if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
10239365Smckusick 		return (ENXIO);
10339365Smckusick 
10437486Smckusick 	switch (vp->v_type) {
10537486Smckusick 
10637486Smckusick 	case VCHR:
10737486Smckusick 		if ((u_int)maj >= nchrdev)
10837486Smckusick 			return (ENXIO);
109*49944Smckusick 		VOP_UNLOCK(vp);
110*49944Smckusick 		error = (*cdevsw[maj].d_open)(dev, mode, S_IFCHR, p);
111*49944Smckusick 		VOP_LOCK(vp);
112*49944Smckusick 		return (error);
11337486Smckusick 
11437486Smckusick 	case VBLK:
11537486Smckusick 		if ((u_int)maj >= nblkdev)
11637486Smckusick 			return (ENXIO);
11740375Smckusick 		if (error = mountedon(vp))
11840375Smckusick 			return (error);
11947540Skarels 		return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK, p));
12037486Smckusick 	}
12137486Smckusick 	return (0);
12237486Smckusick }
12337486Smckusick 
12437486Smckusick /*
12537486Smckusick  * Vnode op for read
12637486Smckusick  */
12741961Smckusick /* ARGSUSED */
12839588Smckusick spec_read(vp, uio, ioflag, cred)
12937486Smckusick 	register struct vnode *vp;
13039614Smckusick 	register struct uio *uio;
13137486Smckusick 	int ioflag;
13237486Smckusick 	struct ucred *cred;
13337486Smckusick {
13448015Smckusick 	struct proc *p = uio->uio_procp;
13539614Smckusick 	struct buf *bp;
13639614Smckusick 	daddr_t bn;
13739614Smckusick 	long bsize, bscale;
13839614Smckusick 	struct partinfo dpart;
13939614Smckusick 	register int n, on;
14039614Smckusick 	int error = 0;
14139588Smckusick 	extern int mem_no;
14237486Smckusick 
14348015Smckusick #ifdef DIAGNOSTIC
14439588Smckusick 	if (uio->uio_rw != UIO_READ)
14539588Smckusick 		panic("spec_read mode");
14648015Smckusick 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
14748015Smckusick 		panic("spec_read proc");
14848015Smckusick #endif
14939588Smckusick 	if (uio->uio_resid == 0)
15039588Smckusick 		return (0);
15139588Smckusick 
15239588Smckusick 	switch (vp->v_type) {
15339588Smckusick 
15439588Smckusick 	case VCHR:
15539588Smckusick 		/*
15639588Smckusick 		 * Negative offsets allowed only for /dev/kmem
15739588Smckusick 		 */
15839588Smckusick 		if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
15939588Smckusick 			return (EINVAL);
16039588Smckusick 		VOP_UNLOCK(vp);
16139588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_read)
16249121Skarels 			(vp->v_rdev, uio, ioflag);
16337725Smckusick 		VOP_LOCK(vp);
16439588Smckusick 		return (error);
16539588Smckusick 
16639588Smckusick 	case VBLK:
16739588Smckusick 		if (uio->uio_offset < 0)
16839588Smckusick 			return (EINVAL);
16939614Smckusick 		bsize = BLKDEV_IOSIZE;
17039614Smckusick 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
17147540Skarels 		    (caddr_t)&dpart, FREAD, p) == 0) {
17239614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
17339614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
17439614Smckusick 				bsize = dpart.part->p_frag *
17539614Smckusick 				    dpart.part->p_fsize;
17639614Smckusick 		}
17739614Smckusick 		bscale = bsize / DEV_BSIZE;
17839614Smckusick 		do {
17939614Smckusick 			bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
18039614Smckusick 			on = uio->uio_offset % bsize;
18139614Smckusick 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
18239614Smckusick 			if (vp->v_lastr + bscale == bn)
18339614Smckusick 				error = breada(vp, bn, (int)bsize, bn + bscale,
18439614Smckusick 					(int)bsize, NOCRED, &bp);
18539614Smckusick 			else
18639614Smckusick 				error = bread(vp, bn, (int)bsize, NOCRED, &bp);
18739614Smckusick 			vp->v_lastr = bn;
18839614Smckusick 			n = MIN(n, bsize - bp->b_resid);
18939614Smckusick 			if (error) {
19039614Smckusick 				brelse(bp);
19139614Smckusick 				return (error);
19239614Smckusick 			}
19339614Smckusick 			error = uiomove(bp->b_un.b_addr + on, n, uio);
19439614Smckusick 			if (n + on == bsize)
19539614Smckusick 				bp->b_flags |= B_AGE;
19639614Smckusick 			brelse(bp);
19739614Smckusick 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
19839614Smckusick 		return (error);
19939588Smckusick 
20039588Smckusick 	default:
20139588Smckusick 		panic("spec_read type");
20239588Smckusick 	}
20339588Smckusick 	/* NOTREACHED */
20437486Smckusick }
20537486Smckusick 
20637486Smckusick /*
20737486Smckusick  * Vnode op for write
20837486Smckusick  */
20941961Smckusick /* ARGSUSED */
21039588Smckusick spec_write(vp, uio, ioflag, cred)
21137486Smckusick 	register struct vnode *vp;
21239614Smckusick 	register struct uio *uio;
21337486Smckusick 	int ioflag;
21437486Smckusick 	struct ucred *cred;
21537486Smckusick {
21648015Smckusick 	struct proc *p = uio->uio_procp;
21739614Smckusick 	struct buf *bp;
21839614Smckusick 	daddr_t bn;
21939614Smckusick 	int bsize, blkmask;
22039614Smckusick 	struct partinfo dpart;
22145731Smckusick 	register int n, on;
22245731Smckusick 	int error = 0;
22339588Smckusick 	extern int mem_no;
22437486Smckusick 
22548015Smckusick #ifdef DIAGNOSTIC
22639588Smckusick 	if (uio->uio_rw != UIO_WRITE)
22739588Smckusick 		panic("spec_write mode");
22848015Smckusick 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
22948015Smckusick 		panic("spec_write proc");
23048015Smckusick #endif
23139588Smckusick 
23239588Smckusick 	switch (vp->v_type) {
23339588Smckusick 
23439588Smckusick 	case VCHR:
23539588Smckusick 		/*
23639588Smckusick 		 * Negative offsets allowed only for /dev/kmem
23739588Smckusick 		 */
23839588Smckusick 		if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
23939588Smckusick 			return (EINVAL);
24039588Smckusick 		VOP_UNLOCK(vp);
24139588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_write)
24249121Skarels 			(vp->v_rdev, uio, ioflag);
24337725Smckusick 		VOP_LOCK(vp);
24439588Smckusick 		return (error);
24539588Smckusick 
24639588Smckusick 	case VBLK:
24739588Smckusick 		if (uio->uio_resid == 0)
24839588Smckusick 			return (0);
24939588Smckusick 		if (uio->uio_offset < 0)
25039588Smckusick 			return (EINVAL);
25139614Smckusick 		bsize = BLKDEV_IOSIZE;
25239614Smckusick 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
25347540Skarels 		    (caddr_t)&dpart, FREAD, p) == 0) {
25439614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
25539614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
25639614Smckusick 				bsize = dpart.part->p_frag *
25739614Smckusick 				    dpart.part->p_fsize;
25839614Smckusick 		}
25939614Smckusick 		blkmask = (bsize / DEV_BSIZE) - 1;
26039614Smckusick 		do {
26139614Smckusick 			bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
26239614Smckusick 			on = uio->uio_offset % bsize;
26339614Smckusick 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
26439614Smckusick 			if (n == bsize)
26539614Smckusick 				bp = getblk(vp, bn, bsize);
26639614Smckusick 			else
26739614Smckusick 				error = bread(vp, bn, bsize, NOCRED, &bp);
26839614Smckusick 			n = MIN(n, bsize - bp->b_resid);
26939614Smckusick 			if (error) {
27039614Smckusick 				brelse(bp);
27139614Smckusick 				return (error);
27239614Smckusick 			}
27339614Smckusick 			error = uiomove(bp->b_un.b_addr + on, n, uio);
27439614Smckusick 			if (n + on == bsize) {
27539614Smckusick 				bp->b_flags |= B_AGE;
27639614Smckusick 				bawrite(bp);
27739614Smckusick 			} else
27839614Smckusick 				bdwrite(bp);
27939614Smckusick 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
28039614Smckusick 		return (error);
28139588Smckusick 
28239588Smckusick 	default:
28339588Smckusick 		panic("spec_write type");
28439588Smckusick 	}
28539588Smckusick 	/* NOTREACHED */
28637486Smckusick }
28737486Smckusick 
28837486Smckusick /*
28937486Smckusick  * Device ioctl operation.
29037486Smckusick  */
29137725Smckusick /* ARGSUSED */
29248015Smckusick spec_ioctl(vp, com, data, fflag, cred, p)
29337486Smckusick 	struct vnode *vp;
29439666Smckusick 	int com;
29537486Smckusick 	caddr_t data;
29637486Smckusick 	int fflag;
29737486Smckusick 	struct ucred *cred;
29848015Smckusick 	struct proc *p;
29937486Smckusick {
30037725Smckusick 	dev_t dev = vp->v_rdev;
30137486Smckusick 
30237486Smckusick 	switch (vp->v_type) {
30337486Smckusick 
30437486Smckusick 	case VCHR:
30547540Skarels 		return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data,
30647540Skarels 		    fflag, p));
30737486Smckusick 
30837486Smckusick 	case VBLK:
30939666Smckusick 		if (com == 0 && (int)data == B_TAPE)
31039666Smckusick 			if (bdevsw[major(dev)].d_flags & B_TAPE)
31139666Smckusick 				return (0);
31239666Smckusick 			else
31339666Smckusick 				return (1);
31447540Skarels 		return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data,
31547540Skarels 		   fflag, p));
31637486Smckusick 
31737486Smckusick 	default:
31839446Smckusick 		panic("spec_ioctl");
31937486Smckusick 		/* NOTREACHED */
32037486Smckusick 	}
32137486Smckusick }
32237486Smckusick 
32337725Smckusick /* ARGSUSED */
32448015Smckusick spec_select(vp, which, fflags, cred, p)
32537486Smckusick 	struct vnode *vp;
32640189Smckusick 	int which, fflags;
32737486Smckusick 	struct ucred *cred;
32848015Smckusick 	struct proc *p;
32937486Smckusick {
33037486Smckusick 	register dev_t dev;
33137486Smckusick 
33237486Smckusick 	switch (vp->v_type) {
33337486Smckusick 
33437486Smckusick 	default:
33537486Smckusick 		return (1);		/* XXX */
33637486Smckusick 
33737486Smckusick 	case VCHR:
33837725Smckusick 		dev = vp->v_rdev;
33947540Skarels 		return (*cdevsw[major(dev)].d_select)(dev, which, p);
34037486Smckusick 	}
34137486Smckusick }
34237486Smckusick 
34337486Smckusick /*
34437486Smckusick  * Just call the device strategy routine
34537486Smckusick  */
34639446Smckusick spec_strategy(bp)
34737486Smckusick 	register struct buf *bp;
34837486Smckusick {
34939666Smckusick 
35037486Smckusick 	(*bdevsw[major(bp->b_dev)].d_strategy)(bp);
35137486Smckusick 	return (0);
35237486Smckusick }
35337486Smckusick 
35439432Smckusick /*
35539666Smckusick  * This is a noop, simply returning what one has been given.
35639666Smckusick  */
35739666Smckusick spec_bmap(vp, bn, vpp, bnp)
35839666Smckusick 	struct vnode *vp;
35939666Smckusick 	daddr_t bn;
36039666Smckusick 	struct vnode **vpp;
36139666Smckusick 	daddr_t *bnp;
36239666Smckusick {
36339666Smckusick 
36439666Smckusick 	if (vpp != NULL)
36539666Smckusick 		*vpp = vp;
36639666Smckusick 	if (bnp != NULL)
36739666Smckusick 		*bnp = bn;
36839666Smckusick 	return (0);
36939666Smckusick }
37039666Smckusick 
37139666Smckusick /*
37239432Smckusick  * At the moment we do not do any locking.
37339432Smckusick  */
37439489Smckusick /* ARGSUSED */
37539446Smckusick spec_lock(vp)
37637486Smckusick 	struct vnode *vp;
37737486Smckusick {
37837486Smckusick 
37937486Smckusick 	return (0);
38037486Smckusick }
38137486Smckusick 
38239489Smckusick /* ARGSUSED */
38339446Smckusick spec_unlock(vp)
38437486Smckusick 	struct vnode *vp;
38537486Smckusick {
38637486Smckusick 
38737486Smckusick 	return (0);
38837486Smckusick }
38937486Smckusick 
39037486Smckusick /*
39137486Smckusick  * Device close routine
39237486Smckusick  */
39337725Smckusick /* ARGSUSED */
39448015Smckusick spec_close(vp, flag, cred, p)
39537725Smckusick 	register struct vnode *vp;
39637486Smckusick 	int flag;
39737486Smckusick 	struct ucred *cred;
39848015Smckusick 	struct proc *p;
39937486Smckusick {
40037486Smckusick 	dev_t dev = vp->v_rdev;
40149273Skarels 	int (*devclose) __P((dev_t, int, int, struct proc *));
40240707Skarels 	int mode;
40337486Smckusick 
40437725Smckusick 	switch (vp->v_type) {
40537725Smckusick 
40637725Smckusick 	case VCHR:
40739485Smckusick 		/*
40839485Smckusick 		 * If the vnode is locked, then we are in the midst
40939485Smckusick 		 * of forcably closing the device, otherwise we only
41039485Smckusick 		 * close on last reference.
41139485Smckusick 		 */
41239630Smckusick 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
41337725Smckusick 			return (0);
41449273Skarels 		devclose = cdevsw[major(dev)].d_close;
41539432Smckusick 		mode = S_IFCHR;
41637725Smckusick 		break;
41737725Smckusick 
41837725Smckusick 	case VBLK:
41937725Smckusick 		/*
42037725Smckusick 		 * On last close of a block device (that isn't mounted)
42137725Smckusick 		 * we must invalidate any in core blocks, so that
42237725Smckusick 		 * we can, for instance, change floppy disks.
42337725Smckusick 		 */
42439666Smckusick 		vflushbuf(vp, 0);
42539666Smckusick 		if (vinvalbuf(vp, 1))
42638613Smckusick 			return (0);
42737725Smckusick 		/*
42839485Smckusick 		 * We do not want to really close the device if it
42939485Smckusick 		 * is still in use unless we are trying to close it
43039485Smckusick 		 * forcibly. Since every use (buffer, vnode, swap, cmap)
43139630Smckusick 		 * holds a reference to the vnode, and because we mark
43239630Smckusick 		 * any other vnodes that alias this device, when the
43339630Smckusick 		 * sum of the reference counts on all the aliased
43439630Smckusick 		 * vnodes descends to one, we are on last close.
43537725Smckusick 		 */
43639630Smckusick 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
43737725Smckusick 			return (0);
43849273Skarels 		devclose = bdevsw[major(dev)].d_close;
43939432Smckusick 		mode = S_IFBLK;
44037725Smckusick 		break;
44137725Smckusick 
44237725Smckusick 	default:
44339446Smckusick 		panic("spec_close: not special");
44437725Smckusick 	}
44537725Smckusick 
44649273Skarels 	return ((*devclose)(dev, flag, mode, p));
44737486Smckusick }
44837486Smckusick 
44937486Smckusick /*
45039666Smckusick  * Print out the contents of a special device vnode.
45139666Smckusick  */
45239666Smckusick spec_print(vp)
45339666Smckusick 	struct vnode *vp;
45439666Smckusick {
45539666Smckusick 
45639666Smckusick 	printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev),
45739666Smckusick 		minor(vp->v_rdev));
45839666Smckusick }
45939666Smckusick 
46039666Smckusick /*
46146196Smckusick  * Special device advisory byte-level locks.
46246196Smckusick  */
46348015Smckusick /* ARGSUSED */
46446196Smckusick spec_advlock(vp, id, op, fl, flags)
46546196Smckusick 	struct vnode *vp;
46646196Smckusick 	caddr_t id;
46746196Smckusick 	int op;
46846196Smckusick 	struct flock *fl;
46946196Smckusick 	int flags;
47046196Smckusick {
47146196Smckusick 
47246196Smckusick 	return (EOPNOTSUPP);
47346196Smckusick }
47446196Smckusick 
47546196Smckusick /*
47639507Smckusick  * Special device failed operation
47737486Smckusick  */
47839507Smckusick spec_ebadf()
47939507Smckusick {
48039507Smckusick 
48139507Smckusick 	return (EBADF);
48239507Smckusick }
48339507Smckusick 
48439507Smckusick /*
48539507Smckusick  * Special device bad operation
48639507Smckusick  */
48739446Smckusick spec_badop()
48837486Smckusick {
48937486Smckusick 
49039446Smckusick 	panic("spec_badop called");
49139292Smckusick 	/* NOTREACHED */
49237486Smckusick }
493