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