1 /* $NetBSD: vnd.c,v 1.218 2011/06/29 09:12:42 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.218 2011/06/29 09:12:42 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 struct vnd_softc *vnd; 922 923 if (*un == -1) 924 *un = unit; 925 if (*un < 0) 926 return EINVAL; 927 928 vnd = device_lookup_private(&vnd_cd, *un); 929 if (vnd == NULL) 930 return (*un >= vnd_cd.cd_ndevs) ? ENXIO : -1; 931 932 if ((vnd->sc_flags & VNF_INITED) == 0) 933 return -1; 934 935 return VOP_GETATTR(vnd->sc_vp, va, l->l_cred); 936 } 937 938 static int 939 vnddoclear(struct vnd_softc *vnd, int pmask, int minor, bool force) 940 { 941 int error; 942 943 if ((error = vndlock(vnd)) != 0) 944 return error; 945 946 /* 947 * Don't unconfigure if any other partitions are open 948 * or if both the character and block flavors of this 949 * partition are open. 950 */ 951 if (DK_BUSY(vnd, pmask) && !force) { 952 vndunlock(vnd); 953 return EBUSY; 954 } 955 956 /* 957 * XXX vndclear() might call vndclose() implicitly; 958 * release lock to avoid recursion 959 * 960 * Set VNF_CLEARING to prevent vndopen() from 961 * sneaking in after we vndunlock(). 962 */ 963 vnd->sc_flags |= VNF_CLEARING; 964 vndunlock(vnd); 965 vndclear(vnd, minor); 966 #ifdef DEBUG 967 if (vnddebug & VDB_INIT) 968 printf("vndioctl: CLRed\n"); 969 #endif 970 971 /* Destroy the xfer and buffer pools. */ 972 pool_destroy(&vnd->sc_vxpool); 973 974 /* Detach the disk. */ 975 disk_detach(&vnd->sc_dkdev); 976 977 return 0; 978 } 979 980 /* ARGSUSED */ 981 static int 982 vndioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 983 { 984 bool force; 985 int unit = vndunit(dev); 986 struct vnd_softc *vnd; 987 struct vnd_ioctl *vio; 988 struct vattr vattr; 989 struct pathbuf *pb; 990 struct nameidata nd; 991 int error, part, pmask; 992 size_t geomsize; 993 int fflags; 994 #ifdef __HAVE_OLD_DISKLABEL 995 struct disklabel newlabel; 996 #endif 997 struct dkwedge_info *dkw; 998 struct dkwedge_list *dkwl; 999 1000 #ifdef DEBUG 1001 if (vnddebug & VDB_FOLLOW) 1002 printf("vndioctl(0x%"PRIx64", 0x%lx, %p, 0x%x, %p): unit %d\n", 1003 dev, cmd, data, flag, l->l_proc, unit); 1004 #endif 1005 vnd = device_lookup_private(&vnd_cd, unit); 1006 if (vnd == NULL && 1007 #ifdef COMPAT_30 1008 cmd != VNDIOCGET30 && 1009 #endif 1010 #ifdef COMPAT_50 1011 cmd != VNDIOCGET50 && 1012 #endif 1013 cmd != VNDIOCGET) 1014 return ENXIO; 1015 vio = (struct vnd_ioctl *)data; 1016 1017 /* Must be open for writes for these commands... */ 1018 switch (cmd) { 1019 case VNDIOCSET: 1020 case VNDIOCCLR: 1021 #ifdef COMPAT_50 1022 case VNDIOCSET50: 1023 case VNDIOCCLR50: 1024 #endif 1025 case DIOCSDINFO: 1026 case DIOCWDINFO: 1027 #ifdef __HAVE_OLD_DISKLABEL 1028 case ODIOCSDINFO: 1029 case ODIOCWDINFO: 1030 #endif 1031 case DIOCKLABEL: 1032 case DIOCWLABEL: 1033 if ((flag & FWRITE) == 0) 1034 return EBADF; 1035 } 1036 1037 /* Must be initialized for these... */ 1038 switch (cmd) { 1039 case VNDIOCCLR: 1040 #ifdef VNDIOCCLR50 1041 case VNDIOCCLR50: 1042 #endif 1043 case DIOCGDINFO: 1044 case DIOCSDINFO: 1045 case DIOCWDINFO: 1046 case DIOCGPART: 1047 case DIOCKLABEL: 1048 case DIOCWLABEL: 1049 case DIOCGDEFLABEL: 1050 case DIOCCACHESYNC: 1051 #ifdef __HAVE_OLD_DISKLABEL 1052 case ODIOCGDINFO: 1053 case ODIOCSDINFO: 1054 case ODIOCWDINFO: 1055 case ODIOCGDEFLABEL: 1056 #endif 1057 if ((vnd->sc_flags & VNF_INITED) == 0) 1058 return ENXIO; 1059 } 1060 1061 switch (cmd) { 1062 #ifdef VNDIOCSET50 1063 case VNDIOCSET50: 1064 #endif 1065 case VNDIOCSET: 1066 if (vnd->sc_flags & VNF_INITED) 1067 return EBUSY; 1068 1069 if ((error = vndlock(vnd)) != 0) 1070 return error; 1071 1072 fflags = FREAD; 1073 if ((vio->vnd_flags & VNDIOF_READONLY) == 0) 1074 fflags |= FWRITE; 1075 error = pathbuf_copyin(vio->vnd_file, &pb); 1076 if (error) { 1077 goto unlock_and_exit; 1078 } 1079 NDINIT(&nd, LOOKUP, FOLLOW, pb); 1080 if ((error = vn_open(&nd, fflags, 0)) != 0) { 1081 pathbuf_destroy(pb); 1082 goto unlock_and_exit; 1083 } 1084 KASSERT(l); 1085 error = VOP_GETATTR(nd.ni_vp, &vattr, l->l_cred); 1086 if (!error && nd.ni_vp->v_type != VREG) 1087 error = EOPNOTSUPP; 1088 if (!error && vattr.va_bytes < vattr.va_size) 1089 /* File is definitely sparse, use vn_rdwr() */ 1090 vnd->sc_flags |= VNF_USE_VN_RDWR; 1091 if (error) { 1092 VOP_UNLOCK(nd.ni_vp); 1093 goto close_and_exit; 1094 } 1095 1096 /* If using a compressed file, initialize its info */ 1097 /* (or abort with an error if kernel has no compression) */ 1098 if (vio->vnd_flags & VNF_COMP) { 1099 #ifdef VND_COMPRESSION 1100 struct vnd_comp_header *ch; 1101 int i; 1102 u_int32_t comp_size; 1103 u_int32_t comp_maxsize; 1104 1105 /* allocate space for compresed file header */ 1106 ch = malloc(sizeof(struct vnd_comp_header), 1107 M_TEMP, M_WAITOK); 1108 1109 /* read compressed file header */ 1110 error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)ch, 1111 sizeof(struct vnd_comp_header), 0, UIO_SYSSPACE, 1112 IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL); 1113 if (error) { 1114 free(ch, M_TEMP); 1115 VOP_UNLOCK(nd.ni_vp); 1116 goto close_and_exit; 1117 } 1118 1119 /* save some header info */ 1120 vnd->sc_comp_blksz = ntohl(ch->block_size); 1121 /* note last offset is the file byte size */ 1122 vnd->sc_comp_numoffs = ntohl(ch->num_blocks)+1; 1123 free(ch, M_TEMP); 1124 if (vnd->sc_comp_blksz == 0 || 1125 vnd->sc_comp_blksz % DEV_BSIZE !=0) { 1126 VOP_UNLOCK(nd.ni_vp); 1127 error = EINVAL; 1128 goto close_and_exit; 1129 } 1130 if (sizeof(struct vnd_comp_header) + 1131 sizeof(u_int64_t) * vnd->sc_comp_numoffs > 1132 vattr.va_size) { 1133 VOP_UNLOCK(nd.ni_vp); 1134 error = EINVAL; 1135 goto close_and_exit; 1136 } 1137 1138 /* set decompressed file size */ 1139 vattr.va_size = 1140 ((u_quad_t)vnd->sc_comp_numoffs - 1) * 1141 (u_quad_t)vnd->sc_comp_blksz; 1142 1143 /* allocate space for all the compressed offsets */ 1144 vnd->sc_comp_offsets = 1145 malloc(sizeof(u_int64_t) * vnd->sc_comp_numoffs, 1146 M_DEVBUF, M_WAITOK); 1147 1148 /* read in the offsets */ 1149 error = vn_rdwr(UIO_READ, nd.ni_vp, 1150 (void *)vnd->sc_comp_offsets, 1151 sizeof(u_int64_t) * vnd->sc_comp_numoffs, 1152 sizeof(struct vnd_comp_header), UIO_SYSSPACE, 1153 IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL); 1154 if (error) { 1155 VOP_UNLOCK(nd.ni_vp); 1156 goto close_and_exit; 1157 } 1158 /* 1159 * find largest block size (used for allocation limit). 1160 * Also convert offset to native byte order. 1161 */ 1162 comp_maxsize = 0; 1163 for (i = 0; i < vnd->sc_comp_numoffs - 1; i++) { 1164 vnd->sc_comp_offsets[i] = 1165 be64toh(vnd->sc_comp_offsets[i]); 1166 comp_size = be64toh(vnd->sc_comp_offsets[i + 1]) 1167 - vnd->sc_comp_offsets[i]; 1168 if (comp_size > comp_maxsize) 1169 comp_maxsize = comp_size; 1170 } 1171 vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1] = 1172 be64toh(vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1]); 1173 1174 /* create compressed data buffer */ 1175 vnd->sc_comp_buff = malloc(comp_maxsize, 1176 M_DEVBUF, M_WAITOK); 1177 1178 /* create decompressed buffer */ 1179 vnd->sc_comp_decombuf = malloc(vnd->sc_comp_blksz, 1180 M_DEVBUF, M_WAITOK); 1181 vnd->sc_comp_buffblk = -1; 1182 1183 /* Initialize decompress stream */ 1184 memset(&vnd->sc_comp_stream, 0, sizeof(z_stream)); 1185 vnd->sc_comp_stream.zalloc = vnd_alloc; 1186 vnd->sc_comp_stream.zfree = vnd_free; 1187 error = inflateInit2(&vnd->sc_comp_stream, MAX_WBITS); 1188 if (error) { 1189 if (vnd->sc_comp_stream.msg) 1190 printf("vnd%d: compressed file, %s\n", 1191 unit, vnd->sc_comp_stream.msg); 1192 VOP_UNLOCK(nd.ni_vp); 1193 error = EINVAL; 1194 goto close_and_exit; 1195 } 1196 1197 vnd->sc_flags |= VNF_COMP | VNF_READONLY; 1198 #else /* !VND_COMPRESSION */ 1199 VOP_UNLOCK(nd.ni_vp); 1200 error = EOPNOTSUPP; 1201 goto close_and_exit; 1202 #endif /* VND_COMPRESSION */ 1203 } 1204 1205 VOP_UNLOCK(nd.ni_vp); 1206 vnd->sc_vp = nd.ni_vp; 1207 vnd->sc_size = btodb(vattr.va_size); /* note truncation */ 1208 1209 /* 1210 * Use pseudo-geometry specified. If none was provided, 1211 * use "standard" Adaptec fictitious geometry. 1212 */ 1213 if (vio->vnd_flags & VNDIOF_HASGEOM) { 1214 1215 memcpy(&vnd->sc_geom, &vio->vnd_geom, 1216 sizeof(vio->vnd_geom)); 1217 1218 /* 1219 * Sanity-check the sector size. 1220 * XXX Don't allow secsize < DEV_BSIZE. Should 1221 * XXX we? 1222 */ 1223 if (vnd->sc_geom.vng_secsize < DEV_BSIZE || 1224 (vnd->sc_geom.vng_secsize % DEV_BSIZE) != 0 || 1225 vnd->sc_geom.vng_ncylinders == 0 || 1226 (vnd->sc_geom.vng_ntracks * 1227 vnd->sc_geom.vng_nsectors) == 0) { 1228 error = EINVAL; 1229 goto close_and_exit; 1230 } 1231 1232 /* 1233 * Compute the size (in DEV_BSIZE blocks) specified 1234 * by the geometry. 1235 */ 1236 geomsize = (vnd->sc_geom.vng_nsectors * 1237 vnd->sc_geom.vng_ntracks * 1238 vnd->sc_geom.vng_ncylinders) * 1239 (vnd->sc_geom.vng_secsize / DEV_BSIZE); 1240 1241 /* 1242 * Sanity-check the size against the specified 1243 * geometry. 1244 */ 1245 if (vnd->sc_size < geomsize) { 1246 error = EINVAL; 1247 goto close_and_exit; 1248 } 1249 } else if (vnd->sc_size >= (32 * 64)) { 1250 /* 1251 * Size must be at least 2048 DEV_BSIZE blocks 1252 * (1M) in order to use this geometry. 1253 */ 1254 vnd->sc_geom.vng_secsize = DEV_BSIZE; 1255 vnd->sc_geom.vng_nsectors = 32; 1256 vnd->sc_geom.vng_ntracks = 64; 1257 vnd->sc_geom.vng_ncylinders = vnd->sc_size / (64 * 32); 1258 } else { 1259 vnd->sc_geom.vng_secsize = DEV_BSIZE; 1260 vnd->sc_geom.vng_nsectors = 1; 1261 vnd->sc_geom.vng_ntracks = 1; 1262 vnd->sc_geom.vng_ncylinders = vnd->sc_size; 1263 } 1264 1265 vnd_set_properties(vnd); 1266 1267 if (vio->vnd_flags & VNDIOF_READONLY) { 1268 vnd->sc_flags |= VNF_READONLY; 1269 } 1270 1271 if ((error = vndsetcred(vnd, l->l_cred)) != 0) 1272 goto close_and_exit; 1273 1274 vndthrottle(vnd, vnd->sc_vp); 1275 vio->vnd_osize = dbtob(vnd->sc_size); 1276 #ifdef VNDIOCSET50 1277 if (cmd != VNDIOCSET50) 1278 #endif 1279 vio->vnd_size = dbtob(vnd->sc_size); 1280 vnd->sc_flags |= VNF_INITED; 1281 1282 /* create the kernel thread, wait for it to be up */ 1283 error = kthread_create(PRI_NONE, 0, NULL, vndthread, vnd, 1284 &vnd->sc_kthread, "%s", device_xname(vnd->sc_dev)); 1285 if (error) 1286 goto close_and_exit; 1287 while ((vnd->sc_flags & VNF_KTHREAD) == 0) { 1288 tsleep(&vnd->sc_kthread, PRIBIO, "vndthr", 0); 1289 } 1290 #ifdef DEBUG 1291 if (vnddebug & VDB_INIT) 1292 printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n", 1293 vnd->sc_vp, (unsigned long) vnd->sc_size, 1294 vnd->sc_geom.vng_secsize, 1295 vnd->sc_geom.vng_nsectors, 1296 vnd->sc_geom.vng_ntracks, 1297 vnd->sc_geom.vng_ncylinders); 1298 #endif 1299 1300 /* Attach the disk. */ 1301 disk_attach(&vnd->sc_dkdev); 1302 disk_blocksize(&vnd->sc_dkdev, vnd->sc_geom.vng_secsize); 1303 1304 /* Initialize the xfer and buffer pools. */ 1305 pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0, 1306 0, 0, "vndxpl", NULL, IPL_BIO); 1307 1308 /* Try and read the disklabel. */ 1309 vndgetdisklabel(dev, vnd); 1310 1311 vndunlock(vnd); 1312 1313 pathbuf_destroy(pb); 1314 break; 1315 1316 close_and_exit: 1317 (void) vn_close(nd.ni_vp, fflags, l->l_cred); 1318 pathbuf_destroy(pb); 1319 unlock_and_exit: 1320 #ifdef VND_COMPRESSION 1321 /* free any allocated memory (for compressed file) */ 1322 if (vnd->sc_comp_offsets) { 1323 free(vnd->sc_comp_offsets, M_DEVBUF); 1324 vnd->sc_comp_offsets = NULL; 1325 } 1326 if (vnd->sc_comp_buff) { 1327 free(vnd->sc_comp_buff, M_DEVBUF); 1328 vnd->sc_comp_buff = NULL; 1329 } 1330 if (vnd->sc_comp_decombuf) { 1331 free(vnd->sc_comp_decombuf, M_DEVBUF); 1332 vnd->sc_comp_decombuf = NULL; 1333 } 1334 #endif /* VND_COMPRESSION */ 1335 vndunlock(vnd); 1336 return error; 1337 1338 #ifdef VNDIOCCLR50 1339 case VNDIOCCLR50: 1340 #endif 1341 case VNDIOCCLR: 1342 part = DISKPART(dev); 1343 pmask = (1 << part); 1344 force = (vio->vnd_flags & VNDIOF_FORCE) != 0; 1345 1346 if ((error = vnddoclear(vnd, pmask, minor(dev), force)) != 0) 1347 return error; 1348 1349 break; 1350 1351 #ifdef COMPAT_30 1352 case VNDIOCGET30: { 1353 struct vnd_user30 *vnu; 1354 struct vattr va; 1355 vnu = (struct vnd_user30 *)data; 1356 KASSERT(l); 1357 switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) { 1358 case 0: 1359 vnu->vnu_dev = va.va_fsid; 1360 vnu->vnu_ino = va.va_fileid; 1361 break; 1362 case -1: 1363 /* unused is not an error */ 1364 vnu->vnu_dev = 0; 1365 vnu->vnu_ino = 0; 1366 break; 1367 default: 1368 return error; 1369 } 1370 break; 1371 } 1372 #endif 1373 1374 #ifdef COMPAT_50 1375 case VNDIOCGET50: { 1376 struct vnd_user50 *vnu; 1377 struct vattr va; 1378 vnu = (struct vnd_user50 *)data; 1379 KASSERT(l); 1380 switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) { 1381 case 0: 1382 vnu->vnu_dev = va.va_fsid; 1383 vnu->vnu_ino = va.va_fileid; 1384 break; 1385 case -1: 1386 /* unused is not an error */ 1387 vnu->vnu_dev = 0; 1388 vnu->vnu_ino = 0; 1389 break; 1390 default: 1391 return error; 1392 } 1393 break; 1394 } 1395 #endif 1396 1397 case VNDIOCGET: { 1398 struct vnd_user *vnu; 1399 struct vattr va; 1400 vnu = (struct vnd_user *)data; 1401 KASSERT(l); 1402 switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) { 1403 case 0: 1404 vnu->vnu_dev = va.va_fsid; 1405 vnu->vnu_ino = va.va_fileid; 1406 break; 1407 case -1: 1408 /* unused is not an error */ 1409 vnu->vnu_dev = 0; 1410 vnu->vnu_ino = 0; 1411 break; 1412 default: 1413 return error; 1414 } 1415 break; 1416 } 1417 1418 case DIOCGDINFO: 1419 *(struct disklabel *)data = *(vnd->sc_dkdev.dk_label); 1420 break; 1421 1422 #ifdef __HAVE_OLD_DISKLABEL 1423 case ODIOCGDINFO: 1424 newlabel = *(vnd->sc_dkdev.dk_label); 1425 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1426 return ENOTTY; 1427 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1428 break; 1429 #endif 1430 1431 case DIOCGPART: 1432 ((struct partinfo *)data)->disklab = vnd->sc_dkdev.dk_label; 1433 ((struct partinfo *)data)->part = 1434 &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(dev)]; 1435 break; 1436 1437 case DIOCWDINFO: 1438 case DIOCSDINFO: 1439 #ifdef __HAVE_OLD_DISKLABEL 1440 case ODIOCWDINFO: 1441 case ODIOCSDINFO: 1442 #endif 1443 { 1444 struct disklabel *lp; 1445 1446 if ((error = vndlock(vnd)) != 0) 1447 return error; 1448 1449 vnd->sc_flags |= VNF_LABELLING; 1450 1451 #ifdef __HAVE_OLD_DISKLABEL 1452 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 1453 memset(&newlabel, 0, sizeof newlabel); 1454 memcpy(&newlabel, data, sizeof (struct olddisklabel)); 1455 lp = &newlabel; 1456 } else 1457 #endif 1458 lp = (struct disklabel *)data; 1459 1460 error = setdisklabel(vnd->sc_dkdev.dk_label, 1461 lp, 0, vnd->sc_dkdev.dk_cpulabel); 1462 if (error == 0) { 1463 if (cmd == DIOCWDINFO 1464 #ifdef __HAVE_OLD_DISKLABEL 1465 || cmd == ODIOCWDINFO 1466 #endif 1467 ) 1468 error = writedisklabel(VNDLABELDEV(dev), 1469 vndstrategy, vnd->sc_dkdev.dk_label, 1470 vnd->sc_dkdev.dk_cpulabel); 1471 } 1472 1473 vnd->sc_flags &= ~VNF_LABELLING; 1474 1475 vndunlock(vnd); 1476 1477 if (error) 1478 return error; 1479 break; 1480 } 1481 1482 case DIOCKLABEL: 1483 if (*(int *)data != 0) 1484 vnd->sc_flags |= VNF_KLABEL; 1485 else 1486 vnd->sc_flags &= ~VNF_KLABEL; 1487 break; 1488 1489 case DIOCWLABEL: 1490 if (*(int *)data != 0) 1491 vnd->sc_flags |= VNF_WLABEL; 1492 else 1493 vnd->sc_flags &= ~VNF_WLABEL; 1494 break; 1495 1496 case DIOCGDEFLABEL: 1497 vndgetdefaultlabel(vnd, (struct disklabel *)data); 1498 break; 1499 1500 #ifdef __HAVE_OLD_DISKLABEL 1501 case ODIOCGDEFLABEL: 1502 vndgetdefaultlabel(vnd, &newlabel); 1503 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1504 return ENOTTY; 1505 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1506 break; 1507 #endif 1508 1509 case DIOCCACHESYNC: 1510 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1511 error = VOP_FSYNC(vnd->sc_vp, vnd->sc_cred, 1512 FSYNC_WAIT | FSYNC_DATAONLY | FSYNC_CACHE, 0, 0); 1513 VOP_UNLOCK(vnd->sc_vp); 1514 return error; 1515 1516 case DIOCAWEDGE: 1517 dkw = (void *) data; 1518 1519 if ((flag & FWRITE) == 0) 1520 return EBADF; 1521 1522 /* If the ioctl happens here, the parent is us. */ 1523 strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev), 1524 sizeof(dkw->dkw_parent)); 1525 return dkwedge_add(dkw); 1526 1527 case DIOCDWEDGE: 1528 dkw = (void *) data; 1529 1530 if ((flag & FWRITE) == 0) 1531 return EBADF; 1532 1533 /* If the ioctl happens here, the parent is us. */ 1534 strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev), 1535 sizeof(dkw->dkw_parent)); 1536 return dkwedge_del(dkw); 1537 1538 case DIOCLWEDGES: 1539 dkwl = (void *) data; 1540 1541 return dkwedge_list(&vnd->sc_dkdev, dkwl, l); 1542 1543 default: 1544 return ENOTTY; 1545 } 1546 1547 return 0; 1548 } 1549 1550 /* 1551 * Duplicate the current processes' credentials. Since we are called only 1552 * as the result of a SET ioctl and only root can do that, any future access 1553 * to this "disk" is essentially as root. Note that credentials may change 1554 * if some other uid can write directly to the mapped file (NFS). 1555 */ 1556 static int 1557 vndsetcred(struct vnd_softc *vnd, kauth_cred_t cred) 1558 { 1559 struct uio auio; 1560 struct iovec aiov; 1561 char *tmpbuf; 1562 int error; 1563 1564 vnd->sc_cred = kauth_cred_dup(cred); 1565 tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK); 1566 1567 /* XXX: Horrible kludge to establish credentials for NFS */ 1568 aiov.iov_base = tmpbuf; 1569 aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size)); 1570 auio.uio_iov = &aiov; 1571 auio.uio_iovcnt = 1; 1572 auio.uio_offset = 0; 1573 auio.uio_rw = UIO_READ; 1574 auio.uio_resid = aiov.iov_len; 1575 UIO_SETUP_SYSSPACE(&auio); 1576 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1577 error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred); 1578 if (error == 0) { 1579 /* 1580 * Because vnd does all IO directly through the vnode 1581 * we need to flush (at least) the buffer from the above 1582 * VOP_READ from the buffer cache to prevent cache 1583 * incoherencies. Also, be careful to write dirty 1584 * buffers back to stable storage. 1585 */ 1586 error = vinvalbuf(vnd->sc_vp, V_SAVE, vnd->sc_cred, 1587 curlwp, 0, 0); 1588 } 1589 VOP_UNLOCK(vnd->sc_vp); 1590 1591 free(tmpbuf, M_TEMP); 1592 return error; 1593 } 1594 1595 /* 1596 * Set maxactive based on FS type 1597 */ 1598 static void 1599 vndthrottle(struct vnd_softc *vnd, struct vnode *vp) 1600 { 1601 1602 if (vp->v_tag == VT_NFS) 1603 vnd->sc_maxactive = 2; 1604 else 1605 vnd->sc_maxactive = 8; 1606 1607 if (vnd->sc_maxactive < 1) 1608 vnd->sc_maxactive = 1; 1609 } 1610 1611 #if 0 1612 static void 1613 vndshutdown(void) 1614 { 1615 struct vnd_softc *vnd; 1616 1617 for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++) 1618 if (vnd->sc_flags & VNF_INITED) 1619 vndclear(vnd); 1620 } 1621 #endif 1622 1623 static void 1624 vndclear(struct vnd_softc *vnd, int myminor) 1625 { 1626 struct vnode *vp = vnd->sc_vp; 1627 int fflags = FREAD; 1628 int bmaj, cmaj, i, mn; 1629 int s; 1630 1631 #ifdef DEBUG 1632 if (vnddebug & VDB_FOLLOW) 1633 printf("vndclear(%p): vp %p\n", vnd, vp); 1634 #endif 1635 /* locate the major number */ 1636 bmaj = bdevsw_lookup_major(&vnd_bdevsw); 1637 cmaj = cdevsw_lookup_major(&vnd_cdevsw); 1638 1639 /* Nuke the vnodes for any open instances */ 1640 for (i = 0; i < MAXPARTITIONS; i++) { 1641 mn = DISKMINOR(device_unit(vnd->sc_dev), i); 1642 vdevgone(bmaj, mn, mn, VBLK); 1643 if (mn != myminor) /* XXX avoid to kill own vnode */ 1644 vdevgone(cmaj, mn, mn, VCHR); 1645 } 1646 1647 if ((vnd->sc_flags & VNF_READONLY) == 0) 1648 fflags |= FWRITE; 1649 1650 s = splbio(); 1651 bufq_drain(vnd->sc_tab); 1652 splx(s); 1653 1654 vnd->sc_flags |= VNF_VUNCONF; 1655 wakeup(&vnd->sc_tab); 1656 while (vnd->sc_flags & VNF_KTHREAD) 1657 tsleep(&vnd->sc_kthread, PRIBIO, "vnthr", 0); 1658 1659 #ifdef VND_COMPRESSION 1660 /* free the compressed file buffers */ 1661 if (vnd->sc_flags & VNF_COMP) { 1662 if (vnd->sc_comp_offsets) { 1663 free(vnd->sc_comp_offsets, M_DEVBUF); 1664 vnd->sc_comp_offsets = NULL; 1665 } 1666 if (vnd->sc_comp_buff) { 1667 free(vnd->sc_comp_buff, M_DEVBUF); 1668 vnd->sc_comp_buff = NULL; 1669 } 1670 if (vnd->sc_comp_decombuf) { 1671 free(vnd->sc_comp_decombuf, M_DEVBUF); 1672 vnd->sc_comp_decombuf = NULL; 1673 } 1674 } 1675 #endif /* VND_COMPRESSION */ 1676 vnd->sc_flags &= 1677 ~(VNF_INITED | VNF_READONLY | VNF_VLABEL 1678 | VNF_VUNCONF | VNF_COMP | VNF_CLEARING); 1679 if (vp == NULL) 1680 panic("vndclear: null vp"); 1681 (void) vn_close(vp, fflags, vnd->sc_cred); 1682 kauth_cred_free(vnd->sc_cred); 1683 vnd->sc_vp = NULL; 1684 vnd->sc_cred = NULL; 1685 vnd->sc_size = 0; 1686 } 1687 1688 static int 1689 vndsize(dev_t dev) 1690 { 1691 struct vnd_softc *sc; 1692 struct disklabel *lp; 1693 int part, unit, omask; 1694 int size; 1695 1696 unit = vndunit(dev); 1697 sc = device_lookup_private(&vnd_cd, unit); 1698 if (sc == NULL) 1699 return -1; 1700 1701 if ((sc->sc_flags & VNF_INITED) == 0) 1702 return -1; 1703 1704 part = DISKPART(dev); 1705 omask = sc->sc_dkdev.dk_openmask & (1 << part); 1706 lp = sc->sc_dkdev.dk_label; 1707 1708 if (omask == 0 && vndopen(dev, 0, S_IFBLK, curlwp)) /* XXX */ 1709 return -1; 1710 1711 if (lp->d_partitions[part].p_fstype != FS_SWAP) 1712 size = -1; 1713 else 1714 size = lp->d_partitions[part].p_size * 1715 (lp->d_secsize / DEV_BSIZE); 1716 1717 if (omask == 0 && vndclose(dev, 0, S_IFBLK, curlwp)) /* XXX */ 1718 return -1; 1719 1720 return size; 1721 } 1722 1723 static int 1724 vnddump(dev_t dev, daddr_t blkno, void *va, 1725 size_t size) 1726 { 1727 1728 /* Not implemented. */ 1729 return ENXIO; 1730 } 1731 1732 static void 1733 vndgetdefaultlabel(struct vnd_softc *sc, struct disklabel *lp) 1734 { 1735 struct vndgeom *vng = &sc->sc_geom; 1736 struct partition *pp; 1737 1738 memset(lp, 0, sizeof(*lp)); 1739 1740 lp->d_secperunit = sc->sc_size / (vng->vng_secsize / DEV_BSIZE); 1741 lp->d_secsize = vng->vng_secsize; 1742 lp->d_nsectors = vng->vng_nsectors; 1743 lp->d_ntracks = vng->vng_ntracks; 1744 lp->d_ncylinders = vng->vng_ncylinders; 1745 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1746 1747 strncpy(lp->d_typename, "vnd", sizeof(lp->d_typename)); 1748 lp->d_type = DTYPE_VND; 1749 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1750 lp->d_rpm = 3600; 1751 lp->d_interleave = 1; 1752 lp->d_flags = 0; 1753 1754 pp = &lp->d_partitions[RAW_PART]; 1755 pp->p_offset = 0; 1756 pp->p_size = lp->d_secperunit; 1757 pp->p_fstype = FS_UNUSED; 1758 lp->d_npartitions = RAW_PART + 1; 1759 1760 lp->d_magic = DISKMAGIC; 1761 lp->d_magic2 = DISKMAGIC; 1762 lp->d_checksum = dkcksum(lp); 1763 } 1764 1765 /* 1766 * Read the disklabel from a vnd. If one is not present, create a fake one. 1767 */ 1768 static void 1769 vndgetdisklabel(dev_t dev, struct vnd_softc *sc) 1770 { 1771 const char *errstring; 1772 struct disklabel *lp = sc->sc_dkdev.dk_label; 1773 struct cpu_disklabel *clp = sc->sc_dkdev.dk_cpulabel; 1774 int i; 1775 1776 memset(clp, 0, sizeof(*clp)); 1777 1778 vndgetdefaultlabel(sc, lp); 1779 1780 /* 1781 * Call the generic disklabel extraction routine. 1782 */ 1783 errstring = readdisklabel(VNDLABELDEV(dev), vndstrategy, lp, clp); 1784 if (errstring) { 1785 /* 1786 * Lack of disklabel is common, but we print the warning 1787 * anyway, since it might contain other useful information. 1788 */ 1789 aprint_normal_dev(sc->sc_dev, "%s\n", errstring); 1790 1791 /* 1792 * For historical reasons, if there's no disklabel 1793 * present, all partitions must be FS_BSDFFS and 1794 * occupy the entire disk. 1795 */ 1796 for (i = 0; i < MAXPARTITIONS; i++) { 1797 /* 1798 * Don't wipe out port specific hack (such as 1799 * dos partition hack of i386 port). 1800 */ 1801 if (lp->d_partitions[i].p_size != 0) 1802 continue; 1803 1804 lp->d_partitions[i].p_size = lp->d_secperunit; 1805 lp->d_partitions[i].p_offset = 0; 1806 lp->d_partitions[i].p_fstype = FS_BSDFFS; 1807 } 1808 1809 strncpy(lp->d_packname, "default label", 1810 sizeof(lp->d_packname)); 1811 1812 lp->d_npartitions = MAXPARTITIONS; 1813 lp->d_checksum = dkcksum(lp); 1814 } 1815 1816 /* In-core label now valid. */ 1817 sc->sc_flags |= VNF_VLABEL; 1818 } 1819 1820 /* 1821 * Wait interruptibly for an exclusive lock. 1822 * 1823 * XXX 1824 * Several drivers do this; it should be abstracted and made MP-safe. 1825 */ 1826 static int 1827 vndlock(struct vnd_softc *sc) 1828 { 1829 int error; 1830 1831 while ((sc->sc_flags & VNF_LOCKED) != 0) { 1832 sc->sc_flags |= VNF_WANTED; 1833 if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0) 1834 return error; 1835 } 1836 sc->sc_flags |= VNF_LOCKED; 1837 return 0; 1838 } 1839 1840 /* 1841 * Unlock and wake up any waiters. 1842 */ 1843 static void 1844 vndunlock(struct vnd_softc *sc) 1845 { 1846 1847 sc->sc_flags &= ~VNF_LOCKED; 1848 if ((sc->sc_flags & VNF_WANTED) != 0) { 1849 sc->sc_flags &= ~VNF_WANTED; 1850 wakeup(sc); 1851 } 1852 } 1853 1854 #ifdef VND_COMPRESSION 1855 /* compressed file read */ 1856 static void 1857 compstrategy(struct buf *bp, off_t bn) 1858 { 1859 int error; 1860 int unit = vndunit(bp->b_dev); 1861 struct vnd_softc *vnd = 1862 device_lookup_private(&vnd_cd, unit); 1863 u_int32_t comp_block; 1864 struct uio auio; 1865 char *addr; 1866 int s; 1867 1868 /* set up constants for data move */ 1869 auio.uio_rw = UIO_READ; 1870 UIO_SETUP_SYSSPACE(&auio); 1871 1872 /* read, and transfer the data */ 1873 addr = bp->b_data; 1874 bp->b_resid = bp->b_bcount; 1875 s = splbio(); 1876 while (bp->b_resid > 0) { 1877 unsigned length; 1878 size_t length_in_buffer; 1879 u_int32_t offset_in_buffer; 1880 struct iovec aiov; 1881 1882 /* calculate the compressed block number */ 1883 comp_block = bn / (off_t)vnd->sc_comp_blksz; 1884 1885 /* check for good block number */ 1886 if (comp_block >= vnd->sc_comp_numoffs) { 1887 bp->b_error = EINVAL; 1888 splx(s); 1889 return; 1890 } 1891 1892 /* read in the compressed block, if not in buffer */ 1893 if (comp_block != vnd->sc_comp_buffblk) { 1894 length = vnd->sc_comp_offsets[comp_block + 1] - 1895 vnd->sc_comp_offsets[comp_block]; 1896 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1897 error = vn_rdwr(UIO_READ, vnd->sc_vp, vnd->sc_comp_buff, 1898 length, vnd->sc_comp_offsets[comp_block], 1899 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, vnd->sc_cred, 1900 NULL, NULL); 1901 if (error) { 1902 bp->b_error = error; 1903 VOP_UNLOCK(vnd->sc_vp); 1904 splx(s); 1905 return; 1906 } 1907 /* uncompress the buffer */ 1908 vnd->sc_comp_stream.next_in = vnd->sc_comp_buff; 1909 vnd->sc_comp_stream.avail_in = length; 1910 vnd->sc_comp_stream.next_out = vnd->sc_comp_decombuf; 1911 vnd->sc_comp_stream.avail_out = vnd->sc_comp_blksz; 1912 inflateReset(&vnd->sc_comp_stream); 1913 error = inflate(&vnd->sc_comp_stream, Z_FINISH); 1914 if (error != Z_STREAM_END) { 1915 if (vnd->sc_comp_stream.msg) 1916 aprint_normal_dev(vnd->sc_dev, 1917 "compressed file, %s\n", 1918 vnd->sc_comp_stream.msg); 1919 bp->b_error = EBADMSG; 1920 VOP_UNLOCK(vnd->sc_vp); 1921 splx(s); 1922 return; 1923 } 1924 vnd->sc_comp_buffblk = comp_block; 1925 VOP_UNLOCK(vnd->sc_vp); 1926 } 1927 1928 /* transfer the usable uncompressed data */ 1929 offset_in_buffer = bn % (off_t)vnd->sc_comp_blksz; 1930 length_in_buffer = vnd->sc_comp_blksz - offset_in_buffer; 1931 if (length_in_buffer > bp->b_resid) 1932 length_in_buffer = bp->b_resid; 1933 auio.uio_iov = &aiov; 1934 auio.uio_iovcnt = 1; 1935 aiov.iov_base = addr; 1936 aiov.iov_len = length_in_buffer; 1937 auio.uio_resid = aiov.iov_len; 1938 auio.uio_offset = 0; 1939 error = uiomove(vnd->sc_comp_decombuf + offset_in_buffer, 1940 length_in_buffer, &auio); 1941 if (error) { 1942 bp->b_error = error; 1943 splx(s); 1944 return; 1945 } 1946 1947 bn += length_in_buffer; 1948 addr += length_in_buffer; 1949 bp->b_resid -= length_in_buffer; 1950 } 1951 splx(s); 1952 } 1953 1954 /* compression memory allocation routines */ 1955 static void * 1956 vnd_alloc(void *aux, u_int items, u_int siz) 1957 { 1958 return malloc(items * siz, M_TEMP, M_NOWAIT); 1959 } 1960 1961 static void 1962 vnd_free(void *aux, void *ptr) 1963 { 1964 free(ptr, M_TEMP); 1965 } 1966 #endif /* VND_COMPRESSION */ 1967 1968 static void 1969 vnd_set_properties(struct vnd_softc *vnd) 1970 { 1971 prop_dictionary_t disk_info, odisk_info, geom; 1972 1973 disk_info = prop_dictionary_create(); 1974 1975 geom = prop_dictionary_create(); 1976 1977 prop_dictionary_set_uint64(geom, "sectors-per-unit", 1978 vnd->sc_geom.vng_nsectors * vnd->sc_geom.vng_ntracks * 1979 vnd->sc_geom.vng_ncylinders); 1980 1981 prop_dictionary_set_uint32(geom, "sector-size", 1982 vnd->sc_geom.vng_secsize); 1983 1984 prop_dictionary_set_uint16(geom, "sectors-per-track", 1985 vnd->sc_geom.vng_nsectors); 1986 1987 prop_dictionary_set_uint16(geom, "tracks-per-cylinder", 1988 vnd->sc_geom.vng_ntracks); 1989 1990 prop_dictionary_set_uint64(geom, "cylinders-per-unit", 1991 vnd->sc_geom.vng_ncylinders); 1992 1993 prop_dictionary_set(disk_info, "geometry", geom); 1994 prop_object_release(geom); 1995 1996 prop_dictionary_set(device_properties(vnd->sc_dev), 1997 "disk-info", disk_info); 1998 1999 /* 2000 * Don't release disk_info here; we keep a reference to it. 2001 * disk_detach() will release it when we go away. 2002 */ 2003 2004 odisk_info = vnd->sc_dkdev.dk_info; 2005 vnd->sc_dkdev.dk_info = disk_info; 2006 if (odisk_info) 2007 prop_object_release(odisk_info); 2008 } 2009 2010 #ifdef _MODULE 2011 2012 #include <sys/module.h> 2013 2014 MODULE(MODULE_CLASS_DRIVER, vnd, NULL); 2015 CFDRIVER_DECL(vnd, DV_DISK, NULL); 2016 2017 static int 2018 vnd_modcmd(modcmd_t cmd, void *arg) 2019 { 2020 int bmajor = -1, cmajor = -1, error = 0; 2021 2022 switch (cmd) { 2023 case MODULE_CMD_INIT: 2024 error = config_cfdriver_attach(&vnd_cd); 2025 if (error) 2026 break; 2027 2028 error = config_cfattach_attach(vnd_cd.cd_name, &vnd_ca); 2029 if (error) { 2030 config_cfdriver_detach(&vnd_cd); 2031 aprint_error("%s: unable to register cfattach\n", 2032 vnd_cd.cd_name); 2033 break; 2034 } 2035 2036 error = devsw_attach("vnd", &vnd_bdevsw, &bmajor, 2037 &vnd_cdevsw, &cmajor); 2038 if (error) { 2039 config_cfattach_detach(vnd_cd.cd_name, &vnd_ca); 2040 config_cfdriver_detach(&vnd_cd); 2041 break; 2042 } 2043 2044 break; 2045 2046 case MODULE_CMD_FINI: 2047 error = config_cfattach_detach(vnd_cd.cd_name, &vnd_ca); 2048 if (error) 2049 break; 2050 config_cfdriver_detach(&vnd_cd); 2051 devsw_detach(&vnd_bdevsw, &vnd_cdevsw); 2052 break; 2053 2054 case MODULE_CMD_STAT: 2055 return ENOTTY; 2056 2057 default: 2058 return ENOTTY; 2059 } 2060 2061 return error; 2062 } 2063 2064 #endif 2065