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