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