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