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