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