vnd.c revision 1.239
1/*	$NetBSD: vnd.c,v 1.239 2015/01/02 19:42:06 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1996, 1997, 1998, 2008 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 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Copyright (c) 1988 University of Utah.
34 * Copyright (c) 1990, 1993
35 *	The Regents of the University of California.  All rights reserved.
36 *
37 * This code is derived from software contributed to Berkeley by
38 * the Systems Programming Group of the University of Utah Computer
39 * Science Department.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 *    notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 *    notice, this list of conditions and the following disclaimer in the
48 *    documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the University nor the names of its contributors
50 *    may be used to endorse or promote products derived from this software
51 *    without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * from: Utah $Hdr: vn.c 1.13 94/04/02$
66 *
67 *	@(#)vn.c	8.9 (Berkeley) 5/14/95
68 */
69
70/*
71 * Vnode disk driver.
72 *
73 * Block/character interface to a vnode.  Allows one to treat a file
74 * as a disk (e.g. build a filesystem in it, mount it, etc.).
75 *
76 * NOTE 1: If the vnode supports the VOP_BMAP and VOP_STRATEGY operations,
77 * this uses them to avoid distorting the local buffer cache.  If those
78 * block-level operations are not available, this falls back to the regular
79 * read and write calls.  Using these may distort the cache in some cases
80 * but better have the driver working than preventing it to work on file
81 * systems where the block-level operations are not implemented for
82 * whatever reason.
83 *
84 * NOTE 2: There is a security issue involved with this driver.
85 * Once mounted all access to the contents of the "mapped" file via
86 * the special file is controlled by the permissions on the special
87 * file, the protection of the mapped file is ignored (effectively,
88 * by using root credentials in all transactions).
89 *
90 * NOTE 3: Doesn't interact with leases, should it?
91 */
92
93#include <sys/cdefs.h>
94__KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.239 2015/01/02 19:42:06 christos Exp $");
95
96#if defined(_KERNEL_OPT)
97#include "opt_vnd.h"
98#include "opt_compat_netbsd.h"
99#endif
100
101#include <sys/param.h>
102#include <sys/systm.h>
103#include <sys/namei.h>
104#include <sys/proc.h>
105#include <sys/kthread.h>
106#include <sys/errno.h>
107#include <sys/buf.h>
108#include <sys/bufq.h>
109#include <sys/malloc.h>
110#include <sys/ioctl.h>
111#include <sys/disklabel.h>
112#include <sys/device.h>
113#include <sys/disk.h>
114#include <sys/stat.h>
115#include <sys/mount.h>
116#include <sys/vnode.h>
117#include <sys/file.h>
118#include <sys/uio.h>
119#include <sys/conf.h>
120#include <sys/kauth.h>
121
122#include <net/zlib.h>
123
124#include <miscfs/genfs/genfs.h>
125#include <miscfs/specfs/specdev.h>
126
127#include <dev/dkvar.h>
128#include <dev/vndvar.h>
129
130#if defined(VNDDEBUG) && !defined(DEBUG)
131#define DEBUG
132#endif
133
134#ifdef DEBUG
135int dovndcluster = 1;
136#define VDB_FOLLOW	0x01
137#define VDB_INIT	0x02
138#define VDB_IO		0x04
139#define VDB_LABEL	0x08
140int vnddebug = 0x00;
141#endif
142
143#define vndunit(x)	DISKUNIT(x)
144
145struct vndxfer {
146	struct buf vx_buf;
147	struct vnd_softc *vx_vnd;
148};
149#define	VND_BUFTOXFER(bp)	((struct vndxfer *)(void *)bp)
150
151#define VND_GETXFER(vnd)	pool_get(&(vnd)->sc_vxpool, PR_WAITOK)
152#define VND_PUTXFER(vnd, vx)	pool_put(&(vnd)->sc_vxpool, (vx))
153
154#define VNDLABELDEV(dev) \
155    (MAKEDISKDEV(major((dev)), vndunit((dev)), RAW_PART))
156
157#define	VND_MAXPENDING(vnd)	((vnd)->sc_maxactive * 4)
158
159/* called by main() at boot time */
160void	vndattach(int);
161
162static void	vndclear(struct vnd_softc *, int);
163static int	vnddoclear(struct vnd_softc *, int, int, bool);
164static int	vndsetcred(struct vnd_softc *, kauth_cred_t);
165static void	vndthrottle(struct vnd_softc *, struct vnode *);
166static void	vndiodone(struct buf *);
167#if 0
168static void	vndshutdown(void);
169#endif
170
171static void	vndgetdefaultlabel(struct vnd_softc *, struct disklabel *);
172static void	vndgetdisklabel(dev_t, struct vnd_softc *);
173
174static int	vndlock(struct vnd_softc *);
175static void	vndunlock(struct vnd_softc *);
176#ifdef VND_COMPRESSION
177static void	compstrategy(struct buf *, off_t);
178static void	*vnd_alloc(void *, u_int, u_int);
179static void	vnd_free(void *, void *);
180#endif /* VND_COMPRESSION */
181
182static void	vndthread(void *);
183static bool	vnode_has_op(const struct vnode *, int);
184static void	handle_with_rdwr(struct vnd_softc *, const struct buf *,
185		    struct buf *);
186static void	handle_with_strategy(struct vnd_softc *, const struct buf *,
187		    struct buf *);
188static void	vnd_set_geometry(struct vnd_softc *);
189
190static dev_type_open(vndopen);
191static dev_type_close(vndclose);
192static dev_type_read(vndread);
193static dev_type_write(vndwrite);
194static dev_type_ioctl(vndioctl);
195static dev_type_strategy(vndstrategy);
196static dev_type_dump(vnddump);
197static dev_type_size(vndsize);
198
199const struct bdevsw vnd_bdevsw = {
200	.d_open = vndopen,
201	.d_close = vndclose,
202	.d_strategy = vndstrategy,
203	.d_ioctl = vndioctl,
204	.d_dump = vnddump,
205	.d_psize = vndsize,
206	.d_discard = nodiscard,
207	.d_flag = D_DISK
208};
209
210const struct cdevsw vnd_cdevsw = {
211	.d_open = vndopen,
212	.d_close = vndclose,
213	.d_read = vndread,
214	.d_write = vndwrite,
215	.d_ioctl = vndioctl,
216	.d_stop = nostop,
217	.d_tty = notty,
218	.d_poll = nopoll,
219	.d_mmap = nommap,
220	.d_kqfilter = nokqfilter,
221	.d_discard = nodiscard,
222	.d_flag = D_DISK
223};
224
225static int	vnd_match(device_t, cfdata_t, void *);
226static void	vnd_attach(device_t, device_t, void *);
227static int	vnd_detach(device_t, int);
228
229CFATTACH_DECL3_NEW(vnd, sizeof(struct vnd_softc),
230    vnd_match, vnd_attach, vnd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
231extern struct cfdriver vnd_cd;
232
233static struct vnd_softc	*vnd_spawn(int);
234int	vnd_destroy(device_t);
235
236static struct	dkdriver vnddkdriver = { vndstrategy, minphys };
237
238void
239vndattach(int num)
240{
241	int error;
242
243	error = config_cfattach_attach(vnd_cd.cd_name, &vnd_ca);
244	if (error)
245		aprint_error("%s: unable to register cfattach\n",
246		    vnd_cd.cd_name);
247}
248
249static int
250vnd_match(device_t self, cfdata_t cfdata, void *aux)
251{
252
253	return 1;
254}
255
256static void
257vnd_attach(device_t parent, device_t self, void *aux)
258{
259	struct vnd_softc *sc = device_private(self);
260
261	sc->sc_dev = self;
262	sc->sc_comp_offsets = NULL;
263	sc->sc_comp_buff = NULL;
264	sc->sc_comp_decombuf = NULL;
265	bufq_alloc(&sc->sc_tab, "disksort", BUFQ_SORT_RAWBLOCK);
266	disk_init(&sc->sc_dkdev, device_xname(self), &vnddkdriver);
267	if (!pmf_device_register(self, NULL, NULL))
268		aprint_error_dev(self, "couldn't establish power handler\n");
269}
270
271static int
272vnd_detach(device_t self, int flags)
273{
274	int error;
275	struct vnd_softc *sc = device_private(self);
276
277	if (sc->sc_flags & VNF_INITED) {
278		error = vnddoclear(sc, 0, -1, (flags & DETACH_FORCE) != 0);
279		if (error != 0)
280			return error;
281	}
282
283	pmf_device_deregister(self);
284	bufq_free(sc->sc_tab);
285	disk_destroy(&sc->sc_dkdev);
286
287	return 0;
288}
289
290static struct vnd_softc *
291vnd_spawn(int unit)
292{
293	cfdata_t cf;
294
295	cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK);
296	cf->cf_name = vnd_cd.cd_name;
297	cf->cf_atname = vnd_cd.cd_name;
298	cf->cf_unit = unit;
299	cf->cf_fstate = FSTATE_STAR;
300
301	return device_private(config_attach_pseudo(cf));
302}
303
304int
305vnd_destroy(device_t dev)
306{
307	int error;
308	cfdata_t cf;
309
310	cf = device_cfdata(dev);
311	error = config_detach(dev, DETACH_QUIET);
312	if (error)
313		return error;
314	free(cf, M_DEVBUF);
315	return 0;
316}
317
318static int
319vndopen(dev_t dev, int flags, int mode, struct lwp *l)
320{
321	int unit = vndunit(dev);
322	struct vnd_softc *sc;
323	int error = 0, part, pmask;
324	struct disklabel *lp;
325
326#ifdef DEBUG
327	if (vnddebug & VDB_FOLLOW)
328		printf("vndopen(0x%"PRIx64", 0x%x, 0x%x, %p)\n", dev, flags, mode, l);
329#endif
330	sc = device_lookup_private(&vnd_cd, unit);
331	if (sc == NULL) {
332		sc = vnd_spawn(unit);
333		if (sc == NULL)
334			return ENOMEM;
335	}
336
337	if ((error = vndlock(sc)) != 0)
338		return error;
339
340	if ((sc->sc_flags & VNF_CLEARING) != 0) {
341		error = ENXIO;
342		goto done;
343	}
344
345	lp = sc->sc_dkdev.dk_label;
346
347	part = DISKPART(dev);
348	pmask = (1 << part);
349
350	if (sc->sc_dkdev.dk_nwedges != 0 && part != RAW_PART) {
351		error = EBUSY;
352		goto done;
353	}
354
355	if (sc->sc_flags & VNF_INITED) {
356		if ((sc->sc_dkdev.dk_openmask & ~(1<<RAW_PART)) != 0) {
357			/*
358			 * If any non-raw partition is open, but the disk
359			 * has been invalidated, disallow further opens.
360			 */
361			if ((sc->sc_flags & VNF_VLABEL) == 0) {
362				error = EIO;
363				goto done;
364			}
365		} else {
366			/*
367			 * Load the partition info if not already loaded.
368			 */
369			if ((sc->sc_flags & VNF_VLABEL) == 0) {
370				sc->sc_flags |= VNF_VLABEL;
371				vndgetdisklabel(dev, sc);
372			}
373		}
374	}
375
376	/* Check that the partitions exists. */
377	if (part != RAW_PART) {
378		if (((sc->sc_flags & VNF_INITED) == 0) ||
379		    ((part >= lp->d_npartitions) ||
380		     (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
381			error = ENXIO;
382			goto done;
383		}
384	}
385
386	/* Prevent our unit from being unconfigured while open. */
387	switch (mode) {
388	case S_IFCHR:
389		sc->sc_dkdev.dk_copenmask |= pmask;
390		break;
391
392	case S_IFBLK:
393		sc->sc_dkdev.dk_bopenmask |= pmask;
394		break;
395	}
396	sc->sc_dkdev.dk_openmask =
397	    sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
398
399 done:
400	vndunlock(sc);
401	return error;
402}
403
404static int
405vndclose(dev_t dev, int flags, int mode, struct lwp *l)
406{
407	int unit = vndunit(dev);
408	struct vnd_softc *sc;
409	int error = 0, part;
410
411#ifdef DEBUG
412	if (vnddebug & VDB_FOLLOW)
413		printf("vndclose(0x%"PRIx64", 0x%x, 0x%x, %p)\n", dev, flags, mode, l);
414#endif
415	sc = device_lookup_private(&vnd_cd, unit);
416	if (sc == NULL)
417		return ENXIO;
418
419	if ((error = vndlock(sc)) != 0)
420		return error;
421
422	part = DISKPART(dev);
423
424	/* ...that much closer to allowing unconfiguration... */
425	switch (mode) {
426	case S_IFCHR:
427		sc->sc_dkdev.dk_copenmask &= ~(1 << part);
428		break;
429
430	case S_IFBLK:
431		sc->sc_dkdev.dk_bopenmask &= ~(1 << part);
432		break;
433	}
434	sc->sc_dkdev.dk_openmask =
435	    sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
436
437	vndunlock(sc);
438
439	if ((sc->sc_flags & VNF_INITED) == 0) {
440		if ((error = vnd_destroy(sc->sc_dev)) != 0) {
441			aprint_error_dev(sc->sc_dev,
442			    "unable to detach instance\n");
443			return error;
444		}
445	}
446
447	return 0;
448}
449
450/*
451 * Queue the request, and wakeup the kernel thread to handle it.
452 */
453static void
454vndstrategy(struct buf *bp)
455{
456	int unit = vndunit(bp->b_dev);
457	struct vnd_softc *vnd =
458	    device_lookup_private(&vnd_cd, unit);
459	struct disklabel *lp;
460	daddr_t blkno;
461	int s = splbio();
462
463	if (vnd == NULL) {
464		bp->b_error = ENXIO;
465		goto done;
466	}
467	lp = vnd->sc_dkdev.dk_label;
468
469	if ((vnd->sc_flags & VNF_INITED) == 0) {
470		bp->b_error = ENXIO;
471		goto done;
472	}
473
474	/*
475	 * The transfer must be a whole number of blocks.
476	 */
477	if ((bp->b_bcount % lp->d_secsize) != 0) {
478		bp->b_error = EINVAL;
479		goto done;
480	}
481
482	/*
483	 * check if we're read-only.
484	 */
485	if ((vnd->sc_flags & VNF_READONLY) && !(bp->b_flags & B_READ)) {
486		bp->b_error = EACCES;
487		goto done;
488	}
489
490	/* If it's a nil transfer, wake up the top half now. */
491	if (bp->b_bcount == 0) {
492		goto done;
493	}
494
495	/*
496	 * Do bounds checking and adjust transfer.  If there's an error,
497	 * the bounds check will flag that for us.
498	 */
499	if (DISKPART(bp->b_dev) == RAW_PART) {
500		if (bounds_check_with_mediasize(bp, DEV_BSIZE,
501		    vnd->sc_size) <= 0)
502			goto done;
503	} else {
504		if (bounds_check_with_label(&vnd->sc_dkdev,
505		    bp, vnd->sc_flags & (VNF_WLABEL|VNF_LABELLING)) <= 0)
506			goto done;
507	}
508
509	/*
510	 * Put the block number in terms of the logical blocksize
511	 * of the "device".
512	 */
513
514	blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
515
516	/*
517	 * Translate the partition-relative block number to an absolute.
518	 */
519	if (DISKPART(bp->b_dev) != RAW_PART) {
520		struct partition *pp;
521
522		pp = &vnd->sc_dkdev.dk_label->d_partitions[
523		    DISKPART(bp->b_dev)];
524		blkno += pp->p_offset;
525	}
526	bp->b_rawblkno = blkno;
527
528#ifdef DEBUG
529	if (vnddebug & VDB_FOLLOW)
530		printf("vndstrategy(%p): unit %d\n", bp, unit);
531#endif
532	if ((vnd->sc_flags & VNF_USE_VN_RDWR)) {
533		KASSERT(vnd->sc_pending >= 0 &&
534		    vnd->sc_pending <= VND_MAXPENDING(vnd));
535		while (vnd->sc_pending == VND_MAXPENDING(vnd))
536			tsleep(&vnd->sc_pending, PRIBIO, "vndpc", 0);
537		vnd->sc_pending++;
538	}
539	bufq_put(vnd->sc_tab, bp);
540	wakeup(&vnd->sc_tab);
541	splx(s);
542	return;
543
544done:
545	bp->b_resid = bp->b_bcount;
546	biodone(bp);
547	splx(s);
548}
549
550static bool
551vnode_has_strategy(struct vnd_softc *vnd)
552{
553	return vnode_has_op(vnd->sc_vp, VOFFSET(vop_bmap)) &&
554	    vnode_has_op(vnd->sc_vp, VOFFSET(vop_strategy));
555}
556
557/* XXX this function needs a reliable check to detect
558 * sparse files. Otherwise, bmap/strategy may be used
559 * and fail on non-allocated blocks. VOP_READ/VOP_WRITE
560 * works on sparse files.
561 */
562#if notyet
563static bool
564vnode_strategy_probe(struct vnd_softc *vnd)
565{
566	int error;
567	daddr_t nbn;
568
569	if (!vnode_has_strategy(vnd))
570		return false;
571
572	/* Convert the first logical block number to its
573	 * physical block number.
574	 */
575	error = 0;
576	vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
577	error = VOP_BMAP(vnd->sc_vp, 0, NULL, &nbn, NULL);
578	VOP_UNLOCK(vnd->sc_vp);
579
580	/* Test if that worked. */
581	if (error == 0 && (long)nbn == -1)
582		return false;
583
584	return true;
585}
586#endif
587
588static void
589vndthread(void *arg)
590{
591	struct vnd_softc *vnd = arg;
592	int s;
593
594	/* Determine whether we can *use* VOP_BMAP and VOP_STRATEGY to
595	 * directly access the backing vnode.  If we can, use these two
596	 * operations to avoid messing with the local buffer cache.
597	 * Otherwise fall back to regular VOP_READ/VOP_WRITE operations
598	 * which are guaranteed to work with any file system. */
599	if ((vnd->sc_flags & VNF_USE_VN_RDWR) == 0 &&
600	    ! vnode_has_strategy(vnd))
601		vnd->sc_flags |= VNF_USE_VN_RDWR;
602
603#ifdef DEBUG
604	if (vnddebug & VDB_INIT)
605		printf("vndthread: vp %p, %s\n", vnd->sc_vp,
606		    (vnd->sc_flags & VNF_USE_VN_RDWR) == 0 ?
607		    "using bmap/strategy operations" :
608		    "using read/write operations");
609#endif
610
611	s = splbio();
612	vnd->sc_flags |= VNF_KTHREAD;
613	wakeup(&vnd->sc_kthread);
614
615	/*
616	 * Dequeue requests and serve them depending on the available
617	 * vnode operations.
618	 */
619	while ((vnd->sc_flags & VNF_VUNCONF) == 0) {
620		struct vndxfer *vnx;
621		struct buf *obp;
622		struct buf *bp;
623
624		obp = bufq_get(vnd->sc_tab);
625		if (obp == NULL) {
626			tsleep(&vnd->sc_tab, PRIBIO, "vndbp", 0);
627			continue;
628		};
629		if ((vnd->sc_flags & VNF_USE_VN_RDWR)) {
630			KASSERT(vnd->sc_pending > 0 &&
631			    vnd->sc_pending <= VND_MAXPENDING(vnd));
632			if (vnd->sc_pending-- == VND_MAXPENDING(vnd))
633				wakeup(&vnd->sc_pending);
634		}
635		splx(s);
636#ifdef DEBUG
637		if (vnddebug & VDB_FOLLOW)
638			printf("vndthread(%p)\n", obp);
639#endif
640
641		if (vnd->sc_vp->v_mount == NULL) {
642			obp->b_error = ENXIO;
643			goto done;
644		}
645#ifdef VND_COMPRESSION
646		/* handle a compressed read */
647		if ((obp->b_flags & B_READ) != 0 && (vnd->sc_flags & VNF_COMP)) {
648			off_t bn;
649
650			/* Convert to a byte offset within the file. */
651			bn = obp->b_rawblkno *
652			    vnd->sc_dkdev.dk_label->d_secsize;
653
654			compstrategy(obp, bn);
655			goto done;
656		}
657#endif /* VND_COMPRESSION */
658
659		/*
660		 * Allocate a header for this transfer and link it to the
661		 * buffer
662		 */
663		s = splbio();
664		vnx = VND_GETXFER(vnd);
665		splx(s);
666		vnx->vx_vnd = vnd;
667
668		s = splbio();
669		while (vnd->sc_active >= vnd->sc_maxactive) {
670			tsleep(&vnd->sc_tab, PRIBIO, "vndac", 0);
671		}
672		vnd->sc_active++;
673		splx(s);
674
675		/* Instrumentation. */
676		disk_busy(&vnd->sc_dkdev);
677
678		bp = &vnx->vx_buf;
679		buf_init(bp);
680		bp->b_flags = (obp->b_flags & B_READ);
681		bp->b_oflags = obp->b_oflags;
682		bp->b_cflags = obp->b_cflags;
683		bp->b_iodone = vndiodone;
684		bp->b_private = obp;
685		bp->b_vp = vnd->sc_vp;
686		bp->b_objlock = bp->b_vp->v_interlock;
687		bp->b_data = obp->b_data;
688		bp->b_bcount = obp->b_bcount;
689		BIO_COPYPRIO(bp, obp);
690
691		/* Handle the request using the appropriate operations. */
692		if ((vnd->sc_flags & VNF_USE_VN_RDWR) == 0)
693			handle_with_strategy(vnd, obp, bp);
694		else
695			handle_with_rdwr(vnd, obp, bp);
696
697		s = splbio();
698		continue;
699
700done:
701		biodone(obp);
702		s = splbio();
703	}
704
705	vnd->sc_flags &= (~VNF_KTHREAD | VNF_VUNCONF);
706	wakeup(&vnd->sc_kthread);
707	splx(s);
708	kthread_exit(0);
709}
710
711/*
712 * Checks if the given vnode supports the requested operation.
713 * The operation is specified the offset returned by VOFFSET.
714 *
715 * XXX The test below used to determine this is quite fragile
716 * because it relies on the file system to use genfs to specify
717 * unimplemented operations.  There might be another way to do
718 * it more cleanly.
719 */
720static bool
721vnode_has_op(const struct vnode *vp, int opoffset)
722{
723	int (*defaultp)(void *);
724	int (*opp)(void *);
725
726	defaultp = vp->v_op[VOFFSET(vop_default)];
727	opp = vp->v_op[opoffset];
728
729	return opp != defaultp && opp != genfs_eopnotsupp &&
730	    opp != genfs_badop && opp != genfs_nullop;
731}
732
733/*
734 * Handes the read/write request given in 'bp' using the vnode's VOP_READ
735 * and VOP_WRITE operations.
736 *
737 * 'obp' is a pointer to the original request fed to the vnd device.
738 */
739static void
740handle_with_rdwr(struct vnd_softc *vnd, const struct buf *obp, struct buf *bp)
741{
742	bool doread;
743	off_t offset;
744	size_t len, resid;
745	struct vnode *vp;
746
747	doread = bp->b_flags & B_READ;
748	offset = obp->b_rawblkno * vnd->sc_dkdev.dk_label->d_secsize;
749	len = bp->b_bcount;
750	vp = vnd->sc_vp;
751
752#if defined(DEBUG)
753	if (vnddebug & VDB_IO)
754		printf("vnd (rdwr): vp %p, %s, rawblkno 0x%" PRIx64
755		    ", secsize %d, offset %" PRIu64
756		    ", bcount %d\n",
757		    vp, doread ? "read" : "write", obp->b_rawblkno,
758		    vnd->sc_dkdev.dk_label->d_secsize, offset,
759		    bp->b_bcount);
760#endif
761
762	/* Issue the read or write operation. */
763	bp->b_error =
764	    vn_rdwr(doread ? UIO_READ : UIO_WRITE,
765	    vp, bp->b_data, len, offset, UIO_SYSSPACE,
766	    IO_ADV_ENCODE(POSIX_FADV_NOREUSE), vnd->sc_cred, &resid, NULL);
767	bp->b_resid = resid;
768
769	mutex_enter(vp->v_interlock);
770	(void) VOP_PUTPAGES(vp, 0, 0,
771	    PGO_ALLPAGES | PGO_CLEANIT | PGO_FREE | PGO_SYNCIO);
772
773	/* We need to increase the number of outputs on the vnode if
774	 * there was any write to it. */
775	if (!doread) {
776		mutex_enter(vp->v_interlock);
777		vp->v_numoutput++;
778		mutex_exit(vp->v_interlock);
779	}
780
781	biodone(bp);
782}
783
784/*
785 * Handes the read/write request given in 'bp' using the vnode's VOP_BMAP
786 * and VOP_STRATEGY operations.
787 *
788 * 'obp' is a pointer to the original request fed to the vnd device.
789 */
790static void
791handle_with_strategy(struct vnd_softc *vnd, const struct buf *obp,
792    struct buf *bp)
793{
794	int bsize, error, flags, skipped;
795	size_t resid, sz;
796	off_t bn, offset;
797	struct vnode *vp;
798
799	flags = obp->b_flags;
800
801	if (!(flags & B_READ)) {
802		vp = bp->b_vp;
803		mutex_enter(vp->v_interlock);
804		vp->v_numoutput++;
805		mutex_exit(vp->v_interlock);
806	}
807
808	/* convert to a byte offset within the file. */
809	bn = obp->b_rawblkno * vnd->sc_dkdev.dk_label->d_secsize;
810
811	bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize;
812	skipped = 0;
813
814	/*
815	 * Break the request into bsize pieces and feed them
816	 * sequentially using VOP_BMAP/VOP_STRATEGY.
817	 * We do it this way to keep from flooding NFS servers if we
818	 * are connected to an NFS file.  This places the burden on
819	 * the client rather than the server.
820	 */
821	error = 0;
822	bp->b_resid = bp->b_bcount;
823	for (offset = 0, resid = bp->b_resid; resid;
824	    resid -= sz, offset += sz) {
825		struct buf *nbp;
826		daddr_t nbn;
827		int off, nra;
828
829		nra = 0;
830		vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
831		error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra);
832		VOP_UNLOCK(vnd->sc_vp);
833
834		if (error == 0 && (long)nbn == -1)
835			error = EIO;
836
837		/*
838		 * If there was an error or a hole in the file...punt.
839		 * Note that we may have to wait for any operations
840		 * that we have already fired off before releasing
841		 * the buffer.
842		 *
843		 * XXX we could deal with holes here but it would be
844		 * a hassle (in the write case).
845		 */
846		if (error) {
847			skipped += resid;
848			break;
849		}
850
851#ifdef DEBUG
852		if (!dovndcluster)
853			nra = 0;
854#endif
855
856		off = bn % bsize;
857		sz = MIN(((off_t)1 + nra) * bsize - off, resid);
858#ifdef	DEBUG
859		if (vnddebug & VDB_IO)
860			printf("vndstrategy: vp %p/%p bn 0x%qx/0x%" PRIx64
861			    " sz 0x%zx\n", vnd->sc_vp, vp, (long long)bn,
862			    nbn, sz);
863#endif
864
865		nbp = getiobuf(vp, true);
866		nestiobuf_setup(bp, nbp, offset, sz);
867		nbp->b_blkno = nbn + btodb(off);
868
869#if 0 /* XXX #ifdef DEBUG */
870		if (vnddebug & VDB_IO)
871			printf("vndstart(%ld): bp %p vp %p blkno "
872			    "0x%" PRIx64 " flags %x addr %p cnt 0x%x\n",
873			    (long) (vnd-vnd_softc), &nbp->vb_buf,
874			    nbp->vb_buf.b_vp, nbp->vb_buf.b_blkno,
875			    nbp->vb_buf.b_flags, nbp->vb_buf.b_data,
876			    nbp->vb_buf.b_bcount);
877#endif
878		VOP_STRATEGY(vp, nbp);
879		bn += sz;
880	}
881	nestiobuf_done(bp, skipped, error);
882}
883
884static void
885vndiodone(struct buf *bp)
886{
887	struct vndxfer *vnx = VND_BUFTOXFER(bp);
888	struct vnd_softc *vnd = vnx->vx_vnd;
889	struct buf *obp = bp->b_private;
890	int s = splbio();
891
892	KASSERT(&vnx->vx_buf == bp);
893	KASSERT(vnd->sc_active > 0);
894#ifdef DEBUG
895	if (vnddebug & VDB_IO) {
896		printf("vndiodone1: bp %p iodone: error %d\n",
897		    bp, bp->b_error);
898	}
899#endif
900	disk_unbusy(&vnd->sc_dkdev, bp->b_bcount - bp->b_resid,
901	    (bp->b_flags & B_READ));
902	vnd->sc_active--;
903	if (vnd->sc_active == 0) {
904		wakeup(&vnd->sc_tab);
905	}
906	splx(s);
907	obp->b_error = bp->b_error;
908	obp->b_resid = bp->b_resid;
909	buf_destroy(bp);
910	VND_PUTXFER(vnd, vnx);
911	biodone(obp);
912}
913
914/* ARGSUSED */
915static int
916vndread(dev_t dev, struct uio *uio, int flags)
917{
918	int unit = vndunit(dev);
919	struct vnd_softc *sc;
920
921#ifdef DEBUG
922	if (vnddebug & VDB_FOLLOW)
923		printf("vndread(0x%"PRIx64", %p)\n", dev, uio);
924#endif
925
926	sc = device_lookup_private(&vnd_cd, unit);
927	if (sc == NULL)
928		return ENXIO;
929
930	if ((sc->sc_flags & VNF_INITED) == 0)
931		return ENXIO;
932
933	return physio(vndstrategy, NULL, dev, B_READ, minphys, uio);
934}
935
936/* ARGSUSED */
937static int
938vndwrite(dev_t dev, struct uio *uio, int flags)
939{
940	int unit = vndunit(dev);
941	struct vnd_softc *sc;
942
943#ifdef DEBUG
944	if (vnddebug & VDB_FOLLOW)
945		printf("vndwrite(0x%"PRIx64", %p)\n", dev, uio);
946#endif
947
948	sc = device_lookup_private(&vnd_cd, unit);
949	if (sc == NULL)
950		return ENXIO;
951
952	if ((sc->sc_flags & VNF_INITED) == 0)
953		return ENXIO;
954
955	return physio(vndstrategy, NULL, dev, B_WRITE, minphys, uio);
956}
957
958static int
959vnd_cget(struct lwp *l, int unit, int *un, struct vattr *va)
960{
961	int error;
962	struct vnd_softc *vnd;
963
964	if (*un == -1)
965		*un = unit;
966	if (*un < 0)
967		return EINVAL;
968
969	vnd = device_lookup_private(&vnd_cd, *un);
970	if (vnd == NULL)
971		return -1;
972
973	if ((vnd->sc_flags & VNF_INITED) == 0)
974		return -1;
975
976	vn_lock(vnd->sc_vp, LK_SHARED | LK_RETRY);
977	error = VOP_GETATTR(vnd->sc_vp, va, l->l_cred);
978	VOP_UNLOCK(vnd->sc_vp);
979	return error;
980}
981
982static int
983vnddoclear(struct vnd_softc *vnd, int pmask, int minor, bool force)
984{
985	int error;
986
987	if ((error = vndlock(vnd)) != 0)
988		return error;
989
990	/*
991	 * Don't unconfigure if any other partitions are open
992	 * or if both the character and block flavors of this
993	 * partition are open.
994	 */
995	if (DK_BUSY(vnd, pmask) && !force) {
996		vndunlock(vnd);
997		return EBUSY;
998	}
999
1000	/* Delete all of our wedges */
1001	dkwedge_delall(&vnd->sc_dkdev);
1002
1003	/*
1004	 * XXX vndclear() might call vndclose() implicitly;
1005	 * release lock to avoid recursion
1006	 *
1007	 * Set VNF_CLEARING to prevent vndopen() from
1008	 * sneaking in after we vndunlock().
1009	 */
1010	vnd->sc_flags |= VNF_CLEARING;
1011	vndunlock(vnd);
1012	vndclear(vnd, minor);
1013#ifdef DEBUG
1014	if (vnddebug & VDB_INIT)
1015		printf("vndioctl: CLRed\n");
1016#endif
1017
1018	/* Destroy the xfer and buffer pools. */
1019	pool_destroy(&vnd->sc_vxpool);
1020
1021	/* Detach the disk. */
1022	disk_detach(&vnd->sc_dkdev);
1023
1024	return 0;
1025}
1026
1027/* ARGSUSED */
1028static int
1029vndioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1030{
1031	bool force;
1032	int unit = vndunit(dev);
1033	struct vnd_softc *vnd;
1034	struct vnd_ioctl *vio;
1035	struct vattr vattr;
1036	struct pathbuf *pb;
1037	struct nameidata nd;
1038	int error, part, pmask;
1039	uint64_t geomsize;
1040	int fflags;
1041#ifdef __HAVE_OLD_DISKLABEL
1042	struct disklabel newlabel;
1043#endif
1044
1045#ifdef DEBUG
1046	if (vnddebug & VDB_FOLLOW)
1047		printf("vndioctl(0x%"PRIx64", 0x%lx, %p, 0x%x, %p): unit %d\n",
1048		    dev, cmd, data, flag, l->l_proc, unit);
1049#endif
1050	vnd = device_lookup_private(&vnd_cd, unit);
1051	if (vnd == NULL &&
1052#ifdef COMPAT_30
1053	    cmd != VNDIOCGET30 &&
1054#endif
1055#ifdef COMPAT_50
1056	    cmd != VNDIOCGET50 &&
1057#endif
1058	    cmd != VNDIOCGET)
1059		return ENXIO;
1060	vio = (struct vnd_ioctl *)data;
1061
1062	/* Must be open for writes for these commands... */
1063	switch (cmd) {
1064	case VNDIOCSET:
1065	case VNDIOCCLR:
1066#ifdef COMPAT_50
1067	case VNDIOCSET50:
1068	case VNDIOCCLR50:
1069#endif
1070	case DIOCSDINFO:
1071	case DIOCWDINFO:
1072#ifdef __HAVE_OLD_DISKLABEL
1073	case ODIOCSDINFO:
1074	case ODIOCWDINFO:
1075#endif
1076	case DIOCKLABEL:
1077	case DIOCWLABEL:
1078		if ((flag & FWRITE) == 0)
1079			return EBADF;
1080	}
1081
1082	/* Must be initialized for these... */
1083	switch (cmd) {
1084	case VNDIOCCLR:
1085#ifdef VNDIOCCLR50
1086	case VNDIOCCLR50:
1087#endif
1088	case DIOCGDINFO:
1089	case DIOCSDINFO:
1090	case DIOCWDINFO:
1091	case DIOCGPART:
1092	case DIOCKLABEL:
1093	case DIOCWLABEL:
1094	case DIOCGDEFLABEL:
1095	case DIOCCACHESYNC:
1096#ifdef __HAVE_OLD_DISKLABEL
1097	case ODIOCGDINFO:
1098	case ODIOCSDINFO:
1099	case ODIOCWDINFO:
1100	case ODIOCGDEFLABEL:
1101#endif
1102		if ((vnd->sc_flags & VNF_INITED) == 0)
1103			return ENXIO;
1104	}
1105
1106	error = disk_ioctl(&vnd->sc_dkdev, dev, cmd, data, flag, l);
1107	if (error != EPASSTHROUGH)
1108		return error;
1109
1110
1111	switch (cmd) {
1112#ifdef VNDIOCSET50
1113	case VNDIOCSET50:
1114#endif
1115	case VNDIOCSET:
1116		if (vnd->sc_flags & VNF_INITED)
1117			return EBUSY;
1118
1119		if ((error = vndlock(vnd)) != 0)
1120			return error;
1121
1122		fflags = FREAD;
1123		if ((vio->vnd_flags & VNDIOF_READONLY) == 0)
1124			fflags |= FWRITE;
1125		error = pathbuf_copyin(vio->vnd_file, &pb);
1126		if (error) {
1127			goto unlock_and_exit;
1128		}
1129		NDINIT(&nd, LOOKUP, FOLLOW, pb);
1130		if ((error = vn_open(&nd, fflags, 0)) != 0) {
1131			pathbuf_destroy(pb);
1132			goto unlock_and_exit;
1133		}
1134		KASSERT(l);
1135		error = VOP_GETATTR(nd.ni_vp, &vattr, l->l_cred);
1136		if (!error && nd.ni_vp->v_type != VREG)
1137			error = EOPNOTSUPP;
1138		if (!error && vattr.va_bytes < vattr.va_size)
1139			/* File is definitely sparse, use vn_rdwr() */
1140			vnd->sc_flags |= VNF_USE_VN_RDWR;
1141		if (error) {
1142			VOP_UNLOCK(nd.ni_vp);
1143			goto close_and_exit;
1144		}
1145
1146		/* If using a compressed file, initialize its info */
1147		/* (or abort with an error if kernel has no compression) */
1148		if (vio->vnd_flags & VNF_COMP) {
1149#ifdef VND_COMPRESSION
1150			struct vnd_comp_header *ch;
1151			int i;
1152			u_int32_t comp_size;
1153			u_int32_t comp_maxsize;
1154
1155			/* allocate space for compresed file header */
1156			ch = malloc(sizeof(struct vnd_comp_header),
1157			M_TEMP, M_WAITOK);
1158
1159			/* read compressed file header */
1160			error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)ch,
1161			  sizeof(struct vnd_comp_header), 0, UIO_SYSSPACE,
1162			  IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL);
1163			if (error) {
1164				free(ch, M_TEMP);
1165				VOP_UNLOCK(nd.ni_vp);
1166				goto close_and_exit;
1167			}
1168
1169			/* save some header info */
1170			vnd->sc_comp_blksz = ntohl(ch->block_size);
1171			/* note last offset is the file byte size */
1172			vnd->sc_comp_numoffs = ntohl(ch->num_blocks)+1;
1173			free(ch, M_TEMP);
1174			if (vnd->sc_comp_blksz == 0 ||
1175			    vnd->sc_comp_blksz % DEV_BSIZE !=0) {
1176				VOP_UNLOCK(nd.ni_vp);
1177				error = EINVAL;
1178				goto close_and_exit;
1179			}
1180			if (sizeof(struct vnd_comp_header) +
1181			  sizeof(u_int64_t) * vnd->sc_comp_numoffs >
1182			  vattr.va_size) {
1183				VOP_UNLOCK(nd.ni_vp);
1184				error = EINVAL;
1185				goto close_and_exit;
1186			}
1187
1188			/* set decompressed file size */
1189			vattr.va_size =
1190			    ((u_quad_t)vnd->sc_comp_numoffs - 1) *
1191			     (u_quad_t)vnd->sc_comp_blksz;
1192
1193			/* allocate space for all the compressed offsets */
1194			vnd->sc_comp_offsets =
1195			malloc(sizeof(u_int64_t) * vnd->sc_comp_numoffs,
1196			M_DEVBUF, M_WAITOK);
1197
1198			/* read in the offsets */
1199			error = vn_rdwr(UIO_READ, nd.ni_vp,
1200			  (void *)vnd->sc_comp_offsets,
1201			  sizeof(u_int64_t) * vnd->sc_comp_numoffs,
1202			  sizeof(struct vnd_comp_header), UIO_SYSSPACE,
1203			  IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL);
1204			if (error) {
1205				VOP_UNLOCK(nd.ni_vp);
1206				goto close_and_exit;
1207			}
1208			/*
1209			 * find largest block size (used for allocation limit).
1210			 * Also convert offset to native byte order.
1211			 */
1212			comp_maxsize = 0;
1213			for (i = 0; i < vnd->sc_comp_numoffs - 1; i++) {
1214				vnd->sc_comp_offsets[i] =
1215				  be64toh(vnd->sc_comp_offsets[i]);
1216				comp_size = be64toh(vnd->sc_comp_offsets[i + 1])
1217				  - vnd->sc_comp_offsets[i];
1218				if (comp_size > comp_maxsize)
1219					comp_maxsize = comp_size;
1220			}
1221			vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1] =
1222			  be64toh(vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1]);
1223
1224			/* create compressed data buffer */
1225			vnd->sc_comp_buff = malloc(comp_maxsize,
1226			  M_DEVBUF, M_WAITOK);
1227
1228			/* create decompressed buffer */
1229			vnd->sc_comp_decombuf = malloc(vnd->sc_comp_blksz,
1230			  M_DEVBUF, M_WAITOK);
1231			vnd->sc_comp_buffblk = -1;
1232
1233			/* Initialize decompress stream */
1234			memset(&vnd->sc_comp_stream, 0, sizeof(z_stream));
1235			vnd->sc_comp_stream.zalloc = vnd_alloc;
1236			vnd->sc_comp_stream.zfree = vnd_free;
1237			error = inflateInit2(&vnd->sc_comp_stream, MAX_WBITS);
1238			if (error) {
1239				if (vnd->sc_comp_stream.msg)
1240					printf("vnd%d: compressed file, %s\n",
1241					  unit, vnd->sc_comp_stream.msg);
1242				VOP_UNLOCK(nd.ni_vp);
1243				error = EINVAL;
1244				goto close_and_exit;
1245			}
1246
1247			vnd->sc_flags |= VNF_COMP | VNF_READONLY;
1248#else /* !VND_COMPRESSION */
1249			VOP_UNLOCK(nd.ni_vp);
1250			error = EOPNOTSUPP;
1251			goto close_and_exit;
1252#endif /* VND_COMPRESSION */
1253		}
1254
1255		VOP_UNLOCK(nd.ni_vp);
1256		vnd->sc_vp = nd.ni_vp;
1257		vnd->sc_size = btodb(vattr.va_size);	/* note truncation */
1258
1259		/*
1260		 * Use pseudo-geometry specified.  If none was provided,
1261		 * use "standard" Adaptec fictitious geometry.
1262		 */
1263		if (vio->vnd_flags & VNDIOF_HASGEOM) {
1264
1265			memcpy(&vnd->sc_geom, &vio->vnd_geom,
1266			    sizeof(vio->vnd_geom));
1267
1268			/*
1269			 * Sanity-check the sector size.
1270			 * XXX Don't allow secsize < DEV_BSIZE.	 Should
1271			 * XXX we?
1272			 */
1273			if (vnd->sc_geom.vng_secsize < DEV_BSIZE ||
1274			    (vnd->sc_geom.vng_secsize % DEV_BSIZE) != 0 ||
1275			    vnd->sc_geom.vng_ncylinders == 0 ||
1276			    (vnd->sc_geom.vng_ntracks *
1277			     vnd->sc_geom.vng_nsectors) == 0) {
1278				error = EINVAL;
1279				goto close_and_exit;
1280			}
1281
1282			/*
1283			 * Compute the size (in DEV_BSIZE blocks) specified
1284			 * by the geometry.
1285			 */
1286			geomsize = (int64_t)vnd->sc_geom.vng_nsectors *
1287			    vnd->sc_geom.vng_ntracks *
1288			    vnd->sc_geom.vng_ncylinders *
1289			    (vnd->sc_geom.vng_secsize / DEV_BSIZE);
1290
1291			/*
1292			 * Sanity-check the size against the specified
1293			 * geometry.
1294			 */
1295			if (vnd->sc_size < geomsize) {
1296				error = EINVAL;
1297				goto close_and_exit;
1298			}
1299		} else if (vnd->sc_size >= (32 * 64)) {
1300			/*
1301			 * Size must be at least 2048 DEV_BSIZE blocks
1302			 * (1M) in order to use this geometry.
1303			 */
1304			vnd->sc_geom.vng_secsize = DEV_BSIZE;
1305			vnd->sc_geom.vng_nsectors = 32;
1306			vnd->sc_geom.vng_ntracks = 64;
1307			vnd->sc_geom.vng_ncylinders = vnd->sc_size / (64 * 32);
1308		} else {
1309			vnd->sc_geom.vng_secsize = DEV_BSIZE;
1310			vnd->sc_geom.vng_nsectors = 1;
1311			vnd->sc_geom.vng_ntracks = 1;
1312			vnd->sc_geom.vng_ncylinders = vnd->sc_size;
1313		}
1314
1315		vnd_set_geometry(vnd);
1316
1317		if (vio->vnd_flags & VNDIOF_READONLY) {
1318			vnd->sc_flags |= VNF_READONLY;
1319		}
1320
1321		if ((error = vndsetcred(vnd, l->l_cred)) != 0)
1322			goto close_and_exit;
1323
1324		vndthrottle(vnd, vnd->sc_vp);
1325		vio->vnd_osize = dbtob(vnd->sc_size);
1326#ifdef VNDIOCSET50
1327		if (cmd != VNDIOCSET50)
1328#endif
1329			vio->vnd_size = dbtob(vnd->sc_size);
1330		vnd->sc_flags |= VNF_INITED;
1331
1332		/* create the kernel thread, wait for it to be up */
1333		error = kthread_create(PRI_NONE, 0, NULL, vndthread, vnd,
1334		    &vnd->sc_kthread, "%s", device_xname(vnd->sc_dev));
1335		if (error)
1336			goto close_and_exit;
1337		while ((vnd->sc_flags & VNF_KTHREAD) == 0) {
1338			tsleep(&vnd->sc_kthread, PRIBIO, "vndthr", 0);
1339		}
1340#ifdef DEBUG
1341		if (vnddebug & VDB_INIT)
1342			printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n",
1343			    vnd->sc_vp, (unsigned long) vnd->sc_size,
1344			    vnd->sc_geom.vng_secsize,
1345			    vnd->sc_geom.vng_nsectors,
1346			    vnd->sc_geom.vng_ntracks,
1347			    vnd->sc_geom.vng_ncylinders);
1348#endif
1349
1350		/* Attach the disk. */
1351		disk_attach(&vnd->sc_dkdev);
1352
1353		/* Initialize the xfer and buffer pools. */
1354		pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0,
1355		    0, 0, "vndxpl", NULL, IPL_BIO);
1356
1357		vndunlock(vnd);
1358
1359		pathbuf_destroy(pb);
1360
1361		/* Discover wedges on this disk */
1362		dkwedge_discover(&vnd->sc_dkdev);
1363
1364		break;
1365
1366close_and_exit:
1367		(void) vn_close(nd.ni_vp, fflags, l->l_cred);
1368		pathbuf_destroy(pb);
1369unlock_and_exit:
1370#ifdef VND_COMPRESSION
1371		/* free any allocated memory (for compressed file) */
1372		if (vnd->sc_comp_offsets) {
1373			free(vnd->sc_comp_offsets, M_DEVBUF);
1374			vnd->sc_comp_offsets = NULL;
1375		}
1376		if (vnd->sc_comp_buff) {
1377			free(vnd->sc_comp_buff, M_DEVBUF);
1378			vnd->sc_comp_buff = NULL;
1379		}
1380		if (vnd->sc_comp_decombuf) {
1381			free(vnd->sc_comp_decombuf, M_DEVBUF);
1382			vnd->sc_comp_decombuf = NULL;
1383		}
1384#endif /* VND_COMPRESSION */
1385		vndunlock(vnd);
1386		return error;
1387
1388#ifdef VNDIOCCLR50
1389	case VNDIOCCLR50:
1390#endif
1391	case VNDIOCCLR:
1392		part = DISKPART(dev);
1393		pmask = (1 << part);
1394		force = (vio->vnd_flags & VNDIOF_FORCE) != 0;
1395
1396		if ((error = vnddoclear(vnd, pmask, minor(dev), force)) != 0)
1397			return error;
1398
1399		break;
1400
1401#ifdef COMPAT_30
1402	case VNDIOCGET30: {
1403		struct vnd_user30 *vnu;
1404		struct vattr va;
1405		vnu = (struct vnd_user30 *)data;
1406		KASSERT(l);
1407		switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
1408		case 0:
1409			vnu->vnu_dev = va.va_fsid;
1410			vnu->vnu_ino = va.va_fileid;
1411			break;
1412		case -1:
1413			/* unused is not an error */
1414			vnu->vnu_dev = 0;
1415			vnu->vnu_ino = 0;
1416			break;
1417		default:
1418			return error;
1419		}
1420		break;
1421	}
1422#endif
1423
1424#ifdef COMPAT_50
1425	case VNDIOCGET50: {
1426		struct vnd_user50 *vnu;
1427		struct vattr va;
1428		vnu = (struct vnd_user50 *)data;
1429		KASSERT(l);
1430		switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
1431		case 0:
1432			vnu->vnu_dev = va.va_fsid;
1433			vnu->vnu_ino = va.va_fileid;
1434			break;
1435		case -1:
1436			/* unused is not an error */
1437			vnu->vnu_dev = 0;
1438			vnu->vnu_ino = 0;
1439			break;
1440		default:
1441			return error;
1442		}
1443		break;
1444	}
1445#endif
1446
1447	case VNDIOCGET: {
1448		struct vnd_user *vnu;
1449		struct vattr va;
1450		vnu = (struct vnd_user *)data;
1451		KASSERT(l);
1452		switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
1453		case 0:
1454			vnu->vnu_dev = va.va_fsid;
1455			vnu->vnu_ino = va.va_fileid;
1456			break;
1457		case -1:
1458			/* unused is not an error */
1459			vnu->vnu_dev = 0;
1460			vnu->vnu_ino = 0;
1461			break;
1462		default:
1463			return error;
1464		}
1465		break;
1466	}
1467
1468	case DIOCWDINFO:
1469	case DIOCSDINFO:
1470#ifdef __HAVE_OLD_DISKLABEL
1471	case ODIOCWDINFO:
1472	case ODIOCSDINFO:
1473#endif
1474	{
1475		struct disklabel *lp;
1476
1477		if ((error = vndlock(vnd)) != 0)
1478			return error;
1479
1480		vnd->sc_flags |= VNF_LABELLING;
1481
1482#ifdef __HAVE_OLD_DISKLABEL
1483		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
1484			memset(&newlabel, 0, sizeof newlabel);
1485			memcpy(&newlabel, data, sizeof (struct olddisklabel));
1486			lp = &newlabel;
1487		} else
1488#endif
1489		lp = (struct disklabel *)data;
1490
1491		error = setdisklabel(vnd->sc_dkdev.dk_label,
1492		    lp, 0, vnd->sc_dkdev.dk_cpulabel);
1493		if (error == 0) {
1494			if (cmd == DIOCWDINFO
1495#ifdef __HAVE_OLD_DISKLABEL
1496			    || cmd == ODIOCWDINFO
1497#endif
1498			   )
1499				error = writedisklabel(VNDLABELDEV(dev),
1500				    vndstrategy, vnd->sc_dkdev.dk_label,
1501				    vnd->sc_dkdev.dk_cpulabel);
1502		}
1503
1504		vnd->sc_flags &= ~VNF_LABELLING;
1505
1506		vndunlock(vnd);
1507
1508		if (error)
1509			return error;
1510		break;
1511	}
1512
1513	case DIOCKLABEL:
1514		if (*(int *)data != 0)
1515			vnd->sc_flags |= VNF_KLABEL;
1516		else
1517			vnd->sc_flags &= ~VNF_KLABEL;
1518		break;
1519
1520	case DIOCWLABEL:
1521		if (*(int *)data != 0)
1522			vnd->sc_flags |= VNF_WLABEL;
1523		else
1524			vnd->sc_flags &= ~VNF_WLABEL;
1525		break;
1526
1527	case DIOCGDEFLABEL:
1528		vndgetdefaultlabel(vnd, (struct disklabel *)data);
1529		break;
1530
1531#ifdef __HAVE_OLD_DISKLABEL
1532	case ODIOCGDEFLABEL:
1533		vndgetdefaultlabel(vnd, &newlabel);
1534		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
1535			return ENOTTY;
1536		memcpy(data, &newlabel, sizeof (struct olddisklabel));
1537		break;
1538#endif
1539
1540	case DIOCCACHESYNC:
1541		vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1542		error = VOP_FSYNC(vnd->sc_vp, vnd->sc_cred,
1543		    FSYNC_WAIT | FSYNC_DATAONLY | FSYNC_CACHE, 0, 0);
1544		VOP_UNLOCK(vnd->sc_vp);
1545		return error;
1546
1547	default:
1548		return ENOTTY;
1549	}
1550
1551	return 0;
1552}
1553
1554/*
1555 * Duplicate the current processes' credentials.  Since we are called only
1556 * as the result of a SET ioctl and only root can do that, any future access
1557 * to this "disk" is essentially as root.  Note that credentials may change
1558 * if some other uid can write directly to the mapped file (NFS).
1559 */
1560static int
1561vndsetcred(struct vnd_softc *vnd, kauth_cred_t cred)
1562{
1563	struct uio auio;
1564	struct iovec aiov;
1565	char *tmpbuf;
1566	int error;
1567
1568	vnd->sc_cred = kauth_cred_dup(cred);
1569	tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);
1570
1571	/* XXX: Horrible kludge to establish credentials for NFS */
1572	aiov.iov_base = tmpbuf;
1573	aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size));
1574	auio.uio_iov = &aiov;
1575	auio.uio_iovcnt = 1;
1576	auio.uio_offset = 0;
1577	auio.uio_rw = UIO_READ;
1578	auio.uio_resid = aiov.iov_len;
1579	UIO_SETUP_SYSSPACE(&auio);
1580	vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1581	error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred);
1582	if (error == 0) {
1583		/*
1584		 * Because vnd does all IO directly through the vnode
1585		 * we need to flush (at least) the buffer from the above
1586		 * VOP_READ from the buffer cache to prevent cache
1587		 * incoherencies.  Also, be careful to write dirty
1588		 * buffers back to stable storage.
1589		 */
1590		error = vinvalbuf(vnd->sc_vp, V_SAVE, vnd->sc_cred,
1591			    curlwp, 0, 0);
1592	}
1593	VOP_UNLOCK(vnd->sc_vp);
1594
1595	free(tmpbuf, M_TEMP);
1596	return error;
1597}
1598
1599/*
1600 * Set maxactive based on FS type
1601 */
1602static void
1603vndthrottle(struct vnd_softc *vnd, struct vnode *vp)
1604{
1605
1606	if (vp->v_tag == VT_NFS)
1607		vnd->sc_maxactive = 2;
1608	else
1609		vnd->sc_maxactive = 8;
1610
1611	if (vnd->sc_maxactive < 1)
1612		vnd->sc_maxactive = 1;
1613}
1614
1615#if 0
1616static void
1617vndshutdown(void)
1618{
1619	struct vnd_softc *vnd;
1620
1621	for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++)
1622		if (vnd->sc_flags & VNF_INITED)
1623			vndclear(vnd);
1624}
1625#endif
1626
1627static void
1628vndclear(struct vnd_softc *vnd, int myminor)
1629{
1630	struct vnode *vp = vnd->sc_vp;
1631	int fflags = FREAD;
1632	int bmaj, cmaj, i, mn;
1633	int s;
1634
1635#ifdef DEBUG
1636	if (vnddebug & VDB_FOLLOW)
1637		printf("vndclear(%p): vp %p\n", vnd, vp);
1638#endif
1639	/* locate the major number */
1640	bmaj = bdevsw_lookup_major(&vnd_bdevsw);
1641	cmaj = cdevsw_lookup_major(&vnd_cdevsw);
1642
1643	/* Nuke the vnodes for any open instances */
1644	for (i = 0; i < MAXPARTITIONS; i++) {
1645		mn = DISKMINOR(device_unit(vnd->sc_dev), i);
1646		vdevgone(bmaj, mn, mn, VBLK);
1647		if (mn != myminor) /* XXX avoid to kill own vnode */
1648			vdevgone(cmaj, mn, mn, VCHR);
1649	}
1650
1651	if ((vnd->sc_flags & VNF_READONLY) == 0)
1652		fflags |= FWRITE;
1653
1654	s = splbio();
1655	bufq_drain(vnd->sc_tab);
1656	splx(s);
1657
1658	vnd->sc_flags |= VNF_VUNCONF;
1659	wakeup(&vnd->sc_tab);
1660	while (vnd->sc_flags & VNF_KTHREAD)
1661		tsleep(&vnd->sc_kthread, PRIBIO, "vnthr", 0);
1662
1663#ifdef VND_COMPRESSION
1664	/* free the compressed file buffers */
1665	if (vnd->sc_flags & VNF_COMP) {
1666		if (vnd->sc_comp_offsets) {
1667			free(vnd->sc_comp_offsets, M_DEVBUF);
1668			vnd->sc_comp_offsets = NULL;
1669		}
1670		if (vnd->sc_comp_buff) {
1671			free(vnd->sc_comp_buff, M_DEVBUF);
1672			vnd->sc_comp_buff = NULL;
1673		}
1674		if (vnd->sc_comp_decombuf) {
1675			free(vnd->sc_comp_decombuf, M_DEVBUF);
1676			vnd->sc_comp_decombuf = NULL;
1677		}
1678	}
1679#endif /* VND_COMPRESSION */
1680	vnd->sc_flags &=
1681	    ~(VNF_INITED | VNF_READONLY | VNF_VLABEL
1682	      | VNF_VUNCONF | VNF_COMP | VNF_CLEARING);
1683	if (vp == NULL)
1684		panic("vndclear: null vp");
1685	(void) vn_close(vp, fflags, vnd->sc_cred);
1686	kauth_cred_free(vnd->sc_cred);
1687	vnd->sc_vp = NULL;
1688	vnd->sc_cred = NULL;
1689	vnd->sc_size = 0;
1690}
1691
1692static int
1693vndsize(dev_t dev)
1694{
1695	struct vnd_softc *sc;
1696	struct disklabel *lp;
1697	int part, unit, omask;
1698	int size;
1699
1700	unit = vndunit(dev);
1701	sc = device_lookup_private(&vnd_cd, unit);
1702	if (sc == NULL)
1703		return -1;
1704
1705	if ((sc->sc_flags & VNF_INITED) == 0)
1706		return -1;
1707
1708	part = DISKPART(dev);
1709	omask = sc->sc_dkdev.dk_openmask & (1 << part);
1710	lp = sc->sc_dkdev.dk_label;
1711
1712	if (omask == 0 && vndopen(dev, 0, S_IFBLK, curlwp))	/* XXX */
1713		return -1;
1714
1715	if (lp->d_partitions[part].p_fstype != FS_SWAP)
1716		size = -1;
1717	else
1718		size = lp->d_partitions[part].p_size *
1719		    (lp->d_secsize / DEV_BSIZE);
1720
1721	if (omask == 0 && vndclose(dev, 0, S_IFBLK, curlwp))	/* XXX */
1722		return -1;
1723
1724	return size;
1725}
1726
1727static int
1728vnddump(dev_t dev, daddr_t blkno, void *va,
1729    size_t size)
1730{
1731
1732	/* Not implemented. */
1733	return ENXIO;
1734}
1735
1736static void
1737vndgetdefaultlabel(struct vnd_softc *sc, struct disklabel *lp)
1738{
1739	struct vndgeom *vng = &sc->sc_geom;
1740	struct partition *pp;
1741	unsigned spb;
1742
1743	memset(lp, 0, sizeof(*lp));
1744
1745	spb = vng->vng_secsize / DEV_BSIZE;
1746	if (sc->sc_size / spb > UINT32_MAX)
1747		lp->d_secperunit = UINT32_MAX;
1748	else
1749		lp->d_secperunit = sc->sc_size / spb;
1750	lp->d_secsize = vng->vng_secsize;
1751	lp->d_nsectors = vng->vng_nsectors;
1752	lp->d_ntracks = vng->vng_ntracks;
1753	lp->d_ncylinders = vng->vng_ncylinders;
1754	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1755
1756	strncpy(lp->d_typename, "vnd", sizeof(lp->d_typename));
1757	lp->d_type = DKTYPE_VND;
1758	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1759	lp->d_rpm = 3600;
1760	lp->d_interleave = 1;
1761	lp->d_flags = 0;
1762
1763	pp = &lp->d_partitions[RAW_PART];
1764	pp->p_offset = 0;
1765	pp->p_size = lp->d_secperunit;
1766	pp->p_fstype = FS_UNUSED;
1767	lp->d_npartitions = RAW_PART + 1;
1768
1769	lp->d_magic = DISKMAGIC;
1770	lp->d_magic2 = DISKMAGIC;
1771	lp->d_checksum = dkcksum(lp);
1772}
1773
1774/*
1775 * Read the disklabel from a vnd.  If one is not present, create a fake one.
1776 */
1777static void
1778vndgetdisklabel(dev_t dev, struct vnd_softc *sc)
1779{
1780	const char *errstring;
1781	struct disklabel *lp = sc->sc_dkdev.dk_label;
1782	struct cpu_disklabel *clp = sc->sc_dkdev.dk_cpulabel;
1783	int i;
1784
1785	memset(clp, 0, sizeof(*clp));
1786
1787	vndgetdefaultlabel(sc, lp);
1788
1789	/*
1790	 * Call the generic disklabel extraction routine.
1791	 */
1792	errstring = readdisklabel(VNDLABELDEV(dev), vndstrategy, lp, clp);
1793	if (errstring) {
1794		/*
1795		 * Lack of disklabel is common, but we print the warning
1796		 * anyway, since it might contain other useful information.
1797		 */
1798		aprint_normal_dev(sc->sc_dev, "%s\n", errstring);
1799
1800		/*
1801		 * For historical reasons, if there's no disklabel
1802		 * present, all partitions must be FS_BSDFFS and
1803		 * occupy the entire disk.
1804		 */
1805		for (i = 0; i < MAXPARTITIONS; i++) {
1806			/*
1807			 * Don't wipe out port specific hack (such as
1808			 * dos partition hack of i386 port).
1809			 */
1810			if (lp->d_partitions[i].p_size != 0)
1811				continue;
1812
1813			lp->d_partitions[i].p_size = lp->d_secperunit;
1814			lp->d_partitions[i].p_offset = 0;
1815			lp->d_partitions[i].p_fstype = FS_BSDFFS;
1816		}
1817
1818		strncpy(lp->d_packname, "default label",
1819		    sizeof(lp->d_packname));
1820
1821		lp->d_npartitions = MAXPARTITIONS;
1822		lp->d_checksum = dkcksum(lp);
1823	}
1824}
1825
1826/*
1827 * Wait interruptibly for an exclusive lock.
1828 *
1829 * XXX
1830 * Several drivers do this; it should be abstracted and made MP-safe.
1831 */
1832static int
1833vndlock(struct vnd_softc *sc)
1834{
1835	int error;
1836
1837	while ((sc->sc_flags & VNF_LOCKED) != 0) {
1838		sc->sc_flags |= VNF_WANTED;
1839		if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0)
1840			return error;
1841	}
1842	sc->sc_flags |= VNF_LOCKED;
1843	return 0;
1844}
1845
1846/*
1847 * Unlock and wake up any waiters.
1848 */
1849static void
1850vndunlock(struct vnd_softc *sc)
1851{
1852
1853	sc->sc_flags &= ~VNF_LOCKED;
1854	if ((sc->sc_flags & VNF_WANTED) != 0) {
1855		sc->sc_flags &= ~VNF_WANTED;
1856		wakeup(sc);
1857	}
1858}
1859
1860#ifdef VND_COMPRESSION
1861/* compressed file read */
1862static void
1863compstrategy(struct buf *bp, off_t bn)
1864{
1865	int error;
1866	int unit = vndunit(bp->b_dev);
1867	struct vnd_softc *vnd =
1868	    device_lookup_private(&vnd_cd, unit);
1869	u_int32_t comp_block;
1870	struct uio auio;
1871	char *addr;
1872	int s;
1873
1874	/* set up constants for data move */
1875	auio.uio_rw = UIO_READ;
1876	UIO_SETUP_SYSSPACE(&auio);
1877
1878	/* read, and transfer the data */
1879	addr = bp->b_data;
1880	bp->b_resid = bp->b_bcount;
1881	s = splbio();
1882	while (bp->b_resid > 0) {
1883		unsigned length;
1884		size_t length_in_buffer;
1885		u_int32_t offset_in_buffer;
1886		struct iovec aiov;
1887
1888		/* calculate the compressed block number */
1889		comp_block = bn / (off_t)vnd->sc_comp_blksz;
1890
1891		/* check for good block number */
1892		if (comp_block >= vnd->sc_comp_numoffs) {
1893			bp->b_error = EINVAL;
1894			splx(s);
1895			return;
1896		}
1897
1898		/* read in the compressed block, if not in buffer */
1899		if (comp_block != vnd->sc_comp_buffblk) {
1900			length = vnd->sc_comp_offsets[comp_block + 1] -
1901			    vnd->sc_comp_offsets[comp_block];
1902			vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1903			error = vn_rdwr(UIO_READ, vnd->sc_vp, vnd->sc_comp_buff,
1904			    length, vnd->sc_comp_offsets[comp_block],
1905			    UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, vnd->sc_cred,
1906			    NULL, NULL);
1907			if (error) {
1908				bp->b_error = error;
1909				VOP_UNLOCK(vnd->sc_vp);
1910				splx(s);
1911				return;
1912			}
1913			/* uncompress the buffer */
1914			vnd->sc_comp_stream.next_in = vnd->sc_comp_buff;
1915			vnd->sc_comp_stream.avail_in = length;
1916			vnd->sc_comp_stream.next_out = vnd->sc_comp_decombuf;
1917			vnd->sc_comp_stream.avail_out = vnd->sc_comp_blksz;
1918			inflateReset(&vnd->sc_comp_stream);
1919			error = inflate(&vnd->sc_comp_stream, Z_FINISH);
1920			if (error != Z_STREAM_END) {
1921				if (vnd->sc_comp_stream.msg)
1922					aprint_normal_dev(vnd->sc_dev,
1923					    "compressed file, %s\n",
1924					    vnd->sc_comp_stream.msg);
1925				bp->b_error = EBADMSG;
1926				VOP_UNLOCK(vnd->sc_vp);
1927				splx(s);
1928				return;
1929			}
1930			vnd->sc_comp_buffblk = comp_block;
1931			VOP_UNLOCK(vnd->sc_vp);
1932		}
1933
1934		/* transfer the usable uncompressed data */
1935		offset_in_buffer = bn % (off_t)vnd->sc_comp_blksz;
1936		length_in_buffer = vnd->sc_comp_blksz - offset_in_buffer;
1937		if (length_in_buffer > bp->b_resid)
1938			length_in_buffer = bp->b_resid;
1939		auio.uio_iov = &aiov;
1940		auio.uio_iovcnt = 1;
1941		aiov.iov_base = addr;
1942		aiov.iov_len = length_in_buffer;
1943		auio.uio_resid = aiov.iov_len;
1944		auio.uio_offset = 0;
1945		error = uiomove(vnd->sc_comp_decombuf + offset_in_buffer,
1946		    length_in_buffer, &auio);
1947		if (error) {
1948			bp->b_error = error;
1949			splx(s);
1950			return;
1951		}
1952
1953		bn += length_in_buffer;
1954		addr += length_in_buffer;
1955		bp->b_resid -= length_in_buffer;
1956	}
1957	splx(s);
1958}
1959
1960/* compression memory allocation routines */
1961static void *
1962vnd_alloc(void *aux, u_int items, u_int siz)
1963{
1964	return malloc(items * siz, M_TEMP, M_NOWAIT);
1965}
1966
1967static void
1968vnd_free(void *aux, void *ptr)
1969{
1970	free(ptr, M_TEMP);
1971}
1972#endif /* VND_COMPRESSION */
1973
1974static void
1975vnd_set_geometry(struct vnd_softc *vnd)
1976{
1977	struct disk_geom *dg = &vnd->sc_dkdev.dk_geom;
1978
1979	memset(dg, 0, sizeof(*dg));
1980
1981	dg->dg_secperunit = (int64_t)vnd->sc_geom.vng_nsectors *
1982	    vnd->sc_geom.vng_ntracks * vnd->sc_geom.vng_ncylinders;
1983	dg->dg_secsize = vnd->sc_geom.vng_secsize;
1984	dg->dg_nsectors = vnd->sc_geom.vng_nsectors;
1985	dg->dg_ntracks = vnd->sc_geom.vng_ntracks;
1986	dg->dg_ncylinders = vnd->sc_geom.vng_ncylinders;
1987
1988#ifdef DEBUG
1989	if (vnddebug & VDB_LABEL) {
1990		printf("dg->dg_secperunit: %" PRId64 "\n", dg->dg_secperunit);
1991		printf("dg->dg_ncylinders: %u\n", dg->dg_ncylinders);
1992	}
1993#endif
1994	disk_set_info(vnd->sc_dev, &vnd->sc_dkdev, NULL);
1995}
1996
1997#ifdef _MODULE
1998
1999#include <sys/module.h>
2000
2001#ifdef VND_COMPRESSION
2002#define VND_DEPENDS "zlib"
2003#else
2004#define VND_DEPENDS NULL
2005#endif
2006
2007MODULE(MODULE_CLASS_DRIVER, vnd, VND_DEPENDS);
2008CFDRIVER_DECL(vnd, DV_DISK, NULL);
2009
2010static int
2011vnd_modcmd(modcmd_t cmd, void *arg)
2012{
2013	int bmajor = -1, cmajor = -1,  error = 0;
2014
2015	switch (cmd) {
2016	case MODULE_CMD_INIT:
2017		error = config_cfdriver_attach(&vnd_cd);
2018		if (error)
2019			break;
2020
2021		error = config_cfattach_attach(vnd_cd.cd_name, &vnd_ca);
2022	        if (error) {
2023			config_cfdriver_detach(&vnd_cd);
2024			aprint_error("%s: unable to register cfattach\n",
2025			    vnd_cd.cd_name);
2026			break;
2027		}
2028
2029		error = devsw_attach("vnd", &vnd_bdevsw, &bmajor,
2030		    &vnd_cdevsw, &cmajor);
2031		if (error) {
2032			config_cfattach_detach(vnd_cd.cd_name, &vnd_ca);
2033			config_cfdriver_detach(&vnd_cd);
2034			break;
2035		}
2036
2037		break;
2038
2039	case MODULE_CMD_FINI:
2040		error = config_cfattach_detach(vnd_cd.cd_name, &vnd_ca);
2041		if (error)
2042			break;
2043		config_cfdriver_detach(&vnd_cd);
2044		devsw_detach(&vnd_bdevsw, &vnd_cdevsw);
2045		break;
2046
2047	case MODULE_CMD_STAT:
2048		return ENOTTY;
2049
2050	default:
2051		return ENOTTY;
2052	}
2053
2054	return error;
2055}
2056
2057#endif
2058