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