xref: /netbsd-src/sys/dev/vnd.c (revision b8c616269f5ebf18ab2e35cb8099d683130a177c)
1 /*	$NetBSD: vnd.c,v 1.90 2003/01/25 23:09:59 kleink Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Copyright (c) 1988 University of Utah.
41  * Copyright (c) 1990, 1993
42  *	The Regents of the University of California.  All rights reserved.
43  *
44  * This code is derived from software contributed to Berkeley by
45  * the Systems Programming Group of the University of Utah Computer
46  * Science Department.
47  *
48  * Redistribution and use in source and binary forms, with or without
49  * modification, are permitted provided that the following conditions
50  * are met:
51  * 1. Redistributions of source code must retain the above copyright
52  *    notice, this list of conditions and the following disclaimer.
53  * 2. Redistributions in binary form must reproduce the above copyright
54  *    notice, this list of conditions and the following disclaimer in the
55  *    documentation and/or other materials provided with the distribution.
56  * 3. All advertising materials mentioning features or use of this software
57  *    must display the following acknowledgement:
58  *	This product includes software developed by the University of
59  *	California, Berkeley and its contributors.
60  * 4. Neither the name of the University nor the names of its contributors
61  *    may be used to endorse or promote products derived from this software
62  *    without specific prior written permission.
63  *
64  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74  * SUCH DAMAGE.
75  *
76  * from: Utah $Hdr: vn.c 1.13 94/04/02$
77  *
78  *	@(#)vn.c	8.9 (Berkeley) 5/14/95
79  */
80 
81 /*
82  * Vnode disk driver.
83  *
84  * Block/character interface to a vnode.  Allows one to treat a file
85  * as a disk (e.g. build a filesystem in it, mount it, etc.).
86  *
87  * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode
88  * instead of a simple VOP_RDWR.  We do this to avoid distorting the
89  * local buffer cache.
90  *
91  * NOTE 2: There is a security issue involved with this driver.
92  * Once mounted all access to the contents of the "mapped" file via
93  * the special file is controlled by the permissions on the special
94  * file, the protection of the mapped file is ignored (effectively,
95  * by using root credentials in all transactions).
96  *
97  * NOTE 3: Doesn't interact with leases, should it?
98  */
99 
100 #include <sys/cdefs.h>
101 __KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.90 2003/01/25 23:09:59 kleink Exp $");
102 
103 #if defined(_KERNEL_OPT)
104 #include "fs_nfs.h"
105 #endif
106 
107 #include <sys/param.h>
108 #include <sys/systm.h>
109 #include <sys/namei.h>
110 #include <sys/proc.h>
111 #include <sys/errno.h>
112 #include <sys/buf.h>
113 #include <sys/malloc.h>
114 #include <sys/ioctl.h>
115 #include <sys/disklabel.h>
116 #include <sys/device.h>
117 #include <sys/disk.h>
118 #include <sys/stat.h>
119 #include <sys/mount.h>
120 #include <sys/vnode.h>
121 #include <sys/file.h>
122 #include <sys/uio.h>
123 #include <sys/conf.h>
124 
125 #include <miscfs/specfs/specdev.h>
126 
127 #include <dev/vndvar.h>
128 
129 #if defined(VNDDEBUG) && !defined(DEBUG)
130 #define	DEBUG
131 #endif
132 
133 #ifdef DEBUG
134 int dovndcluster = 1;
135 #define	VDB_FOLLOW	0x01
136 #define	VDB_INIT	0x02
137 #define	VDB_IO		0x04
138 #define	VDB_LABEL	0x08
139 int vnddebug = 0x00;
140 #endif
141 
142 #define	vndunit(x)	DISKUNIT(x)
143 
144 struct vndxfer {
145 	struct buf	*vx_bp;		/* Pointer to parent buffer */
146 	int		vx_error;
147 	int		vx_pending;	/* # of pending aux buffers */
148 	int		vx_flags;
149 #define VX_BUSY		1
150 };
151 
152 struct vndbuf {
153 	struct buf	vb_buf;
154 	struct vndxfer	*vb_xfer;
155 };
156 
157 #define	VND_GETXFER(vnd)	pool_get(&(vnd)->sc_vxpool, PR_NOWAIT)
158 #define	VND_PUTXFER(vnd, vx)	pool_put(&(vnd)->sc_vxpool, (vx))
159 
160 #define	VND_GETBUF(vnd)		pool_get(&(vnd)->sc_vbpool, PR_NOWAIT)
161 #define	VND_PUTBUF(vnd, vb)	pool_put(&(vnd)->sc_vbpool, (vb))
162 
163 struct vnd_softc *vnd_softc;
164 int numvnd = 0;
165 
166 #define	VNDLABELDEV(dev) \
167 	(MAKEDISKDEV(major((dev)), vndunit((dev)), RAW_PART))
168 
169 /* called by main() at boot time (XXX: and the LKM driver) */
170 void	vndattach __P((int));
171 int	vnddetach __P((void));
172 
173 void	vndclear __P((struct vnd_softc *));
174 void	vndstart __P((struct vnd_softc *));
175 int	vndsetcred __P((struct vnd_softc *, struct ucred *));
176 void	vndthrottle __P((struct vnd_softc *, struct vnode *));
177 void	vndiodone __P((struct buf *));
178 void	vndshutdown __P((void));
179 
180 void	vndgetdefaultlabel __P((struct vnd_softc *, struct disklabel *));
181 void	vndgetdisklabel __P((dev_t));
182 
183 static	int vndlock __P((struct vnd_softc *));
184 static	void vndunlock __P((struct vnd_softc *));
185 
186 dev_type_open(vndopen);
187 dev_type_close(vndclose);
188 dev_type_read(vndread);
189 dev_type_write(vndwrite);
190 dev_type_ioctl(vndioctl);
191 dev_type_strategy(vndstrategy);
192 dev_type_dump(vnddump);
193 dev_type_size(vndsize);
194 
195 const struct bdevsw vnd_bdevsw = {
196 	vndopen, vndclose, vndstrategy, vndioctl, vnddump, vndsize, D_DISK
197 };
198 
199 const struct cdevsw vnd_cdevsw = {
200 	vndopen, vndclose, vndread, vndwrite, vndioctl,
201 	nostop, notty, nopoll, nommap, nokqfilter, D_DISK
202 };
203 
204 int vndattached = 0;
205 
206 void
207 vndattach(num)
208 	int num;
209 {
210 	int i;
211 	char *mem;
212 
213 	if (vndattached)
214 		return;
215 	vndattached = 1;
216 	if (num <= 0)
217 		return;
218 	i = num * sizeof(struct vnd_softc);
219 	mem = malloc(i, M_DEVBUF, M_NOWAIT|M_ZERO);
220 	if (mem == NULL) {
221 		printf("WARNING: no memory for vnode disks\n");
222 		return;
223 	}
224 	vnd_softc = (struct vnd_softc *)mem;
225 	numvnd = num;
226 
227 	for (i = 0; i < numvnd; i++)
228 		bufq_alloc(&vnd_softc[i].sc_tab,
229 		    BUFQ_DISKSORT|BUFQ_SORT_RAWBLOCK);
230 }
231 
232 int
233 vnddetach()
234 {
235 	int i;
236 
237 	/* First check we aren't in use. */
238 	for (i = 0; i < numvnd; i++)
239 		if (vnd_softc[i].sc_flags & VNF_INITED)
240 			return (EBUSY);
241 
242 	for (i = 0; i < numvnd; i++)
243 		bufq_free(&vnd_softc[i].sc_tab);
244 
245 	free(vnd_softc, M_DEVBUF);
246 	vndattached = 0;
247 
248 	return (0);
249 }
250 
251 int
252 vndopen(dev, flags, mode, p)
253 	dev_t dev;
254 	int flags, mode;
255 	struct proc *p;
256 {
257 	int unit = vndunit(dev);
258 	struct vnd_softc *sc;
259 	int error = 0, part, pmask;
260 	struct disklabel *lp;
261 
262 #ifdef DEBUG
263 	if (vnddebug & VDB_FOLLOW)
264 		printf("vndopen(0x%x, 0x%x, 0x%x, %p)\n", dev, flags, mode, p);
265 #endif
266 	if (unit >= numvnd)
267 		return (ENXIO);
268 	sc = &vnd_softc[unit];
269 
270 	if ((error = vndlock(sc)) != 0)
271 		return (error);
272 
273 	lp = sc->sc_dkdev.dk_label;
274 
275 	part = DISKPART(dev);
276 	pmask = (1 << part);
277 
278 	/*
279 	 * If we're initialized, check to see if there are any other
280 	 * open partitions.  If not, then it's safe to update the
281 	 * in-core disklabel.
282 	 */
283 	if ((sc->sc_flags & VNF_INITED) && (sc->sc_dkdev.dk_openmask == 0))
284 		vndgetdisklabel(dev);
285 
286 	/* Check that the partitions exists. */
287 	if (part != RAW_PART) {
288 		if (((sc->sc_flags & VNF_INITED) == 0) ||
289 		    ((part >= lp->d_npartitions) ||
290 		     (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
291 			error = ENXIO;
292 			goto done;
293 		}
294 	}
295 
296 	/* Prevent our unit from being unconfigured while open. */
297 	switch (mode) {
298 	case S_IFCHR:
299 		sc->sc_dkdev.dk_copenmask |= pmask;
300 		break;
301 
302 	case S_IFBLK:
303 		sc->sc_dkdev.dk_bopenmask |= pmask;
304 		break;
305 	}
306 	sc->sc_dkdev.dk_openmask =
307 	    sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
308 
309  done:
310 	vndunlock(sc);
311 	return (error);
312 }
313 
314 int
315 vndclose(dev, flags, mode, p)
316 	dev_t dev;
317 	int flags, mode;
318 	struct proc *p;
319 {
320 	int unit = vndunit(dev);
321 	struct vnd_softc *sc;
322 	int error = 0, part;
323 
324 #ifdef DEBUG
325 	if (vnddebug & VDB_FOLLOW)
326 		printf("vndclose(0x%x, 0x%x, 0x%x, %p)\n", dev, flags, mode, p);
327 #endif
328 
329 	if (unit >= numvnd)
330 		return (ENXIO);
331 	sc = &vnd_softc[unit];
332 
333 	if ((error = vndlock(sc)) != 0)
334 		return (error);
335 
336 	part = DISKPART(dev);
337 
338 	/* ...that much closer to allowing unconfiguration... */
339 	switch (mode) {
340 	case S_IFCHR:
341 		sc->sc_dkdev.dk_copenmask &= ~(1 << part);
342 		break;
343 
344 	case S_IFBLK:
345 		sc->sc_dkdev.dk_bopenmask &= ~(1 << part);
346 		break;
347 	}
348 	sc->sc_dkdev.dk_openmask =
349 	    sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
350 
351 	vndunlock(sc);
352 	return (0);
353 }
354 
355 /*
356  * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY.
357  */
358 void
359 vndstrategy(bp)
360 	struct buf *bp;
361 {
362 	int unit = vndunit(bp->b_dev);
363 	struct vnd_softc *vnd = &vnd_softc[unit];
364 	struct vndxfer *vnx;
365 	int s, bsize, resid;
366 	off_t bn;
367 	caddr_t addr;
368 	int sz, flags, error, wlabel;
369 	struct disklabel *lp;
370 	struct partition *pp;
371 
372 #ifdef DEBUG
373 	if (vnddebug & VDB_FOLLOW)
374 		printf("vndstrategy(%p): unit %d\n", bp, unit);
375 #endif
376 	if ((vnd->sc_flags & VNF_INITED) == 0) {
377 		bp->b_error = ENXIO;
378 		bp->b_flags |= B_ERROR;
379 		goto done;
380 	}
381 
382 	/* If it's a nil transfer, wake up the top half now. */
383 	if (bp->b_bcount == 0)
384 		goto done;
385 
386 	lp = vnd->sc_dkdev.dk_label;
387 
388 	/*
389 	 * The transfer must be a whole number of blocks.
390 	 */
391 	if ((bp->b_bcount % lp->d_secsize) != 0) {
392 		bp->b_error = EINVAL;
393 		bp->b_flags |= B_ERROR;
394 		goto done;
395 	}
396 
397 	/*
398 	 * Do bounds checking and adjust transfer.  If there's an error,
399 	 * the bounds check will flag that for us.
400 	 */
401 	wlabel = vnd->sc_flags & (VNF_WLABEL|VNF_LABELLING);
402 	if (DISKPART(bp->b_dev) != RAW_PART)
403 		if (bounds_check_with_label(bp, lp, wlabel) <= 0)
404 			goto done;
405 
406 	bp->b_resid = bp->b_bcount;
407 
408 	/*
409 	 * Put the block number in terms of the logical blocksize
410 	 * of the "device".
411 	 */
412 	bn = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
413 
414 	/*
415 	 * Translate the partition-relative block number to an absolute.
416 	 */
417 	if (DISKPART(bp->b_dev) != RAW_PART) {
418 		pp = &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
419 		bn += pp->p_offset;
420 	}
421 
422 	/* ...and convert to a byte offset within the file. */
423 	bn *= lp->d_secsize;
424 
425 	if (vnd->sc_vp->v_mount == NULL) {
426 		bp->b_error = ENXIO;
427 		bp->b_flags |= B_ERROR;
428 		goto done;
429 	}
430  	bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize;
431 	addr = bp->b_data;
432 	flags = (bp->b_flags & (B_READ|B_ASYNC)) | B_CALL;
433 
434 	/* Allocate a header for this transfer and link it to the buffer */
435 	s = splbio();
436 	vnx = VND_GETXFER(vnd);
437 	splx(s);
438 	vnx->vx_flags = VX_BUSY;
439 	vnx->vx_error = 0;
440 	vnx->vx_pending = 0;
441 	vnx->vx_bp = bp;
442 
443 	for (resid = bp->b_resid; resid; resid -= sz) {
444 		struct vndbuf *nbp;
445 		struct vnode *vp;
446 		daddr_t nbn;
447 		int off, nra;
448 
449 		nra = 0;
450 		vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE);
451 		error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra);
452 		VOP_UNLOCK(vnd->sc_vp, 0);
453 
454 		if (error == 0 && (long)nbn == -1)
455 			error = EIO;
456 
457 		/*
458 		 * If there was an error or a hole in the file...punt.
459 		 * Note that we may have to wait for any operations
460 		 * that we have already fired off before releasing
461 		 * the buffer.
462 		 *
463 		 * XXX we could deal with holes here but it would be
464 		 * a hassle (in the write case).
465 		 */
466 		if (error) {
467 			s = splbio();
468 			vnx->vx_error = error;
469 			goto out;
470 		}
471 
472 #ifdef DEBUG
473 		if (!dovndcluster)
474 			nra = 0;
475 #endif
476 
477 		if ((off = bn % bsize) != 0)
478 			sz = bsize - off;
479 		else
480 			sz = (1 + nra) * bsize;
481 		if (resid < sz)
482 			sz = resid;
483 #ifdef DEBUG
484 		if (vnddebug & VDB_IO)
485 			printf("vndstrategy: vp %p/%p bn 0x%qx/0x%" PRIx64
486 			       " sz 0x%x\n",
487 			    vnd->sc_vp, vp, (long long)bn, nbn, sz);
488 #endif
489 
490 		s = splbio();
491 		nbp = VND_GETBUF(vnd);
492 		splx(s);
493 		nbp->vb_buf.b_flags = flags;
494 		nbp->vb_buf.b_bcount = sz;
495 		nbp->vb_buf.b_bufsize = round_page((ulong)addr + sz)
496 		    - trunc_page((ulong) addr);
497 		nbp->vb_buf.b_error = 0;
498 		nbp->vb_buf.b_data = addr;
499 		nbp->vb_buf.b_blkno = nbp->vb_buf.b_rawblkno = nbn + btodb(off);
500 		nbp->vb_buf.b_proc = bp->b_proc;
501 		nbp->vb_buf.b_iodone = vndiodone;
502 		nbp->vb_buf.b_vp = NULLVP;
503 		LIST_INIT(&nbp->vb_buf.b_dep);
504 
505 		nbp->vb_xfer = vnx;
506 
507 		/*
508 		 * Just sort by block number
509 		 */
510 		s = splbio();
511 		if (vnx->vx_error != 0) {
512 			VND_PUTBUF(vnd, nbp);
513 			goto out;
514 		}
515 		vnx->vx_pending++;
516 		bgetvp(vp, &nbp->vb_buf);
517 		BUFQ_PUT(&vnd->sc_tab, &nbp->vb_buf);
518 		vndstart(vnd);
519 		splx(s);
520 		bn += sz;
521 		addr += sz;
522 	}
523 
524 	s = splbio();
525 
526 out: /* Arrive here at splbio */
527 	vnx->vx_flags &= ~VX_BUSY;
528 	if (vnx->vx_pending == 0) {
529 		if (vnx->vx_error != 0) {
530 			bp->b_error = vnx->vx_error;
531 			bp->b_flags |= B_ERROR;
532 		}
533 		VND_PUTXFER(vnd, vnx);
534 		biodone(bp);
535 	}
536 	splx(s);
537 	return;
538 
539  done:
540 	biodone(bp);
541 }
542 
543 /*
544  * Feed requests sequentially.
545  * We do it this way to keep from flooding NFS servers if we are connected
546  * to an NFS file.  This places the burden on the client rather than the
547  * server.
548  */
549 void
550 vndstart(vnd)
551 	struct vnd_softc *vnd;
552 {
553 	struct buf	*bp;
554 
555 	/*
556 	 * Dequeue now since lower level strategy routine might
557 	 * queue using same links
558 	 */
559 
560 	if ((vnd->sc_flags & VNF_BUSY) != 0)
561 		return;
562 
563 	vnd->sc_flags |= VNF_BUSY;
564 
565 	while (vnd->sc_active < vnd->sc_maxactive) {
566 		bp = BUFQ_GET(&vnd->sc_tab);
567 		if (bp == NULL)
568 			break;
569 		vnd->sc_active++;
570 #ifdef DEBUG
571 		if (vnddebug & VDB_IO)
572 			printf("vndstart(%ld): bp %p vp %p blkno 0x%" PRIx64
573 				" flags %lx addr %p cnt 0x%lx\n",
574 			    (long) (vnd-vnd_softc), bp, bp->b_vp, bp->b_blkno,
575 			    bp->b_flags, bp->b_data, bp->b_bcount);
576 #endif
577 
578 		/* Instrumentation. */
579 		disk_busy(&vnd->sc_dkdev);
580 
581 		if ((bp->b_flags & B_READ) == 0)
582 			bp->b_vp->v_numoutput++;
583 		VOP_STRATEGY(bp);
584 	}
585 	vnd->sc_flags &= ~VNF_BUSY;
586 }
587 
588 void
589 vndiodone(bp)
590 	struct buf *bp;
591 {
592 	struct vndbuf *vbp = (struct vndbuf *) bp;
593 	struct vndxfer *vnx = (struct vndxfer *)vbp->vb_xfer;
594 	struct buf *pbp = vnx->vx_bp;
595 	struct vnd_softc *vnd = &vnd_softc[vndunit(pbp->b_dev)];
596 	int s, resid;
597 
598 	s = splbio();
599 #ifdef DEBUG
600 	if (vnddebug & VDB_IO)
601 		printf("vndiodone(%ld): vbp %p vp %p blkno 0x%" PRIx64
602 		       " addr %p cnt 0x%lx\n",
603 		    (long) (vnd-vnd_softc), vbp, vbp->vb_buf.b_vp,
604 		    vbp->vb_buf.b_blkno, vbp->vb_buf.b_data,
605 		    vbp->vb_buf.b_bcount);
606 #endif
607 
608 	resid = vbp->vb_buf.b_bcount - vbp->vb_buf.b_resid;
609 	pbp->b_resid -= resid;
610 	disk_unbusy(&vnd->sc_dkdev, resid, (pbp->b_flags & B_READ));
611 	vnx->vx_pending--;
612 
613 	if (vbp->vb_buf.b_error) {
614 #ifdef DEBUG
615 		if (vnddebug & VDB_IO)
616 			printf("vndiodone: vbp %p error %d\n", vbp,
617 			    vbp->vb_buf.b_error);
618 #endif
619 		vnx->vx_error = vbp->vb_buf.b_error;
620 	}
621 
622 	if (vbp->vb_buf.b_vp != NULLVP)
623 		brelvp(&vbp->vb_buf);
624 
625 	VND_PUTBUF(vnd, vbp);
626 
627 	/*
628 	 * Wrap up this transaction if it has run to completion or, in
629 	 * case of an error, when all auxiliary buffers have returned.
630 	 */
631 	if (vnx->vx_error != 0) {
632 		pbp->b_flags |= B_ERROR;
633 		pbp->b_error = vnx->vx_error;
634 		if ((vnx->vx_flags & VX_BUSY) == 0 && vnx->vx_pending == 0) {
635 
636 #ifdef DEBUG
637 			if (vnddebug & VDB_IO)
638 				printf("vndiodone: pbp %p iodone: error %d\n",
639 					pbp, vnx->vx_error);
640 #endif
641 			VND_PUTXFER(vnd, vnx);
642 			biodone(pbp);
643 		}
644 	} else if (pbp->b_resid == 0) {
645 
646 #ifdef DIAGNOSTIC
647 		if (vnx->vx_pending != 0)
648 			panic("vndiodone: vnx pending: %d", vnx->vx_pending);
649 #endif
650 
651 		if ((vnx->vx_flags & VX_BUSY) == 0) {
652 #ifdef DEBUG
653 			if (vnddebug & VDB_IO)
654 				printf("vndiodone: pbp %p iodone\n", pbp);
655 #endif
656 			VND_PUTXFER(vnd, vnx);
657 			biodone(pbp);
658 		}
659 	}
660 
661 	vnd->sc_active--;
662 	vndstart(vnd);
663 	splx(s);
664 }
665 
666 /* ARGSUSED */
667 int
668 vndread(dev, uio, flags)
669 	dev_t dev;
670 	struct uio *uio;
671 	int flags;
672 {
673 	int unit = vndunit(dev);
674 	struct vnd_softc *sc;
675 
676 #ifdef DEBUG
677 	if (vnddebug & VDB_FOLLOW)
678 		printf("vndread(0x%x, %p)\n", dev, uio);
679 #endif
680 
681 	if (unit >= numvnd)
682 		return (ENXIO);
683 	sc = &vnd_softc[unit];
684 
685 	if ((sc->sc_flags & VNF_INITED) == 0)
686 		return (ENXIO);
687 
688 	return (physio(vndstrategy, NULL, dev, B_READ, minphys, uio));
689 }
690 
691 /* ARGSUSED */
692 int
693 vndwrite(dev, uio, flags)
694 	dev_t dev;
695 	struct uio *uio;
696 	int flags;
697 {
698 	int unit = vndunit(dev);
699 	struct vnd_softc *sc;
700 
701 #ifdef DEBUG
702 	if (vnddebug & VDB_FOLLOW)
703 		printf("vndwrite(0x%x, %p)\n", dev, uio);
704 #endif
705 
706 	if (unit >= numvnd)
707 		return (ENXIO);
708 	sc = &vnd_softc[unit];
709 
710 	if ((sc->sc_flags & VNF_INITED) == 0)
711 		return (ENXIO);
712 
713 	return (physio(vndstrategy, NULL, dev, B_WRITE, minphys, uio));
714 }
715 
716 /* ARGSUSED */
717 int
718 vndioctl(dev, cmd, data, flag, p)
719 	dev_t dev;
720 	u_long cmd;
721 	caddr_t data;
722 	int flag;
723 	struct proc *p;
724 {
725 	int unit = vndunit(dev);
726 	struct vnd_softc *vnd;
727 	struct vnd_ioctl *vio;
728 	struct vattr vattr;
729 	struct nameidata nd;
730 	int error, part, pmask;
731 	size_t geomsize;
732 #ifdef __HAVE_OLD_DISKLABEL
733 	struct disklabel newlabel;
734 #endif
735 
736 #ifdef DEBUG
737 	if (vnddebug & VDB_FOLLOW)
738 		printf("vndioctl(0x%x, 0x%lx, %p, 0x%x, %p): unit %d\n",
739 		    dev, cmd, data, flag, p, unit);
740 #endif
741 	error = suser(p->p_ucred, &p->p_acflag);
742 	if (error)
743 		return (error);
744 	if (unit >= numvnd)
745 		return (ENXIO);
746 
747 	vnd = &vnd_softc[unit];
748 	vio = (struct vnd_ioctl *)data;
749 
750 	/* Must be open for writes for these commands... */
751 	switch (cmd) {
752 	case VNDIOCSET:
753 	case VNDIOCCLR:
754 	case DIOCSDINFO:
755 	case DIOCWDINFO:
756 #ifdef __HAVE_OLD_DISKLABEL
757 	case ODIOCSDINFO:
758 	case ODIOCWDINFO:
759 #endif
760 	case DIOCWLABEL:
761 		if ((flag & FWRITE) == 0)
762 			return (EBADF);
763 	}
764 
765 	/* Must be initialized for these... */
766 	switch (cmd) {
767 	case VNDIOCCLR:
768 	case DIOCGDINFO:
769 	case DIOCSDINFO:
770 	case DIOCWDINFO:
771 	case DIOCGPART:
772 	case DIOCWLABEL:
773 	case DIOCGDEFLABEL:
774 #ifdef __HAVE_OLD_DISKLABEL
775 	case ODIOCGDINFO:
776 	case ODIOCSDINFO:
777 	case ODIOCWDINFO:
778 	case ODIOCGDEFLABEL:
779 #endif
780 		if ((vnd->sc_flags & VNF_INITED) == 0)
781 			return (ENXIO);
782 	}
783 
784 	switch (cmd) {
785 	case VNDIOCSET:
786 		if (vnd->sc_flags & VNF_INITED)
787 			return (EBUSY);
788 
789 		if ((error = vndlock(vnd)) != 0)
790 			return (error);
791 
792 		/*
793 		 * Always open for read and write.
794 		 * This is probably bogus, but it lets vn_open()
795 		 * weed out directories, sockets, etc. so we don't
796 		 * have to worry about them.
797 		 */
798 		NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p);
799 		if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0)
800 			goto unlock_and_exit;
801 		error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
802 		VOP_UNLOCK(nd.ni_vp, 0);
803 		if (error)
804 			goto close_and_exit;
805 		vnd->sc_vp = nd.ni_vp;
806 		vnd->sc_size = btodb(vattr.va_size);	/* note truncation */
807 
808 		/*
809 		 * Use pseudo-geometry specified.  If none was provided,
810 		 * use "standard" Adaptec fictitious geometry.
811 		 */
812 		if (vio->vnd_flags & VNDIOF_HASGEOM) {
813 
814 			memcpy(&vnd->sc_geom, &vio->vnd_geom,
815 			    sizeof(vio->vnd_geom));
816 
817 			/*
818 			 * Sanity-check the sector size.
819 			 * XXX Don't allow secsize < DEV_BSIZE.  Should
820 			 * XXX we?
821 			 */
822 			if (vnd->sc_geom.vng_secsize < DEV_BSIZE ||
823 			    (vnd->sc_geom.vng_secsize % DEV_BSIZE) != 0) {
824 				error = EINVAL;
825 				goto close_and_exit;
826 			}
827 
828 			/*
829 			 * Compute the size (in DEV_BSIZE blocks) specified
830 			 * by the geometry.
831 			 */
832 			geomsize = (vnd->sc_geom.vng_nsectors *
833 			    vnd->sc_geom.vng_ntracks *
834 			    vnd->sc_geom.vng_ncylinders) *
835 			    (vnd->sc_geom.vng_secsize / DEV_BSIZE);
836 
837 			/*
838 			 * Sanity-check the size against the specified
839 			 * geometry.
840 			 */
841 			if (vnd->sc_size < geomsize) {
842 				error = EINVAL;
843 				goto close_and_exit;
844 			}
845 		} else {
846 			/*
847 			 * Size must be at least 2048 DEV_BSIZE blocks
848 			 * (1M) in order to use this geometry.
849 			 */
850 			if (vnd->sc_size < (32 * 64)) {
851 				error = EINVAL;
852 				goto close_and_exit;
853 			}
854 
855 			vnd->sc_geom.vng_secsize = DEV_BSIZE;
856 			vnd->sc_geom.vng_nsectors = 32;
857 			vnd->sc_geom.vng_ntracks = 64;
858 			vnd->sc_geom.vng_ncylinders = vnd->sc_size / (64 * 32);
859 		}
860 
861 		if ((error = vndsetcred(vnd, p->p_ucred)) != 0)
862 			goto close_and_exit;
863 		vndthrottle(vnd, vnd->sc_vp);
864 		vio->vnd_size = dbtob(vnd->sc_size);
865 		vnd->sc_flags |= VNF_INITED;
866 #ifdef DEBUG
867 		if (vnddebug & VDB_INIT)
868 			printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n",
869 			    vnd->sc_vp, (unsigned long) vnd->sc_size,
870 			    vnd->sc_geom.vng_secsize,
871 			    vnd->sc_geom.vng_nsectors,
872 			    vnd->sc_geom.vng_ntracks,
873 			    vnd->sc_geom.vng_ncylinders);
874 #endif
875 
876 		/* Attach the disk. */
877 		memset(vnd->sc_xname, 0, sizeof(vnd->sc_xname)); /* XXX */
878 		sprintf(vnd->sc_xname, "vnd%d", unit);		/* XXX */
879 		vnd->sc_dkdev.dk_name = vnd->sc_xname;
880 		disk_attach(&vnd->sc_dkdev);
881 
882 		/* Initialize the xfer and buffer pools. */
883 		pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0,
884 		    0, 0, "vndxpl", NULL);
885 		pool_init(&vnd->sc_vbpool, sizeof(struct vndbuf), 0,
886 		    0, 0, "vndbpl", NULL);
887 
888 		/* Try and read the disklabel. */
889 		vndgetdisklabel(dev);
890 
891 		vndunlock(vnd);
892 
893 		break;
894 
895 close_and_exit:
896 		(void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
897 unlock_and_exit:
898 		vndunlock(vnd);
899 		return (error);
900 
901 	case VNDIOCCLR:
902 		if ((error = vndlock(vnd)) != 0)
903 			return (error);
904 
905 		/*
906 		 * Don't unconfigure if any other partitions are open
907 		 * or if both the character and block flavors of this
908 		 * partition are open.
909 		 */
910 		part = DISKPART(dev);
911 		pmask = (1 << part);
912 		if ((vnd->sc_dkdev.dk_openmask & ~pmask) ||
913 		    ((vnd->sc_dkdev.dk_bopenmask & pmask) &&
914 		    (vnd->sc_dkdev.dk_copenmask & pmask))) {
915 			vndunlock(vnd);
916 			return (EBUSY);
917 		}
918 
919 		vndclear(vnd);
920 #ifdef DEBUG
921 		if (vnddebug & VDB_INIT)
922 			printf("vndioctl: CLRed\n");
923 #endif
924 
925 		/* Destroy the xfer and buffer pools. */
926 		pool_destroy(&vnd->sc_vxpool);
927 		pool_destroy(&vnd->sc_vbpool);
928 
929 		/* Detatch the disk. */
930 		disk_detach(&vnd->sc_dkdev);
931 
932 		vndunlock(vnd);
933 
934 		break;
935 
936 	case VNDIOCGET: {
937 		struct vnd_user *vnu;
938 		struct vattr va;
939 
940 		vnu = (struct vnd_user *)data;
941 
942 		if (vnu->vnu_unit == -1)
943 			vnu->vnu_unit = unit;
944 		if (vnu->vnu_unit >= numvnd)
945 			return (ENXIO);
946 		if (vnu->vnu_unit < 0)
947 			return (EINVAL);
948 
949 		vnd = &vnd_softc[vnu->vnu_unit];
950 
951 		if (vnd->sc_flags & VNF_INITED) {
952 			error = VOP_GETATTR(vnd->sc_vp, &va, p->p_ucred, p);
953 			if (error)
954 				return (error);
955 			vnu->vnu_dev = va.va_fsid;
956 			vnu->vnu_ino = va.va_fileid;
957 		}
958 		else {
959 			/* unused is not an error */
960 			vnu->vnu_dev = 0;
961 			vnu->vnu_ino = 0;
962 		}
963 
964 		break;
965 	}
966 
967 	case DIOCGDINFO:
968 		*(struct disklabel *)data = *(vnd->sc_dkdev.dk_label);
969 		break;
970 
971 #ifdef __HAVE_OLD_DISKLABEL
972 	case ODIOCGDINFO:
973 		newlabel = *(vnd->sc_dkdev.dk_label);
974 		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
975 			return ENOTTY;
976 		memcpy(data, &newlabel, sizeof (struct olddisklabel));
977 		break;
978 #endif
979 
980 	case DIOCGPART:
981 		((struct partinfo *)data)->disklab = vnd->sc_dkdev.dk_label;
982 		((struct partinfo *)data)->part =
983 		    &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
984 		break;
985 
986 	case DIOCWDINFO:
987 	case DIOCSDINFO:
988 #ifdef __HAVE_OLD_DISKLABEL
989 	case ODIOCWDINFO:
990 	case ODIOCSDINFO:
991 #endif
992 	{
993 		struct disklabel *lp;
994 
995 		if ((error = vndlock(vnd)) != 0)
996 			return (error);
997 
998 		vnd->sc_flags |= VNF_LABELLING;
999 
1000 #ifdef __HAVE_OLD_DISKLABEL
1001 		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
1002 			memset(&newlabel, 0, sizeof newlabel);
1003 			memcpy(&newlabel, data, sizeof (struct olddisklabel));
1004 			lp = &newlabel;
1005 		} else
1006 #endif
1007 		lp = (struct disklabel *)data;
1008 
1009 		error = setdisklabel(vnd->sc_dkdev.dk_label,
1010 		    lp, 0, vnd->sc_dkdev.dk_cpulabel);
1011 		if (error == 0) {
1012 			if (cmd == DIOCWDINFO
1013 #ifdef __HAVE_OLD_DISKLABEL
1014 			    || cmd == ODIOCWDINFO
1015 #endif
1016 			   )
1017 				error = writedisklabel(VNDLABELDEV(dev),
1018 				    vndstrategy, vnd->sc_dkdev.dk_label,
1019 				    vnd->sc_dkdev.dk_cpulabel);
1020 		}
1021 
1022 		vnd->sc_flags &= ~VNF_LABELLING;
1023 
1024 		vndunlock(vnd);
1025 
1026 		if (error)
1027 			return (error);
1028 		break;
1029 	}
1030 
1031 	case DIOCWLABEL:
1032 		if (*(int *)data != 0)
1033 			vnd->sc_flags |= VNF_WLABEL;
1034 		else
1035 			vnd->sc_flags &= ~VNF_WLABEL;
1036 		break;
1037 
1038 	case DIOCGDEFLABEL:
1039 		vndgetdefaultlabel(vnd, (struct disklabel *)data);
1040 		break;
1041 
1042 #ifdef __HAVE_OLD_DISKLABEL
1043 	case ODIOCGDEFLABEL:
1044 		vndgetdefaultlabel(vnd, &newlabel);
1045 		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
1046 			return ENOTTY;
1047 		memcpy(data, &newlabel, sizeof (struct olddisklabel));
1048 		break;
1049 #endif
1050 
1051 	default:
1052 		return (ENOTTY);
1053 	}
1054 
1055 	return (0);
1056 }
1057 
1058 /*
1059  * Duplicate the current processes' credentials.  Since we are called only
1060  * as the result of a SET ioctl and only root can do that, any future access
1061  * to this "disk" is essentially as root.  Note that credentials may change
1062  * if some other uid can write directly to the mapped file (NFS).
1063  */
1064 int
1065 vndsetcred(vnd, cred)
1066 	struct vnd_softc *vnd;
1067 	struct ucred *cred;
1068 {
1069 	struct uio auio;
1070 	struct iovec aiov;
1071 	char *tmpbuf;
1072 	int error;
1073 
1074 	vnd->sc_cred = crdup(cred);
1075 	tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);
1076 
1077 	/* XXX: Horrible kludge to establish credentials for NFS */
1078 	aiov.iov_base = tmpbuf;
1079 	aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size));
1080 	auio.uio_iov = &aiov;
1081 	auio.uio_iovcnt = 1;
1082 	auio.uio_offset = 0;
1083 	auio.uio_rw = UIO_READ;
1084 	auio.uio_segflg = UIO_SYSSPACE;
1085 	auio.uio_resid = aiov.iov_len;
1086 	vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1087 	error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred);
1088 	if (error == 0) {
1089 		/*
1090 		 * Because vnd does all IO directly through the vnode
1091 		 * we need to flush (at least) the buffer from the above
1092 		 * VOP_READ from the buffer cache to prevent cache
1093 		 * incoherencies.  Also, be careful to write dirty
1094 		 * buffers back to stable storage.
1095 		 */
1096 		error = vinvalbuf(vnd->sc_vp, V_SAVE, vnd->sc_cred,
1097 			    curproc, 0, 0);
1098 	}
1099 	VOP_UNLOCK(vnd->sc_vp, 0);
1100 
1101 	free(tmpbuf, M_TEMP);
1102 	return (error);
1103 }
1104 
1105 /*
1106  * Set maxactive based on FS type
1107  */
1108 void
1109 vndthrottle(vnd, vp)
1110 	struct vnd_softc *vnd;
1111 	struct vnode *vp;
1112 {
1113 #ifdef NFS
1114 	extern int (**nfsv2_vnodeop_p) __P((void *));
1115 
1116 	if (vp->v_op == nfsv2_vnodeop_p)
1117 		vnd->sc_maxactive = 2;
1118 	else
1119 #endif
1120 		vnd->sc_maxactive = 8;
1121 
1122 	if (vnd->sc_maxactive < 1)
1123 		vnd->sc_maxactive = 1;
1124 }
1125 
1126 void
1127 vndshutdown()
1128 {
1129 	struct vnd_softc *vnd;
1130 
1131 	for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++)
1132 		if (vnd->sc_flags & VNF_INITED)
1133 			vndclear(vnd);
1134 }
1135 
1136 void
1137 vndclear(vnd)
1138 	struct vnd_softc *vnd;
1139 {
1140 	struct vnode *vp = vnd->sc_vp;
1141 	struct proc *p = curproc;		/* XXX */
1142 
1143 #ifdef DEBUG
1144 	if (vnddebug & VDB_FOLLOW)
1145 		printf("vndclear(%p): vp %p\n", vnd, vp);
1146 #endif
1147 	vnd->sc_flags &= ~VNF_INITED;
1148 	if (vp == (struct vnode *)0)
1149 		panic("vndioctl: null vp");
1150 	(void) vn_close(vp, FREAD|FWRITE, vnd->sc_cred, p);
1151 	crfree(vnd->sc_cred);
1152 	vnd->sc_vp = (struct vnode *)0;
1153 	vnd->sc_cred = (struct ucred *)0;
1154 	vnd->sc_size = 0;
1155 }
1156 
1157 int
1158 vndsize(dev)
1159 	dev_t dev;
1160 {
1161 	struct vnd_softc *sc;
1162 	struct disklabel *lp;
1163 	int part, unit, omask;
1164 	int size;
1165 
1166 	unit = vndunit(dev);
1167 	if (unit >= numvnd)
1168 		return (-1);
1169 	sc = &vnd_softc[unit];
1170 
1171 	if ((sc->sc_flags & VNF_INITED) == 0)
1172 		return (-1);
1173 
1174 	part = DISKPART(dev);
1175 	omask = sc->sc_dkdev.dk_openmask & (1 << part);
1176 	lp = sc->sc_dkdev.dk_label;
1177 
1178 	if (omask == 0 && vndopen(dev, 0, S_IFBLK, curproc))
1179 		return (-1);
1180 
1181 	if (lp->d_partitions[part].p_fstype != FS_SWAP)
1182 		size = -1;
1183 	else
1184 		size = lp->d_partitions[part].p_size *
1185 		    (lp->d_secsize / DEV_BSIZE);
1186 
1187 	if (omask == 0 && vndclose(dev, 0, S_IFBLK, curproc))
1188 		return (-1);
1189 
1190 	return (size);
1191 }
1192 
1193 int
1194 vnddump(dev, blkno, va, size)
1195 	dev_t dev;
1196 	daddr_t blkno;
1197 	caddr_t va;
1198 	size_t size;
1199 {
1200 
1201 	/* Not implemented. */
1202 	return ENXIO;
1203 }
1204 
1205 void
1206 vndgetdefaultlabel(sc, lp)
1207 	struct vnd_softc *sc;
1208 	struct disklabel *lp;
1209 {
1210 	struct vndgeom *vng = &sc->sc_geom;
1211 	struct partition *pp;
1212 
1213 	memset(lp, 0, sizeof(*lp));
1214 
1215 	lp->d_secperunit = sc->sc_size / (vng->vng_secsize / DEV_BSIZE);
1216 	lp->d_secsize = vng->vng_secsize;
1217 	lp->d_nsectors = vng->vng_nsectors;
1218 	lp->d_ntracks = vng->vng_ntracks;
1219 	lp->d_ncylinders = vng->vng_ncylinders;
1220 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1221 
1222 	strncpy(lp->d_typename, "vnd", sizeof(lp->d_typename));
1223 	lp->d_type = DTYPE_VND;
1224 	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1225 	lp->d_rpm = 3600;
1226 	lp->d_interleave = 1;
1227 	lp->d_flags = 0;
1228 
1229 	pp = &lp->d_partitions[RAW_PART];
1230 	pp->p_offset = 0;
1231 	pp->p_size = lp->d_secperunit;
1232 	pp->p_fstype = FS_UNUSED;
1233 	lp->d_npartitions = RAW_PART + 1;
1234 
1235 	lp->d_magic = DISKMAGIC;
1236 	lp->d_magic2 = DISKMAGIC;
1237 	lp->d_checksum = dkcksum(lp);
1238 }
1239 
1240 /*
1241  * Read the disklabel from a vnd.  If one is not present, create a fake one.
1242  */
1243 void
1244 vndgetdisklabel(dev)
1245 	dev_t dev;
1246 {
1247 	struct vnd_softc *sc = &vnd_softc[vndunit(dev)];
1248 	char *errstring;
1249 	struct disklabel *lp = sc->sc_dkdev.dk_label;
1250 	struct cpu_disklabel *clp = sc->sc_dkdev.dk_cpulabel;
1251 	int i;
1252 
1253 	memset(clp, 0, sizeof(*clp));
1254 
1255 	vndgetdefaultlabel(sc, lp);
1256 
1257 	/*
1258 	 * Call the generic disklabel extraction routine.
1259 	 */
1260 	errstring = readdisklabel(VNDLABELDEV(dev), vndstrategy, lp, clp);
1261 	if (errstring) {
1262 		/*
1263 		 * Lack of disklabel is common, but we print the warning
1264 		 * anyway, since it might contain other useful information.
1265 		 */
1266 		printf("%s: %s\n", sc->sc_xname, errstring);
1267 
1268 		/*
1269 		 * For historical reasons, if there's no disklabel
1270 		 * present, all partitions must be FS_BSDFFS and
1271 		 * occupy the entire disk.
1272 		 */
1273 		for (i = 0; i < MAXPARTITIONS; i++) {
1274 			/*
1275 			 * Don't wipe out port specific hack (such as
1276 			 * dos partition hack of i386 port).
1277 			 */
1278 			if (lp->d_partitions[i].p_fstype != FS_UNUSED)
1279 				continue;
1280 
1281 			lp->d_partitions[i].p_size = lp->d_secperunit;
1282 			lp->d_partitions[i].p_offset = 0;
1283 			lp->d_partitions[i].p_fstype = FS_BSDFFS;
1284 		}
1285 
1286 		strncpy(lp->d_packname, "default label",
1287 		    sizeof(lp->d_packname));
1288 
1289 		lp->d_checksum = dkcksum(lp);
1290 	}
1291 }
1292 
1293 /*
1294  * Wait interruptibly for an exclusive lock.
1295  *
1296  * XXX
1297  * Several drivers do this; it should be abstracted and made MP-safe.
1298  */
1299 static int
1300 vndlock(sc)
1301 	struct vnd_softc *sc;
1302 {
1303 	int error;
1304 
1305 	while ((sc->sc_flags & VNF_LOCKED) != 0) {
1306 		sc->sc_flags |= VNF_WANTED;
1307 		if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0)
1308 			return (error);
1309 	}
1310 	sc->sc_flags |= VNF_LOCKED;
1311 	return (0);
1312 }
1313 
1314 /*
1315  * Unlock and wake up any waiters.
1316  */
1317 static void
1318 vndunlock(sc)
1319 	struct vnd_softc *sc;
1320 {
1321 
1322 	sc->sc_flags &= ~VNF_LOCKED;
1323 	if ((sc->sc_flags & VNF_WANTED) != 0) {
1324 		sc->sc_flags &= ~VNF_WANTED;
1325 		wakeup(sc);
1326 	}
1327 }
1328