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