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