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