xref: /csrg-svn/sys/miscfs/specfs/spec_vnops.c (revision 39588)
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*39588Smckusick  *	@(#)spec_vnops.c	7.15 (Berkeley) 11/22/89
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"
28*39588Smckusick #include "../ufs/inode.h"
2939432Smckusick #include "stat.h"
3037486Smckusick #include "errno.h"
3137486Smckusick 
3239446Smckusick int	spec_lookup(),
3339446Smckusick 	spec_open(),
3439446Smckusick 	spec_read(),
3539446Smckusick 	spec_write(),
3639446Smckusick 	spec_strategy(),
3739446Smckusick 	spec_ioctl(),
3839446Smckusick 	spec_select(),
3939446Smckusick 	spec_lock(),
4039446Smckusick 	spec_unlock(),
4139446Smckusick 	spec_close(),
4239507Smckusick 	spec_ebadf(),
4339446Smckusick 	spec_badop(),
4439446Smckusick 	spec_nullop();
4537486Smckusick 
4639446Smckusick struct vnodeops spec_vnodeops = {
4739507Smckusick 	spec_lookup,		/* lookup */
4839507Smckusick 	spec_badop,		/* create */
4939507Smckusick 	spec_badop,		/* mknod */
5039507Smckusick 	spec_open,		/* open */
5139507Smckusick 	spec_close,		/* close */
5239507Smckusick 	spec_ebadf,		/* access */
5339507Smckusick 	spec_ebadf,		/* getattr */
5439507Smckusick 	spec_ebadf,		/* setattr */
5539507Smckusick 	spec_read,		/* read */
5639507Smckusick 	spec_write,		/* write */
5739507Smckusick 	spec_ioctl,		/* ioctl */
5839507Smckusick 	spec_select,		/* select */
5939507Smckusick 	spec_badop,		/* mmap */
6039507Smckusick 	spec_nullop,		/* fsync */
6139507Smckusick 	spec_badop,		/* seek */
6239507Smckusick 	spec_badop,		/* remove */
6339507Smckusick 	spec_badop,		/* link */
6439507Smckusick 	spec_badop,		/* rename */
6539507Smckusick 	spec_badop,		/* mkdir */
6639507Smckusick 	spec_badop,		/* rmdir */
6739507Smckusick 	spec_badop,		/* symlink */
6839507Smckusick 	spec_badop,		/* readdir */
6939507Smckusick 	spec_badop,		/* readlink */
7039507Smckusick 	spec_badop,		/* abortop */
7139507Smckusick 	spec_nullop,		/* inactive */
7239507Smckusick 	spec_nullop,		/* reclaim */
7339507Smckusick 	spec_lock,		/* lock */
7439507Smckusick 	spec_unlock,		/* unlock */
7539507Smckusick 	spec_badop,		/* bmap */
7639507Smckusick 	spec_strategy,		/* strategy */
7737486Smckusick };
7837486Smckusick 
7937486Smckusick /*
8039292Smckusick  * Trivial lookup routine that always fails.
8139292Smckusick  */
8239446Smckusick spec_lookup(vp, ndp)
8339292Smckusick 	struct vnode *vp;
8439292Smckusick 	struct nameidata *ndp;
8539292Smckusick {
8639292Smckusick 
8739292Smckusick 	ndp->ni_dvp = vp;
8839292Smckusick 	ndp->ni_vp = NULL;
8939292Smckusick 	return (ENOTDIR);
9039292Smckusick }
9139292Smckusick 
9239292Smckusick /*
9337486Smckusick  * Open called to allow handler
9437486Smckusick  * of special files to initialize and
9537486Smckusick  * validate before actual IO.
9637486Smckusick  */
9737725Smckusick /* ARGSUSED */
9839446Smckusick spec_open(vp, mode, cred)
9937486Smckusick 	register struct vnode *vp;
10037486Smckusick 	int mode;
10137486Smckusick 	struct ucred *cred;
10237486Smckusick {
10337486Smckusick 	dev_t dev = (dev_t)vp->v_rdev;
10437486Smckusick 	register int maj = major(dev);
10537486Smckusick 
10639365Smckusick 	if (vp->v_mount && (vp->v_mount->m_flag & M_NODEV))
10739365Smckusick 		return (ENXIO);
10839365Smckusick 
10937486Smckusick 	switch (vp->v_type) {
11037486Smckusick 
11137486Smckusick 	case VCHR:
11237486Smckusick 		if ((u_int)maj >= nchrdev)
11337486Smckusick 			return (ENXIO);
11439432Smckusick 		return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR));
11537486Smckusick 
11637486Smckusick 	case VBLK:
11737486Smckusick 		if ((u_int)maj >= nblkdev)
11837486Smckusick 			return (ENXIO);
11939432Smckusick 		return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK));
12037486Smckusick 	}
12137486Smckusick 	return (0);
12237486Smckusick }
12337486Smckusick 
12437486Smckusick /*
12537486Smckusick  * Vnode op for read
12637486Smckusick  */
127*39588Smckusick spec_read(vp, uio, ioflag, cred)
12837486Smckusick 	register struct vnode *vp;
12937486Smckusick 	struct uio *uio;
13037486Smckusick 	int ioflag;
13137486Smckusick 	struct ucred *cred;
13237486Smckusick {
133*39588Smckusick 	int error;
134*39588Smckusick 	extern int mem_no;
13537486Smckusick 
136*39588Smckusick 	if (uio->uio_rw != UIO_READ)
137*39588Smckusick 		panic("spec_read mode");
138*39588Smckusick 	if (uio->uio_resid == 0)
139*39588Smckusick 		return (0);
140*39588Smckusick 	/*
141*39588Smckusick 	 * XXX  Set access flag for the ufs filesystem.
142*39588Smckusick 	 */
143*39588Smckusick 	if (vp->v_tag == VT_UFS)
144*39588Smckusick 		VTOI(vp)->i_flag |= IACC;
145*39588Smckusick 
146*39588Smckusick 	switch (vp->v_type) {
147*39588Smckusick 
148*39588Smckusick 	case VCHR:
149*39588Smckusick 		/*
150*39588Smckusick 		 * Negative offsets allowed only for /dev/kmem
151*39588Smckusick 		 */
152*39588Smckusick 		if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
153*39588Smckusick 			return (EINVAL);
154*39588Smckusick 		VOP_UNLOCK(vp);
155*39588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_read)
156*39588Smckusick 			(vp->v_rdev, uio, ioflag);
15737725Smckusick 		VOP_LOCK(vp);
158*39588Smckusick 		return (error);
159*39588Smckusick 
160*39588Smckusick 	case VBLK:
161*39588Smckusick 		if (uio->uio_offset < 0)
162*39588Smckusick 			return (EINVAL);
163*39588Smckusick 		return (readblkvp(vp, uio, cred, ioflag));
164*39588Smckusick 
165*39588Smckusick 	default:
166*39588Smckusick 		panic("spec_read type");
167*39588Smckusick 	}
168*39588Smckusick 	/* NOTREACHED */
16937486Smckusick }
17037486Smckusick 
17137486Smckusick /*
17237486Smckusick  * Vnode op for write
17337486Smckusick  */
174*39588Smckusick spec_write(vp, uio, ioflag, cred)
17537486Smckusick 	register struct vnode *vp;
17637486Smckusick 	struct uio *uio;
17737486Smckusick 	int ioflag;
17837486Smckusick 	struct ucred *cred;
17937486Smckusick {
180*39588Smckusick 	int error;
181*39588Smckusick 	extern int mem_no;
18237486Smckusick 
183*39588Smckusick 	if (uio->uio_rw != UIO_WRITE)
184*39588Smckusick 		panic("spec_write mode");
185*39588Smckusick 	/*
186*39588Smckusick 	 * XXX  Set update and change flags for the ufs filesystem.
187*39588Smckusick 	 */
188*39588Smckusick 	if (vp->v_tag == VT_UFS)
189*39588Smckusick 		VTOI(vp)->i_flag |= IUPD|ICHG;
190*39588Smckusick 
191*39588Smckusick 	switch (vp->v_type) {
192*39588Smckusick 
193*39588Smckusick 	case VCHR:
194*39588Smckusick 		/*
195*39588Smckusick 		 * Negative offsets allowed only for /dev/kmem
196*39588Smckusick 		 */
197*39588Smckusick 		if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
198*39588Smckusick 			return (EINVAL);
199*39588Smckusick 		VOP_UNLOCK(vp);
200*39588Smckusick 		error = (*cdevsw[major(vp->v_rdev)].d_write)
201*39588Smckusick 			(vp->v_rdev, uio, ioflag);
20237725Smckusick 		VOP_LOCK(vp);
203*39588Smckusick 		return (error);
204*39588Smckusick 
205*39588Smckusick 	case VBLK:
206*39588Smckusick 		if (uio->uio_resid == 0)
207*39588Smckusick 			return (0);
208*39588Smckusick 		if (uio->uio_offset < 0)
209*39588Smckusick 			return (EINVAL);
210*39588Smckusick 		return (writeblkvp(vp, uio, cred, ioflag));
211*39588Smckusick 
212*39588Smckusick 	default:
213*39588Smckusick 		panic("spec_write type");
214*39588Smckusick 	}
215*39588Smckusick 	/* NOTREACHED */
21637486Smckusick }
21737486Smckusick 
21837486Smckusick /*
21937486Smckusick  * Device ioctl operation.
22037486Smckusick  */
22137725Smckusick /* ARGSUSED */
22239446Smckusick spec_ioctl(vp, com, data, fflag, cred)
22337486Smckusick 	struct vnode *vp;
22437486Smckusick 	register int com;
22537486Smckusick 	caddr_t data;
22637486Smckusick 	int fflag;
22737486Smckusick 	struct ucred *cred;
22837486Smckusick {
22937725Smckusick 	dev_t dev = vp->v_rdev;
23037486Smckusick 
23137486Smckusick 	switch (vp->v_type) {
23237486Smckusick 
23337486Smckusick 	case VCHR:
23437486Smckusick 		return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
23537486Smckusick 
23637486Smckusick 	case VBLK:
23737486Smckusick 		return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
23837486Smckusick 
23937486Smckusick 	default:
24039446Smckusick 		panic("spec_ioctl");
24137486Smckusick 		/* NOTREACHED */
24237486Smckusick 	}
24337486Smckusick }
24437486Smckusick 
24537725Smckusick /* ARGSUSED */
24639446Smckusick spec_select(vp, which, cred)
24737486Smckusick 	struct vnode *vp;
24837486Smckusick 	int which;
24937486Smckusick 	struct ucred *cred;
25037486Smckusick {
25137486Smckusick 	register dev_t dev;
25237486Smckusick 
25337486Smckusick 	switch (vp->v_type) {
25437486Smckusick 
25537486Smckusick 	default:
25637486Smckusick 		return (1);		/* XXX */
25737486Smckusick 
25837486Smckusick 	case VCHR:
25937725Smckusick 		dev = vp->v_rdev;
26037486Smckusick 		return (*cdevsw[major(dev)].d_select)(dev, which);
26137486Smckusick 	}
26237486Smckusick }
26337486Smckusick 
26437486Smckusick /*
26537486Smckusick  * Just call the device strategy routine
26637486Smckusick  */
26739446Smckusick spec_strategy(bp)
26837486Smckusick 	register struct buf *bp;
26937486Smckusick {
27037486Smckusick 	(*bdevsw[major(bp->b_dev)].d_strategy)(bp);
27137486Smckusick 	return (0);
27237486Smckusick }
27337486Smckusick 
27439432Smckusick /*
27539432Smckusick  * At the moment we do not do any locking.
27639432Smckusick  */
27739489Smckusick /* ARGSUSED */
27839446Smckusick spec_lock(vp)
27937486Smckusick 	struct vnode *vp;
28037486Smckusick {
28137486Smckusick 
28237486Smckusick 	return (0);
28337486Smckusick }
28437486Smckusick 
28539489Smckusick /* ARGSUSED */
28639446Smckusick spec_unlock(vp)
28737486Smckusick 	struct vnode *vp;
28837486Smckusick {
28937486Smckusick 
29037486Smckusick 	return (0);
29137486Smckusick }
29237486Smckusick 
29337486Smckusick /*
29437486Smckusick  * Device close routine
29537486Smckusick  */
29637725Smckusick /* ARGSUSED */
29739446Smckusick spec_close(vp, flag, cred)
29837725Smckusick 	register struct vnode *vp;
29937486Smckusick 	int flag;
30037486Smckusick 	struct ucred *cred;
30137486Smckusick {
30237486Smckusick 	dev_t dev = vp->v_rdev;
30337725Smckusick 	int (*cfunc)();
30437725Smckusick 	int error, mode;
30537486Smckusick 
30637725Smckusick 	switch (vp->v_type) {
30737725Smckusick 
30837725Smckusick 	case VCHR:
30939485Smckusick 		/*
31039485Smckusick 		 * If the vnode is locked, then we are in the midst
31139485Smckusick 		 * of forcably closing the device, otherwise we only
31239485Smckusick 		 * close on last reference.
31339485Smckusick 		 */
31439485Smckusick 		if (vp->v_count > 1 && (vp->v_flag & VXLOCK) == 0)
31537725Smckusick 			return (0);
31637725Smckusick 		cfunc = cdevsw[major(dev)].d_close;
31739432Smckusick 		mode = S_IFCHR;
31837725Smckusick 		break;
31937725Smckusick 
32037725Smckusick 	case VBLK:
32137725Smckusick 		/*
32237725Smckusick 		 * On last close of a block device (that isn't mounted)
32337725Smckusick 		 * we must invalidate any in core blocks, so that
32437725Smckusick 		 * we can, for instance, change floppy disks.
32537725Smckusick 		 */
32638777Smckusick 		bflush(vp->v_mount);
32738777Smckusick 		if (binval(vp->v_mount))
32838613Smckusick 			return (0);
32937725Smckusick 		/*
33039485Smckusick 		 * We do not want to really close the device if it
33139485Smckusick 		 * is still in use unless we are trying to close it
33239485Smckusick 		 * forcibly. Since every use (buffer, vnode, swap, cmap)
33337725Smckusick 		 * holds a reference to the vnode, and because we ensure
33437725Smckusick 		 * that there cannot be more than one vnode per device,
33537725Smckusick 		 * we need only check that we are down to the last
33639485Smckusick 		 * reference to detect last close.
33737725Smckusick 		 */
33839485Smckusick 		if (vp->v_count > 1 && (vp->v_flag & VXLOCK) == 0)
33937725Smckusick 			return (0);
34037725Smckusick 		cfunc = bdevsw[major(dev)].d_close;
34139432Smckusick 		mode = S_IFBLK;
34237725Smckusick 		break;
34337725Smckusick 
34437725Smckusick 	default:
34539446Smckusick 		panic("spec_close: not special");
34637725Smckusick 	}
34737725Smckusick 
34837725Smckusick 	if (setjmp(&u.u_qsave)) {
34937725Smckusick 		/*
35037725Smckusick 		 * If device close routine is interrupted,
35137725Smckusick 		 * must return so closef can clean up.
35237725Smckusick 		 */
35337725Smckusick 		error = EINTR;
35437725Smckusick 	} else
35537725Smckusick 		error = (*cfunc)(dev, flag, mode);
35637725Smckusick 	return (error);
35737486Smckusick }
35837486Smckusick 
35937486Smckusick /*
36039507Smckusick  * Special device failed operation
36137486Smckusick  */
36239507Smckusick spec_ebadf()
36339507Smckusick {
36439507Smckusick 
36539507Smckusick 	return (EBADF);
36639507Smckusick }
36739507Smckusick 
36839507Smckusick /*
36939507Smckusick  * Special device bad operation
37039507Smckusick  */
37139446Smckusick spec_badop()
37237486Smckusick {
37337486Smckusick 
37439446Smckusick 	panic("spec_badop called");
37539292Smckusick 	/* NOTREACHED */
37637486Smckusick }
37737486Smckusick 
37837486Smckusick /*
37939507Smckusick  * Special device null operation
38037486Smckusick  */
38139446Smckusick spec_nullop()
38237486Smckusick {
38337486Smckusick 
38437486Smckusick 	return (0);
38537486Smckusick }
386