xref: /csrg-svn/sys/dev/vn.c (revision 63145)
141480Smckusick /*
241480Smckusick  * Copyright (c) 1988 University of Utah.
3*63145Sbostic  * Copyright (c) 1990, 1993
4*63145Sbostic  *	The Regents of the University of California.  All rights reserved.
541480Smckusick  *
641480Smckusick  * This code is derived from software contributed to Berkeley by
741480Smckusick  * the Systems Programming Group of the University of Utah Computer
841480Smckusick  * Science Department.
941480Smckusick  *
1041480Smckusick  * %sccs.include.redist.c%
1141480Smckusick  *
1257301Shibler  * from: Utah $Hdr: vn.c 1.8 92/12/20$
1341480Smckusick  *
14*63145Sbostic  *	@(#)vn.c	8.1 (Berkeley) 06/10/93
1541480Smckusick  */
1641480Smckusick 
1741480Smckusick /*
1849299Shibler  * Vnode disk driver.
1941480Smckusick  *
2049299Shibler  * Block/character interface to a vnode.  Allows one to treat a file
2149299Shibler  * as a disk (e.g. build a filesystem in it, mount it, etc.).
2241480Smckusick  *
2349299Shibler  * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode
2449299Shibler  * instead of a simple VOP_RDWR.  We do this to avoid distorting the
2549299Shibler  * local buffer cache.
2649299Shibler  *
2749299Shibler  * NOTE 2: There is a security issue involved with this driver.
2841480Smckusick  * Once mounted all access to the contents of the "mapped" file via
2941480Smckusick  * the special file is controlled by the permissions on the special
3041480Smckusick  * file, the protection of the mapped file is ignored (effectively,
3141480Smckusick  * by using root credentials in all transactions).
3257301Shibler  *
3357301Shibler  * NOTE 3: Doesn't interact with leases, should it?
3441480Smckusick  */
3549299Shibler #include "vn.h"
3649299Shibler #if NVN > 0
3741480Smckusick 
3855159Spendry #include <sys/param.h>
3955159Spendry #include <sys/systm.h>
4055159Spendry #include <sys/namei.h>
4155159Spendry #include <sys/proc.h>
4255159Spendry #include <sys/errno.h>
4355159Spendry #include <sys/dkstat.h>
4455159Spendry #include <sys/buf.h>
4555159Spendry #include <sys/malloc.h>
4655159Spendry #include <sys/ioctl.h>
4755159Spendry #include <sys/mount.h>
4855159Spendry #include <sys/vnode.h>
4955159Spendry #include <sys/file.h>
5055159Spendry #include <sys/uio.h>
5141480Smckusick 
5255159Spendry #include <miscfs/specfs/specdev.h>
5355159Spendry 
5456503Sbostic #include <dev/vnioctl.h>
5541480Smckusick 
5641480Smckusick #ifdef DEBUG
5749299Shibler int vndebug = 0x00;
5849299Shibler #define VDB_FOLLOW	0x01
5949299Shibler #define VDB_INIT	0x02
6049299Shibler #define VDB_IO		0x04
6141480Smckusick #endif
6241480Smckusick 
6341480Smckusick #define b_cylin	b_resid
6441480Smckusick 
6549299Shibler #define	vnunit(x)	((minor(x) >> 3) & 0x7)	/* for consistency */
6641480Smckusick 
6749299Shibler #define	getvnbuf()	\
6841480Smckusick 	((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK))
6949299Shibler #define putvnbuf(bp)	\
7041480Smckusick 	free((caddr_t)(bp), M_DEVBUF)
7141480Smckusick 
7249299Shibler struct vn_softc {
7341480Smckusick 	int		 sc_flags;	/* flags */
7449299Shibler 	size_t		 sc_size;	/* size of vn */
7541480Smckusick 	struct vnode	*sc_vp;		/* vnode */
7641480Smckusick 	struct ucred	*sc_cred;	/* credentials */
7741480Smckusick 	int		 sc_maxactive;	/* max # of active requests */
7859342Shibler 	struct buf	 sc_tab;	/* transfer queue */
7959342Shibler };
8041480Smckusick 
8141480Smckusick /* sc_flags */
8249299Shibler #define	VNF_ALIVE	0x01
8349299Shibler #define VNF_INITED	0x02
8441480Smckusick 
8559342Shibler #if 0	/* if you need static allocation */
8659342Shibler struct vn_softc vn_softc[NVN];
8759342Shibler int numvnd = NVN;
8859342Shibler #else
8959342Shibler struct vn_softc *vn_softc;
9059342Shibler int numvnd;
9159342Shibler #endif
9259342Shibler 
9359342Shibler void
9459342Shibler vnattach(num)
9559342Shibler 	int num;
9659342Shibler {
9759342Shibler 	char *mem;
9859342Shibler 	register u_long size;
9959342Shibler 
10059342Shibler 	if (num <= 0)
10159342Shibler 		return;
10259342Shibler 	size = num * sizeof(struct vn_softc);
10359342Shibler 	mem = malloc(size, M_DEVBUF, M_NOWAIT);
10459342Shibler 	if (mem == NULL) {
10559342Shibler 		printf("WARNING: no memory for vnode disks\n");
10659342Shibler 		return;
10759342Shibler 	}
10859342Shibler 	bzero(mem, size);
10959342Shibler 	vn_softc = (struct vn_softc *)mem;
11059342Shibler 	numvnd = num;
11159342Shibler }
11259342Shibler 
11349299Shibler int
11449299Shibler vnopen(dev, flags, mode, p)
11541480Smckusick 	dev_t dev;
11649299Shibler 	int flags, mode;
11749299Shibler 	struct proc *p;
11841480Smckusick {
11949299Shibler 	int unit = vnunit(dev);
12041480Smckusick 
12141480Smckusick #ifdef DEBUG
12249299Shibler 	if (vndebug & VDB_FOLLOW)
12349299Shibler 		printf("vnopen(%x, %x, %x, %x)\n", dev, flags, mode, p);
12441480Smckusick #endif
12559342Shibler 	if (unit >= numvnd)
12641480Smckusick 		return(ENXIO);
12741480Smckusick 	return(0);
12841480Smckusick }
12941480Smckusick 
13041480Smckusick /*
13141480Smckusick  * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY.
13241480Smckusick  * Note that this driver can only be used for swapping over NFS on the hp
13341480Smckusick  * since nfs_strategy on the vax cannot handle u-areas and page tables.
13441480Smckusick  */
13549299Shibler vnstrategy(bp)
13641480Smckusick 	register struct buf *bp;
13741480Smckusick {
13849299Shibler 	int unit = vnunit(bp->b_dev);
13949299Shibler 	register struct vn_softc *vn = &vn_softc[unit];
14041480Smckusick 	register struct buf *nbp;
14141480Smckusick 	register int bn, bsize, resid;
14241480Smckusick 	register caddr_t addr;
14341480Smckusick 	int sz, flags;
14453921Shibler 	extern void vniodone();
14541480Smckusick 
14641480Smckusick #ifdef DEBUG
14749299Shibler 	if (vndebug & VDB_FOLLOW)
14849299Shibler 		printf("vnstrategy(%x): unit %d\n", bp, unit);
14941480Smckusick #endif
15049299Shibler 	if ((vn->sc_flags & VNF_INITED) == 0) {
15141480Smckusick 		bp->b_error = ENXIO;
15241480Smckusick 		bp->b_flags |= B_ERROR;
15349299Shibler 		biodone(bp);
15441480Smckusick 		return;
15541480Smckusick 	}
15641480Smckusick 	bn = bp->b_blkno;
15741480Smckusick 	sz = howmany(bp->b_bcount, DEV_BSIZE);
15841480Smckusick 	bp->b_resid = bp->b_bcount;
15949299Shibler 	if (bn < 0 || bn + sz > vn->sc_size) {
16049299Shibler 		if (bn != vn->sc_size) {
16141480Smckusick 			bp->b_error = EINVAL;
16241480Smckusick 			bp->b_flags |= B_ERROR;
16341480Smckusick 		}
16449299Shibler 		biodone(bp);
16541480Smckusick 		return;
16641480Smckusick 	}
16741480Smckusick 	bn = dbtob(bn);
16851945Smckusick 	bsize = vn->sc_vp->v_mount->mnt_stat.f_iosize;
16941480Smckusick 	addr = bp->b_un.b_addr;
17041480Smckusick 	flags = bp->b_flags | B_CALL;
17141480Smckusick 	for (resid = bp->b_resid; resid; resid -= sz) {
17241480Smckusick 		struct vnode *vp;
17341480Smckusick 		daddr_t nbn;
17441480Smckusick 		int off, s;
17541480Smckusick 
17649299Shibler 		nbp = getvnbuf();
17741480Smckusick 		off = bn % bsize;
17855159Spendry 		sz = min(bsize - off, resid);
17956453Smargo 		(void) VOP_BMAP(vn->sc_vp, bn / bsize, &vp, &nbn, NULL);
18041480Smckusick #ifdef DEBUG
18149299Shibler 		if (vndebug & VDB_IO)
18249299Shibler 			printf("vnstrategy: vp %x/%x bn %x/%x\n",
18349299Shibler 			       vn->sc_vp, vp, bn, nbn);
18441480Smckusick #endif
18541480Smckusick 		nbp->b_flags = flags;
18641480Smckusick 		nbp->b_bcount = sz;
18741480Smckusick 		nbp->b_bufsize = bp->b_bufsize;
18841480Smckusick 		nbp->b_error = 0;
18949299Shibler 		if (vp->v_type == VBLK || vp->v_type == VCHR)
19049299Shibler 			nbp->b_dev = vp->v_rdev;
19149299Shibler 		else
19249299Shibler 			nbp->b_dev = NODEV;
19341480Smckusick 		nbp->b_un.b_addr = addr;
19441480Smckusick 		nbp->b_blkno = nbn + btodb(off);
19541480Smckusick 		nbp->b_proc = bp->b_proc;
19649299Shibler 		nbp->b_iodone = vniodone;
19741480Smckusick 		nbp->b_vp = vp;
19841480Smckusick 		nbp->b_pfcent = (int) bp;	/* XXX */
19957301Shibler 		nbp->b_rcred = vn->sc_cred;	/* XXX crdup? */
20057301Shibler 		nbp->b_wcred = vn->sc_cred;	/* XXX crdup? */
20157301Shibler 		nbp->b_dirtyoff = bp->b_dirtyoff;
20257301Shibler 		nbp->b_dirtyend = bp->b_dirtyend;
20357301Shibler 		nbp->b_validoff = bp->b_validoff;
20457301Shibler 		nbp->b_validend = bp->b_validend;
20541480Smckusick 		/*
20641480Smckusick 		 * Just sort by block number
20741480Smckusick 		 */
20841480Smckusick 		nbp->b_cylin = nbp->b_blkno;
20941480Smckusick 		s = splbio();
21059342Shibler 		disksort(&vn->sc_tab, nbp);
21159342Shibler 		if (vn->sc_tab.b_active < vn->sc_maxactive) {
21259342Shibler 			vn->sc_tab.b_active++;
21359342Shibler 			vnstart(vn);
21441480Smckusick 		}
21541480Smckusick 		splx(s);
21641480Smckusick 		bn += sz;
21741480Smckusick 		addr += sz;
21841480Smckusick 	}
21941480Smckusick }
22041480Smckusick 
22141480Smckusick /*
22241480Smckusick  * Feed requests sequentially.
22341480Smckusick  * We do it this way to keep from flooding NFS servers if we are connected
22441480Smckusick  * to an NFS file.  This places the burden on the client rather than the
22541480Smckusick  * server.
22641480Smckusick  */
22759342Shibler vnstart(vn)
22859342Shibler 	register struct vn_softc *vn;
22941480Smckusick {
23041480Smckusick 	register struct buf *bp;
23141480Smckusick 
23241480Smckusick 	/*
23341480Smckusick 	 * Dequeue now since lower level strategy routine might
23441480Smckusick 	 * queue using same links
23541480Smckusick 	 */
23659342Shibler 	bp = vn->sc_tab.b_actf;
23759342Shibler 	vn->sc_tab.b_actf = bp->b_actf;
23841480Smckusick #ifdef DEBUG
23949299Shibler 	if (vndebug & VDB_IO)
24049299Shibler 		printf("vnstart(%d): bp %x vp %x blkno %x addr %x cnt %x\n",
24159342Shibler 		       vn-vn_softc, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr,
24241480Smckusick 		       bp->b_bcount);
24341480Smckusick #endif
24457301Shibler 	if ((bp->b_flags & B_READ) == 0)
24557301Shibler 		bp->b_vp->v_numoutput++;
24641480Smckusick 	VOP_STRATEGY(bp);
24741480Smckusick }
24841480Smckusick 
24953921Shibler void
25049299Shibler vniodone(bp)
25141480Smckusick 	register struct buf *bp;
25241480Smckusick {
25341480Smckusick 	register struct buf *pbp = (struct buf *)bp->b_pfcent;	/* XXX */
25459342Shibler 	register struct vn_softc *vn = &vn_softc[vnunit(pbp->b_dev)];
25541480Smckusick 	int s;
25641480Smckusick 
25741480Smckusick 	s = splbio();
25841480Smckusick #ifdef DEBUG
25949299Shibler 	if (vndebug & VDB_IO)
26049299Shibler 		printf("vniodone(%d): bp %x vp %x blkno %x addr %x cnt %x\n",
26159342Shibler 		       vn-vn_softc, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr,
26241480Smckusick 		       bp->b_bcount);
26341480Smckusick #endif
26441480Smckusick 	if (bp->b_error) {
26541480Smckusick #ifdef DEBUG
26649299Shibler 		if (vndebug & VDB_IO)
26749299Shibler 			printf("vniodone: bp %x error %d\n", bp, bp->b_error);
26841480Smckusick #endif
26941480Smckusick 		pbp->b_flags |= B_ERROR;
27049299Shibler 		pbp->b_error = biowait(bp);
27141480Smckusick 	}
27241480Smckusick 	pbp->b_resid -= bp->b_bcount;
27349299Shibler 	putvnbuf(bp);
27441480Smckusick 	if (pbp->b_resid == 0) {
27541480Smckusick #ifdef DEBUG
27649299Shibler 		if (vndebug & VDB_IO)
27749299Shibler 			printf("vniodone: pbp %x iodone\n", pbp);
27841480Smckusick #endif
27949299Shibler 		biodone(pbp);
28041480Smckusick 	}
28159342Shibler 	if (vn->sc_tab.b_actf)
28259342Shibler 		vnstart(vn);
28341480Smckusick 	else
28459342Shibler 		vn->sc_tab.b_active--;
28541480Smckusick 	splx(s);
28641480Smckusick }
28741480Smckusick 
28849299Shibler vnread(dev, uio, flags, p)
28941480Smckusick 	dev_t dev;
29041480Smckusick 	struct uio *uio;
29149299Shibler 	int flags;
29249299Shibler 	struct proc *p;
29341480Smckusick {
29441480Smckusick 
29541480Smckusick #ifdef DEBUG
29649299Shibler 	if (vndebug & VDB_FOLLOW)
29749299Shibler 		printf("vnread(%x, %x, %x, %x)\n", dev, uio, flags, p);
29841480Smckusick #endif
29959342Shibler 	return(physio(vnstrategy, NULL, dev, B_READ, minphys, uio));
30041480Smckusick }
30141480Smckusick 
30249299Shibler vnwrite(dev, uio, flags, p)
30341480Smckusick 	dev_t dev;
30441480Smckusick 	struct uio *uio;
30549299Shibler 	int flags;
30649299Shibler 	struct proc *p;
30741480Smckusick {
30841480Smckusick 
30941480Smckusick #ifdef DEBUG
31049299Shibler 	if (vndebug & VDB_FOLLOW)
31149299Shibler 		printf("vnwrite(%x, %x, %x, %x)\n", dev, uio, flags, p);
31241480Smckusick #endif
31359342Shibler 	return(physio(vnstrategy, NULL, dev, B_WRITE, minphys, uio));
31441480Smckusick }
31541480Smckusick 
31641480Smckusick /* ARGSUSED */
31749299Shibler vnioctl(dev, cmd, data, flag, p)
31841480Smckusick 	dev_t dev;
31941480Smckusick 	u_long cmd;
32041480Smckusick 	caddr_t data;
32141480Smckusick 	int flag;
32249299Shibler 	struct proc *p;
32341480Smckusick {
32449299Shibler 	int unit = vnunit(dev);
32549299Shibler 	register struct vn_softc *vn;
32649299Shibler 	struct vn_ioctl *vio;
32741480Smckusick 	struct vattr vattr;
32849299Shibler 	struct nameidata nd;
32941480Smckusick 	int error;
33041480Smckusick 
33141480Smckusick #ifdef DEBUG
33249299Shibler 	if (vndebug & VDB_FOLLOW)
33349299Shibler 		printf("vnioctl(%x, %x, %x, %x, %x): unit %d\n",
33449299Shibler 		       dev, cmd, data, flag, p, unit);
33541480Smckusick #endif
33649299Shibler 	error = suser(p->p_ucred, &p->p_acflag);
33741480Smckusick 	if (error)
33841480Smckusick 		return (error);
33959342Shibler 	if (unit >= numvnd)
34041480Smckusick 		return (ENXIO);
34141480Smckusick 
34249299Shibler 	vn = &vn_softc[unit];
34349299Shibler 	vio = (struct vn_ioctl *)data;
34441480Smckusick 	switch (cmd) {
34541480Smckusick 
34649299Shibler 	case VNIOCSET:
34749299Shibler 		if (vn->sc_flags & VNF_INITED)
34841480Smckusick 			return(EBUSY);
34941480Smckusick 		/*
35041480Smckusick 		 * Always open for read and write.
35141480Smckusick 		 * This is probably bogus, but it lets vn_open()
35241480Smckusick 		 * weed out directories, sockets, etc. so we don't
35341480Smckusick 		 * have to worry about them.
35441480Smckusick 		 */
35552761Shibler 		NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vn_file, p);
35652761Shibler 		if (error = vn_open(&nd, FREAD|FWRITE, 0))
35741480Smckusick 			return(error);
35850115Smckusick 		if (error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p)) {
35950115Smckusick 			VOP_UNLOCK(nd.ni_vp);
36050115Smckusick 			(void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
36141480Smckusick 			return(error);
36241480Smckusick 		}
36350115Smckusick 		VOP_UNLOCK(nd.ni_vp);
36449299Shibler 		vn->sc_vp = nd.ni_vp;
36549299Shibler 		vn->sc_size = btodb(vattr.va_size);	/* note truncation */
36650115Smckusick 		if (error = vnsetcred(vn, p->p_ucred)) {
36750115Smckusick 			(void) vn_close(vn->sc_vp, FREAD|FWRITE, p->p_ucred, p);
36841480Smckusick 			return(error);
36941480Smckusick 		}
37049299Shibler 		vnthrottle(vn, vn->sc_vp);
37149299Shibler 		vio->vn_size = dbtob(vn->sc_size);
37249299Shibler 		vn->sc_flags |= VNF_INITED;
37341480Smckusick #ifdef DEBUG
37449299Shibler 		if (vndebug & VDB_INIT)
37549299Shibler 			printf("vnioctl: SET vp %x size %x\n",
37649299Shibler 			       vn->sc_vp, vn->sc_size);
37741480Smckusick #endif
37841480Smckusick 		break;
37941480Smckusick 
38049299Shibler 	case VNIOCCLR:
38149299Shibler 		if ((vn->sc_flags & VNF_INITED) == 0)
38241480Smckusick 			return(ENXIO);
38349299Shibler 		vnclear(vn);
38441480Smckusick #ifdef DEBUG
38549299Shibler 		if (vndebug & VDB_INIT)
38649299Shibler 			printf("vnioctl: CLRed\n");
38741480Smckusick #endif
38841480Smckusick 		break;
38941480Smckusick 
39041480Smckusick 	default:
39141480Smckusick 		return(ENXIO);
39241480Smckusick 	}
39341480Smckusick 	return(0);
39441480Smckusick }
39541480Smckusick 
39641480Smckusick /*
39741480Smckusick  * Duplicate the current processes' credentials.  Since we are called only
39841480Smckusick  * as the result of a SET ioctl and only root can do that, any future access
39941480Smckusick  * to this "disk" is essentially as root.  Note that credentials may change
40041480Smckusick  * if some other uid can write directly to the mapped file (NFS).
40141480Smckusick  */
40249299Shibler vnsetcred(vn, cred)
40349299Shibler 	register struct vn_softc *vn;
40449299Shibler 	struct ucred cred;
40541480Smckusick {
40641480Smckusick 	struct uio auio;
40741480Smckusick 	struct iovec aiov;
40841480Smckusick 	char tmpbuf[DEV_BSIZE];
40941480Smckusick 
41049299Shibler 	vn->sc_cred = crdup(cred);
41141480Smckusick 	/* XXX: Horrible kludge to establish credentials for NFS */
41241480Smckusick 	aiov.iov_base = tmpbuf;
41355159Spendry 	aiov.iov_len = min(DEV_BSIZE, dbtob(vn->sc_size));
41441480Smckusick 	auio.uio_iov = &aiov;
41541480Smckusick 	auio.uio_iovcnt = 1;
41641480Smckusick 	auio.uio_offset = 0;
41741480Smckusick 	auio.uio_rw = UIO_READ;
41841480Smckusick 	auio.uio_segflg = UIO_SYSSPACE;
41941480Smckusick 	auio.uio_resid = aiov.iov_len;
42049299Shibler 	return(VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred));
42141480Smckusick }
42241480Smckusick 
42341480Smckusick /*
42441480Smckusick  * Set maxactive based on FS type
42541480Smckusick  */
42649299Shibler vnthrottle(vn, vp)
42749299Shibler 	register struct vn_softc *vn;
42841480Smckusick 	struct vnode *vp;
42941480Smckusick {
43053517Sheideman 	extern int (**nfsv2_vnodeop_p)();
43141480Smckusick 
43253517Sheideman 	if (vp->v_op == nfsv2_vnodeop_p)
43349299Shibler 		vn->sc_maxactive = 2;
43441480Smckusick 	else
43549299Shibler 		vn->sc_maxactive = 8;
43641480Smckusick 
43749299Shibler 	if (vn->sc_maxactive < 1)
43849299Shibler 		vn->sc_maxactive = 1;
43941480Smckusick }
44041480Smckusick 
44149299Shibler vnshutdown()
44241480Smckusick {
44349299Shibler 	register struct vn_softc *vn;
44441480Smckusick 
44559342Shibler 	for (vn = &vn_softc[0]; vn < &vn_softc[numvnd]; vn++)
44649299Shibler 		if (vn->sc_flags & VNF_INITED)
44749299Shibler 			vnclear(vn);
44841480Smckusick }
44941480Smckusick 
45049299Shibler vnclear(vn)
45149299Shibler 	register struct vn_softc *vn;
45241480Smckusick {
45349299Shibler 	register struct vnode *vp = vn->sc_vp;
45450115Smckusick 	struct proc *p = curproc;		/* XXX */
45541480Smckusick 
45641480Smckusick #ifdef DEBUG
45749299Shibler 	if (vndebug & VDB_FOLLOW)
45849299Shibler 		printf("vnclear(%x): vp %x\n", vp);
45941480Smckusick #endif
46049299Shibler 	vn->sc_flags &= ~VNF_INITED;
46141480Smckusick 	if (vp == (struct vnode *)0)
46249299Shibler 		panic("vnioctl: null vp");
46341480Smckusick #if 0
46441480Smckusick 	/* XXX - this doesn't work right now */
46549299Shibler 	(void) VOP_FSYNC(vp, 0, vn->sc_cred, MNT_WAIT, p);
46641480Smckusick #endif
46750115Smckusick 	(void) vn_close(vp, FREAD|FWRITE, vn->sc_cred, p);
46849299Shibler 	crfree(vn->sc_cred);
46949299Shibler 	vn->sc_vp = (struct vnode *)0;
47049299Shibler 	vn->sc_cred = (struct ucred *)0;
47149299Shibler 	vn->sc_size = 0;
47241480Smckusick }
47341480Smckusick 
47449299Shibler vnsize(dev)
47541480Smckusick 	dev_t dev;
47641480Smckusick {
47749299Shibler 	int unit = vnunit(dev);
47849299Shibler 	register struct vn_softc *vn = &vn_softc[unit];
47941480Smckusick 
48059342Shibler 	if (unit >= numvnd || (vn->sc_flags & VNF_INITED) == 0)
48141480Smckusick 		return(-1);
48249299Shibler 	return(vn->sc_size);
48341480Smckusick }
48441480Smckusick 
48549299Shibler vndump(dev)
48641480Smckusick {
48741480Smckusick 	return(ENXIO);
48841480Smckusick }
48941480Smckusick #endif
490