vnd.c revision 1.205
1/* $NetBSD: vnd.c,v 1.205 2009/12/06 16:33:18 dsl 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.205 2009/12/06 16:33:18 dsl 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#ifdef VNDIOOCSET 1041 case VNDIOOCSET: 1042 case VNDIOOCCLR: 1043#endif 1044 case DIOCSDINFO: 1045 case DIOCWDINFO: 1046#ifdef __HAVE_OLD_DISKLABEL 1047 case ODIOCSDINFO: 1048 case ODIOCWDINFO: 1049#endif 1050 case DIOCKLABEL: 1051 case DIOCWLABEL: 1052 if ((flag & FWRITE) == 0) 1053 return EBADF; 1054 } 1055 1056 /* Must be initialized for these... */ 1057 switch (cmd) { 1058 case VNDIOCCLR: 1059#ifdef VNDIOOCCLR 1060 case VNDIOOCCLR: 1061#endif 1062 case DIOCGDINFO: 1063 case DIOCSDINFO: 1064 case DIOCWDINFO: 1065 case DIOCGPART: 1066 case DIOCKLABEL: 1067 case DIOCWLABEL: 1068 case DIOCGDEFLABEL: 1069 case DIOCCACHESYNC: 1070#ifdef __HAVE_OLD_DISKLABEL 1071 case ODIOCGDINFO: 1072 case ODIOCSDINFO: 1073 case ODIOCWDINFO: 1074 case ODIOCGDEFLABEL: 1075#endif 1076 if ((vnd->sc_flags & VNF_INITED) == 0) 1077 return ENXIO; 1078 } 1079 1080 switch (cmd) { 1081#ifdef VNDIOOCSET 1082 case VNDIOOCSET: 1083#endif 1084 case VNDIOCSET: 1085 if (vnd->sc_flags & VNF_INITED) 1086 return EBUSY; 1087 1088 if ((error = vndlock(vnd)) != 0) 1089 return error; 1090 1091 fflags = FREAD; 1092 if ((vio->vnd_flags & VNDIOF_READONLY) == 0) 1093 fflags |= FWRITE; 1094 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file); 1095 if ((error = vn_open(&nd, fflags, 0)) != 0) 1096 goto unlock_and_exit; 1097 KASSERT(l); 1098 error = VOP_GETATTR(nd.ni_vp, &vattr, l->l_cred); 1099 if (!error && nd.ni_vp->v_type != VREG) 1100 error = EOPNOTSUPP; 1101 if (!error && vattr.va_bytes < vattr.va_size) 1102 /* File is definitely sparse, reject here */ 1103 error = EINVAL; 1104 if (error) { 1105 VOP_UNLOCK(nd.ni_vp, 0); 1106 goto close_and_exit; 1107 } 1108 1109 /* If using a compressed file, initialize its info */ 1110 /* (or abort with an error if kernel has no compression) */ 1111 if (vio->vnd_flags & VNF_COMP) { 1112#ifdef VND_COMPRESSION 1113 struct vnd_comp_header *ch; 1114 int i; 1115 u_int32_t comp_size; 1116 u_int32_t comp_maxsize; 1117 1118 /* allocate space for compresed file header */ 1119 ch = malloc(sizeof(struct vnd_comp_header), 1120 M_TEMP, M_WAITOK); 1121 1122 /* read compressed file header */ 1123 error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)ch, 1124 sizeof(struct vnd_comp_header), 0, UIO_SYSSPACE, 1125 IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL); 1126 if (error) { 1127 free(ch, M_TEMP); 1128 VOP_UNLOCK(nd.ni_vp, 0); 1129 goto close_and_exit; 1130 } 1131 1132 /* save some header info */ 1133 vnd->sc_comp_blksz = ntohl(ch->block_size); 1134 /* note last offset is the file byte size */ 1135 vnd->sc_comp_numoffs = ntohl(ch->num_blocks)+1; 1136 free(ch, M_TEMP); 1137 if (vnd->sc_comp_blksz == 0 || 1138 vnd->sc_comp_blksz % DEV_BSIZE !=0) { 1139 VOP_UNLOCK(nd.ni_vp, 0); 1140 error = EINVAL; 1141 goto close_and_exit; 1142 } 1143 if (sizeof(struct vnd_comp_header) + 1144 sizeof(u_int64_t) * vnd->sc_comp_numoffs > 1145 vattr.va_size) { 1146 VOP_UNLOCK(nd.ni_vp, 0); 1147 error = EINVAL; 1148 goto close_and_exit; 1149 } 1150 1151 /* set decompressed file size */ 1152 vattr.va_size = 1153 ((u_quad_t)vnd->sc_comp_numoffs - 1) * 1154 (u_quad_t)vnd->sc_comp_blksz; 1155 1156 /* allocate space for all the compressed offsets */ 1157 vnd->sc_comp_offsets = 1158 malloc(sizeof(u_int64_t) * vnd->sc_comp_numoffs, 1159 M_DEVBUF, M_WAITOK); 1160 1161 /* read in the offsets */ 1162 error = vn_rdwr(UIO_READ, nd.ni_vp, 1163 (void *)vnd->sc_comp_offsets, 1164 sizeof(u_int64_t) * vnd->sc_comp_numoffs, 1165 sizeof(struct vnd_comp_header), UIO_SYSSPACE, 1166 IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL); 1167 if (error) { 1168 VOP_UNLOCK(nd.ni_vp, 0); 1169 goto close_and_exit; 1170 } 1171 /* 1172 * find largest block size (used for allocation limit). 1173 * Also convert offset to native byte order. 1174 */ 1175 comp_maxsize = 0; 1176 for (i = 0; i < vnd->sc_comp_numoffs - 1; i++) { 1177 vnd->sc_comp_offsets[i] = 1178 be64toh(vnd->sc_comp_offsets[i]); 1179 comp_size = be64toh(vnd->sc_comp_offsets[i + 1]) 1180 - vnd->sc_comp_offsets[i]; 1181 if (comp_size > comp_maxsize) 1182 comp_maxsize = comp_size; 1183 } 1184 vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1] = 1185 be64toh(vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1]); 1186 1187 /* create compressed data buffer */ 1188 vnd->sc_comp_buff = malloc(comp_maxsize, 1189 M_DEVBUF, M_WAITOK); 1190 1191 /* create decompressed buffer */ 1192 vnd->sc_comp_decombuf = malloc(vnd->sc_comp_blksz, 1193 M_DEVBUF, M_WAITOK); 1194 vnd->sc_comp_buffblk = -1; 1195 1196 /* Initialize decompress stream */ 1197 memset(&vnd->sc_comp_stream, 0, sizeof(z_stream)); 1198 vnd->sc_comp_stream.zalloc = vnd_alloc; 1199 vnd->sc_comp_stream.zfree = vnd_free; 1200 error = inflateInit2(&vnd->sc_comp_stream, MAX_WBITS); 1201 if (error) { 1202 if (vnd->sc_comp_stream.msg) 1203 printf("vnd%d: compressed file, %s\n", 1204 unit, vnd->sc_comp_stream.msg); 1205 VOP_UNLOCK(nd.ni_vp, 0); 1206 error = EINVAL; 1207 goto close_and_exit; 1208 } 1209 1210 vnd->sc_flags |= VNF_COMP | VNF_READONLY; 1211#else /* !VND_COMPRESSION */ 1212 VOP_UNLOCK(nd.ni_vp, 0); 1213 error = EOPNOTSUPP; 1214 goto close_and_exit; 1215#endif /* VND_COMPRESSION */ 1216 } 1217 1218 VOP_UNLOCK(nd.ni_vp, 0); 1219 vnd->sc_vp = nd.ni_vp; 1220 vnd->sc_size = btodb(vattr.va_size); /* note truncation */ 1221 1222 /* 1223 * Use pseudo-geometry specified. If none was provided, 1224 * use "standard" Adaptec fictitious geometry. 1225 */ 1226 if (vio->vnd_flags & VNDIOF_HASGEOM) { 1227 1228 memcpy(&vnd->sc_geom, &vio->vnd_geom, 1229 sizeof(vio->vnd_geom)); 1230 1231 /* 1232 * Sanity-check the sector size. 1233 * XXX Don't allow secsize < DEV_BSIZE. Should 1234 * XXX we? 1235 */ 1236 if (vnd->sc_geom.vng_secsize < DEV_BSIZE || 1237 (vnd->sc_geom.vng_secsize % DEV_BSIZE) != 0 || 1238 vnd->sc_geom.vng_ncylinders == 0 || 1239 (vnd->sc_geom.vng_ntracks * 1240 vnd->sc_geom.vng_nsectors) == 0) { 1241 error = EINVAL; 1242 goto close_and_exit; 1243 } 1244 1245 /* 1246 * Compute the size (in DEV_BSIZE blocks) specified 1247 * by the geometry. 1248 */ 1249 geomsize = (vnd->sc_geom.vng_nsectors * 1250 vnd->sc_geom.vng_ntracks * 1251 vnd->sc_geom.vng_ncylinders) * 1252 (vnd->sc_geom.vng_secsize / DEV_BSIZE); 1253 1254 /* 1255 * Sanity-check the size against the specified 1256 * geometry. 1257 */ 1258 if (vnd->sc_size < geomsize) { 1259 error = EINVAL; 1260 goto close_and_exit; 1261 } 1262 } else if (vnd->sc_size >= (32 * 64)) { 1263 /* 1264 * Size must be at least 2048 DEV_BSIZE blocks 1265 * (1M) in order to use this geometry. 1266 */ 1267 vnd->sc_geom.vng_secsize = DEV_BSIZE; 1268 vnd->sc_geom.vng_nsectors = 32; 1269 vnd->sc_geom.vng_ntracks = 64; 1270 vnd->sc_geom.vng_ncylinders = vnd->sc_size / (64 * 32); 1271 } else { 1272 vnd->sc_geom.vng_secsize = DEV_BSIZE; 1273 vnd->sc_geom.vng_nsectors = 1; 1274 vnd->sc_geom.vng_ntracks = 1; 1275 vnd->sc_geom.vng_ncylinders = vnd->sc_size; 1276 } 1277 1278 vnd_set_properties(vnd); 1279 1280 if (vio->vnd_flags & VNDIOF_READONLY) { 1281 vnd->sc_flags |= VNF_READONLY; 1282 } 1283 1284 if ((error = vndsetcred(vnd, l->l_cred)) != 0) 1285 goto close_and_exit; 1286 1287 vndthrottle(vnd, vnd->sc_vp); 1288 vio->vnd_osize = dbtob(vnd->sc_size); 1289#ifdef VNDIOOCSET 1290 if (cmd != VNDIOOCSET) 1291#endif 1292 vio->vnd_size = dbtob(vnd->sc_size); 1293 vnd->sc_flags |= VNF_INITED; 1294 1295 /* create the kernel thread, wait for it to be up */ 1296 error = kthread_create(PRI_NONE, 0, NULL, vndthread, vnd, 1297 &vnd->sc_kthread, device_xname(vnd->sc_dev)); 1298 if (error) 1299 goto close_and_exit; 1300 while ((vnd->sc_flags & VNF_KTHREAD) == 0) { 1301 tsleep(&vnd->sc_kthread, PRIBIO, "vndthr", 0); 1302 } 1303#ifdef DEBUG 1304 if (vnddebug & VDB_INIT) 1305 printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n", 1306 vnd->sc_vp, (unsigned long) vnd->sc_size, 1307 vnd->sc_geom.vng_secsize, 1308 vnd->sc_geom.vng_nsectors, 1309 vnd->sc_geom.vng_ntracks, 1310 vnd->sc_geom.vng_ncylinders); 1311#endif 1312 1313 /* Attach the disk. */ 1314 disk_attach(&vnd->sc_dkdev); 1315 1316 /* Initialize the xfer and buffer pools. */ 1317 pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0, 1318 0, 0, "vndxpl", NULL, IPL_BIO); 1319 1320 /* Try and read the disklabel. */ 1321 vndgetdisklabel(dev, vnd); 1322 1323 vndunlock(vnd); 1324 1325 break; 1326 1327close_and_exit: 1328 (void) vn_close(nd.ni_vp, fflags, l->l_cred); 1329unlock_and_exit: 1330#ifdef VND_COMPRESSION 1331 /* free any allocated memory (for compressed file) */ 1332 if (vnd->sc_comp_offsets) { 1333 free(vnd->sc_comp_offsets, M_DEVBUF); 1334 vnd->sc_comp_offsets = NULL; 1335 } 1336 if (vnd->sc_comp_buff) { 1337 free(vnd->sc_comp_buff, M_DEVBUF); 1338 vnd->sc_comp_buff = NULL; 1339 } 1340 if (vnd->sc_comp_decombuf) { 1341 free(vnd->sc_comp_decombuf, M_DEVBUF); 1342 vnd->sc_comp_decombuf = NULL; 1343 } 1344#endif /* VND_COMPRESSION */ 1345 vndunlock(vnd); 1346 return error; 1347 1348#ifdef VNDIOOCCLR 1349 case VNDIOOCCLR: 1350#endif 1351 case VNDIOCCLR: 1352 part = DISKPART(dev); 1353 pmask = (1 << part); 1354 force = (vio->vnd_flags & VNDIOF_FORCE) != 0; 1355 1356 if ((error = vnddoclear(vnd, pmask, minor(dev), force)) != 0) 1357 return error; 1358 1359 break; 1360 1361#ifdef COMPAT_30 1362 case VNDIOOCGET: { 1363 struct vnd_ouser *vnu; 1364 struct vattr va; 1365 vnu = (struct vnd_ouser *)data; 1366 KASSERT(l); 1367 switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) { 1368 case 0: 1369 vnu->vnu_dev = va.va_fsid; 1370 vnu->vnu_ino = va.va_fileid; 1371 break; 1372 case -1: 1373 /* unused is not an error */ 1374 vnu->vnu_dev = 0; 1375 vnu->vnu_ino = 0; 1376 break; 1377 default: 1378 return error; 1379 } 1380 break; 1381 } 1382#endif 1383 case VNDIOCGET: { 1384 struct vnd_user *vnu; 1385 struct vattr va; 1386 vnu = (struct vnd_user *)data; 1387 KASSERT(l); 1388 switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) { 1389 case 0: 1390 vnu->vnu_dev = va.va_fsid; 1391 vnu->vnu_ino = va.va_fileid; 1392 break; 1393 case -1: 1394 /* unused is not an error */ 1395 vnu->vnu_dev = 0; 1396 vnu->vnu_ino = 0; 1397 break; 1398 default: 1399 return error; 1400 } 1401 break; 1402 } 1403 1404 case DIOCGDINFO: 1405 *(struct disklabel *)data = *(vnd->sc_dkdev.dk_label); 1406 break; 1407 1408#ifdef __HAVE_OLD_DISKLABEL 1409 case ODIOCGDINFO: 1410 newlabel = *(vnd->sc_dkdev.dk_label); 1411 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1412 return ENOTTY; 1413 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1414 break; 1415#endif 1416 1417 case DIOCGPART: 1418 ((struct partinfo *)data)->disklab = vnd->sc_dkdev.dk_label; 1419 ((struct partinfo *)data)->part = 1420 &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(dev)]; 1421 break; 1422 1423 case DIOCWDINFO: 1424 case DIOCSDINFO: 1425#ifdef __HAVE_OLD_DISKLABEL 1426 case ODIOCWDINFO: 1427 case ODIOCSDINFO: 1428#endif 1429 { 1430 struct disklabel *lp; 1431 1432 if ((error = vndlock(vnd)) != 0) 1433 return error; 1434 1435 vnd->sc_flags |= VNF_LABELLING; 1436 1437#ifdef __HAVE_OLD_DISKLABEL 1438 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 1439 memset(&newlabel, 0, sizeof newlabel); 1440 memcpy(&newlabel, data, sizeof (struct olddisklabel)); 1441 lp = &newlabel; 1442 } else 1443#endif 1444 lp = (struct disklabel *)data; 1445 1446 error = setdisklabel(vnd->sc_dkdev.dk_label, 1447 lp, 0, vnd->sc_dkdev.dk_cpulabel); 1448 if (error == 0) { 1449 if (cmd == DIOCWDINFO 1450#ifdef __HAVE_OLD_DISKLABEL 1451 || cmd == ODIOCWDINFO 1452#endif 1453 ) 1454 error = writedisklabel(VNDLABELDEV(dev), 1455 vndstrategy, vnd->sc_dkdev.dk_label, 1456 vnd->sc_dkdev.dk_cpulabel); 1457 } 1458 1459 vnd->sc_flags &= ~VNF_LABELLING; 1460 1461 vndunlock(vnd); 1462 1463 if (error) 1464 return error; 1465 break; 1466 } 1467 1468 case DIOCKLABEL: 1469 if (*(int *)data != 0) 1470 vnd->sc_flags |= VNF_KLABEL; 1471 else 1472 vnd->sc_flags &= ~VNF_KLABEL; 1473 break; 1474 1475 case DIOCWLABEL: 1476 if (*(int *)data != 0) 1477 vnd->sc_flags |= VNF_WLABEL; 1478 else 1479 vnd->sc_flags &= ~VNF_WLABEL; 1480 break; 1481 1482 case DIOCGDEFLABEL: 1483 vndgetdefaultlabel(vnd, (struct disklabel *)data); 1484 break; 1485 1486#ifdef __HAVE_OLD_DISKLABEL 1487 case ODIOCGDEFLABEL: 1488 vndgetdefaultlabel(vnd, &newlabel); 1489 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1490 return ENOTTY; 1491 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1492 break; 1493#endif 1494 1495 case DIOCCACHESYNC: 1496 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1497 error = VOP_FSYNC(vnd->sc_vp, vnd->sc_cred, 1498 FSYNC_WAIT | FSYNC_DATAONLY | FSYNC_CACHE, 0, 0); 1499 VOP_UNLOCK(vnd->sc_vp, 0); 1500 return error; 1501 1502 default: 1503 return ENOTTY; 1504 } 1505 1506 return 0; 1507} 1508 1509/* 1510 * Duplicate the current processes' credentials. Since we are called only 1511 * as the result of a SET ioctl and only root can do that, any future access 1512 * to this "disk" is essentially as root. Note that credentials may change 1513 * if some other uid can write directly to the mapped file (NFS). 1514 */ 1515static int 1516vndsetcred(struct vnd_softc *vnd, kauth_cred_t cred) 1517{ 1518 struct uio auio; 1519 struct iovec aiov; 1520 char *tmpbuf; 1521 int error; 1522 1523 vnd->sc_cred = kauth_cred_dup(cred); 1524 tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK); 1525 1526 /* XXX: Horrible kludge to establish credentials for NFS */ 1527 aiov.iov_base = tmpbuf; 1528 aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size)); 1529 auio.uio_iov = &aiov; 1530 auio.uio_iovcnt = 1; 1531 auio.uio_offset = 0; 1532 auio.uio_rw = UIO_READ; 1533 auio.uio_resid = aiov.iov_len; 1534 UIO_SETUP_SYSSPACE(&auio); 1535 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1536 error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred); 1537 if (error == 0) { 1538 /* 1539 * Because vnd does all IO directly through the vnode 1540 * we need to flush (at least) the buffer from the above 1541 * VOP_READ from the buffer cache to prevent cache 1542 * incoherencies. Also, be careful to write dirty 1543 * buffers back to stable storage. 1544 */ 1545 error = vinvalbuf(vnd->sc_vp, V_SAVE, vnd->sc_cred, 1546 curlwp, 0, 0); 1547 } 1548 VOP_UNLOCK(vnd->sc_vp, 0); 1549 1550 free(tmpbuf, M_TEMP); 1551 return error; 1552} 1553 1554/* 1555 * Set maxactive based on FS type 1556 */ 1557static void 1558vndthrottle(struct vnd_softc *vnd, struct vnode *vp) 1559{ 1560#ifdef NFS 1561 extern int (**nfsv2_vnodeop_p)(void *); 1562 1563 if (vp->v_op == nfsv2_vnodeop_p) 1564 vnd->sc_maxactive = 2; 1565 else 1566#endif 1567 vnd->sc_maxactive = 8; 1568 1569 if (vnd->sc_maxactive < 1) 1570 vnd->sc_maxactive = 1; 1571} 1572 1573#if 0 1574static void 1575vndshutdown(void) 1576{ 1577 struct vnd_softc *vnd; 1578 1579 for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++) 1580 if (vnd->sc_flags & VNF_INITED) 1581 vndclear(vnd); 1582} 1583#endif 1584 1585static void 1586vndclear(struct vnd_softc *vnd, int myminor) 1587{ 1588 struct vnode *vp = vnd->sc_vp; 1589 int fflags = FREAD; 1590 int bmaj, cmaj, i, mn; 1591 int s; 1592 1593#ifdef DEBUG 1594 if (vnddebug & VDB_FOLLOW) 1595 printf("vndclear(%p): vp %p\n", vnd, vp); 1596#endif 1597 /* locate the major number */ 1598 bmaj = bdevsw_lookup_major(&vnd_bdevsw); 1599 cmaj = cdevsw_lookup_major(&vnd_cdevsw); 1600 1601 /* Nuke the vnodes for any open instances */ 1602 for (i = 0; i < MAXPARTITIONS; i++) { 1603 mn = DISKMINOR(device_unit(vnd->sc_dev), i); 1604 vdevgone(bmaj, mn, mn, VBLK); 1605 if (mn != myminor) /* XXX avoid to kill own vnode */ 1606 vdevgone(cmaj, mn, mn, VCHR); 1607 } 1608 1609 if ((vnd->sc_flags & VNF_READONLY) == 0) 1610 fflags |= FWRITE; 1611 1612 s = splbio(); 1613 bufq_drain(vnd->sc_tab); 1614 splx(s); 1615 1616 vnd->sc_flags |= VNF_VUNCONF; 1617 wakeup(&vnd->sc_tab); 1618 while (vnd->sc_flags & VNF_KTHREAD) 1619 tsleep(&vnd->sc_kthread, PRIBIO, "vnthr", 0); 1620 1621#ifdef VND_COMPRESSION 1622 /* free the compressed file buffers */ 1623 if (vnd->sc_flags & VNF_COMP) { 1624 if (vnd->sc_comp_offsets) { 1625 free(vnd->sc_comp_offsets, M_DEVBUF); 1626 vnd->sc_comp_offsets = NULL; 1627 } 1628 if (vnd->sc_comp_buff) { 1629 free(vnd->sc_comp_buff, M_DEVBUF); 1630 vnd->sc_comp_buff = NULL; 1631 } 1632 if (vnd->sc_comp_decombuf) { 1633 free(vnd->sc_comp_decombuf, M_DEVBUF); 1634 vnd->sc_comp_decombuf = NULL; 1635 } 1636 } 1637#endif /* VND_COMPRESSION */ 1638 vnd->sc_flags &= 1639 ~(VNF_INITED | VNF_READONLY | VNF_VLABEL 1640 | VNF_VUNCONF | VNF_COMP | VNF_CLEARING); 1641 if (vp == NULL) 1642 panic("vndclear: null vp"); 1643 (void) vn_close(vp, fflags, vnd->sc_cred); 1644 kauth_cred_free(vnd->sc_cred); 1645 vnd->sc_vp = NULL; 1646 vnd->sc_cred = NULL; 1647 vnd->sc_size = 0; 1648} 1649 1650static int 1651vndsize(dev_t dev) 1652{ 1653 struct vnd_softc *sc; 1654 struct disklabel *lp; 1655 int part, unit, omask; 1656 int size; 1657 1658 unit = vndunit(dev); 1659 sc = device_lookup_private(&vnd_cd, unit); 1660 if (sc == NULL) 1661 return -1; 1662 1663 if ((sc->sc_flags & VNF_INITED) == 0) 1664 return -1; 1665 1666 part = DISKPART(dev); 1667 omask = sc->sc_dkdev.dk_openmask & (1 << part); 1668 lp = sc->sc_dkdev.dk_label; 1669 1670 if (omask == 0 && vndopen(dev, 0, S_IFBLK, curlwp)) /* XXX */ 1671 return -1; 1672 1673 if (lp->d_partitions[part].p_fstype != FS_SWAP) 1674 size = -1; 1675 else 1676 size = lp->d_partitions[part].p_size * 1677 (lp->d_secsize / DEV_BSIZE); 1678 1679 if (omask == 0 && vndclose(dev, 0, S_IFBLK, curlwp)) /* XXX */ 1680 return -1; 1681 1682 return size; 1683} 1684 1685static int 1686vnddump(dev_t dev, daddr_t blkno, void *va, 1687 size_t size) 1688{ 1689 1690 /* Not implemented. */ 1691 return ENXIO; 1692} 1693 1694static void 1695vndgetdefaultlabel(struct vnd_softc *sc, struct disklabel *lp) 1696{ 1697 struct vndgeom *vng = &sc->sc_geom; 1698 struct partition *pp; 1699 1700 memset(lp, 0, sizeof(*lp)); 1701 1702 lp->d_secperunit = sc->sc_size / (vng->vng_secsize / DEV_BSIZE); 1703 lp->d_secsize = vng->vng_secsize; 1704 lp->d_nsectors = vng->vng_nsectors; 1705 lp->d_ntracks = vng->vng_ntracks; 1706 lp->d_ncylinders = vng->vng_ncylinders; 1707 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1708 1709 strncpy(lp->d_typename, "vnd", sizeof(lp->d_typename)); 1710 lp->d_type = DTYPE_VND; 1711 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1712 lp->d_rpm = 3600; 1713 lp->d_interleave = 1; 1714 lp->d_flags = 0; 1715 1716 pp = &lp->d_partitions[RAW_PART]; 1717 pp->p_offset = 0; 1718 pp->p_size = lp->d_secperunit; 1719 pp->p_fstype = FS_UNUSED; 1720 lp->d_npartitions = RAW_PART + 1; 1721 1722 lp->d_magic = DISKMAGIC; 1723 lp->d_magic2 = DISKMAGIC; 1724 lp->d_checksum = dkcksum(lp); 1725} 1726 1727/* 1728 * Read the disklabel from a vnd. If one is not present, create a fake one. 1729 */ 1730static void 1731vndgetdisklabel(dev_t dev, struct vnd_softc *sc) 1732{ 1733 const char *errstring; 1734 struct disklabel *lp = sc->sc_dkdev.dk_label; 1735 struct cpu_disklabel *clp = sc->sc_dkdev.dk_cpulabel; 1736 int i; 1737 1738 memset(clp, 0, sizeof(*clp)); 1739 1740 vndgetdefaultlabel(sc, lp); 1741 1742 /* 1743 * Call the generic disklabel extraction routine. 1744 */ 1745 errstring = readdisklabel(VNDLABELDEV(dev), vndstrategy, lp, clp); 1746 if (errstring) { 1747 /* 1748 * Lack of disklabel is common, but we print the warning 1749 * anyway, since it might contain other useful information. 1750 */ 1751 aprint_normal_dev(sc->sc_dev, "%s\n", errstring); 1752 1753 /* 1754 * For historical reasons, if there's no disklabel 1755 * present, all partitions must be FS_BSDFFS and 1756 * occupy the entire disk. 1757 */ 1758 for (i = 0; i < MAXPARTITIONS; i++) { 1759 /* 1760 * Don't wipe out port specific hack (such as 1761 * dos partition hack of i386 port). 1762 */ 1763 if (lp->d_partitions[i].p_size != 0) 1764 continue; 1765 1766 lp->d_partitions[i].p_size = lp->d_secperunit; 1767 lp->d_partitions[i].p_offset = 0; 1768 lp->d_partitions[i].p_fstype = FS_BSDFFS; 1769 } 1770 1771 strncpy(lp->d_packname, "default label", 1772 sizeof(lp->d_packname)); 1773 1774 lp->d_npartitions = MAXPARTITIONS; 1775 lp->d_checksum = dkcksum(lp); 1776 } 1777 1778 /* In-core label now valid. */ 1779 sc->sc_flags |= VNF_VLABEL; 1780} 1781 1782/* 1783 * Wait interruptibly for an exclusive lock. 1784 * 1785 * XXX 1786 * Several drivers do this; it should be abstracted and made MP-safe. 1787 */ 1788static int 1789vndlock(struct vnd_softc *sc) 1790{ 1791 int error; 1792 1793 while ((sc->sc_flags & VNF_LOCKED) != 0) { 1794 sc->sc_flags |= VNF_WANTED; 1795 if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0) 1796 return error; 1797 } 1798 sc->sc_flags |= VNF_LOCKED; 1799 return 0; 1800} 1801 1802/* 1803 * Unlock and wake up any waiters. 1804 */ 1805static void 1806vndunlock(struct vnd_softc *sc) 1807{ 1808 1809 sc->sc_flags &= ~VNF_LOCKED; 1810 if ((sc->sc_flags & VNF_WANTED) != 0) { 1811 sc->sc_flags &= ~VNF_WANTED; 1812 wakeup(sc); 1813 } 1814} 1815 1816#ifdef VND_COMPRESSION 1817/* compressed file read */ 1818static void 1819compstrategy(struct buf *bp, off_t bn) 1820{ 1821 int error; 1822 int unit = vndunit(bp->b_dev); 1823 struct vnd_softc *vnd = 1824 device_lookup_private(&vnd_cd, unit); 1825 u_int32_t comp_block; 1826 struct uio auio; 1827 char *addr; 1828 int s; 1829 1830 /* set up constants for data move */ 1831 auio.uio_rw = UIO_READ; 1832 UIO_SETUP_SYSSPACE(&auio); 1833 1834 /* read, and transfer the data */ 1835 addr = bp->b_data; 1836 bp->b_resid = bp->b_bcount; 1837 s = splbio(); 1838 while (bp->b_resid > 0) { 1839 unsigned length; 1840 size_t length_in_buffer; 1841 u_int32_t offset_in_buffer; 1842 struct iovec aiov; 1843 1844 /* calculate the compressed block number */ 1845 comp_block = bn / (off_t)vnd->sc_comp_blksz; 1846 1847 /* check for good block number */ 1848 if (comp_block >= vnd->sc_comp_numoffs) { 1849 bp->b_error = EINVAL; 1850 splx(s); 1851 return; 1852 } 1853 1854 /* read in the compressed block, if not in buffer */ 1855 if (comp_block != vnd->sc_comp_buffblk) { 1856 length = vnd->sc_comp_offsets[comp_block + 1] - 1857 vnd->sc_comp_offsets[comp_block]; 1858 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1859 error = vn_rdwr(UIO_READ, vnd->sc_vp, vnd->sc_comp_buff, 1860 length, vnd->sc_comp_offsets[comp_block], 1861 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, vnd->sc_cred, 1862 NULL, NULL); 1863 if (error) { 1864 bp->b_error = error; 1865 VOP_UNLOCK(vnd->sc_vp, 0); 1866 splx(s); 1867 return; 1868 } 1869 /* uncompress the buffer */ 1870 vnd->sc_comp_stream.next_in = vnd->sc_comp_buff; 1871 vnd->sc_comp_stream.avail_in = length; 1872 vnd->sc_comp_stream.next_out = vnd->sc_comp_decombuf; 1873 vnd->sc_comp_stream.avail_out = vnd->sc_comp_blksz; 1874 inflateReset(&vnd->sc_comp_stream); 1875 error = inflate(&vnd->sc_comp_stream, Z_FINISH); 1876 if (error != Z_STREAM_END) { 1877 if (vnd->sc_comp_stream.msg) 1878 aprint_normal_dev(vnd->sc_dev, 1879 "compressed file, %s\n", 1880 vnd->sc_comp_stream.msg); 1881 bp->b_error = EBADMSG; 1882 VOP_UNLOCK(vnd->sc_vp, 0); 1883 splx(s); 1884 return; 1885 } 1886 vnd->sc_comp_buffblk = comp_block; 1887 VOP_UNLOCK(vnd->sc_vp, 0); 1888 } 1889 1890 /* transfer the usable uncompressed data */ 1891 offset_in_buffer = bn % (off_t)vnd->sc_comp_blksz; 1892 length_in_buffer = vnd->sc_comp_blksz - offset_in_buffer; 1893 if (length_in_buffer > bp->b_resid) 1894 length_in_buffer = bp->b_resid; 1895 auio.uio_iov = &aiov; 1896 auio.uio_iovcnt = 1; 1897 aiov.iov_base = addr; 1898 aiov.iov_len = length_in_buffer; 1899 auio.uio_resid = aiov.iov_len; 1900 auio.uio_offset = 0; 1901 error = uiomove(vnd->sc_comp_decombuf + offset_in_buffer, 1902 length_in_buffer, &auio); 1903 if (error) { 1904 bp->b_error = error; 1905 splx(s); 1906 return; 1907 } 1908 1909 bn += length_in_buffer; 1910 addr += length_in_buffer; 1911 bp->b_resid -= length_in_buffer; 1912 } 1913 splx(s); 1914} 1915 1916/* compression memory allocation routines */ 1917static void * 1918vnd_alloc(void *aux, u_int items, u_int siz) 1919{ 1920 return malloc(items * siz, M_TEMP, M_NOWAIT); 1921} 1922 1923static void 1924vnd_free(void *aux, void *ptr) 1925{ 1926 free(ptr, M_TEMP); 1927} 1928#endif /* VND_COMPRESSION */ 1929 1930static void 1931vnd_set_properties(struct vnd_softc *vnd) 1932{ 1933 prop_dictionary_t disk_info, odisk_info, geom; 1934 1935 disk_info = prop_dictionary_create(); 1936 1937 geom = prop_dictionary_create(); 1938 1939 prop_dictionary_set_uint64(geom, "sectors-per-unit", 1940 vnd->sc_geom.vng_nsectors * vnd->sc_geom.vng_ntracks * 1941 vnd->sc_geom.vng_ncylinders); 1942 1943 prop_dictionary_set_uint32(geom, "sector-size", 1944 vnd->sc_geom.vng_secsize); 1945 1946 prop_dictionary_set_uint16(geom, "sectors-per-track", 1947 vnd->sc_geom.vng_nsectors); 1948 1949 prop_dictionary_set_uint16(geom, "tracks-per-cylinder", 1950 vnd->sc_geom.vng_ntracks); 1951 1952 prop_dictionary_set_uint64(geom, "cylinders-per-unit", 1953 vnd->sc_geom.vng_ncylinders); 1954 1955 prop_dictionary_set(disk_info, "geometry", geom); 1956 prop_object_release(geom); 1957 1958 prop_dictionary_set(device_properties(vnd->sc_dev), 1959 "disk-info", disk_info); 1960 1961 /* 1962 * Don't release disk_info here; we keep a reference to it. 1963 * disk_detach() will release it when we go away. 1964 */ 1965 1966 odisk_info = vnd->sc_dkdev.dk_info; 1967 vnd->sc_dkdev.dk_info = disk_info; 1968 if (odisk_info) 1969 prop_object_release(odisk_info); 1970} 1971 1972#ifdef _MODULE 1973 1974#include <sys/module.h> 1975 1976MODULE(MODULE_CLASS_DRIVER, vnd, NULL); 1977CFDRIVER_DECL(vnd, DV_DISK, NULL); 1978 1979static int 1980vnd_modcmd(modcmd_t cmd, void *arg) 1981{ 1982 int bmajor = -1, cmajor = -1, error = 0; 1983 1984 switch (cmd) { 1985 case MODULE_CMD_INIT: 1986 error = config_cfdriver_attach(&vnd_cd); 1987 if (error) 1988 break; 1989 1990 error = config_cfattach_attach(vnd_cd.cd_name, &vnd_ca); 1991 if (error) { 1992 config_cfdriver_detach(&vnd_cd); 1993 aprint_error("%s: unable to register cfattach\n", 1994 vnd_cd.cd_name); 1995 break; 1996 } 1997 1998 error = devsw_attach("vnd", &vnd_bdevsw, &bmajor, 1999 &vnd_cdevsw, &cmajor); 2000 if (error) { 2001 config_cfattach_detach(vnd_cd.cd_name, &vnd_ca); 2002 config_cfdriver_detach(&vnd_cd); 2003 break; 2004 } 2005 2006 break; 2007 2008 case MODULE_CMD_FINI: 2009 error = config_cfattach_detach(vnd_cd.cd_name, &vnd_ca); 2010 if (error) 2011 break; 2012 config_cfdriver_detach(&vnd_cd); 2013 devsw_detach(&vnd_bdevsw, &vnd_cdevsw); 2014 break; 2015 2016 case MODULE_CMD_STAT: 2017 return ENOTTY; 2018 2019 default: 2020 return ENOTTY; 2021 } 2022 2023 return error; 2024} 2025 2026#endif 2027