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