xref: /csrg-svn/sys/miscfs/specfs/spec_vnops.c (revision 40375)
137486Smckusick /*
237486Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337486Smckusick  * All rights reserved.
437486Smckusick  *
537486Smckusick  * Redistribution and use in source and binary forms are permitted
637486Smckusick  * provided that the above copyright notice and this paragraph are
737486Smckusick  * duplicated in all such forms and that any documentation,
837486Smckusick  * advertising materials, and other materials related to such
937486Smckusick  * distribution and use acknowledge that the software was developed
1037486Smckusick  * by the University of California, Berkeley.  The name of the
1137486Smckusick  * University may not be used to endorse or promote products derived
1237486Smckusick  * from this software without specific prior written permission.
1337486Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437486Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537486Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637486Smckusick  *
17*40375Smckusick  *	@(#)spec_vnops.c	7.23 (Berkeley) 03/09/90
1837486Smckusick  */
1937486Smckusick 
2037486Smckusick #include "param.h"
2137486Smckusick #include "systm.h"
2237725Smckusick #include "user.h"
2337725Smckusick #include "kernel.h"
2437486Smckusick #include "conf.h"
2537486Smckusick #include "buf.h"
2639365Smckusick #include "mount.h"
2737486Smckusick #include "vnode.h"
2839432Smckusick #include "stat.h"
2937486Smckusick #include "errno.h"
3039614Smckusick #include "ioctl.h"
3139614Smckusick #include "file.h"
3239614Smckusick #include "disklabel.h"
3337486Smckusick 
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(),
4639507Smckusick 	spec_ebadf(),
4739446Smckusick 	spec_badop(),
4839446Smckusick 	spec_nullop();
4937486Smckusick 
5039446Smckusick struct vnodeops spec_vnodeops = {
5139507Smckusick 	spec_lookup,		/* lookup */
5239507Smckusick 	spec_badop,		/* create */
5339507Smckusick 	spec_badop,		/* mknod */
5439507Smckusick 	spec_open,		/* open */
5539507Smckusick 	spec_close,		/* close */
5639507Smckusick 	spec_ebadf,		/* access */
5739507Smckusick 	spec_ebadf,		/* getattr */
5839507Smckusick 	spec_ebadf,		/* setattr */
5939507Smckusick 	spec_read,		/* read */
6039507Smckusick 	spec_write,		/* write */
6139507Smckusick 	spec_ioctl,		/* ioctl */
6239507Smckusick 	spec_select,		/* select */
6339507Smckusick 	spec_badop,		/* mmap */
6439507Smckusick 	spec_nullop,		/* fsync */
6539507Smckusick 	spec_badop,		/* seek */
6639507Smckusick 	spec_badop,		/* remove */
6739507Smckusick 	spec_badop,		/* link */
6839507Smckusick 	spec_badop,		/* rename */
6939507Smckusick 	spec_badop,		/* mkdir */
7039507Smckusick 	spec_badop,		/* rmdir */
7139507Smckusick 	spec_badop,		/* symlink */
7239507Smckusick 	spec_badop,		/* readdir */
7339507Smckusick 	spec_badop,		/* readlink */
7439507Smckusick 	spec_badop,		/* abortop */
7539507Smckusick 	spec_nullop,		/* inactive */
7639507Smckusick 	spec_nullop,		/* reclaim */
7739507Smckusick 	spec_lock,		/* lock */
7839507Smckusick 	spec_unlock,		/* unlock */
7939666Smckusick 	spec_bmap,		/* bmap */
8039507Smckusick 	spec_strategy,		/* strategy */
8139666Smckusick 	spec_print,		/* print */
8239912Smckusick 	spec_nullop,		/* islocked */
8337486Smckusick };
8437486Smckusick 
8537486Smckusick /*
8639292Smckusick  * Trivial lookup routine that always fails.
8739292Smckusick  */
8839446Smckusick spec_lookup(vp, ndp)
8939292Smckusick 	struct vnode *vp;
9039292Smckusick 	struct nameidata *ndp;
9139292Smckusick {
9239292Smckusick 
9339292Smckusick 	ndp->ni_dvp = vp;
9439292Smckusick 	ndp->ni_vp = NULL;
9539292Smckusick 	return (ENOTDIR);
9639292Smckusick }
9739292Smckusick 
9839292Smckusick /*
9937486Smckusick  * Open called to allow handler
10037486Smckusick  * of special files to initialize and
10137486Smckusick  * validate before actual IO.
10237486Smckusick  */
10337725Smckusick /* ARGSUSED */
10439446Smckusick spec_open(vp, mode, cred)
10537486Smckusick 	register struct vnode *vp;
10637486Smckusick 	int mode;
10737486Smckusick 	struct ucred *cred;
10837486Smckusick {
10937486Smckusick 	dev_t dev = (dev_t)vp->v_rdev;
11037486Smckusick 	register int maj = major(dev);
111*40375Smckusick 	int error;
11237486Smckusick 
11339365Smckusick 	if (vp->v_mount && (vp->v_mount->m_flag & M_NODEV))
11439365Smckusick 		return (ENXIO);
11539365Smckusick 
11637486Smckusick 	switch (vp->v_type) {
11737486Smckusick 
11837486Smckusick 	case VCHR:
11937486Smckusick 		if ((u_int)maj >= nchrdev)
12037486Smckusick 			return (ENXIO);
12139432Smckusick 		return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR));
12237486Smckusick 
12337486Smckusick 	case VBLK:
12437486Smckusick 		if ((u_int)maj >= nblkdev)
12537486Smckusick 			return (ENXIO);
126*40375Smckusick 		if (error = mountedon(vp))
127*40375Smckusick 			return (error);
12839432Smckusick 		return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK));
12937486Smckusick 	}
13037486Smckusick 	return (0);
13137486Smckusick }
13237486Smckusick 
13337486Smckusick /*
13437486Smckusick  * Vnode op for read
13537486Smckusick  */
13639588Smckusick spec_read(vp, uio, ioflag, cred)
13737486Smckusick 	register struct vnode *vp;
13839614Smckusick 	register struct uio *uio;
13937486Smckusick 	int ioflag;
14037486Smckusick 	struct ucred *cred;
14137486Smckusick {
14239614Smckusick 	struct buf *bp;
14339614Smckusick 	daddr_t bn;
14439614Smckusick 	long bsize, bscale;
14539614Smckusick 	struct partinfo dpart;
14639614Smckusick 	register int n, on;
14739614Smckusick 	int error = 0;
14839588Smckusick 	extern int mem_no;
14937486Smckusick 
15039588Smckusick 	if (uio->uio_rw != UIO_READ)
15139588Smckusick 		panic("spec_read mode");
15239588Smckusick 	if (uio->uio_resid == 0)
15339588Smckusick 		return (0);
15439588Smckusick 
15539588Smckusick 	switch (vp->v_type) {
15639588Smckusick 
15739588Smckusick 	case VCHR:
15839588Smckusick 		/*
15939588Smckusick 		 * Negative offsets allowed only for /dev/kmem
16039588Smckusick 		 */
16139588Smckusick 		if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
16239588Smckusick 			return (EINVAL);
16339588Smckusick 		VOP_UNLOCK(vp);
16439588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_read)
16539588Smckusick 			(vp->v_rdev, uio, ioflag);
16637725Smckusick 		VOP_LOCK(vp);
16739588Smckusick 		return (error);
16839588Smckusick 
16939588Smckusick 	case VBLK:
17039588Smckusick 		if (uio->uio_offset < 0)
17139588Smckusick 			return (EINVAL);
17239614Smckusick 		bsize = BLKDEV_IOSIZE;
17339614Smckusick 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
17439614Smckusick 		    (caddr_t)&dpart, FREAD) == 0) {
17539614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
17639614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
17739614Smckusick 				bsize = dpart.part->p_frag *
17839614Smckusick 				    dpart.part->p_fsize;
17939614Smckusick 		}
18039614Smckusick 		bscale = bsize / DEV_BSIZE;
18139614Smckusick 		do {
18239614Smckusick 			bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
18339614Smckusick 			on = uio->uio_offset % bsize;
18439614Smckusick 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
18539614Smckusick 			if (vp->v_lastr + bscale == bn)
18639614Smckusick 				error = breada(vp, bn, (int)bsize, bn + bscale,
18739614Smckusick 					(int)bsize, NOCRED, &bp);
18839614Smckusick 			else
18939614Smckusick 				error = bread(vp, bn, (int)bsize, NOCRED, &bp);
19039614Smckusick 			vp->v_lastr = bn;
19139614Smckusick 			n = MIN(n, bsize - bp->b_resid);
19239614Smckusick 			if (error) {
19339614Smckusick 				brelse(bp);
19439614Smckusick 				return (error);
19539614Smckusick 			}
19639614Smckusick 			error = uiomove(bp->b_un.b_addr + on, n, uio);
19739614Smckusick 			if (n + on == bsize)
19839614Smckusick 				bp->b_flags |= B_AGE;
19939614Smckusick 			brelse(bp);
20039614Smckusick 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
20139614Smckusick 		return (error);
20239588Smckusick 
20339588Smckusick 	default:
20439588Smckusick 		panic("spec_read type");
20539588Smckusick 	}
20639588Smckusick 	/* NOTREACHED */
20737486Smckusick }
20837486Smckusick 
20937486Smckusick /*
21037486Smckusick  * Vnode op for write
21137486Smckusick  */
21239588Smckusick spec_write(vp, uio, ioflag, cred)
21337486Smckusick 	register struct vnode *vp;
21439614Smckusick 	register struct uio *uio;
21537486Smckusick 	int ioflag;
21637486Smckusick 	struct ucred *cred;
21737486Smckusick {
21839614Smckusick 	struct buf *bp;
21939614Smckusick 	daddr_t bn;
22039614Smckusick 	int bsize, blkmask;
22139614Smckusick 	struct partinfo dpart;
22239614Smckusick 	register int n, on, i;
22339614Smckusick 	int count, error = 0;
22439588Smckusick 	extern int mem_no;
22537486Smckusick 
22639588Smckusick 	if (uio->uio_rw != UIO_WRITE)
22739588Smckusick 		panic("spec_write mode");
22839588Smckusick 
22939588Smckusick 	switch (vp->v_type) {
23039588Smckusick 
23139588Smckusick 	case VCHR:
23239588Smckusick 		/*
23339588Smckusick 		 * Negative offsets allowed only for /dev/kmem
23439588Smckusick 		 */
23539588Smckusick 		if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
23639588Smckusick 			return (EINVAL);
23739588Smckusick 		VOP_UNLOCK(vp);
23839588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_write)
23939588Smckusick 			(vp->v_rdev, uio, ioflag);
24037725Smckusick 		VOP_LOCK(vp);
24139588Smckusick 		return (error);
24239588Smckusick 
24339588Smckusick 	case VBLK:
24439588Smckusick 		if (uio->uio_resid == 0)
24539588Smckusick 			return (0);
24639588Smckusick 		if (uio->uio_offset < 0)
24739588Smckusick 			return (EINVAL);
24839614Smckusick 		bsize = BLKDEV_IOSIZE;
24939614Smckusick 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
25039614Smckusick 		    (caddr_t)&dpart, FREAD) == 0) {
25139614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
25239614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
25339614Smckusick 				bsize = dpart.part->p_frag *
25439614Smckusick 				    dpart.part->p_fsize;
25539614Smckusick 		}
25639614Smckusick 		blkmask = (bsize / DEV_BSIZE) - 1;
25739614Smckusick 		do {
25839614Smckusick 			bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
25939614Smckusick 			on = uio->uio_offset % bsize;
26039614Smckusick 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
26139614Smckusick 			count = howmany(bsize, CLBYTES);
26239614Smckusick 			for (i = 0; i < count; i++)
26339614Smckusick 				munhash(vp, bn + i * (CLBYTES / DEV_BSIZE));
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 */
29239446Smckusick spec_ioctl(vp, com, data, fflag, cred)
29337486Smckusick 	struct vnode *vp;
29439666Smckusick 	int com;
29537486Smckusick 	caddr_t data;
29637486Smckusick 	int fflag;
29737486Smckusick 	struct ucred *cred;
29837486Smckusick {
29937725Smckusick 	dev_t dev = vp->v_rdev;
30037486Smckusick 
30137486Smckusick 	switch (vp->v_type) {
30237486Smckusick 
30337486Smckusick 	case VCHR:
30437486Smckusick 		return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
30537486Smckusick 
30637486Smckusick 	case VBLK:
30739666Smckusick 		if (com == 0 && (int)data == B_TAPE)
30839666Smckusick 			if (bdevsw[major(dev)].d_flags & B_TAPE)
30939666Smckusick 				return (0);
31039666Smckusick 			else
31139666Smckusick 				return (1);
31237486Smckusick 		return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
31337486Smckusick 
31437486Smckusick 	default:
31539446Smckusick 		panic("spec_ioctl");
31637486Smckusick 		/* NOTREACHED */
31737486Smckusick 	}
31837486Smckusick }
31937486Smckusick 
32037725Smckusick /* ARGSUSED */
32140189Smckusick spec_select(vp, which, fflags, cred)
32237486Smckusick 	struct vnode *vp;
32340189Smckusick 	int which, fflags;
32437486Smckusick 	struct ucred *cred;
32537486Smckusick {
32637486Smckusick 	register dev_t dev;
32737486Smckusick 
32837486Smckusick 	switch (vp->v_type) {
32937486Smckusick 
33037486Smckusick 	default:
33137486Smckusick 		return (1);		/* XXX */
33237486Smckusick 
33337486Smckusick 	case VCHR:
33437725Smckusick 		dev = vp->v_rdev;
33537486Smckusick 		return (*cdevsw[major(dev)].d_select)(dev, which);
33637486Smckusick 	}
33737486Smckusick }
33837486Smckusick 
33937486Smckusick /*
34037486Smckusick  * Just call the device strategy routine
34137486Smckusick  */
34239446Smckusick spec_strategy(bp)
34337486Smckusick 	register struct buf *bp;
34437486Smckusick {
34539666Smckusick 
34637486Smckusick 	(*bdevsw[major(bp->b_dev)].d_strategy)(bp);
34737486Smckusick 	return (0);
34837486Smckusick }
34937486Smckusick 
35039432Smckusick /*
35139666Smckusick  * This is a noop, simply returning what one has been given.
35239666Smckusick  */
35339666Smckusick spec_bmap(vp, bn, vpp, bnp)
35439666Smckusick 	struct vnode *vp;
35539666Smckusick 	daddr_t bn;
35639666Smckusick 	struct vnode **vpp;
35739666Smckusick 	daddr_t *bnp;
35839666Smckusick {
35939666Smckusick 
36039666Smckusick 	if (vpp != NULL)
36139666Smckusick 		*vpp = vp;
36239666Smckusick 	if (bnp != NULL)
36339666Smckusick 		*bnp = bn;
36439666Smckusick 	return (0);
36539666Smckusick }
36639666Smckusick 
36739666Smckusick /*
36839432Smckusick  * At the moment we do not do any locking.
36939432Smckusick  */
37039489Smckusick /* ARGSUSED */
37139446Smckusick spec_lock(vp)
37237486Smckusick 	struct vnode *vp;
37337486Smckusick {
37437486Smckusick 
37537486Smckusick 	return (0);
37637486Smckusick }
37737486Smckusick 
37839489Smckusick /* ARGSUSED */
37939446Smckusick spec_unlock(vp)
38037486Smckusick 	struct vnode *vp;
38137486Smckusick {
38237486Smckusick 
38337486Smckusick 	return (0);
38437486Smckusick }
38537486Smckusick 
38637486Smckusick /*
38737486Smckusick  * Device close routine
38837486Smckusick  */
38937725Smckusick /* ARGSUSED */
39039446Smckusick spec_close(vp, flag, cred)
39137725Smckusick 	register struct vnode *vp;
39237486Smckusick 	int flag;
39337486Smckusick 	struct ucred *cred;
39437486Smckusick {
39537486Smckusick 	dev_t dev = vp->v_rdev;
39637725Smckusick 	int (*cfunc)();
39737725Smckusick 	int error, mode;
39837486Smckusick 
39937725Smckusick 	switch (vp->v_type) {
40037725Smckusick 
40137725Smckusick 	case VCHR:
40239485Smckusick 		/*
40339485Smckusick 		 * If the vnode is locked, then we are in the midst
40439485Smckusick 		 * of forcably closing the device, otherwise we only
40539485Smckusick 		 * close on last reference.
40639485Smckusick 		 */
40739630Smckusick 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
40837725Smckusick 			return (0);
40937725Smckusick 		cfunc = cdevsw[major(dev)].d_close;
41039432Smckusick 		mode = S_IFCHR;
41137725Smckusick 		break;
41237725Smckusick 
41337725Smckusick 	case VBLK:
41437725Smckusick 		/*
41537725Smckusick 		 * On last close of a block device (that isn't mounted)
41637725Smckusick 		 * we must invalidate any in core blocks, so that
41737725Smckusick 		 * we can, for instance, change floppy disks.
41837725Smckusick 		 */
41939666Smckusick 		vflushbuf(vp, 0);
42039666Smckusick 		if (vinvalbuf(vp, 1))
42138613Smckusick 			return (0);
42237725Smckusick 		/*
42339485Smckusick 		 * We do not want to really close the device if it
42439485Smckusick 		 * is still in use unless we are trying to close it
42539485Smckusick 		 * forcibly. Since every use (buffer, vnode, swap, cmap)
42639630Smckusick 		 * holds a reference to the vnode, and because we mark
42739630Smckusick 		 * any other vnodes that alias this device, when the
42839630Smckusick 		 * sum of the reference counts on all the aliased
42939630Smckusick 		 * vnodes descends to one, we are on last close.
43037725Smckusick 		 */
43139630Smckusick 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
43237725Smckusick 			return (0);
43337725Smckusick 		cfunc = bdevsw[major(dev)].d_close;
43439432Smckusick 		mode = S_IFBLK;
43537725Smckusick 		break;
43637725Smckusick 
43737725Smckusick 	default:
43839446Smckusick 		panic("spec_close: not special");
43937725Smckusick 	}
44037725Smckusick 
44137725Smckusick 	if (setjmp(&u.u_qsave)) {
44237725Smckusick 		/*
44337725Smckusick 		 * If device close routine is interrupted,
44437725Smckusick 		 * must return so closef can clean up.
44537725Smckusick 		 */
44637725Smckusick 		error = EINTR;
44737725Smckusick 	} else
44837725Smckusick 		error = (*cfunc)(dev, flag, mode);
44937725Smckusick 	return (error);
45037486Smckusick }
45137486Smckusick 
45237486Smckusick /*
45339666Smckusick  * Print out the contents of a special device vnode.
45439666Smckusick  */
45539666Smckusick spec_print(vp)
45639666Smckusick 	struct vnode *vp;
45739666Smckusick {
45839666Smckusick 
45939666Smckusick 	printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev),
46039666Smckusick 		minor(vp->v_rdev));
46139666Smckusick }
46239666Smckusick 
46339666Smckusick /*
46439507Smckusick  * Special device failed operation
46537486Smckusick  */
46639507Smckusick spec_ebadf()
46739507Smckusick {
46839507Smckusick 
46939507Smckusick 	return (EBADF);
47039507Smckusick }
47139507Smckusick 
47239507Smckusick /*
47339507Smckusick  * Special device bad operation
47439507Smckusick  */
47539446Smckusick spec_badop()
47637486Smckusick {
47737486Smckusick 
47839446Smckusick 	panic("spec_badop called");
47939292Smckusick 	/* NOTREACHED */
48037486Smckusick }
48137486Smckusick 
48237486Smckusick /*
48339507Smckusick  * Special device null operation
48437486Smckusick  */
48539446Smckusick spec_nullop()
48637486Smckusick {
48737486Smckusick 
48837486Smckusick 	return (0);
48937486Smckusick }
490