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