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