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