xref: /csrg-svn/sys/miscfs/specfs/spec_vnops.c (revision 39485)
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*39485Smckusick  *	@(#)spec_vnops.c	7.12 (Berkeley) 11/02/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"
2839432Smckusick #include "stat.h"
2937486Smckusick #include "errno.h"
3037486Smckusick 
3139446Smckusick int	spec_lookup(),
3239446Smckusick 	spec_open(),
3339446Smckusick 	spec_read(),
3439446Smckusick 	spec_write(),
3539446Smckusick 	spec_strategy(),
3639446Smckusick 	spec_ioctl(),
3739446Smckusick 	spec_select(),
3839446Smckusick 	spec_lock(),
3939446Smckusick 	spec_unlock(),
4039446Smckusick 	spec_close(),
4139446Smckusick 	spec_badop(),
4239446Smckusick 	spec_nullop();
4337486Smckusick 
4439446Smckusick struct vnodeops spec_vnodeops = {
4539446Smckusick 	spec_lookup,
4639446Smckusick 	spec_badop,
4739446Smckusick 	spec_badop,
4839446Smckusick 	spec_open,
4939446Smckusick 	spec_close,
5039446Smckusick 	spec_badop,
5139446Smckusick 	spec_badop,
5239446Smckusick 	spec_badop,
5339446Smckusick 	spec_read,
5439446Smckusick 	spec_write,
5539446Smckusick 	spec_ioctl,
5639446Smckusick 	spec_select,
5739446Smckusick 	spec_badop,
5839446Smckusick 	spec_nullop,
5939446Smckusick 	spec_badop,
6039446Smckusick 	spec_badop,
6139446Smckusick 	spec_badop,
6239446Smckusick 	spec_badop,
6339446Smckusick 	spec_badop,
6439446Smckusick 	spec_badop,
6539446Smckusick 	spec_badop,
6639446Smckusick 	spec_badop,
6739446Smckusick 	spec_badop,
6839446Smckusick 	spec_badop,
6939446Smckusick 	spec_nullop,
7039446Smckusick 	spec_nullop,
7139446Smckusick 	spec_lock,
7239446Smckusick 	spec_unlock,
7339446Smckusick 	spec_badop,
7439446Smckusick 	spec_strategy,
7537486Smckusick };
7637486Smckusick 
7737486Smckusick /*
7839292Smckusick  * Trivial lookup routine that always fails.
7939292Smckusick  */
8039446Smckusick spec_lookup(vp, ndp)
8139292Smckusick 	struct vnode *vp;
8239292Smckusick 	struct nameidata *ndp;
8339292Smckusick {
8439292Smckusick 
8539292Smckusick 	ndp->ni_dvp = vp;
8639292Smckusick 	ndp->ni_vp = NULL;
8739292Smckusick 	return (ENOTDIR);
8839292Smckusick }
8939292Smckusick 
9039292Smckusick /*
9137486Smckusick  * Open called to allow handler
9237486Smckusick  * of special files to initialize and
9337486Smckusick  * validate before actual IO.
9437486Smckusick  */
9537725Smckusick /* ARGSUSED */
9639446Smckusick spec_open(vp, mode, cred)
9737486Smckusick 	register struct vnode *vp;
9837486Smckusick 	int mode;
9937486Smckusick 	struct ucred *cred;
10037486Smckusick {
10137486Smckusick 	dev_t dev = (dev_t)vp->v_rdev;
10237486Smckusick 	register int maj = major(dev);
10337486Smckusick 
10439365Smckusick 	if (vp->v_mount && (vp->v_mount->m_flag & M_NODEV))
10539365Smckusick 		return (ENXIO);
10639365Smckusick 
10737486Smckusick 	switch (vp->v_type) {
10837486Smckusick 
10937486Smckusick 	case VCHR:
11037486Smckusick 		if ((u_int)maj >= nchrdev)
11137486Smckusick 			return (ENXIO);
11239432Smckusick 		return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR));
11337486Smckusick 
11437486Smckusick 	case VBLK:
11537486Smckusick 		if ((u_int)maj >= nblkdev)
11637486Smckusick 			return (ENXIO);
11739432Smckusick 		return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK));
11837486Smckusick 	}
11937486Smckusick 	return (0);
12037486Smckusick }
12137486Smckusick 
12237486Smckusick /*
12337486Smckusick  * Vnode op for read
12437486Smckusick  */
12539446Smckusick spec_read(vp, uio, offp, ioflag, cred)
12637486Smckusick 	register struct vnode *vp;
12737486Smckusick 	struct uio *uio;
12837486Smckusick 	off_t *offp;
12937486Smckusick 	int ioflag;
13037486Smckusick 	struct ucred *cred;
13137486Smckusick {
13237486Smckusick 	int count, error;
13337486Smckusick 
13437725Smckusick 	if (vp->v_type == VBLK && vp->v_data)
13537725Smckusick 		VOP_LOCK(vp);
13637486Smckusick 	uio->uio_offset = *offp;
13737486Smckusick 	count = uio->uio_resid;
13837725Smckusick 	error = readblkvp(vp, uio, cred, ioflag);
13937486Smckusick 	*offp += count - uio->uio_resid;
14037725Smckusick 	if (vp->v_type == VBLK && vp->v_data)
14137725Smckusick 		VOP_UNLOCK(vp);
14237486Smckusick 	return (error);
14337486Smckusick }
14437486Smckusick 
14537486Smckusick /*
14637486Smckusick  * Vnode op for write
14737486Smckusick  */
14839446Smckusick spec_write(vp, uio, offp, ioflag, cred)
14937486Smckusick 	register struct vnode *vp;
15037486Smckusick 	struct uio *uio;
15137486Smckusick 	off_t *offp;
15237486Smckusick 	int ioflag;
15337486Smckusick 	struct ucred *cred;
15437486Smckusick {
15537486Smckusick 	int count, error;
15637486Smckusick 
15737725Smckusick 	if (vp->v_type == VBLK && vp->v_data)
15837725Smckusick 		VOP_LOCK(vp);
15937486Smckusick 	uio->uio_offset = *offp;
16037486Smckusick 	count = uio->uio_resid;
16137725Smckusick 	error = writeblkvp(vp, uio, cred, ioflag);
16237486Smckusick 	*offp += count - uio->uio_resid;
16337725Smckusick 	if (vp->v_type == VBLK && vp->v_data)
16437725Smckusick 		VOP_UNLOCK(vp);
16537486Smckusick 	return (error);
16637486Smckusick }
16737486Smckusick 
16837486Smckusick /*
16937486Smckusick  * Device ioctl operation.
17037486Smckusick  */
17137725Smckusick /* ARGSUSED */
17239446Smckusick spec_ioctl(vp, com, data, fflag, cred)
17337486Smckusick 	struct vnode *vp;
17437486Smckusick 	register int com;
17537486Smckusick 	caddr_t data;
17637486Smckusick 	int fflag;
17737486Smckusick 	struct ucred *cred;
17837486Smckusick {
17937725Smckusick 	dev_t dev = vp->v_rdev;
18037486Smckusick 
18137486Smckusick 	switch (vp->v_type) {
18237486Smckusick 
18337486Smckusick 	case VCHR:
18437486Smckusick 		return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
18537486Smckusick 
18637486Smckusick 	case VBLK:
18737486Smckusick 		return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
18837486Smckusick 
18937486Smckusick 	default:
19039446Smckusick 		panic("spec_ioctl");
19137486Smckusick 		/* NOTREACHED */
19237486Smckusick 	}
19337486Smckusick }
19437486Smckusick 
19537725Smckusick /* ARGSUSED */
19639446Smckusick spec_select(vp, which, cred)
19737486Smckusick 	struct vnode *vp;
19837486Smckusick 	int which;
19937486Smckusick 	struct ucred *cred;
20037486Smckusick {
20137486Smckusick 	register dev_t dev;
20237486Smckusick 
20337486Smckusick 	switch (vp->v_type) {
20437486Smckusick 
20537486Smckusick 	default:
20637486Smckusick 		return (1);		/* XXX */
20737486Smckusick 
20837486Smckusick 	case VCHR:
20937725Smckusick 		dev = vp->v_rdev;
21037486Smckusick 		return (*cdevsw[major(dev)].d_select)(dev, which);
21137486Smckusick 	}
21237486Smckusick }
21337486Smckusick 
21437486Smckusick /*
21537486Smckusick  * Just call the device strategy routine
21637486Smckusick  */
21739446Smckusick spec_strategy(bp)
21837486Smckusick 	register struct buf *bp;
21937486Smckusick {
22037486Smckusick 	(*bdevsw[major(bp->b_dev)].d_strategy)(bp);
22137486Smckusick 	return (0);
22237486Smckusick }
22337486Smckusick 
22439432Smckusick /*
22539432Smckusick  * At the moment we do not do any locking.
22639432Smckusick  */
22739446Smckusick spec_lock(vp)
22837486Smckusick 	struct vnode *vp;
22937486Smckusick {
23037486Smckusick 
23137486Smckusick 	return (0);
23237486Smckusick }
23337486Smckusick 
23439446Smckusick spec_unlock(vp)
23537486Smckusick 	struct vnode *vp;
23637486Smckusick {
23737486Smckusick 
23837486Smckusick 	return (0);
23937486Smckusick }
24037486Smckusick 
24137486Smckusick /*
24237486Smckusick  * Device close routine
24337486Smckusick  */
24437725Smckusick /* ARGSUSED */
24539446Smckusick spec_close(vp, flag, cred)
24637725Smckusick 	register struct vnode *vp;
24737486Smckusick 	int flag;
24837486Smckusick 	struct ucred *cred;
24937486Smckusick {
25037486Smckusick 	dev_t dev = vp->v_rdev;
25137725Smckusick 	int (*cfunc)();
25237725Smckusick 	int error, mode;
25337486Smckusick 
25437725Smckusick 	switch (vp->v_type) {
25537725Smckusick 
25637725Smckusick 	case VCHR:
257*39485Smckusick 		/*
258*39485Smckusick 		 * If the vnode is locked, then we are in the midst
259*39485Smckusick 		 * of forcably closing the device, otherwise we only
260*39485Smckusick 		 * close on last reference.
261*39485Smckusick 		 */
262*39485Smckusick 		if (vp->v_count > 1 && (vp->v_flag & VXLOCK) == 0)
26337725Smckusick 			return (0);
26437725Smckusick 		cfunc = cdevsw[major(dev)].d_close;
26539432Smckusick 		mode = S_IFCHR;
26637725Smckusick 		break;
26737725Smckusick 
26837725Smckusick 	case VBLK:
26937725Smckusick 		/*
27037725Smckusick 		 * On last close of a block device (that isn't mounted)
27137725Smckusick 		 * we must invalidate any in core blocks, so that
27237725Smckusick 		 * we can, for instance, change floppy disks.
27337725Smckusick 		 */
27438777Smckusick 		bflush(vp->v_mount);
27538777Smckusick 		if (binval(vp->v_mount))
27638613Smckusick 			return (0);
27737725Smckusick 		/*
278*39485Smckusick 		 * We do not want to really close the device if it
279*39485Smckusick 		 * is still in use unless we are trying to close it
280*39485Smckusick 		 * forcibly. Since every use (buffer, vnode, swap, cmap)
28137725Smckusick 		 * holds a reference to the vnode, and because we ensure
28237725Smckusick 		 * that there cannot be more than one vnode per device,
28337725Smckusick 		 * we need only check that we are down to the last
284*39485Smckusick 		 * reference to detect last close.
28537725Smckusick 		 */
286*39485Smckusick 		if (vp->v_count > 1 && (vp->v_flag & VXLOCK) == 0)
28737725Smckusick 			return (0);
28837725Smckusick 		cfunc = bdevsw[major(dev)].d_close;
28939432Smckusick 		mode = S_IFBLK;
29037725Smckusick 		break;
29137725Smckusick 
29237725Smckusick 	default:
29339446Smckusick 		panic("spec_close: not special");
29437725Smckusick 	}
29537725Smckusick 
29637725Smckusick 	if (setjmp(&u.u_qsave)) {
29737725Smckusick 		/*
29837725Smckusick 		 * If device close routine is interrupted,
29937725Smckusick 		 * must return so closef can clean up.
30037725Smckusick 		 */
30137725Smckusick 		error = EINTR;
30237725Smckusick 	} else
30337725Smckusick 		error = (*cfunc)(dev, flag, mode);
30437725Smckusick 	return (error);
30537486Smckusick }
30637486Smckusick 
30737486Smckusick /*
30837486Smckusick  * Block device bad operation
30937486Smckusick  */
31039446Smckusick spec_badop()
31137486Smckusick {
31237486Smckusick 
31339446Smckusick 	panic("spec_badop called");
31439292Smckusick 	/* NOTREACHED */
31537486Smckusick }
31637486Smckusick 
31737486Smckusick /*
31837486Smckusick  * Block device null operation
31937486Smckusick  */
32039446Smckusick spec_nullop()
32137486Smckusick {
32237486Smckusick 
32337486Smckusick 	return (0);
32437486Smckusick }
325