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