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