vnd.c revision 1.231 1 /* $NetBSD: vnd.c,v 1.231 2014/07/25 08:02:19 dholland 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.231 2014/07/25 08:02:19 dholland 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
135 int dovndcluster = 1;
136 #define VDB_FOLLOW 0x01
137 #define VDB_INIT 0x02
138 #define VDB_IO 0x04
139 #define VDB_LABEL 0x08
140 int vnddebug = 0x00;
141 #endif
142
143 #define vndunit(x) DISKUNIT(x)
144
145 struct 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 */
160 void vndattach(int);
161
162 static void vndclear(struct vnd_softc *, int);
163 static int vnddoclear(struct vnd_softc *, int, int, bool);
164 static int vndsetcred(struct vnd_softc *, kauth_cred_t);
165 static void vndthrottle(struct vnd_softc *, struct vnode *);
166 static void vndiodone(struct buf *);
167 #if 0
168 static void vndshutdown(void);
169 #endif
170
171 static void vndgetdefaultlabel(struct vnd_softc *, struct disklabel *);
172 static void vndgetdisklabel(dev_t, struct vnd_softc *);
173
174 static int vndlock(struct vnd_softc *);
175 static void vndunlock(struct vnd_softc *);
176 #ifdef VND_COMPRESSION
177 static void compstrategy(struct buf *, off_t);
178 static void *vnd_alloc(void *, u_int, u_int);
179 static void vnd_free(void *, void *);
180 #endif /* VND_COMPRESSION */
181
182 static void vndthread(void *);
183 static bool vnode_has_op(const struct vnode *, int);
184 static void handle_with_rdwr(struct vnd_softc *, const struct buf *,
185 struct buf *);
186 static void handle_with_strategy(struct vnd_softc *, const struct buf *,
187 struct buf *);
188 static void vnd_set_geometry(struct vnd_softc *);
189
190 static dev_type_open(vndopen);
191 static dev_type_close(vndclose);
192 static dev_type_read(vndread);
193 static dev_type_write(vndwrite);
194 static dev_type_ioctl(vndioctl);
195 static dev_type_strategy(vndstrategy);
196 static dev_type_dump(vnddump);
197 static dev_type_size(vndsize);
198
199 const 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
210 const 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_flag = D_DISK
222 };
223
224 static int vnd_match(device_t, cfdata_t, void *);
225 static void vnd_attach(device_t, device_t, void *);
226 static int vnd_detach(device_t, int);
227
228 CFATTACH_DECL3_NEW(vnd, sizeof(struct vnd_softc),
229 vnd_match, vnd_attach, vnd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
230 extern struct cfdriver vnd_cd;
231
232 static struct vnd_softc *vnd_spawn(int);
233 int vnd_destroy(device_t);
234
235 static struct dkdriver vnddkdriver = { vndstrategy, minphys };
236
237 void
238 vndattach(int num)
239 {
240 int error;
241
242 error = config_cfattach_attach(vnd_cd.cd_name, &vnd_ca);
243 if (error)
244 aprint_error("%s: unable to register cfattach\n",
245 vnd_cd.cd_name);
246 }
247
248 static int
249 vnd_match(device_t self, cfdata_t cfdata, void *aux)
250 {
251
252 return 1;
253 }
254
255 static void
256 vnd_attach(device_t parent, device_t self, void *aux)
257 {
258 struct vnd_softc *sc = device_private(self);
259
260 sc->sc_dev = self;
261 sc->sc_comp_offsets = NULL;
262 sc->sc_comp_buff = NULL;
263 sc->sc_comp_decombuf = NULL;
264 bufq_alloc(&sc->sc_tab, "disksort", BUFQ_SORT_RAWBLOCK);
265 disk_init(&sc->sc_dkdev, device_xname(self), &vnddkdriver);
266 if (!pmf_device_register(self, NULL, NULL))
267 aprint_error_dev(self, "couldn't establish power handler\n");
268 }
269
270 static int
271 vnd_detach(device_t self, int flags)
272 {
273 int error;
274 struct vnd_softc *sc = device_private(self);
275
276 if (sc->sc_flags & VNF_INITED) {
277 error = vnddoclear(sc, 0, -1, (flags & DETACH_FORCE) != 0);
278 if (error != 0)
279 return error;
280 }
281
282 pmf_device_deregister(self);
283 bufq_free(sc->sc_tab);
284 disk_destroy(&sc->sc_dkdev);
285
286 return 0;
287 }
288
289 static struct vnd_softc *
290 vnd_spawn(int unit)
291 {
292 cfdata_t cf;
293
294 cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK);
295 cf->cf_name = vnd_cd.cd_name;
296 cf->cf_atname = vnd_cd.cd_name;
297 cf->cf_unit = unit;
298 cf->cf_fstate = FSTATE_STAR;
299
300 return device_private(config_attach_pseudo(cf));
301 }
302
303 int
304 vnd_destroy(device_t dev)
305 {
306 int error;
307 cfdata_t cf;
308
309 cf = device_cfdata(dev);
310 error = config_detach(dev, DETACH_QUIET);
311 if (error)
312 return error;
313 free(cf, M_DEVBUF);
314 return 0;
315 }
316
317 static int
318 vndopen(dev_t dev, int flags, int mode, struct lwp *l)
319 {
320 int unit = vndunit(dev);
321 struct vnd_softc *sc;
322 int error = 0, part, pmask;
323 struct disklabel *lp;
324
325 #ifdef DEBUG
326 if (vnddebug & VDB_FOLLOW)
327 printf("vndopen(0x%"PRIx64", 0x%x, 0x%x, %p)\n", dev, flags, mode, l);
328 #endif
329 sc = device_lookup_private(&vnd_cd, unit);
330 if (sc == NULL) {
331 sc = vnd_spawn(unit);
332 if (sc == NULL)
333 return ENOMEM;
334 }
335
336 if ((error = vndlock(sc)) != 0)
337 return error;
338
339 if ((sc->sc_flags & VNF_CLEARING) != 0) {
340 error = ENXIO;
341 goto done;
342 }
343
344 lp = sc->sc_dkdev.dk_label;
345
346 part = DISKPART(dev);
347 pmask = (1 << part);
348
349 if (sc->sc_dkdev.dk_nwedges != 0 && part != RAW_PART) {
350 error = EBUSY;
351 goto done;
352 }
353
354 if (sc->sc_flags & VNF_INITED) {
355 if ((sc->sc_dkdev.dk_openmask & ~(1<<RAW_PART)) != 0) {
356 /*
357 * If any non-raw partition is open, but the disk
358 * has been invalidated, disallow further opens.
359 */
360 if ((sc->sc_flags & VNF_VLABEL) == 0) {
361 error = EIO;
362 goto done;
363 }
364 } else {
365 /*
366 * Load the partition info if not already loaded.
367 */
368 if ((sc->sc_flags & VNF_VLABEL) == 0) {
369 sc->sc_flags |= VNF_VLABEL;
370 vndgetdisklabel(dev, sc);
371 }
372 }
373 }
374
375 /* Check that the partitions exists. */
376 if (part != RAW_PART) {
377 if (((sc->sc_flags & VNF_INITED) == 0) ||
378 ((part >= lp->d_npartitions) ||
379 (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
380 error = ENXIO;
381 goto done;
382 }
383 }
384
385 /* Prevent our unit from being unconfigured while open. */
386 switch (mode) {
387 case S_IFCHR:
388 sc->sc_dkdev.dk_copenmask |= pmask;
389 break;
390
391 case S_IFBLK:
392 sc->sc_dkdev.dk_bopenmask |= pmask;
393 break;
394 }
395 sc->sc_dkdev.dk_openmask =
396 sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
397
398 done:
399 vndunlock(sc);
400 return error;
401 }
402
403 static int
404 vndclose(dev_t dev, int flags, int mode, struct lwp *l)
405 {
406 int unit = vndunit(dev);
407 struct vnd_softc *sc;
408 int error = 0, part;
409
410 #ifdef DEBUG
411 if (vnddebug & VDB_FOLLOW)
412 printf("vndclose(0x%"PRIx64", 0x%x, 0x%x, %p)\n", dev, flags, mode, l);
413 #endif
414 sc = device_lookup_private(&vnd_cd, unit);
415 if (sc == NULL)
416 return ENXIO;
417
418 if ((error = vndlock(sc)) != 0)
419 return error;
420
421 part = DISKPART(dev);
422
423 /* ...that much closer to allowing unconfiguration... */
424 switch (mode) {
425 case S_IFCHR:
426 sc->sc_dkdev.dk_copenmask &= ~(1 << part);
427 break;
428
429 case S_IFBLK:
430 sc->sc_dkdev.dk_bopenmask &= ~(1 << part);
431 break;
432 }
433 sc->sc_dkdev.dk_openmask =
434 sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
435
436 vndunlock(sc);
437
438 if ((sc->sc_flags & VNF_INITED) == 0) {
439 if ((error = vnd_destroy(sc->sc_dev)) != 0) {
440 aprint_error_dev(sc->sc_dev,
441 "unable to detach instance\n");
442 return error;
443 }
444 }
445
446 return 0;
447 }
448
449 /*
450 * Queue the request, and wakeup the kernel thread to handle it.
451 */
452 static void
453 vndstrategy(struct buf *bp)
454 {
455 int unit = vndunit(bp->b_dev);
456 struct vnd_softc *vnd =
457 device_lookup_private(&vnd_cd, unit);
458 struct disklabel *lp;
459 daddr_t blkno;
460 int s = splbio();
461
462 if (vnd == NULL) {
463 bp->b_error = ENXIO;
464 goto done;
465 }
466 lp = vnd->sc_dkdev.dk_label;
467
468 if ((vnd->sc_flags & VNF_INITED) == 0) {
469 bp->b_error = ENXIO;
470 goto done;
471 }
472
473 /*
474 * The transfer must be a whole number of blocks.
475 */
476 if ((bp->b_bcount % lp->d_secsize) != 0) {
477 bp->b_error = EINVAL;
478 goto done;
479 }
480
481 /*
482 * check if we're read-only.
483 */
484 if ((vnd->sc_flags & VNF_READONLY) && !(bp->b_flags & B_READ)) {
485 bp->b_error = EACCES;
486 goto done;
487 }
488
489 /* If it's a nil transfer, wake up the top half now. */
490 if (bp->b_bcount == 0) {
491 goto done;
492 }
493
494 /*
495 * Do bounds checking and adjust transfer. If there's an error,
496 * the bounds check will flag that for us.
497 */
498 if (DISKPART(bp->b_dev) == RAW_PART) {
499 if (bounds_check_with_mediasize(bp, DEV_BSIZE,
500 vnd->sc_size) <= 0)
501 goto done;
502 } else {
503 if (bounds_check_with_label(&vnd->sc_dkdev,
504 bp, vnd->sc_flags & (VNF_WLABEL|VNF_LABELLING)) <= 0)
505 goto done;
506 }
507
508 /*
509 * Put the block number in terms of the logical blocksize
510 * of the "device".
511 */
512
513 blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
514
515 /*
516 * Translate the partition-relative block number to an absolute.
517 */
518 if (DISKPART(bp->b_dev) != RAW_PART) {
519 struct partition *pp;
520
521 pp = &vnd->sc_dkdev.dk_label->d_partitions[
522 DISKPART(bp->b_dev)];
523 blkno += pp->p_offset;
524 }
525 bp->b_rawblkno = blkno;
526
527 #ifdef DEBUG
528 if (vnddebug & VDB_FOLLOW)
529 printf("vndstrategy(%p): unit %d\n", bp, unit);
530 #endif
531 if ((vnd->sc_flags & VNF_USE_VN_RDWR)) {
532 KASSERT(vnd->sc_pending >= 0 &&
533 vnd->sc_pending <= VND_MAXPENDING(vnd));
534 while (vnd->sc_pending == VND_MAXPENDING(vnd))
535 tsleep(&vnd->sc_pending, PRIBIO, "vndpc", 0);
536 vnd->sc_pending++;
537 }
538 bufq_put(vnd->sc_tab, bp);
539 wakeup(&vnd->sc_tab);
540 splx(s);
541 return;
542
543 done:
544 bp->b_resid = bp->b_bcount;
545 biodone(bp);
546 splx(s);
547 }
548
549 static bool
550 vnode_has_strategy(struct vnd_softc *vnd)
551 {
552 return vnode_has_op(vnd->sc_vp, VOFFSET(vop_bmap)) &&
553 vnode_has_op(vnd->sc_vp, VOFFSET(vop_strategy));
554 }
555
556 /* XXX this function needs a reliable check to detect
557 * sparse files. Otherwise, bmap/strategy may be used
558 * and fail on non-allocated blocks. VOP_READ/VOP_WRITE
559 * works on sparse files.
560 */
561 #if notyet
562 static bool
563 vnode_strategy_probe(struct vnd_softc *vnd)
564 {
565 int error;
566 daddr_t nbn;
567
568 if (!vnode_has_strategy(vnd))
569 return false;
570
571 /* Convert the first logical block number to its
572 * physical block number.
573 */
574 error = 0;
575 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
576 error = VOP_BMAP(vnd->sc_vp, 0, NULL, &nbn, NULL);
577 VOP_UNLOCK(vnd->sc_vp);
578
579 /* Test if that worked. */
580 if (error == 0 && (long)nbn == -1)
581 return false;
582
583 return true;
584 }
585 #endif
586
587 static void
588 vndthread(void *arg)
589 {
590 struct vnd_softc *vnd = arg;
591 int s;
592
593 /* Determine whether we can *use* VOP_BMAP and VOP_STRATEGY to
594 * directly access the backing vnode. If we can, use these two
595 * operations to avoid messing with the local buffer cache.
596 * Otherwise fall back to regular VOP_READ/VOP_WRITE operations
597 * which are guaranteed to work with any file system. */
598 if ((vnd->sc_flags & VNF_USE_VN_RDWR) == 0 &&
599 ! vnode_has_strategy(vnd))
600 vnd->sc_flags |= VNF_USE_VN_RDWR;
601
602 #ifdef DEBUG
603 if (vnddebug & VDB_INIT)
604 printf("vndthread: vp %p, %s\n", vnd->sc_vp,
605 (vnd->sc_flags & VNF_USE_VN_RDWR) == 0 ?
606 "using bmap/strategy operations" :
607 "using read/write operations");
608 #endif
609
610 s = splbio();
611 vnd->sc_flags |= VNF_KTHREAD;
612 wakeup(&vnd->sc_kthread);
613
614 /*
615 * Dequeue requests and serve them depending on the available
616 * vnode operations.
617 */
618 while ((vnd->sc_flags & VNF_VUNCONF) == 0) {
619 struct vndxfer *vnx;
620 struct buf *obp;
621 struct buf *bp;
622
623 obp = bufq_get(vnd->sc_tab);
624 if (obp == NULL) {
625 tsleep(&vnd->sc_tab, PRIBIO, "vndbp", 0);
626 continue;
627 };
628 if ((vnd->sc_flags & VNF_USE_VN_RDWR)) {
629 KASSERT(vnd->sc_pending > 0 &&
630 vnd->sc_pending <= VND_MAXPENDING(vnd));
631 if (vnd->sc_pending-- == VND_MAXPENDING(vnd))
632 wakeup(&vnd->sc_pending);
633 }
634 splx(s);
635 #ifdef DEBUG
636 if (vnddebug & VDB_FOLLOW)
637 printf("vndthread(%p)\n", obp);
638 #endif
639
640 if (vnd->sc_vp->v_mount == NULL) {
641 obp->b_error = ENXIO;
642 goto done;
643 }
644 #ifdef VND_COMPRESSION
645 /* handle a compressed read */
646 if ((obp->b_flags & B_READ) != 0 && (vnd->sc_flags & VNF_COMP)) {
647 off_t bn;
648
649 /* Convert to a byte offset within the file. */
650 bn = obp->b_rawblkno *
651 vnd->sc_dkdev.dk_label->d_secsize;
652
653 compstrategy(obp, bn);
654 goto done;
655 }
656 #endif /* VND_COMPRESSION */
657
658 /*
659 * Allocate a header for this transfer and link it to the
660 * buffer
661 */
662 s = splbio();
663 vnx = VND_GETXFER(vnd);
664 splx(s);
665 vnx->vx_vnd = vnd;
666
667 s = splbio();
668 while (vnd->sc_active >= vnd->sc_maxactive) {
669 tsleep(&vnd->sc_tab, PRIBIO, "vndac", 0);
670 }
671 vnd->sc_active++;
672 splx(s);
673
674 /* Instrumentation. */
675 disk_busy(&vnd->sc_dkdev);
676
677 bp = &vnx->vx_buf;
678 buf_init(bp);
679 bp->b_flags = (obp->b_flags & B_READ);
680 bp->b_oflags = obp->b_oflags;
681 bp->b_cflags = obp->b_cflags;
682 bp->b_iodone = vndiodone;
683 bp->b_private = obp;
684 bp->b_vp = vnd->sc_vp;
685 bp->b_objlock = bp->b_vp->v_interlock;
686 bp->b_data = obp->b_data;
687 bp->b_bcount = obp->b_bcount;
688 BIO_COPYPRIO(bp, obp);
689
690 /* Handle the request using the appropriate operations. */
691 if ((vnd->sc_flags & VNF_USE_VN_RDWR) == 0)
692 handle_with_strategy(vnd, obp, bp);
693 else
694 handle_with_rdwr(vnd, obp, bp);
695
696 s = splbio();
697 continue;
698
699 done:
700 biodone(obp);
701 s = splbio();
702 }
703
704 vnd->sc_flags &= (~VNF_KTHREAD | VNF_VUNCONF);
705 wakeup(&vnd->sc_kthread);
706 splx(s);
707 kthread_exit(0);
708 }
709
710 /*
711 * Checks if the given vnode supports the requested operation.
712 * The operation is specified the offset returned by VOFFSET.
713 *
714 * XXX The test below used to determine this is quite fragile
715 * because it relies on the file system to use genfs to specify
716 * unimplemented operations. There might be another way to do
717 * it more cleanly.
718 */
719 static bool
720 vnode_has_op(const struct vnode *vp, int opoffset)
721 {
722 int (*defaultp)(void *);
723 int (*opp)(void *);
724
725 defaultp = vp->v_op[VOFFSET(vop_default)];
726 opp = vp->v_op[opoffset];
727
728 return opp != defaultp && opp != genfs_eopnotsupp &&
729 opp != genfs_badop && opp != genfs_nullop;
730 }
731
732 /*
733 * Handes the read/write request given in 'bp' using the vnode's VOP_READ
734 * and VOP_WRITE operations.
735 *
736 * 'obp' is a pointer to the original request fed to the vnd device.
737 */
738 static void
739 handle_with_rdwr(struct vnd_softc *vnd, const struct buf *obp, struct buf *bp)
740 {
741 bool doread;
742 off_t offset;
743 size_t len, resid;
744 struct vnode *vp;
745
746 doread = bp->b_flags & B_READ;
747 offset = obp->b_rawblkno * vnd->sc_dkdev.dk_label->d_secsize;
748 len = bp->b_bcount;
749 vp = vnd->sc_vp;
750
751 #if defined(DEBUG)
752 if (vnddebug & VDB_IO)
753 printf("vnd (rdwr): vp %p, %s, rawblkno 0x%" PRIx64
754 ", secsize %d, offset %" PRIu64
755 ", bcount %d\n",
756 vp, doread ? "read" : "write", obp->b_rawblkno,
757 vnd->sc_dkdev.dk_label->d_secsize, offset,
758 bp->b_bcount);
759 #endif
760
761 /* Issue the read or write operation. */
762 bp->b_error =
763 vn_rdwr(doread ? UIO_READ : UIO_WRITE,
764 vp, bp->b_data, len, offset, UIO_SYSSPACE,
765 IO_ADV_ENCODE(POSIX_FADV_NOREUSE), vnd->sc_cred, &resid, NULL);
766 bp->b_resid = resid;
767
768 mutex_enter(vp->v_interlock);
769 (void) VOP_PUTPAGES(vp, 0, 0,
770 PGO_ALLPAGES | PGO_CLEANIT | PGO_FREE | PGO_SYNCIO);
771
772 /* We need to increase the number of outputs on the vnode if
773 * there was any write to it. */
774 if (!doread) {
775 mutex_enter(vp->v_interlock);
776 vp->v_numoutput++;
777 mutex_exit(vp->v_interlock);
778 }
779
780 biodone(bp);
781 }
782
783 /*
784 * Handes the read/write request given in 'bp' using the vnode's VOP_BMAP
785 * and VOP_STRATEGY operations.
786 *
787 * 'obp' is a pointer to the original request fed to the vnd device.
788 */
789 static void
790 handle_with_strategy(struct vnd_softc *vnd, const struct buf *obp,
791 struct buf *bp)
792 {
793 int bsize, error, flags, skipped;
794 size_t resid, sz;
795 off_t bn, offset;
796 struct vnode *vp;
797
798 flags = obp->b_flags;
799
800 if (!(flags & B_READ)) {
801 vp = bp->b_vp;
802 mutex_enter(vp->v_interlock);
803 vp->v_numoutput++;
804 mutex_exit(vp->v_interlock);
805 }
806
807 /* convert to a byte offset within the file. */
808 bn = obp->b_rawblkno * vnd->sc_dkdev.dk_label->d_secsize;
809
810 bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize;
811 skipped = 0;
812
813 /*
814 * Break the request into bsize pieces and feed them
815 * sequentially using VOP_BMAP/VOP_STRATEGY.
816 * We do it this way to keep from flooding NFS servers if we
817 * are connected to an NFS file. This places the burden on
818 * the client rather than the server.
819 */
820 error = 0;
821 bp->b_resid = bp->b_bcount;
822 for (offset = 0, resid = bp->b_resid; resid;
823 resid -= sz, offset += sz) {
824 struct buf *nbp;
825 daddr_t nbn;
826 int off, nra;
827
828 nra = 0;
829 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
830 error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra);
831 VOP_UNLOCK(vnd->sc_vp);
832
833 if (error == 0 && (long)nbn == -1)
834 error = EIO;
835
836 /*
837 * If there was an error or a hole in the file...punt.
838 * Note that we may have to wait for any operations
839 * that we have already fired off before releasing
840 * the buffer.
841 *
842 * XXX we could deal with holes here but it would be
843 * a hassle (in the write case).
844 */
845 if (error) {
846 skipped += resid;
847 break;
848 }
849
850 #ifdef DEBUG
851 if (!dovndcluster)
852 nra = 0;
853 #endif
854
855 off = bn % bsize;
856 sz = MIN(((off_t)1 + nra) * bsize - off, resid);
857 #ifdef DEBUG
858 if (vnddebug & VDB_IO)
859 printf("vndstrategy: vp %p/%p bn 0x%qx/0x%" PRIx64
860 " sz 0x%zx\n", vnd->sc_vp, vp, (long long)bn,
861 nbn, sz);
862 #endif
863
864 nbp = getiobuf(vp, true);
865 nestiobuf_setup(bp, nbp, offset, sz);
866 nbp->b_blkno = nbn + btodb(off);
867
868 #if 0 /* XXX #ifdef DEBUG */
869 if (vnddebug & VDB_IO)
870 printf("vndstart(%ld): bp %p vp %p blkno "
871 "0x%" PRIx64 " flags %x addr %p cnt 0x%x\n",
872 (long) (vnd-vnd_softc), &nbp->vb_buf,
873 nbp->vb_buf.b_vp, nbp->vb_buf.b_blkno,
874 nbp->vb_buf.b_flags, nbp->vb_buf.b_data,
875 nbp->vb_buf.b_bcount);
876 #endif
877 VOP_STRATEGY(vp, nbp);
878 bn += sz;
879 }
880 nestiobuf_done(bp, skipped, error);
881 }
882
883 static void
884 vndiodone(struct buf *bp)
885 {
886 struct vndxfer *vnx = VND_BUFTOXFER(bp);
887 struct vnd_softc *vnd = vnx->vx_vnd;
888 struct buf *obp = bp->b_private;
889 int s = splbio();
890
891 KASSERT(&vnx->vx_buf == bp);
892 KASSERT(vnd->sc_active > 0);
893 #ifdef DEBUG
894 if (vnddebug & VDB_IO) {
895 printf("vndiodone1: bp %p iodone: error %d\n",
896 bp, bp->b_error);
897 }
898 #endif
899 disk_unbusy(&vnd->sc_dkdev, bp->b_bcount - bp->b_resid,
900 (bp->b_flags & B_READ));
901 vnd->sc_active--;
902 if (vnd->sc_active == 0) {
903 wakeup(&vnd->sc_tab);
904 }
905 splx(s);
906 obp->b_error = bp->b_error;
907 obp->b_resid = bp->b_resid;
908 buf_destroy(bp);
909 VND_PUTXFER(vnd, vnx);
910 biodone(obp);
911 }
912
913 /* ARGSUSED */
914 static int
915 vndread(dev_t dev, struct uio *uio, int flags)
916 {
917 int unit = vndunit(dev);
918 struct vnd_softc *sc;
919
920 #ifdef DEBUG
921 if (vnddebug & VDB_FOLLOW)
922 printf("vndread(0x%"PRIx64", %p)\n", dev, uio);
923 #endif
924
925 sc = device_lookup_private(&vnd_cd, unit);
926 if (sc == NULL)
927 return ENXIO;
928
929 if ((sc->sc_flags & VNF_INITED) == 0)
930 return ENXIO;
931
932 return physio(vndstrategy, NULL, dev, B_READ, minphys, uio);
933 }
934
935 /* ARGSUSED */
936 static int
937 vndwrite(dev_t dev, struct uio *uio, int flags)
938 {
939 int unit = vndunit(dev);
940 struct vnd_softc *sc;
941
942 #ifdef DEBUG
943 if (vnddebug & VDB_FOLLOW)
944 printf("vndwrite(0x%"PRIx64", %p)\n", dev, uio);
945 #endif
946
947 sc = device_lookup_private(&vnd_cd, unit);
948 if (sc == NULL)
949 return ENXIO;
950
951 if ((sc->sc_flags & VNF_INITED) == 0)
952 return ENXIO;
953
954 return physio(vndstrategy, NULL, dev, B_WRITE, minphys, uio);
955 }
956
957 static int
958 vnd_cget(struct lwp *l, int unit, int *un, struct vattr *va)
959 {
960 int error;
961 struct vnd_softc *vnd;
962
963 if (*un == -1)
964 *un = unit;
965 if (*un < 0)
966 return EINVAL;
967
968 vnd = device_lookup_private(&vnd_cd, *un);
969 if (vnd == NULL)
970 return -1;
971
972 if ((vnd->sc_flags & VNF_INITED) == 0)
973 return -1;
974
975 vn_lock(vnd->sc_vp, LK_SHARED | LK_RETRY);
976 error = VOP_GETATTR(vnd->sc_vp, va, l->l_cred);
977 VOP_UNLOCK(vnd->sc_vp);
978 return error;
979 }
980
981 static int
982 vnddoclear(struct vnd_softc *vnd, int pmask, int minor, bool force)
983 {
984 int error;
985
986 if ((error = vndlock(vnd)) != 0)
987 return error;
988
989 /*
990 * Don't unconfigure if any other partitions are open
991 * or if both the character and block flavors of this
992 * partition are open.
993 */
994 if (DK_BUSY(vnd, pmask) && !force) {
995 vndunlock(vnd);
996 return EBUSY;
997 }
998
999 /* Delete all of our wedges */
1000 dkwedge_delall(&vnd->sc_dkdev);
1001
1002 /*
1003 * XXX vndclear() might call vndclose() implicitly;
1004 * release lock to avoid recursion
1005 *
1006 * Set VNF_CLEARING to prevent vndopen() from
1007 * sneaking in after we vndunlock().
1008 */
1009 vnd->sc_flags |= VNF_CLEARING;
1010 vndunlock(vnd);
1011 vndclear(vnd, minor);
1012 #ifdef DEBUG
1013 if (vnddebug & VDB_INIT)
1014 printf("vndioctl: CLRed\n");
1015 #endif
1016
1017 /* Destroy the xfer and buffer pools. */
1018 pool_destroy(&vnd->sc_vxpool);
1019
1020 /* Detach the disk. */
1021 disk_detach(&vnd->sc_dkdev);
1022
1023 return 0;
1024 }
1025
1026 /* ARGSUSED */
1027 static int
1028 vndioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1029 {
1030 bool force;
1031 int unit = vndunit(dev);
1032 struct vnd_softc *vnd;
1033 struct vnd_ioctl *vio;
1034 struct vattr vattr;
1035 struct pathbuf *pb;
1036 struct nameidata nd;
1037 int error, part, pmask;
1038 uint64_t geomsize;
1039 int fflags;
1040 #ifdef __HAVE_OLD_DISKLABEL
1041 struct disklabel newlabel;
1042 #endif
1043 struct dkwedge_info *dkw;
1044 struct dkwedge_list *dkwl;
1045
1046 #ifdef DEBUG
1047 if (vnddebug & VDB_FOLLOW)
1048 printf("vndioctl(0x%"PRIx64", 0x%lx, %p, 0x%x, %p): unit %d\n",
1049 dev, cmd, data, flag, l->l_proc, unit);
1050 #endif
1051 vnd = device_lookup_private(&vnd_cd, unit);
1052 if (vnd == NULL &&
1053 #ifdef COMPAT_30
1054 cmd != VNDIOCGET30 &&
1055 #endif
1056 #ifdef COMPAT_50
1057 cmd != VNDIOCGET50 &&
1058 #endif
1059 cmd != VNDIOCGET)
1060 return ENXIO;
1061 vio = (struct vnd_ioctl *)data;
1062
1063 error = disk_ioctl(&vnd->sc_dkdev, cmd, data, flag, l);
1064 if (error != EPASSTHROUGH)
1065 return (error);
1066
1067 /* Must be open for writes for these commands... */
1068 switch (cmd) {
1069 case VNDIOCSET:
1070 case VNDIOCCLR:
1071 #ifdef COMPAT_50
1072 case VNDIOCSET50:
1073 case VNDIOCCLR50:
1074 #endif
1075 case DIOCSDINFO:
1076 case DIOCWDINFO:
1077 #ifdef __HAVE_OLD_DISKLABEL
1078 case ODIOCSDINFO:
1079 case ODIOCWDINFO:
1080 #endif
1081 case DIOCKLABEL:
1082 case DIOCWLABEL:
1083 if ((flag & FWRITE) == 0)
1084 return EBADF;
1085 }
1086
1087 /* Must be initialized for these... */
1088 switch (cmd) {
1089 case VNDIOCCLR:
1090 #ifdef VNDIOCCLR50
1091 case VNDIOCCLR50:
1092 #endif
1093 case DIOCGDINFO:
1094 case DIOCSDINFO:
1095 case DIOCWDINFO:
1096 case DIOCGPART:
1097 case DIOCKLABEL:
1098 case DIOCWLABEL:
1099 case DIOCGDEFLABEL:
1100 case DIOCCACHESYNC:
1101 #ifdef __HAVE_OLD_DISKLABEL
1102 case ODIOCGDINFO:
1103 case ODIOCSDINFO:
1104 case ODIOCWDINFO:
1105 case ODIOCGDEFLABEL:
1106 #endif
1107 if ((vnd->sc_flags & VNF_INITED) == 0)
1108 return ENXIO;
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 = (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 disk_blocksize(&vnd->sc_dkdev, vnd->sc_geom.vng_secsize);
1353
1354 /* Initialize the xfer and buffer pools. */
1355 pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0,
1356 0, 0, "vndxpl", NULL, IPL_BIO);
1357
1358 vndunlock(vnd);
1359
1360 pathbuf_destroy(pb);
1361
1362 /* Discover wedges on this disk */
1363 dkwedge_discover(&vnd->sc_dkdev);
1364
1365 break;
1366
1367 close_and_exit:
1368 (void) vn_close(nd.ni_vp, fflags, l->l_cred);
1369 pathbuf_destroy(pb);
1370 unlock_and_exit:
1371 #ifdef VND_COMPRESSION
1372 /* free any allocated memory (for compressed file) */
1373 if (vnd->sc_comp_offsets) {
1374 free(vnd->sc_comp_offsets, M_DEVBUF);
1375 vnd->sc_comp_offsets = NULL;
1376 }
1377 if (vnd->sc_comp_buff) {
1378 free(vnd->sc_comp_buff, M_DEVBUF);
1379 vnd->sc_comp_buff = NULL;
1380 }
1381 if (vnd->sc_comp_decombuf) {
1382 free(vnd->sc_comp_decombuf, M_DEVBUF);
1383 vnd->sc_comp_decombuf = NULL;
1384 }
1385 #endif /* VND_COMPRESSION */
1386 vndunlock(vnd);
1387 return error;
1388
1389 #ifdef VNDIOCCLR50
1390 case VNDIOCCLR50:
1391 #endif
1392 case VNDIOCCLR:
1393 part = DISKPART(dev);
1394 pmask = (1 << part);
1395 force = (vio->vnd_flags & VNDIOF_FORCE) != 0;
1396
1397 if ((error = vnddoclear(vnd, pmask, minor(dev), force)) != 0)
1398 return error;
1399
1400 break;
1401
1402 #ifdef COMPAT_30
1403 case VNDIOCGET30: {
1404 struct vnd_user30 *vnu;
1405 struct vattr va;
1406 vnu = (struct vnd_user30 *)data;
1407 KASSERT(l);
1408 switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
1409 case 0:
1410 vnu->vnu_dev = va.va_fsid;
1411 vnu->vnu_ino = va.va_fileid;
1412 break;
1413 case -1:
1414 /* unused is not an error */
1415 vnu->vnu_dev = 0;
1416 vnu->vnu_ino = 0;
1417 break;
1418 default:
1419 return error;
1420 }
1421 break;
1422 }
1423 #endif
1424
1425 #ifdef COMPAT_50
1426 case VNDIOCGET50: {
1427 struct vnd_user50 *vnu;
1428 struct vattr va;
1429 vnu = (struct vnd_user50 *)data;
1430 KASSERT(l);
1431 switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
1432 case 0:
1433 vnu->vnu_dev = va.va_fsid;
1434 vnu->vnu_ino = va.va_fileid;
1435 break;
1436 case -1:
1437 /* unused is not an error */
1438 vnu->vnu_dev = 0;
1439 vnu->vnu_ino = 0;
1440 break;
1441 default:
1442 return error;
1443 }
1444 break;
1445 }
1446 #endif
1447
1448 case VNDIOCGET: {
1449 struct vnd_user *vnu;
1450 struct vattr va;
1451 vnu = (struct vnd_user *)data;
1452 KASSERT(l);
1453 switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
1454 case 0:
1455 vnu->vnu_dev = va.va_fsid;
1456 vnu->vnu_ino = va.va_fileid;
1457 break;
1458 case -1:
1459 /* unused is not an error */
1460 vnu->vnu_dev = 0;
1461 vnu->vnu_ino = 0;
1462 break;
1463 default:
1464 return error;
1465 }
1466 break;
1467 }
1468
1469 case DIOCGDINFO:
1470 *(struct disklabel *)data = *(vnd->sc_dkdev.dk_label);
1471 break;
1472
1473 #ifdef __HAVE_OLD_DISKLABEL
1474 case ODIOCGDINFO:
1475 newlabel = *(vnd->sc_dkdev.dk_label);
1476 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
1477 return ENOTTY;
1478 memcpy(data, &newlabel, sizeof (struct olddisklabel));
1479 break;
1480 #endif
1481
1482 case DIOCGPART:
1483 ((struct partinfo *)data)->disklab = vnd->sc_dkdev.dk_label;
1484 ((struct partinfo *)data)->part =
1485 &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
1486 break;
1487
1488 case DIOCWDINFO:
1489 case DIOCSDINFO:
1490 #ifdef __HAVE_OLD_DISKLABEL
1491 case ODIOCWDINFO:
1492 case ODIOCSDINFO:
1493 #endif
1494 {
1495 struct disklabel *lp;
1496
1497 if ((error = vndlock(vnd)) != 0)
1498 return error;
1499
1500 vnd->sc_flags |= VNF_LABELLING;
1501
1502 #ifdef __HAVE_OLD_DISKLABEL
1503 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
1504 memset(&newlabel, 0, sizeof newlabel);
1505 memcpy(&newlabel, data, sizeof (struct olddisklabel));
1506 lp = &newlabel;
1507 } else
1508 #endif
1509 lp = (struct disklabel *)data;
1510
1511 error = setdisklabel(vnd->sc_dkdev.dk_label,
1512 lp, 0, vnd->sc_dkdev.dk_cpulabel);
1513 if (error == 0) {
1514 if (cmd == DIOCWDINFO
1515 #ifdef __HAVE_OLD_DISKLABEL
1516 || cmd == ODIOCWDINFO
1517 #endif
1518 )
1519 error = writedisklabel(VNDLABELDEV(dev),
1520 vndstrategy, vnd->sc_dkdev.dk_label,
1521 vnd->sc_dkdev.dk_cpulabel);
1522 }
1523
1524 vnd->sc_flags &= ~VNF_LABELLING;
1525
1526 vndunlock(vnd);
1527
1528 if (error)
1529 return error;
1530 break;
1531 }
1532
1533 case DIOCKLABEL:
1534 if (*(int *)data != 0)
1535 vnd->sc_flags |= VNF_KLABEL;
1536 else
1537 vnd->sc_flags &= ~VNF_KLABEL;
1538 break;
1539
1540 case DIOCWLABEL:
1541 if (*(int *)data != 0)
1542 vnd->sc_flags |= VNF_WLABEL;
1543 else
1544 vnd->sc_flags &= ~VNF_WLABEL;
1545 break;
1546
1547 case DIOCGDEFLABEL:
1548 vndgetdefaultlabel(vnd, (struct disklabel *)data);
1549 break;
1550
1551 #ifdef __HAVE_OLD_DISKLABEL
1552 case ODIOCGDEFLABEL:
1553 vndgetdefaultlabel(vnd, &newlabel);
1554 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
1555 return ENOTTY;
1556 memcpy(data, &newlabel, sizeof (struct olddisklabel));
1557 break;
1558 #endif
1559
1560 case DIOCCACHESYNC:
1561 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1562 error = VOP_FSYNC(vnd->sc_vp, vnd->sc_cred,
1563 FSYNC_WAIT | FSYNC_DATAONLY | FSYNC_CACHE, 0, 0);
1564 VOP_UNLOCK(vnd->sc_vp);
1565 return error;
1566
1567 case DIOCAWEDGE:
1568 dkw = (void *) data;
1569
1570 if ((flag & FWRITE) == 0)
1571 return EBADF;
1572
1573 /* If the ioctl happens here, the parent is us. */
1574 strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev),
1575 sizeof(dkw->dkw_parent));
1576 return dkwedge_add(dkw);
1577
1578 case DIOCDWEDGE:
1579 dkw = (void *) data;
1580
1581 if ((flag & FWRITE) == 0)
1582 return EBADF;
1583
1584 /* If the ioctl happens here, the parent is us. */
1585 strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev),
1586 sizeof(dkw->dkw_parent));
1587 return dkwedge_del(dkw);
1588
1589 case DIOCLWEDGES:
1590 dkwl = (void *) data;
1591
1592 return dkwedge_list(&vnd->sc_dkdev, dkwl, l);
1593
1594 default:
1595 return ENOTTY;
1596 }
1597
1598 return 0;
1599 }
1600
1601 /*
1602 * Duplicate the current processes' credentials. Since we are called only
1603 * as the result of a SET ioctl and only root can do that, any future access
1604 * to this "disk" is essentially as root. Note that credentials may change
1605 * if some other uid can write directly to the mapped file (NFS).
1606 */
1607 static int
1608 vndsetcred(struct vnd_softc *vnd, kauth_cred_t cred)
1609 {
1610 struct uio auio;
1611 struct iovec aiov;
1612 char *tmpbuf;
1613 int error;
1614
1615 vnd->sc_cred = kauth_cred_dup(cred);
1616 tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);
1617
1618 /* XXX: Horrible kludge to establish credentials for NFS */
1619 aiov.iov_base = tmpbuf;
1620 aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size));
1621 auio.uio_iov = &aiov;
1622 auio.uio_iovcnt = 1;
1623 auio.uio_offset = 0;
1624 auio.uio_rw = UIO_READ;
1625 auio.uio_resid = aiov.iov_len;
1626 UIO_SETUP_SYSSPACE(&auio);
1627 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1628 error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred);
1629 if (error == 0) {
1630 /*
1631 * Because vnd does all IO directly through the vnode
1632 * we need to flush (at least) the buffer from the above
1633 * VOP_READ from the buffer cache to prevent cache
1634 * incoherencies. Also, be careful to write dirty
1635 * buffers back to stable storage.
1636 */
1637 error = vinvalbuf(vnd->sc_vp, V_SAVE, vnd->sc_cred,
1638 curlwp, 0, 0);
1639 }
1640 VOP_UNLOCK(vnd->sc_vp);
1641
1642 free(tmpbuf, M_TEMP);
1643 return error;
1644 }
1645
1646 /*
1647 * Set maxactive based on FS type
1648 */
1649 static void
1650 vndthrottle(struct vnd_softc *vnd, struct vnode *vp)
1651 {
1652
1653 if (vp->v_tag == VT_NFS)
1654 vnd->sc_maxactive = 2;
1655 else
1656 vnd->sc_maxactive = 8;
1657
1658 if (vnd->sc_maxactive < 1)
1659 vnd->sc_maxactive = 1;
1660 }
1661
1662 #if 0
1663 static void
1664 vndshutdown(void)
1665 {
1666 struct vnd_softc *vnd;
1667
1668 for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++)
1669 if (vnd->sc_flags & VNF_INITED)
1670 vndclear(vnd);
1671 }
1672 #endif
1673
1674 static void
1675 vndclear(struct vnd_softc *vnd, int myminor)
1676 {
1677 struct vnode *vp = vnd->sc_vp;
1678 int fflags = FREAD;
1679 int bmaj, cmaj, i, mn;
1680 int s;
1681
1682 #ifdef DEBUG
1683 if (vnddebug & VDB_FOLLOW)
1684 printf("vndclear(%p): vp %p\n", vnd, vp);
1685 #endif
1686 /* locate the major number */
1687 bmaj = bdevsw_lookup_major(&vnd_bdevsw);
1688 cmaj = cdevsw_lookup_major(&vnd_cdevsw);
1689
1690 /* Nuke the vnodes for any open instances */
1691 for (i = 0; i < MAXPARTITIONS; i++) {
1692 mn = DISKMINOR(device_unit(vnd->sc_dev), i);
1693 vdevgone(bmaj, mn, mn, VBLK);
1694 if (mn != myminor) /* XXX avoid to kill own vnode */
1695 vdevgone(cmaj, mn, mn, VCHR);
1696 }
1697
1698 if ((vnd->sc_flags & VNF_READONLY) == 0)
1699 fflags |= FWRITE;
1700
1701 s = splbio();
1702 bufq_drain(vnd->sc_tab);
1703 splx(s);
1704
1705 vnd->sc_flags |= VNF_VUNCONF;
1706 wakeup(&vnd->sc_tab);
1707 while (vnd->sc_flags & VNF_KTHREAD)
1708 tsleep(&vnd->sc_kthread, PRIBIO, "vnthr", 0);
1709
1710 #ifdef VND_COMPRESSION
1711 /* free the compressed file buffers */
1712 if (vnd->sc_flags & VNF_COMP) {
1713 if (vnd->sc_comp_offsets) {
1714 free(vnd->sc_comp_offsets, M_DEVBUF);
1715 vnd->sc_comp_offsets = NULL;
1716 }
1717 if (vnd->sc_comp_buff) {
1718 free(vnd->sc_comp_buff, M_DEVBUF);
1719 vnd->sc_comp_buff = NULL;
1720 }
1721 if (vnd->sc_comp_decombuf) {
1722 free(vnd->sc_comp_decombuf, M_DEVBUF);
1723 vnd->sc_comp_decombuf = NULL;
1724 }
1725 }
1726 #endif /* VND_COMPRESSION */
1727 vnd->sc_flags &=
1728 ~(VNF_INITED | VNF_READONLY | VNF_VLABEL
1729 | VNF_VUNCONF | VNF_COMP | VNF_CLEARING);
1730 if (vp == NULL)
1731 panic("vndclear: null vp");
1732 (void) vn_close(vp, fflags, vnd->sc_cred);
1733 kauth_cred_free(vnd->sc_cred);
1734 vnd->sc_vp = NULL;
1735 vnd->sc_cred = NULL;
1736 vnd->sc_size = 0;
1737 }
1738
1739 static int
1740 vndsize(dev_t dev)
1741 {
1742 struct vnd_softc *sc;
1743 struct disklabel *lp;
1744 int part, unit, omask;
1745 int size;
1746
1747 unit = vndunit(dev);
1748 sc = device_lookup_private(&vnd_cd, unit);
1749 if (sc == NULL)
1750 return -1;
1751
1752 if ((sc->sc_flags & VNF_INITED) == 0)
1753 return -1;
1754
1755 part = DISKPART(dev);
1756 omask = sc->sc_dkdev.dk_openmask & (1 << part);
1757 lp = sc->sc_dkdev.dk_label;
1758
1759 if (omask == 0 && vndopen(dev, 0, S_IFBLK, curlwp)) /* XXX */
1760 return -1;
1761
1762 if (lp->d_partitions[part].p_fstype != FS_SWAP)
1763 size = -1;
1764 else
1765 size = lp->d_partitions[part].p_size *
1766 (lp->d_secsize / DEV_BSIZE);
1767
1768 if (omask == 0 && vndclose(dev, 0, S_IFBLK, curlwp)) /* XXX */
1769 return -1;
1770
1771 return size;
1772 }
1773
1774 static int
1775 vnddump(dev_t dev, daddr_t blkno, void *va,
1776 size_t size)
1777 {
1778
1779 /* Not implemented. */
1780 return ENXIO;
1781 }
1782
1783 static void
1784 vndgetdefaultlabel(struct vnd_softc *sc, struct disklabel *lp)
1785 {
1786 struct vndgeom *vng = &sc->sc_geom;
1787 struct partition *pp;
1788
1789 memset(lp, 0, sizeof(*lp));
1790
1791 lp->d_secperunit = sc->sc_size / (vng->vng_secsize / DEV_BSIZE);
1792 lp->d_secsize = vng->vng_secsize;
1793 lp->d_nsectors = vng->vng_nsectors;
1794 lp->d_ntracks = vng->vng_ntracks;
1795 lp->d_ncylinders = vng->vng_ncylinders;
1796 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1797
1798 strncpy(lp->d_typename, "vnd", sizeof(lp->d_typename));
1799 lp->d_type = DTYPE_VND;
1800 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1801 lp->d_rpm = 3600;
1802 lp->d_interleave = 1;
1803 lp->d_flags = 0;
1804
1805 pp = &lp->d_partitions[RAW_PART];
1806 pp->p_offset = 0;
1807 pp->p_size = lp->d_secperunit;
1808 pp->p_fstype = FS_UNUSED;
1809 lp->d_npartitions = RAW_PART + 1;
1810
1811 lp->d_magic = DISKMAGIC;
1812 lp->d_magic2 = DISKMAGIC;
1813 lp->d_checksum = dkcksum(lp);
1814 }
1815
1816 /*
1817 * Read the disklabel from a vnd. If one is not present, create a fake one.
1818 */
1819 static void
1820 vndgetdisklabel(dev_t dev, struct vnd_softc *sc)
1821 {
1822 const char *errstring;
1823 struct disklabel *lp = sc->sc_dkdev.dk_label;
1824 struct cpu_disklabel *clp = sc->sc_dkdev.dk_cpulabel;
1825 int i;
1826
1827 memset(clp, 0, sizeof(*clp));
1828
1829 vndgetdefaultlabel(sc, lp);
1830
1831 /*
1832 * Call the generic disklabel extraction routine.
1833 */
1834 errstring = readdisklabel(VNDLABELDEV(dev), vndstrategy, lp, clp);
1835 if (errstring) {
1836 /*
1837 * Lack of disklabel is common, but we print the warning
1838 * anyway, since it might contain other useful information.
1839 */
1840 aprint_normal_dev(sc->sc_dev, "%s\n", errstring);
1841
1842 /*
1843 * For historical reasons, if there's no disklabel
1844 * present, all partitions must be FS_BSDFFS and
1845 * occupy the entire disk.
1846 */
1847 for (i = 0; i < MAXPARTITIONS; i++) {
1848 /*
1849 * Don't wipe out port specific hack (such as
1850 * dos partition hack of i386 port).
1851 */
1852 if (lp->d_partitions[i].p_size != 0)
1853 continue;
1854
1855 lp->d_partitions[i].p_size = lp->d_secperunit;
1856 lp->d_partitions[i].p_offset = 0;
1857 lp->d_partitions[i].p_fstype = FS_BSDFFS;
1858 }
1859
1860 strncpy(lp->d_packname, "default label",
1861 sizeof(lp->d_packname));
1862
1863 lp->d_npartitions = MAXPARTITIONS;
1864 lp->d_checksum = dkcksum(lp);
1865 }
1866 }
1867
1868 /*
1869 * Wait interruptibly for an exclusive lock.
1870 *
1871 * XXX
1872 * Several drivers do this; it should be abstracted and made MP-safe.
1873 */
1874 static int
1875 vndlock(struct vnd_softc *sc)
1876 {
1877 int error;
1878
1879 while ((sc->sc_flags & VNF_LOCKED) != 0) {
1880 sc->sc_flags |= VNF_WANTED;
1881 if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0)
1882 return error;
1883 }
1884 sc->sc_flags |= VNF_LOCKED;
1885 return 0;
1886 }
1887
1888 /*
1889 * Unlock and wake up any waiters.
1890 */
1891 static void
1892 vndunlock(struct vnd_softc *sc)
1893 {
1894
1895 sc->sc_flags &= ~VNF_LOCKED;
1896 if ((sc->sc_flags & VNF_WANTED) != 0) {
1897 sc->sc_flags &= ~VNF_WANTED;
1898 wakeup(sc);
1899 }
1900 }
1901
1902 #ifdef VND_COMPRESSION
1903 /* compressed file read */
1904 static void
1905 compstrategy(struct buf *bp, off_t bn)
1906 {
1907 int error;
1908 int unit = vndunit(bp->b_dev);
1909 struct vnd_softc *vnd =
1910 device_lookup_private(&vnd_cd, unit);
1911 u_int32_t comp_block;
1912 struct uio auio;
1913 char *addr;
1914 int s;
1915
1916 /* set up constants for data move */
1917 auio.uio_rw = UIO_READ;
1918 UIO_SETUP_SYSSPACE(&auio);
1919
1920 /* read, and transfer the data */
1921 addr = bp->b_data;
1922 bp->b_resid = bp->b_bcount;
1923 s = splbio();
1924 while (bp->b_resid > 0) {
1925 unsigned length;
1926 size_t length_in_buffer;
1927 u_int32_t offset_in_buffer;
1928 struct iovec aiov;
1929
1930 /* calculate the compressed block number */
1931 comp_block = bn / (off_t)vnd->sc_comp_blksz;
1932
1933 /* check for good block number */
1934 if (comp_block >= vnd->sc_comp_numoffs) {
1935 bp->b_error = EINVAL;
1936 splx(s);
1937 return;
1938 }
1939
1940 /* read in the compressed block, if not in buffer */
1941 if (comp_block != vnd->sc_comp_buffblk) {
1942 length = vnd->sc_comp_offsets[comp_block + 1] -
1943 vnd->sc_comp_offsets[comp_block];
1944 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1945 error = vn_rdwr(UIO_READ, vnd->sc_vp, vnd->sc_comp_buff,
1946 length, vnd->sc_comp_offsets[comp_block],
1947 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, vnd->sc_cred,
1948 NULL, NULL);
1949 if (error) {
1950 bp->b_error = error;
1951 VOP_UNLOCK(vnd->sc_vp);
1952 splx(s);
1953 return;
1954 }
1955 /* uncompress the buffer */
1956 vnd->sc_comp_stream.next_in = vnd->sc_comp_buff;
1957 vnd->sc_comp_stream.avail_in = length;
1958 vnd->sc_comp_stream.next_out = vnd->sc_comp_decombuf;
1959 vnd->sc_comp_stream.avail_out = vnd->sc_comp_blksz;
1960 inflateReset(&vnd->sc_comp_stream);
1961 error = inflate(&vnd->sc_comp_stream, Z_FINISH);
1962 if (error != Z_STREAM_END) {
1963 if (vnd->sc_comp_stream.msg)
1964 aprint_normal_dev(vnd->sc_dev,
1965 "compressed file, %s\n",
1966 vnd->sc_comp_stream.msg);
1967 bp->b_error = EBADMSG;
1968 VOP_UNLOCK(vnd->sc_vp);
1969 splx(s);
1970 return;
1971 }
1972 vnd->sc_comp_buffblk = comp_block;
1973 VOP_UNLOCK(vnd->sc_vp);
1974 }
1975
1976 /* transfer the usable uncompressed data */
1977 offset_in_buffer = bn % (off_t)vnd->sc_comp_blksz;
1978 length_in_buffer = vnd->sc_comp_blksz - offset_in_buffer;
1979 if (length_in_buffer > bp->b_resid)
1980 length_in_buffer = bp->b_resid;
1981 auio.uio_iov = &aiov;
1982 auio.uio_iovcnt = 1;
1983 aiov.iov_base = addr;
1984 aiov.iov_len = length_in_buffer;
1985 auio.uio_resid = aiov.iov_len;
1986 auio.uio_offset = 0;
1987 error = uiomove(vnd->sc_comp_decombuf + offset_in_buffer,
1988 length_in_buffer, &auio);
1989 if (error) {
1990 bp->b_error = error;
1991 splx(s);
1992 return;
1993 }
1994
1995 bn += length_in_buffer;
1996 addr += length_in_buffer;
1997 bp->b_resid -= length_in_buffer;
1998 }
1999 splx(s);
2000 }
2001
2002 /* compression memory allocation routines */
2003 static void *
2004 vnd_alloc(void *aux, u_int items, u_int siz)
2005 {
2006 return malloc(items * siz, M_TEMP, M_NOWAIT);
2007 }
2008
2009 static void
2010 vnd_free(void *aux, void *ptr)
2011 {
2012 free(ptr, M_TEMP);
2013 }
2014 #endif /* VND_COMPRESSION */
2015
2016 static void
2017 vnd_set_geometry(struct vnd_softc *vnd)
2018 {
2019 struct disk_geom *dg = &vnd->sc_dkdev.dk_geom;
2020
2021 memset(dg, 0, sizeof(*dg));
2022
2023 dg->dg_secperunit = (int64_t)vnd->sc_geom.vng_nsectors *
2024 vnd->sc_geom.vng_ntracks * vnd->sc_geom.vng_ncylinders;
2025 dg->dg_secsize = vnd->sc_geom.vng_secsize;
2026 dg->dg_nsectors = vnd->sc_geom.vng_nsectors;
2027 dg->dg_ntracks = vnd->sc_geom.vng_ntracks;
2028 dg->dg_ncylinders = vnd->sc_geom.vng_ncylinders;
2029
2030 #ifdef DEBUG
2031 if (vnddebug & VDB_LABEL) {
2032 printf("dg->dg_secperunit: %" PRId64 "\n", dg->dg_secperunit);
2033 printf("dg->dg_ncylinders: %u\n", dg->dg_ncylinders);
2034 }
2035 #endif
2036 disk_set_info(vnd->sc_dev, &vnd->sc_dkdev, NULL);
2037 }
2038
2039 #ifdef _MODULE
2040
2041 #include <sys/module.h>
2042
2043 #ifdef VND_COMPRESSION
2044 #define VND_DEPENDS "zlib"
2045 #else
2046 #define VND_DEPENDS NULL
2047 #endif
2048
2049 MODULE(MODULE_CLASS_DRIVER, vnd, VND_DEPENDS);
2050 CFDRIVER_DECL(vnd, DV_DISK, NULL);
2051
2052 static int
2053 vnd_modcmd(modcmd_t cmd, void *arg)
2054 {
2055 int bmajor = -1, cmajor = -1, error = 0;
2056
2057 switch (cmd) {
2058 case MODULE_CMD_INIT:
2059 error = config_cfdriver_attach(&vnd_cd);
2060 if (error)
2061 break;
2062
2063 error = config_cfattach_attach(vnd_cd.cd_name, &vnd_ca);
2064 if (error) {
2065 config_cfdriver_detach(&vnd_cd);
2066 aprint_error("%s: unable to register cfattach\n",
2067 vnd_cd.cd_name);
2068 break;
2069 }
2070
2071 error = devsw_attach("vnd", &vnd_bdevsw, &bmajor,
2072 &vnd_cdevsw, &cmajor);
2073 if (error) {
2074 config_cfattach_detach(vnd_cd.cd_name, &vnd_ca);
2075 config_cfdriver_detach(&vnd_cd);
2076 break;
2077 }
2078
2079 break;
2080
2081 case MODULE_CMD_FINI:
2082 error = config_cfattach_detach(vnd_cd.cd_name, &vnd_ca);
2083 if (error)
2084 break;
2085 config_cfdriver_detach(&vnd_cd);
2086 devsw_detach(&vnd_bdevsw, &vnd_cdevsw);
2087 break;
2088
2089 case MODULE_CMD_STAT:
2090 return ENOTTY;
2091
2092 default:
2093 return ENOTTY;
2094 }
2095
2096 return error;
2097 }
2098
2099 #endif
2100