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