xref: /csrg-svn/sys/miscfs/specfs/spec_vnops.c (revision 41961)
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*41961Smckusick  *	@(#)spec_vnops.c	7.27 (Berkeley) 05/15/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"
2840652Smckusick #include "specdev.h"
2939432Smckusick #include "stat.h"
3037486Smckusick #include "errno.h"
3139614Smckusick #include "ioctl.h"
3239614Smckusick #include "file.h"
3339614Smckusick #include "disklabel.h"
3437486Smckusick 
3540707Skarels /* symbolic sleep message strings for devices */
3640707Skarels char	devopn[] = "devopn";
3740707Skarels char	devio[] = "devio";
3840707Skarels char	devwait[] = "devwait";
3940707Skarels char	devin[] = "devin";
4040707Skarels char	devout[] = "devout";
4140707Skarels char	devioc[] = "devioc";
4240707Skarels char	devcls[] = "devcls";
4340707Skarels 
4439446Smckusick int	spec_lookup(),
4539446Smckusick 	spec_open(),
4639446Smckusick 	spec_read(),
4739446Smckusick 	spec_write(),
4839446Smckusick 	spec_strategy(),
4939666Smckusick 	spec_bmap(),
5039446Smckusick 	spec_ioctl(),
5139446Smckusick 	spec_select(),
5239446Smckusick 	spec_lock(),
5339446Smckusick 	spec_unlock(),
5439446Smckusick 	spec_close(),
5539666Smckusick 	spec_print(),
5639507Smckusick 	spec_ebadf(),
5739446Smckusick 	spec_badop(),
5839446Smckusick 	spec_nullop();
5937486Smckusick 
6039446Smckusick struct vnodeops spec_vnodeops = {
6139507Smckusick 	spec_lookup,		/* lookup */
6239507Smckusick 	spec_badop,		/* create */
6339507Smckusick 	spec_badop,		/* mknod */
6439507Smckusick 	spec_open,		/* open */
6539507Smckusick 	spec_close,		/* close */
6639507Smckusick 	spec_ebadf,		/* access */
6739507Smckusick 	spec_ebadf,		/* getattr */
6839507Smckusick 	spec_ebadf,		/* setattr */
6939507Smckusick 	spec_read,		/* read */
7039507Smckusick 	spec_write,		/* write */
7139507Smckusick 	spec_ioctl,		/* ioctl */
7239507Smckusick 	spec_select,		/* select */
7339507Smckusick 	spec_badop,		/* mmap */
7439507Smckusick 	spec_nullop,		/* fsync */
7539507Smckusick 	spec_badop,		/* seek */
7639507Smckusick 	spec_badop,		/* remove */
7739507Smckusick 	spec_badop,		/* link */
7839507Smckusick 	spec_badop,		/* rename */
7939507Smckusick 	spec_badop,		/* mkdir */
8039507Smckusick 	spec_badop,		/* rmdir */
8139507Smckusick 	spec_badop,		/* symlink */
8239507Smckusick 	spec_badop,		/* readdir */
8339507Smckusick 	spec_badop,		/* readlink */
8439507Smckusick 	spec_badop,		/* abortop */
8539507Smckusick 	spec_nullop,		/* inactive */
8639507Smckusick 	spec_nullop,		/* reclaim */
8739507Smckusick 	spec_lock,		/* lock */
8839507Smckusick 	spec_unlock,		/* unlock */
8939666Smckusick 	spec_bmap,		/* bmap */
9039507Smckusick 	spec_strategy,		/* strategy */
9139666Smckusick 	spec_print,		/* print */
9239912Smckusick 	spec_nullop,		/* islocked */
9337486Smckusick };
9437486Smckusick 
9537486Smckusick /*
9639292Smckusick  * Trivial lookup routine that always fails.
9739292Smckusick  */
9839446Smckusick spec_lookup(vp, ndp)
9939292Smckusick 	struct vnode *vp;
10039292Smckusick 	struct nameidata *ndp;
10139292Smckusick {
10239292Smckusick 
10339292Smckusick 	ndp->ni_dvp = vp;
10439292Smckusick 	ndp->ni_vp = NULL;
10539292Smckusick 	return (ENOTDIR);
10639292Smckusick }
10739292Smckusick 
10839292Smckusick /*
10937486Smckusick  * Open called to allow handler
11037486Smckusick  * of special files to initialize and
11137486Smckusick  * validate before actual IO.
11237486Smckusick  */
11337725Smckusick /* ARGSUSED */
11439446Smckusick spec_open(vp, mode, cred)
11537486Smckusick 	register struct vnode *vp;
11637486Smckusick 	int mode;
11737486Smckusick 	struct ucred *cred;
11837486Smckusick {
11937486Smckusick 	dev_t dev = (dev_t)vp->v_rdev;
12037486Smckusick 	register int maj = major(dev);
12140375Smckusick 	int error;
12237486Smckusick 
12341400Smckusick 	if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
12439365Smckusick 		return (ENXIO);
12539365Smckusick 
12637486Smckusick 	switch (vp->v_type) {
12737486Smckusick 
12837486Smckusick 	case VCHR:
12937486Smckusick 		if ((u_int)maj >= nchrdev)
13037486Smckusick 			return (ENXIO);
13139432Smckusick 		return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR));
13237486Smckusick 
13337486Smckusick 	case VBLK:
13437486Smckusick 		if ((u_int)maj >= nblkdev)
13537486Smckusick 			return (ENXIO);
13640375Smckusick 		if (error = mountedon(vp))
13740375Smckusick 			return (error);
13839432Smckusick 		return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK));
13937486Smckusick 	}
14037486Smckusick 	return (0);
14137486Smckusick }
14237486Smckusick 
14337486Smckusick /*
14437486Smckusick  * Vnode op for read
14537486Smckusick  */
146*41961Smckusick /* ARGSUSED */
14739588Smckusick spec_read(vp, uio, ioflag, cred)
14837486Smckusick 	register struct vnode *vp;
14939614Smckusick 	register struct uio *uio;
15037486Smckusick 	int ioflag;
15137486Smckusick 	struct ucred *cred;
15237486Smckusick {
15339614Smckusick 	struct buf *bp;
15439614Smckusick 	daddr_t bn;
15539614Smckusick 	long bsize, bscale;
15639614Smckusick 	struct partinfo dpart;
15739614Smckusick 	register int n, on;
15839614Smckusick 	int error = 0;
15939588Smckusick 	extern int mem_no;
16037486Smckusick 
16139588Smckusick 	if (uio->uio_rw != UIO_READ)
16239588Smckusick 		panic("spec_read mode");
16339588Smckusick 	if (uio->uio_resid == 0)
16439588Smckusick 		return (0);
16539588Smckusick 
16639588Smckusick 	switch (vp->v_type) {
16739588Smckusick 
16839588Smckusick 	case VCHR:
16939588Smckusick 		/*
17039588Smckusick 		 * Negative offsets allowed only for /dev/kmem
17139588Smckusick 		 */
17239588Smckusick 		if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
17339588Smckusick 			return (EINVAL);
17439588Smckusick 		VOP_UNLOCK(vp);
17539588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_read)
17639588Smckusick 			(vp->v_rdev, uio, ioflag);
17737725Smckusick 		VOP_LOCK(vp);
17839588Smckusick 		return (error);
17939588Smckusick 
18039588Smckusick 	case VBLK:
18139588Smckusick 		if (uio->uio_offset < 0)
18239588Smckusick 			return (EINVAL);
18339614Smckusick 		bsize = BLKDEV_IOSIZE;
18439614Smckusick 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
18539614Smckusick 		    (caddr_t)&dpart, FREAD) == 0) {
18639614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
18739614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
18839614Smckusick 				bsize = dpart.part->p_frag *
18939614Smckusick 				    dpart.part->p_fsize;
19039614Smckusick 		}
19139614Smckusick 		bscale = bsize / DEV_BSIZE;
19239614Smckusick 		do {
19339614Smckusick 			bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
19439614Smckusick 			on = uio->uio_offset % bsize;
19539614Smckusick 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
19639614Smckusick 			if (vp->v_lastr + bscale == bn)
19739614Smckusick 				error = breada(vp, bn, (int)bsize, bn + bscale,
19839614Smckusick 					(int)bsize, NOCRED, &bp);
19939614Smckusick 			else
20039614Smckusick 				error = bread(vp, bn, (int)bsize, NOCRED, &bp);
20139614Smckusick 			vp->v_lastr = bn;
20239614Smckusick 			n = MIN(n, bsize - bp->b_resid);
20339614Smckusick 			if (error) {
20439614Smckusick 				brelse(bp);
20539614Smckusick 				return (error);
20639614Smckusick 			}
20739614Smckusick 			error = uiomove(bp->b_un.b_addr + on, n, uio);
20839614Smckusick 			if (n + on == bsize)
20939614Smckusick 				bp->b_flags |= B_AGE;
21039614Smckusick 			brelse(bp);
21139614Smckusick 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
21239614Smckusick 		return (error);
21339588Smckusick 
21439588Smckusick 	default:
21539588Smckusick 		panic("spec_read type");
21639588Smckusick 	}
21739588Smckusick 	/* NOTREACHED */
21837486Smckusick }
21937486Smckusick 
22037486Smckusick /*
22137486Smckusick  * Vnode op for write
22237486Smckusick  */
223*41961Smckusick /* ARGSUSED */
22439588Smckusick spec_write(vp, uio, ioflag, cred)
22537486Smckusick 	register struct vnode *vp;
22639614Smckusick 	register struct uio *uio;
22737486Smckusick 	int ioflag;
22837486Smckusick 	struct ucred *cred;
22937486Smckusick {
23039614Smckusick 	struct buf *bp;
23139614Smckusick 	daddr_t bn;
23239614Smckusick 	int bsize, blkmask;
23339614Smckusick 	struct partinfo dpart;
23439614Smckusick 	register int n, on, i;
23539614Smckusick 	int count, error = 0;
23639588Smckusick 	extern int mem_no;
23737486Smckusick 
23839588Smckusick 	if (uio->uio_rw != UIO_WRITE)
23939588Smckusick 		panic("spec_write mode");
24039588Smckusick 
24139588Smckusick 	switch (vp->v_type) {
24239588Smckusick 
24339588Smckusick 	case VCHR:
24439588Smckusick 		/*
24539588Smckusick 		 * Negative offsets allowed only for /dev/kmem
24639588Smckusick 		 */
24739588Smckusick 		if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
24839588Smckusick 			return (EINVAL);
24939588Smckusick 		VOP_UNLOCK(vp);
25039588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_write)
25139588Smckusick 			(vp->v_rdev, uio, ioflag);
25237725Smckusick 		VOP_LOCK(vp);
25339588Smckusick 		return (error);
25439588Smckusick 
25539588Smckusick 	case VBLK:
25639588Smckusick 		if (uio->uio_resid == 0)
25739588Smckusick 			return (0);
25839588Smckusick 		if (uio->uio_offset < 0)
25939588Smckusick 			return (EINVAL);
26039614Smckusick 		bsize = BLKDEV_IOSIZE;
26139614Smckusick 		if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
26239614Smckusick 		    (caddr_t)&dpart, FREAD) == 0) {
26339614Smckusick 			if (dpart.part->p_fstype == FS_BSDFFS &&
26439614Smckusick 			    dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
26539614Smckusick 				bsize = dpart.part->p_frag *
26639614Smckusick 				    dpart.part->p_fsize;
26739614Smckusick 		}
26839614Smckusick 		blkmask = (bsize / DEV_BSIZE) - 1;
26939614Smckusick 		do {
27039614Smckusick 			bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
27139614Smckusick 			on = uio->uio_offset % bsize;
27239614Smckusick 			n = MIN((unsigned)(bsize - on), uio->uio_resid);
27339614Smckusick 			count = howmany(bsize, CLBYTES);
27439614Smckusick 			for (i = 0; i < count; i++)
27539614Smckusick 				munhash(vp, bn + i * (CLBYTES / DEV_BSIZE));
27639614Smckusick 			if (n == bsize)
27739614Smckusick 				bp = getblk(vp, bn, bsize);
27839614Smckusick 			else
27939614Smckusick 				error = bread(vp, bn, bsize, NOCRED, &bp);
28039614Smckusick 			n = MIN(n, bsize - bp->b_resid);
28139614Smckusick 			if (error) {
28239614Smckusick 				brelse(bp);
28339614Smckusick 				return (error);
28439614Smckusick 			}
28539614Smckusick 			error = uiomove(bp->b_un.b_addr + on, n, uio);
28639614Smckusick 			if (n + on == bsize) {
28739614Smckusick 				bp->b_flags |= B_AGE;
28839614Smckusick 				bawrite(bp);
28939614Smckusick 			} else
29039614Smckusick 				bdwrite(bp);
29139614Smckusick 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
29239614Smckusick 		return (error);
29339588Smckusick 
29439588Smckusick 	default:
29539588Smckusick 		panic("spec_write type");
29639588Smckusick 	}
29739588Smckusick 	/* NOTREACHED */
29837486Smckusick }
29937486Smckusick 
30037486Smckusick /*
30137486Smckusick  * Device ioctl operation.
30237486Smckusick  */
30337725Smckusick /* ARGSUSED */
30439446Smckusick spec_ioctl(vp, com, data, fflag, cred)
30537486Smckusick 	struct vnode *vp;
30639666Smckusick 	int com;
30737486Smckusick 	caddr_t data;
30837486Smckusick 	int fflag;
30937486Smckusick 	struct ucred *cred;
31037486Smckusick {
31137725Smckusick 	dev_t dev = vp->v_rdev;
31237486Smckusick 
31337486Smckusick 	switch (vp->v_type) {
31437486Smckusick 
31537486Smckusick 	case VCHR:
31637486Smckusick 		return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
31737486Smckusick 
31837486Smckusick 	case VBLK:
31939666Smckusick 		if (com == 0 && (int)data == B_TAPE)
32039666Smckusick 			if (bdevsw[major(dev)].d_flags & B_TAPE)
32139666Smckusick 				return (0);
32239666Smckusick 			else
32339666Smckusick 				return (1);
32437486Smckusick 		return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
32537486Smckusick 
32637486Smckusick 	default:
32739446Smckusick 		panic("spec_ioctl");
32837486Smckusick 		/* NOTREACHED */
32937486Smckusick 	}
33037486Smckusick }
33137486Smckusick 
33237725Smckusick /* ARGSUSED */
33340189Smckusick spec_select(vp, which, fflags, cred)
33437486Smckusick 	struct vnode *vp;
33540189Smckusick 	int which, fflags;
33637486Smckusick 	struct ucred *cred;
33737486Smckusick {
33837486Smckusick 	register dev_t dev;
33937486Smckusick 
34037486Smckusick 	switch (vp->v_type) {
34137486Smckusick 
34237486Smckusick 	default:
34337486Smckusick 		return (1);		/* XXX */
34437486Smckusick 
34537486Smckusick 	case VCHR:
34637725Smckusick 		dev = vp->v_rdev;
34737486Smckusick 		return (*cdevsw[major(dev)].d_select)(dev, which);
34837486Smckusick 	}
34937486Smckusick }
35037486Smckusick 
35137486Smckusick /*
35237486Smckusick  * Just call the device strategy routine
35337486Smckusick  */
35439446Smckusick spec_strategy(bp)
35537486Smckusick 	register struct buf *bp;
35637486Smckusick {
35739666Smckusick 
35837486Smckusick 	(*bdevsw[major(bp->b_dev)].d_strategy)(bp);
35937486Smckusick 	return (0);
36037486Smckusick }
36137486Smckusick 
36239432Smckusick /*
36339666Smckusick  * This is a noop, simply returning what one has been given.
36439666Smckusick  */
36539666Smckusick spec_bmap(vp, bn, vpp, bnp)
36639666Smckusick 	struct vnode *vp;
36739666Smckusick 	daddr_t bn;
36839666Smckusick 	struct vnode **vpp;
36939666Smckusick 	daddr_t *bnp;
37039666Smckusick {
37139666Smckusick 
37239666Smckusick 	if (vpp != NULL)
37339666Smckusick 		*vpp = vp;
37439666Smckusick 	if (bnp != NULL)
37539666Smckusick 		*bnp = bn;
37639666Smckusick 	return (0);
37739666Smckusick }
37839666Smckusick 
37939666Smckusick /*
38039432Smckusick  * At the moment we do not do any locking.
38139432Smckusick  */
38239489Smckusick /* ARGSUSED */
38339446Smckusick spec_lock(vp)
38437486Smckusick 	struct vnode *vp;
38537486Smckusick {
38637486Smckusick 
38737486Smckusick 	return (0);
38837486Smckusick }
38937486Smckusick 
39039489Smckusick /* ARGSUSED */
39139446Smckusick spec_unlock(vp)
39237486Smckusick 	struct vnode *vp;
39337486Smckusick {
39437486Smckusick 
39537486Smckusick 	return (0);
39637486Smckusick }
39737486Smckusick 
39837486Smckusick /*
39937486Smckusick  * Device close routine
40037486Smckusick  */
40137725Smckusick /* ARGSUSED */
40239446Smckusick spec_close(vp, flag, cred)
40337725Smckusick 	register struct vnode *vp;
40437486Smckusick 	int flag;
40537486Smckusick 	struct ucred *cred;
40637486Smckusick {
40737486Smckusick 	dev_t dev = vp->v_rdev;
40837725Smckusick 	int (*cfunc)();
40940707Skarels 	int mode;
41037486Smckusick 
41137725Smckusick 	switch (vp->v_type) {
41237725Smckusick 
41337725Smckusick 	case VCHR:
41439485Smckusick 		/*
41539485Smckusick 		 * If the vnode is locked, then we are in the midst
41639485Smckusick 		 * of forcably closing the device, otherwise we only
41739485Smckusick 		 * close on last reference.
41839485Smckusick 		 */
41939630Smckusick 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
42037725Smckusick 			return (0);
42137725Smckusick 		cfunc = cdevsw[major(dev)].d_close;
42239432Smckusick 		mode = S_IFCHR;
42337725Smckusick 		break;
42437725Smckusick 
42537725Smckusick 	case VBLK:
42637725Smckusick 		/*
42737725Smckusick 		 * On last close of a block device (that isn't mounted)
42837725Smckusick 		 * we must invalidate any in core blocks, so that
42937725Smckusick 		 * we can, for instance, change floppy disks.
43037725Smckusick 		 */
43139666Smckusick 		vflushbuf(vp, 0);
43239666Smckusick 		if (vinvalbuf(vp, 1))
43338613Smckusick 			return (0);
43437725Smckusick 		/*
43539485Smckusick 		 * We do not want to really close the device if it
43639485Smckusick 		 * is still in use unless we are trying to close it
43739485Smckusick 		 * forcibly. Since every use (buffer, vnode, swap, cmap)
43839630Smckusick 		 * holds a reference to the vnode, and because we mark
43939630Smckusick 		 * any other vnodes that alias this device, when the
44039630Smckusick 		 * sum of the reference counts on all the aliased
44139630Smckusick 		 * vnodes descends to one, we are on last close.
44237725Smckusick 		 */
44339630Smckusick 		if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
44437725Smckusick 			return (0);
44537725Smckusick 		cfunc = bdevsw[major(dev)].d_close;
44639432Smckusick 		mode = S_IFBLK;
44737725Smckusick 		break;
44837725Smckusick 
44937725Smckusick 	default:
45039446Smckusick 		panic("spec_close: not special");
45137725Smckusick 	}
45237725Smckusick 
45340707Skarels 	return ((*cfunc)(dev, flag, mode));
45437486Smckusick }
45537486Smckusick 
45637486Smckusick /*
45739666Smckusick  * Print out the contents of a special device vnode.
45839666Smckusick  */
45939666Smckusick spec_print(vp)
46039666Smckusick 	struct vnode *vp;
46139666Smckusick {
46239666Smckusick 
46339666Smckusick 	printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev),
46439666Smckusick 		minor(vp->v_rdev));
46539666Smckusick }
46639666Smckusick 
46739666Smckusick /*
46839507Smckusick  * Special device failed operation
46937486Smckusick  */
47039507Smckusick spec_ebadf()
47139507Smckusick {
47239507Smckusick 
47339507Smckusick 	return (EBADF);
47439507Smckusick }
47539507Smckusick 
47639507Smckusick /*
47739507Smckusick  * Special device bad operation
47839507Smckusick  */
47939446Smckusick spec_badop()
48037486Smckusick {
48137486Smckusick 
48239446Smckusick 	panic("spec_badop called");
48339292Smckusick 	/* NOTREACHED */
48437486Smckusick }
48537486Smckusick 
48637486Smckusick /*
48739507Smckusick  * Special device null operation
48837486Smckusick  */
48939446Smckusick spec_nullop()
49037486Smckusick {
49137486Smckusick 
49237486Smckusick 	return (0);
49337486Smckusick }
494