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