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