vnd.c revision 1.216
1/* $NetBSD: vnd.c,v 1.216 2011/05/23 21:30:56 joerg 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.216 2011/05/23 21:30:56 joerg 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 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 = 0x00; 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/* called by main() at boot time */ 160void vndattach(int); 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_properties(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 vndopen, vndclose, vndstrategy, vndioctl, vnddump, vndsize, D_DISK 201}; 202 203const struct cdevsw vnd_cdevsw = { 204 vndopen, vndclose, vndread, vndwrite, vndioctl, 205 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 206}; 207 208static int vnd_match(device_t, cfdata_t, void *); 209static void vnd_attach(device_t, device_t, void *); 210static int vnd_detach(device_t, int); 211 212CFATTACH_DECL3_NEW(vnd, sizeof(struct vnd_softc), 213 vnd_match, vnd_attach, vnd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); 214extern struct cfdriver vnd_cd; 215 216static struct vnd_softc *vnd_spawn(int); 217int vnd_destroy(device_t); 218 219static struct dkdriver vnddkdriver = { vndstrategy, minphys }; 220 221void 222vndattach(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 232static int 233vnd_match(device_t self, cfdata_t cfdata, void *aux) 234{ 235 236 return 1; 237} 238 239static void 240vnd_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 254static int 255vnd_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 273static struct vnd_softc * 274vnd_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 287int 288vnd_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 301static int 302vndopen(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 371static int 372vndclose(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 */ 420static void 421vndstrategy(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 504done: 505 bp->b_resid = bp->b_bcount; 506 biodone(bp); 507 splx(s); 508} 509 510static bool 511vnode_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 523static bool 524vnode_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 548static void 549vndthread(void *arg) 550{ 551 struct vnd_softc *vnd = arg; 552 bool usestrategy; 553 int s; 554 555 /* Determine whether we can *use* VOP_BMAP and VOP_STRATEGY to 556 * directly access the backing vnode. If we can, use these two 557 * operations to avoid messing with the local buffer cache. 558 * Otherwise fall back to regular VOP_READ/VOP_WRITE operations 559 * which are guaranteed to work with any file system. */ 560 usestrategy = vnode_has_strategy(vnd); 561 562#ifdef DEBUG 563 if (vnddebug & VDB_INIT) 564 printf("vndthread: vp %p, %s\n", vnd->sc_vp, 565 usestrategy ? 566 "using bmap/strategy operations" : 567 "using read/write operations"); 568#endif 569 570 s = splbio(); 571 vnd->sc_flags |= VNF_KTHREAD; 572 wakeup(&vnd->sc_kthread); 573 574 /* 575 * Dequeue requests and serve them depending on the available 576 * vnode operations. 577 */ 578 while ((vnd->sc_flags & VNF_VUNCONF) == 0) { 579 struct vndxfer *vnx; 580 int flags; 581 struct buf *obp; 582 struct buf *bp; 583 584 obp = bufq_get(vnd->sc_tab); 585 if (obp == NULL) { 586 tsleep(&vnd->sc_tab, PRIBIO, "vndbp", 0); 587 continue; 588 }; 589 splx(s); 590 flags = obp->b_flags; 591#ifdef DEBUG 592 if (vnddebug & VDB_FOLLOW) 593 printf("vndthread(%p)\n", obp); 594#endif 595 596 if (vnd->sc_vp->v_mount == NULL) { 597 obp->b_error = ENXIO; 598 goto done; 599 } 600#ifdef VND_COMPRESSION 601 /* handle a compressed read */ 602 if ((flags & B_READ) != 0 && (vnd->sc_flags & VNF_COMP)) { 603 off_t bn; 604 605 /* Convert to a byte offset within the file. */ 606 bn = obp->b_rawblkno * 607 vnd->sc_dkdev.dk_label->d_secsize; 608 609 compstrategy(obp, bn); 610 goto done; 611 } 612#endif /* VND_COMPRESSION */ 613 614 /* 615 * Allocate a header for this transfer and link it to the 616 * buffer 617 */ 618 s = splbio(); 619 vnx = VND_GETXFER(vnd); 620 splx(s); 621 vnx->vx_vnd = vnd; 622 623 s = splbio(); 624 while (vnd->sc_active >= vnd->sc_maxactive) { 625 tsleep(&vnd->sc_tab, PRIBIO, "vndac", 0); 626 } 627 vnd->sc_active++; 628 splx(s); 629 630 /* Instrumentation. */ 631 disk_busy(&vnd->sc_dkdev); 632 633 bp = &vnx->vx_buf; 634 buf_init(bp); 635 bp->b_flags = (obp->b_flags & B_READ); 636 bp->b_oflags = obp->b_oflags; 637 bp->b_cflags = obp->b_cflags; 638 bp->b_iodone = vndiodone; 639 bp->b_private = obp; 640 bp->b_vp = vnd->sc_vp; 641 bp->b_objlock = &bp->b_vp->v_interlock; 642 bp->b_data = obp->b_data; 643 bp->b_bcount = obp->b_bcount; 644 BIO_COPYPRIO(bp, obp); 645 646 /* Handle the request using the appropriate operations. */ 647 if (usestrategy) 648 handle_with_strategy(vnd, obp, bp); 649 else 650 handle_with_rdwr(vnd, obp, bp); 651 652 s = splbio(); 653 continue; 654 655done: 656 biodone(obp); 657 s = splbio(); 658 } 659 660 vnd->sc_flags &= (~VNF_KTHREAD | VNF_VUNCONF); 661 wakeup(&vnd->sc_kthread); 662 splx(s); 663 kthread_exit(0); 664} 665 666/* 667 * Checks if the given vnode supports the requested operation. 668 * The operation is specified the offset returned by VOFFSET. 669 * 670 * XXX The test below used to determine this is quite fragile 671 * because it relies on the file system to use genfs to specify 672 * unimplemented operations. There might be another way to do 673 * it more cleanly. 674 */ 675static bool 676vnode_has_op(const struct vnode *vp, int opoffset) 677{ 678 int (*defaultp)(void *); 679 int (*opp)(void *); 680 681 defaultp = vp->v_op[VOFFSET(vop_default)]; 682 opp = vp->v_op[opoffset]; 683 684 return opp != defaultp && opp != genfs_eopnotsupp && 685 opp != genfs_badop && opp != genfs_nullop; 686} 687 688/* 689 * Handes the read/write request given in 'bp' using the vnode's VOP_READ 690 * and VOP_WRITE operations. 691 * 692 * 'obp' is a pointer to the original request fed to the vnd device. 693 */ 694static void 695handle_with_rdwr(struct vnd_softc *vnd, const struct buf *obp, struct buf *bp) 696{ 697 bool doread; 698 off_t offset; 699 size_t resid; 700 struct vnode *vp; 701 702 doread = bp->b_flags & B_READ; 703 offset = obp->b_rawblkno * vnd->sc_dkdev.dk_label->d_secsize; 704 vp = vnd->sc_vp; 705 706#if defined(DEBUG) 707 if (vnddebug & VDB_IO) 708 printf("vnd (rdwr): vp %p, %s, rawblkno 0x%" PRIx64 709 ", secsize %d, offset %" PRIu64 710 ", bcount %d\n", 711 vp, doread ? "read" : "write", obp->b_rawblkno, 712 vnd->sc_dkdev.dk_label->d_secsize, offset, 713 bp->b_bcount); 714#endif 715 716 /* Issue the read or write operation. */ 717 bp->b_error = 718 vn_rdwr(doread ? UIO_READ : UIO_WRITE, 719 vp, bp->b_data, bp->b_bcount, offset, 720 UIO_SYSSPACE, 0, vnd->sc_cred, &resid, NULL); 721 bp->b_resid = resid; 722 723 /* We need to increase the number of outputs on the vnode if 724 * there was any write to it. */ 725 if (!doread) { 726 mutex_enter(&vp->v_interlock); 727 vp->v_numoutput++; 728 mutex_exit(&vp->v_interlock); 729 } 730 731 biodone(bp); 732} 733 734/* 735 * Handes the read/write request given in 'bp' using the vnode's VOP_BMAP 736 * and VOP_STRATEGY operations. 737 * 738 * 'obp' is a pointer to the original request fed to the vnd device. 739 */ 740static void 741handle_with_strategy(struct vnd_softc *vnd, const struct buf *obp, 742 struct buf *bp) 743{ 744 int bsize, error, flags, skipped; 745 size_t resid, sz; 746 off_t bn, offset; 747 struct vnode *vp; 748 749 flags = obp->b_flags; 750 751 if (!(flags & B_READ)) { 752 vp = bp->b_vp; 753 mutex_enter(&vp->v_interlock); 754 vp->v_numoutput++; 755 mutex_exit(&vp->v_interlock); 756 } 757 758 /* convert to a byte offset within the file. */ 759 bn = obp->b_rawblkno * vnd->sc_dkdev.dk_label->d_secsize; 760 761 bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize; 762 skipped = 0; 763 764 /* 765 * Break the request into bsize pieces and feed them 766 * sequentially using VOP_BMAP/VOP_STRATEGY. 767 * We do it this way to keep from flooding NFS servers if we 768 * are connected to an NFS file. This places the burden on 769 * the client rather than the server. 770 */ 771 error = 0; 772 bp->b_resid = bp->b_bcount; 773 for (offset = 0, resid = bp->b_resid; resid; 774 resid -= sz, offset += sz) { 775 struct buf *nbp; 776 daddr_t nbn; 777 int off, nra; 778 779 nra = 0; 780 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 781 error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra); 782 VOP_UNLOCK(vnd->sc_vp); 783 784 if (error == 0 && (long)nbn == -1) 785 error = EIO; 786 787 /* 788 * If there was an error or a hole in the file...punt. 789 * Note that we may have to wait for any operations 790 * that we have already fired off before releasing 791 * the buffer. 792 * 793 * XXX we could deal with holes here but it would be 794 * a hassle (in the write case). 795 */ 796 if (error) { 797 skipped += resid; 798 break; 799 } 800 801#ifdef DEBUG 802 if (!dovndcluster) 803 nra = 0; 804#endif 805 806 off = bn % bsize; 807 sz = MIN(((off_t)1 + nra) * bsize - off, resid); 808#ifdef DEBUG 809 if (vnddebug & VDB_IO) 810 printf("vndstrategy: vp %p/%p bn 0x%qx/0x%" PRIx64 811 " sz 0x%zx\n", vnd->sc_vp, vp, (long long)bn, 812 nbn, sz); 813#endif 814 815 nbp = getiobuf(vp, true); 816 nestiobuf_setup(bp, nbp, offset, sz); 817 nbp->b_blkno = nbn + btodb(off); 818 819#if 0 /* XXX #ifdef DEBUG */ 820 if (vnddebug & VDB_IO) 821 printf("vndstart(%ld): bp %p vp %p blkno " 822 "0x%" PRIx64 " flags %x addr %p cnt 0x%x\n", 823 (long) (vnd-vnd_softc), &nbp->vb_buf, 824 nbp->vb_buf.b_vp, nbp->vb_buf.b_blkno, 825 nbp->vb_buf.b_flags, nbp->vb_buf.b_data, 826 nbp->vb_buf.b_bcount); 827#endif 828 VOP_STRATEGY(vp, nbp); 829 bn += sz; 830 } 831 nestiobuf_done(bp, skipped, error); 832} 833 834static void 835vndiodone(struct buf *bp) 836{ 837 struct vndxfer *vnx = VND_BUFTOXFER(bp); 838 struct vnd_softc *vnd = vnx->vx_vnd; 839 struct buf *obp = bp->b_private; 840 int s = splbio(); 841 842 KASSERT(&vnx->vx_buf == bp); 843 KASSERT(vnd->sc_active > 0); 844#ifdef DEBUG 845 if (vnddebug & VDB_IO) { 846 printf("vndiodone1: bp %p iodone: error %d\n", 847 bp, bp->b_error); 848 } 849#endif 850 disk_unbusy(&vnd->sc_dkdev, bp->b_bcount - bp->b_resid, 851 (bp->b_flags & B_READ)); 852 vnd->sc_active--; 853 if (vnd->sc_active == 0) { 854 wakeup(&vnd->sc_tab); 855 } 856 splx(s); 857 obp->b_error = bp->b_error; 858 obp->b_resid = bp->b_resid; 859 buf_destroy(bp); 860 VND_PUTXFER(vnd, vnx); 861 biodone(obp); 862} 863 864/* ARGSUSED */ 865static int 866vndread(dev_t dev, struct uio *uio, int flags) 867{ 868 int unit = vndunit(dev); 869 struct vnd_softc *sc; 870 871#ifdef DEBUG 872 if (vnddebug & VDB_FOLLOW) 873 printf("vndread(0x%"PRIx64", %p)\n", dev, uio); 874#endif 875 876 sc = device_lookup_private(&vnd_cd, unit); 877 if (sc == NULL) 878 return ENXIO; 879 880 if ((sc->sc_flags & VNF_INITED) == 0) 881 return ENXIO; 882 883 return physio(vndstrategy, NULL, dev, B_READ, minphys, uio); 884} 885 886/* ARGSUSED */ 887static int 888vndwrite(dev_t dev, struct uio *uio, int flags) 889{ 890 int unit = vndunit(dev); 891 struct vnd_softc *sc; 892 893#ifdef DEBUG 894 if (vnddebug & VDB_FOLLOW) 895 printf("vndwrite(0x%"PRIx64", %p)\n", dev, uio); 896#endif 897 898 sc = device_lookup_private(&vnd_cd, unit); 899 if (sc == NULL) 900 return ENXIO; 901 902 if ((sc->sc_flags & VNF_INITED) == 0) 903 return ENXIO; 904 905 return physio(vndstrategy, NULL, dev, B_WRITE, minphys, uio); 906} 907 908static int 909vnd_cget(struct lwp *l, int unit, int *un, struct vattr *va) 910{ 911 struct vnd_softc *vnd; 912 913 if (*un == -1) 914 *un = unit; 915 if (*un < 0) 916 return EINVAL; 917 918 vnd = device_lookup_private(&vnd_cd, *un); 919 if (vnd == NULL) 920 return (*un >= vnd_cd.cd_ndevs) ? ENXIO : -1; 921 922 if ((vnd->sc_flags & VNF_INITED) == 0) 923 return -1; 924 925 return VOP_GETATTR(vnd->sc_vp, va, l->l_cred); 926} 927 928static int 929vnddoclear(struct vnd_softc *vnd, int pmask, int minor, bool force) 930{ 931 int error; 932 933 if ((error = vndlock(vnd)) != 0) 934 return error; 935 936 /* 937 * Don't unconfigure if any other partitions are open 938 * or if both the character and block flavors of this 939 * partition are open. 940 */ 941 if (DK_BUSY(vnd, pmask) && !force) { 942 vndunlock(vnd); 943 return EBUSY; 944 } 945 946 /* 947 * XXX vndclear() might call vndclose() implicitly; 948 * release lock to avoid recursion 949 * 950 * Set VNF_CLEARING to prevent vndopen() from 951 * sneaking in after we vndunlock(). 952 */ 953 vnd->sc_flags |= VNF_CLEARING; 954 vndunlock(vnd); 955 vndclear(vnd, minor); 956#ifdef DEBUG 957 if (vnddebug & VDB_INIT) 958 printf("vndioctl: CLRed\n"); 959#endif 960 961 /* Destroy the xfer and buffer pools. */ 962 pool_destroy(&vnd->sc_vxpool); 963 964 /* Detach the disk. */ 965 disk_detach(&vnd->sc_dkdev); 966 967 return 0; 968} 969 970/* ARGSUSED */ 971static int 972vndioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 973{ 974 bool force; 975 int unit = vndunit(dev); 976 struct vnd_softc *vnd; 977 struct vnd_ioctl *vio; 978 struct vattr vattr; 979 struct pathbuf *pb; 980 struct nameidata nd; 981 int error, part, pmask; 982 size_t geomsize; 983 int fflags; 984#ifdef __HAVE_OLD_DISKLABEL 985 struct disklabel newlabel; 986#endif 987 struct dkwedge_info *dkw; 988 struct dkwedge_list *dkwl; 989 990#ifdef DEBUG 991 if (vnddebug & VDB_FOLLOW) 992 printf("vndioctl(0x%"PRIx64", 0x%lx, %p, 0x%x, %p): unit %d\n", 993 dev, cmd, data, flag, l->l_proc, unit); 994#endif 995 vnd = device_lookup_private(&vnd_cd, unit); 996 if (vnd == NULL && 997#ifdef COMPAT_30 998 cmd != VNDIOCGET30 && 999#endif 1000#ifdef COMPAT_50 1001 cmd != VNDIOCGET50 && 1002#endif 1003 cmd != VNDIOCGET) 1004 return ENXIO; 1005 vio = (struct vnd_ioctl *)data; 1006 1007 /* Must be open for writes for these commands... */ 1008 switch (cmd) { 1009 case VNDIOCSET: 1010 case VNDIOCCLR: 1011#ifdef COMPAT_50 1012 case VNDIOCSET50: 1013 case VNDIOCCLR50: 1014#endif 1015 case DIOCSDINFO: 1016 case DIOCWDINFO: 1017#ifdef __HAVE_OLD_DISKLABEL 1018 case ODIOCSDINFO: 1019 case ODIOCWDINFO: 1020#endif 1021 case DIOCKLABEL: 1022 case DIOCWLABEL: 1023 if ((flag & FWRITE) == 0) 1024 return EBADF; 1025 } 1026 1027 /* Must be initialized for these... */ 1028 switch (cmd) { 1029 case VNDIOCCLR: 1030#ifdef VNDIOCCLR50 1031 case VNDIOCCLR50: 1032#endif 1033 case DIOCGDINFO: 1034 case DIOCSDINFO: 1035 case DIOCWDINFO: 1036 case DIOCGPART: 1037 case DIOCKLABEL: 1038 case DIOCWLABEL: 1039 case DIOCGDEFLABEL: 1040 case DIOCCACHESYNC: 1041#ifdef __HAVE_OLD_DISKLABEL 1042 case ODIOCGDINFO: 1043 case ODIOCSDINFO: 1044 case ODIOCWDINFO: 1045 case ODIOCGDEFLABEL: 1046#endif 1047 if ((vnd->sc_flags & VNF_INITED) == 0) 1048 return ENXIO; 1049 } 1050 1051 switch (cmd) { 1052#ifdef VNDIOCSET50 1053 case VNDIOCSET50: 1054#endif 1055 case VNDIOCSET: 1056 if (vnd->sc_flags & VNF_INITED) 1057 return EBUSY; 1058 1059 if ((error = vndlock(vnd)) != 0) 1060 return error; 1061 1062 fflags = FREAD; 1063 if ((vio->vnd_flags & VNDIOF_READONLY) == 0) 1064 fflags |= FWRITE; 1065 error = pathbuf_copyin(vio->vnd_file, &pb); 1066 if (error) { 1067 goto unlock_and_exit; 1068 } 1069 NDINIT(&nd, LOOKUP, FOLLOW, pb); 1070 if ((error = vn_open(&nd, fflags, 0)) != 0) { 1071 pathbuf_destroy(pb); 1072 goto unlock_and_exit; 1073 } 1074 KASSERT(l); 1075 error = VOP_GETATTR(nd.ni_vp, &vattr, l->l_cred); 1076 if (!error && nd.ni_vp->v_type != VREG) 1077 error = EOPNOTSUPP; 1078 if (!error && vattr.va_bytes < vattr.va_size) 1079 /* File is definitely sparse, reject here */ 1080 error = EINVAL; 1081 if (error) { 1082 VOP_UNLOCK(nd.ni_vp); 1083 goto close_and_exit; 1084 } 1085 1086 /* If using a compressed file, initialize its info */ 1087 /* (or abort with an error if kernel has no compression) */ 1088 if (vio->vnd_flags & VNF_COMP) { 1089#ifdef VND_COMPRESSION 1090 struct vnd_comp_header *ch; 1091 int i; 1092 u_int32_t comp_size; 1093 u_int32_t comp_maxsize; 1094 1095 /* allocate space for compresed file header */ 1096 ch = malloc(sizeof(struct vnd_comp_header), 1097 M_TEMP, M_WAITOK); 1098 1099 /* read compressed file header */ 1100 error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)ch, 1101 sizeof(struct vnd_comp_header), 0, UIO_SYSSPACE, 1102 IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL); 1103 if (error) { 1104 free(ch, M_TEMP); 1105 VOP_UNLOCK(nd.ni_vp); 1106 goto close_and_exit; 1107 } 1108 1109 /* save some header info */ 1110 vnd->sc_comp_blksz = ntohl(ch->block_size); 1111 /* note last offset is the file byte size */ 1112 vnd->sc_comp_numoffs = ntohl(ch->num_blocks)+1; 1113 free(ch, M_TEMP); 1114 if (vnd->sc_comp_blksz == 0 || 1115 vnd->sc_comp_blksz % DEV_BSIZE !=0) { 1116 VOP_UNLOCK(nd.ni_vp); 1117 error = EINVAL; 1118 goto close_and_exit; 1119 } 1120 if (sizeof(struct vnd_comp_header) + 1121 sizeof(u_int64_t) * vnd->sc_comp_numoffs > 1122 vattr.va_size) { 1123 VOP_UNLOCK(nd.ni_vp); 1124 error = EINVAL; 1125 goto close_and_exit; 1126 } 1127 1128 /* set decompressed file size */ 1129 vattr.va_size = 1130 ((u_quad_t)vnd->sc_comp_numoffs - 1) * 1131 (u_quad_t)vnd->sc_comp_blksz; 1132 1133 /* allocate space for all the compressed offsets */ 1134 vnd->sc_comp_offsets = 1135 malloc(sizeof(u_int64_t) * vnd->sc_comp_numoffs, 1136 M_DEVBUF, M_WAITOK); 1137 1138 /* read in the offsets */ 1139 error = vn_rdwr(UIO_READ, nd.ni_vp, 1140 (void *)vnd->sc_comp_offsets, 1141 sizeof(u_int64_t) * vnd->sc_comp_numoffs, 1142 sizeof(struct vnd_comp_header), UIO_SYSSPACE, 1143 IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL); 1144 if (error) { 1145 VOP_UNLOCK(nd.ni_vp); 1146 goto close_and_exit; 1147 } 1148 /* 1149 * find largest block size (used for allocation limit). 1150 * Also convert offset to native byte order. 1151 */ 1152 comp_maxsize = 0; 1153 for (i = 0; i < vnd->sc_comp_numoffs - 1; i++) { 1154 vnd->sc_comp_offsets[i] = 1155 be64toh(vnd->sc_comp_offsets[i]); 1156 comp_size = be64toh(vnd->sc_comp_offsets[i + 1]) 1157 - vnd->sc_comp_offsets[i]; 1158 if (comp_size > comp_maxsize) 1159 comp_maxsize = comp_size; 1160 } 1161 vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1] = 1162 be64toh(vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1]); 1163 1164 /* create compressed data buffer */ 1165 vnd->sc_comp_buff = malloc(comp_maxsize, 1166 M_DEVBUF, M_WAITOK); 1167 1168 /* create decompressed buffer */ 1169 vnd->sc_comp_decombuf = malloc(vnd->sc_comp_blksz, 1170 M_DEVBUF, M_WAITOK); 1171 vnd->sc_comp_buffblk = -1; 1172 1173 /* Initialize decompress stream */ 1174 memset(&vnd->sc_comp_stream, 0, sizeof(z_stream)); 1175 vnd->sc_comp_stream.zalloc = vnd_alloc; 1176 vnd->sc_comp_stream.zfree = vnd_free; 1177 error = inflateInit2(&vnd->sc_comp_stream, MAX_WBITS); 1178 if (error) { 1179 if (vnd->sc_comp_stream.msg) 1180 printf("vnd%d: compressed file, %s\n", 1181 unit, vnd->sc_comp_stream.msg); 1182 VOP_UNLOCK(nd.ni_vp); 1183 error = EINVAL; 1184 goto close_and_exit; 1185 } 1186 1187 vnd->sc_flags |= VNF_COMP | VNF_READONLY; 1188#else /* !VND_COMPRESSION */ 1189 VOP_UNLOCK(nd.ni_vp); 1190 error = EOPNOTSUPP; 1191 goto close_and_exit; 1192#endif /* VND_COMPRESSION */ 1193 } 1194 1195 VOP_UNLOCK(nd.ni_vp); 1196 vnd->sc_vp = nd.ni_vp; 1197 vnd->sc_size = btodb(vattr.va_size); /* note truncation */ 1198 1199 /* 1200 * Use pseudo-geometry specified. If none was provided, 1201 * use "standard" Adaptec fictitious geometry. 1202 */ 1203 if (vio->vnd_flags & VNDIOF_HASGEOM) { 1204 1205 memcpy(&vnd->sc_geom, &vio->vnd_geom, 1206 sizeof(vio->vnd_geom)); 1207 1208 /* 1209 * Sanity-check the sector size. 1210 * XXX Don't allow secsize < DEV_BSIZE. Should 1211 * XXX we? 1212 */ 1213 if (vnd->sc_geom.vng_secsize < DEV_BSIZE || 1214 (vnd->sc_geom.vng_secsize % DEV_BSIZE) != 0 || 1215 vnd->sc_geom.vng_ncylinders == 0 || 1216 (vnd->sc_geom.vng_ntracks * 1217 vnd->sc_geom.vng_nsectors) == 0) { 1218 error = EINVAL; 1219 goto close_and_exit; 1220 } 1221 1222 /* 1223 * Compute the size (in DEV_BSIZE blocks) specified 1224 * by the geometry. 1225 */ 1226 geomsize = (vnd->sc_geom.vng_nsectors * 1227 vnd->sc_geom.vng_ntracks * 1228 vnd->sc_geom.vng_ncylinders) * 1229 (vnd->sc_geom.vng_secsize / DEV_BSIZE); 1230 1231 /* 1232 * Sanity-check the size against the specified 1233 * geometry. 1234 */ 1235 if (vnd->sc_size < geomsize) { 1236 error = EINVAL; 1237 goto close_and_exit; 1238 } 1239 } else if (vnd->sc_size >= (32 * 64)) { 1240 /* 1241 * Size must be at least 2048 DEV_BSIZE blocks 1242 * (1M) in order to use this geometry. 1243 */ 1244 vnd->sc_geom.vng_secsize = DEV_BSIZE; 1245 vnd->sc_geom.vng_nsectors = 32; 1246 vnd->sc_geom.vng_ntracks = 64; 1247 vnd->sc_geom.vng_ncylinders = vnd->sc_size / (64 * 32); 1248 } else { 1249 vnd->sc_geom.vng_secsize = DEV_BSIZE; 1250 vnd->sc_geom.vng_nsectors = 1; 1251 vnd->sc_geom.vng_ntracks = 1; 1252 vnd->sc_geom.vng_ncylinders = vnd->sc_size; 1253 } 1254 1255 vnd_set_properties(vnd); 1256 1257 if (vio->vnd_flags & VNDIOF_READONLY) { 1258 vnd->sc_flags |= VNF_READONLY; 1259 } 1260 1261 if ((error = vndsetcred(vnd, l->l_cred)) != 0) 1262 goto close_and_exit; 1263 1264 vndthrottle(vnd, vnd->sc_vp); 1265 vio->vnd_osize = dbtob(vnd->sc_size); 1266#ifdef VNDIOCSET50 1267 if (cmd != VNDIOCSET50) 1268#endif 1269 vio->vnd_size = dbtob(vnd->sc_size); 1270 vnd->sc_flags |= VNF_INITED; 1271 1272 /* create the kernel thread, wait for it to be up */ 1273 error = kthread_create(PRI_NONE, 0, NULL, vndthread, vnd, 1274 &vnd->sc_kthread, "%s", device_xname(vnd->sc_dev)); 1275 if (error) 1276 goto close_and_exit; 1277 while ((vnd->sc_flags & VNF_KTHREAD) == 0) { 1278 tsleep(&vnd->sc_kthread, PRIBIO, "vndthr", 0); 1279 } 1280#ifdef DEBUG 1281 if (vnddebug & VDB_INIT) 1282 printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n", 1283 vnd->sc_vp, (unsigned long) vnd->sc_size, 1284 vnd->sc_geom.vng_secsize, 1285 vnd->sc_geom.vng_nsectors, 1286 vnd->sc_geom.vng_ntracks, 1287 vnd->sc_geom.vng_ncylinders); 1288#endif 1289 1290 /* Attach the disk. */ 1291 disk_attach(&vnd->sc_dkdev); 1292 disk_blocksize(&vnd->sc_dkdev, vnd->sc_geom.vng_secsize); 1293 1294 /* Initialize the xfer and buffer pools. */ 1295 pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0, 1296 0, 0, "vndxpl", NULL, IPL_BIO); 1297 1298 /* Try and read the disklabel. */ 1299 vndgetdisklabel(dev, vnd); 1300 1301 vndunlock(vnd); 1302 1303 pathbuf_destroy(pb); 1304 break; 1305 1306close_and_exit: 1307 (void) vn_close(nd.ni_vp, fflags, l->l_cred); 1308 pathbuf_destroy(pb); 1309unlock_and_exit: 1310#ifdef VND_COMPRESSION 1311 /* free any allocated memory (for compressed file) */ 1312 if (vnd->sc_comp_offsets) { 1313 free(vnd->sc_comp_offsets, M_DEVBUF); 1314 vnd->sc_comp_offsets = NULL; 1315 } 1316 if (vnd->sc_comp_buff) { 1317 free(vnd->sc_comp_buff, M_DEVBUF); 1318 vnd->sc_comp_buff = NULL; 1319 } 1320 if (vnd->sc_comp_decombuf) { 1321 free(vnd->sc_comp_decombuf, M_DEVBUF); 1322 vnd->sc_comp_decombuf = NULL; 1323 } 1324#endif /* VND_COMPRESSION */ 1325 vndunlock(vnd); 1326 return error; 1327 1328#ifdef VNDIOCCLR50 1329 case VNDIOCCLR50: 1330#endif 1331 case VNDIOCCLR: 1332 part = DISKPART(dev); 1333 pmask = (1 << part); 1334 force = (vio->vnd_flags & VNDIOF_FORCE) != 0; 1335 1336 if ((error = vnddoclear(vnd, pmask, minor(dev), force)) != 0) 1337 return error; 1338 1339 break; 1340 1341#ifdef COMPAT_30 1342 case VNDIOCGET30: { 1343 struct vnd_user30 *vnu; 1344 struct vattr va; 1345 vnu = (struct vnd_user30 *)data; 1346 KASSERT(l); 1347 switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) { 1348 case 0: 1349 vnu->vnu_dev = va.va_fsid; 1350 vnu->vnu_ino = va.va_fileid; 1351 break; 1352 case -1: 1353 /* unused is not an error */ 1354 vnu->vnu_dev = 0; 1355 vnu->vnu_ino = 0; 1356 break; 1357 default: 1358 return error; 1359 } 1360 break; 1361 } 1362#endif 1363 1364#ifdef COMPAT_50 1365 case VNDIOCGET50: { 1366 struct vnd_user50 *vnu; 1367 struct vattr va; 1368 vnu = (struct vnd_user50 *)data; 1369 KASSERT(l); 1370 switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) { 1371 case 0: 1372 vnu->vnu_dev = va.va_fsid; 1373 vnu->vnu_ino = va.va_fileid; 1374 break; 1375 case -1: 1376 /* unused is not an error */ 1377 vnu->vnu_dev = 0; 1378 vnu->vnu_ino = 0; 1379 break; 1380 default: 1381 return error; 1382 } 1383 break; 1384 } 1385#endif 1386 1387 case VNDIOCGET: { 1388 struct vnd_user *vnu; 1389 struct vattr va; 1390 vnu = (struct vnd_user *)data; 1391 KASSERT(l); 1392 switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) { 1393 case 0: 1394 vnu->vnu_dev = va.va_fsid; 1395 vnu->vnu_ino = va.va_fileid; 1396 break; 1397 case -1: 1398 /* unused is not an error */ 1399 vnu->vnu_dev = 0; 1400 vnu->vnu_ino = 0; 1401 break; 1402 default: 1403 return error; 1404 } 1405 break; 1406 } 1407 1408 case DIOCGDINFO: 1409 *(struct disklabel *)data = *(vnd->sc_dkdev.dk_label); 1410 break; 1411 1412#ifdef __HAVE_OLD_DISKLABEL 1413 case ODIOCGDINFO: 1414 newlabel = *(vnd->sc_dkdev.dk_label); 1415 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1416 return ENOTTY; 1417 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1418 break; 1419#endif 1420 1421 case DIOCGPART: 1422 ((struct partinfo *)data)->disklab = vnd->sc_dkdev.dk_label; 1423 ((struct partinfo *)data)->part = 1424 &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(dev)]; 1425 break; 1426 1427 case DIOCWDINFO: 1428 case DIOCSDINFO: 1429#ifdef __HAVE_OLD_DISKLABEL 1430 case ODIOCWDINFO: 1431 case ODIOCSDINFO: 1432#endif 1433 { 1434 struct disklabel *lp; 1435 1436 if ((error = vndlock(vnd)) != 0) 1437 return error; 1438 1439 vnd->sc_flags |= VNF_LABELLING; 1440 1441#ifdef __HAVE_OLD_DISKLABEL 1442 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 1443 memset(&newlabel, 0, sizeof newlabel); 1444 memcpy(&newlabel, data, sizeof (struct olddisklabel)); 1445 lp = &newlabel; 1446 } else 1447#endif 1448 lp = (struct disklabel *)data; 1449 1450 error = setdisklabel(vnd->sc_dkdev.dk_label, 1451 lp, 0, vnd->sc_dkdev.dk_cpulabel); 1452 if (error == 0) { 1453 if (cmd == DIOCWDINFO 1454#ifdef __HAVE_OLD_DISKLABEL 1455 || cmd == ODIOCWDINFO 1456#endif 1457 ) 1458 error = writedisklabel(VNDLABELDEV(dev), 1459 vndstrategy, vnd->sc_dkdev.dk_label, 1460 vnd->sc_dkdev.dk_cpulabel); 1461 } 1462 1463 vnd->sc_flags &= ~VNF_LABELLING; 1464 1465 vndunlock(vnd); 1466 1467 if (error) 1468 return error; 1469 break; 1470 } 1471 1472 case DIOCKLABEL: 1473 if (*(int *)data != 0) 1474 vnd->sc_flags |= VNF_KLABEL; 1475 else 1476 vnd->sc_flags &= ~VNF_KLABEL; 1477 break; 1478 1479 case DIOCWLABEL: 1480 if (*(int *)data != 0) 1481 vnd->sc_flags |= VNF_WLABEL; 1482 else 1483 vnd->sc_flags &= ~VNF_WLABEL; 1484 break; 1485 1486 case DIOCGDEFLABEL: 1487 vndgetdefaultlabel(vnd, (struct disklabel *)data); 1488 break; 1489 1490#ifdef __HAVE_OLD_DISKLABEL 1491 case ODIOCGDEFLABEL: 1492 vndgetdefaultlabel(vnd, &newlabel); 1493 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1494 return ENOTTY; 1495 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1496 break; 1497#endif 1498 1499 case DIOCCACHESYNC: 1500 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1501 error = VOP_FSYNC(vnd->sc_vp, vnd->sc_cred, 1502 FSYNC_WAIT | FSYNC_DATAONLY | FSYNC_CACHE, 0, 0); 1503 VOP_UNLOCK(vnd->sc_vp); 1504 return error; 1505 1506 case DIOCAWEDGE: 1507 dkw = (void *) data; 1508 1509 if ((flag & FWRITE) == 0) 1510 return EBADF; 1511 1512 /* If the ioctl happens here, the parent is us. */ 1513 strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev), 1514 sizeof(dkw->dkw_parent)); 1515 return dkwedge_add(dkw); 1516 1517 case DIOCDWEDGE: 1518 dkw = (void *) data; 1519 1520 if ((flag & FWRITE) == 0) 1521 return EBADF; 1522 1523 /* If the ioctl happens here, the parent is us. */ 1524 strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev), 1525 sizeof(dkw->dkw_parent)); 1526 return dkwedge_del(dkw); 1527 1528 case DIOCLWEDGES: 1529 dkwl = (void *) data; 1530 1531 return dkwedge_list(&vnd->sc_dkdev, dkwl, l); 1532 1533 default: 1534 return ENOTTY; 1535 } 1536 1537 return 0; 1538} 1539 1540/* 1541 * Duplicate the current processes' credentials. Since we are called only 1542 * as the result of a SET ioctl and only root can do that, any future access 1543 * to this "disk" is essentially as root. Note that credentials may change 1544 * if some other uid can write directly to the mapped file (NFS). 1545 */ 1546static int 1547vndsetcred(struct vnd_softc *vnd, kauth_cred_t cred) 1548{ 1549 struct uio auio; 1550 struct iovec aiov; 1551 char *tmpbuf; 1552 int error; 1553 1554 vnd->sc_cred = kauth_cred_dup(cred); 1555 tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK); 1556 1557 /* XXX: Horrible kludge to establish credentials for NFS */ 1558 aiov.iov_base = tmpbuf; 1559 aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size)); 1560 auio.uio_iov = &aiov; 1561 auio.uio_iovcnt = 1; 1562 auio.uio_offset = 0; 1563 auio.uio_rw = UIO_READ; 1564 auio.uio_resid = aiov.iov_len; 1565 UIO_SETUP_SYSSPACE(&auio); 1566 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1567 error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred); 1568 if (error == 0) { 1569 /* 1570 * Because vnd does all IO directly through the vnode 1571 * we need to flush (at least) the buffer from the above 1572 * VOP_READ from the buffer cache to prevent cache 1573 * incoherencies. Also, be careful to write dirty 1574 * buffers back to stable storage. 1575 */ 1576 error = vinvalbuf(vnd->sc_vp, V_SAVE, vnd->sc_cred, 1577 curlwp, 0, 0); 1578 } 1579 VOP_UNLOCK(vnd->sc_vp); 1580 1581 free(tmpbuf, M_TEMP); 1582 return error; 1583} 1584 1585/* 1586 * Set maxactive based on FS type 1587 */ 1588static void 1589vndthrottle(struct vnd_softc *vnd, struct vnode *vp) 1590{ 1591 1592 if (vp->v_tag == VT_NFS) 1593 vnd->sc_maxactive = 2; 1594 else 1595 vnd->sc_maxactive = 8; 1596 1597 if (vnd->sc_maxactive < 1) 1598 vnd->sc_maxactive = 1; 1599} 1600 1601#if 0 1602static void 1603vndshutdown(void) 1604{ 1605 struct vnd_softc *vnd; 1606 1607 for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++) 1608 if (vnd->sc_flags & VNF_INITED) 1609 vndclear(vnd); 1610} 1611#endif 1612 1613static void 1614vndclear(struct vnd_softc *vnd, int myminor) 1615{ 1616 struct vnode *vp = vnd->sc_vp; 1617 int fflags = FREAD; 1618 int bmaj, cmaj, i, mn; 1619 int s; 1620 1621#ifdef DEBUG 1622 if (vnddebug & VDB_FOLLOW) 1623 printf("vndclear(%p): vp %p\n", vnd, vp); 1624#endif 1625 /* locate the major number */ 1626 bmaj = bdevsw_lookup_major(&vnd_bdevsw); 1627 cmaj = cdevsw_lookup_major(&vnd_cdevsw); 1628 1629 /* Nuke the vnodes for any open instances */ 1630 for (i = 0; i < MAXPARTITIONS; i++) { 1631 mn = DISKMINOR(device_unit(vnd->sc_dev), i); 1632 vdevgone(bmaj, mn, mn, VBLK); 1633 if (mn != myminor) /* XXX avoid to kill own vnode */ 1634 vdevgone(cmaj, mn, mn, VCHR); 1635 } 1636 1637 if ((vnd->sc_flags & VNF_READONLY) == 0) 1638 fflags |= FWRITE; 1639 1640 s = splbio(); 1641 bufq_drain(vnd->sc_tab); 1642 splx(s); 1643 1644 vnd->sc_flags |= VNF_VUNCONF; 1645 wakeup(&vnd->sc_tab); 1646 while (vnd->sc_flags & VNF_KTHREAD) 1647 tsleep(&vnd->sc_kthread, PRIBIO, "vnthr", 0); 1648 1649#ifdef VND_COMPRESSION 1650 /* free the compressed file buffers */ 1651 if (vnd->sc_flags & VNF_COMP) { 1652 if (vnd->sc_comp_offsets) { 1653 free(vnd->sc_comp_offsets, M_DEVBUF); 1654 vnd->sc_comp_offsets = NULL; 1655 } 1656 if (vnd->sc_comp_buff) { 1657 free(vnd->sc_comp_buff, M_DEVBUF); 1658 vnd->sc_comp_buff = NULL; 1659 } 1660 if (vnd->sc_comp_decombuf) { 1661 free(vnd->sc_comp_decombuf, M_DEVBUF); 1662 vnd->sc_comp_decombuf = NULL; 1663 } 1664 } 1665#endif /* VND_COMPRESSION */ 1666 vnd->sc_flags &= 1667 ~(VNF_INITED | VNF_READONLY | VNF_VLABEL 1668 | VNF_VUNCONF | VNF_COMP | VNF_CLEARING); 1669 if (vp == NULL) 1670 panic("vndclear: null vp"); 1671 (void) vn_close(vp, fflags, vnd->sc_cred); 1672 kauth_cred_free(vnd->sc_cred); 1673 vnd->sc_vp = NULL; 1674 vnd->sc_cred = NULL; 1675 vnd->sc_size = 0; 1676} 1677 1678static int 1679vndsize(dev_t dev) 1680{ 1681 struct vnd_softc *sc; 1682 struct disklabel *lp; 1683 int part, unit, omask; 1684 int size; 1685 1686 unit = vndunit(dev); 1687 sc = device_lookup_private(&vnd_cd, unit); 1688 if (sc == NULL) 1689 return -1; 1690 1691 if ((sc->sc_flags & VNF_INITED) == 0) 1692 return -1; 1693 1694 part = DISKPART(dev); 1695 omask = sc->sc_dkdev.dk_openmask & (1 << part); 1696 lp = sc->sc_dkdev.dk_label; 1697 1698 if (omask == 0 && vndopen(dev, 0, S_IFBLK, curlwp)) /* XXX */ 1699 return -1; 1700 1701 if (lp->d_partitions[part].p_fstype != FS_SWAP) 1702 size = -1; 1703 else 1704 size = lp->d_partitions[part].p_size * 1705 (lp->d_secsize / DEV_BSIZE); 1706 1707 if (omask == 0 && vndclose(dev, 0, S_IFBLK, curlwp)) /* XXX */ 1708 return -1; 1709 1710 return size; 1711} 1712 1713static int 1714vnddump(dev_t dev, daddr_t blkno, void *va, 1715 size_t size) 1716{ 1717 1718 /* Not implemented. */ 1719 return ENXIO; 1720} 1721 1722static void 1723vndgetdefaultlabel(struct vnd_softc *sc, struct disklabel *lp) 1724{ 1725 struct vndgeom *vng = &sc->sc_geom; 1726 struct partition *pp; 1727 1728 memset(lp, 0, sizeof(*lp)); 1729 1730 lp->d_secperunit = sc->sc_size / (vng->vng_secsize / DEV_BSIZE); 1731 lp->d_secsize = vng->vng_secsize; 1732 lp->d_nsectors = vng->vng_nsectors; 1733 lp->d_ntracks = vng->vng_ntracks; 1734 lp->d_ncylinders = vng->vng_ncylinders; 1735 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1736 1737 strncpy(lp->d_typename, "vnd", sizeof(lp->d_typename)); 1738 lp->d_type = DTYPE_VND; 1739 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1740 lp->d_rpm = 3600; 1741 lp->d_interleave = 1; 1742 lp->d_flags = 0; 1743 1744 pp = &lp->d_partitions[RAW_PART]; 1745 pp->p_offset = 0; 1746 pp->p_size = lp->d_secperunit; 1747 pp->p_fstype = FS_UNUSED; 1748 lp->d_npartitions = RAW_PART + 1; 1749 1750 lp->d_magic = DISKMAGIC; 1751 lp->d_magic2 = DISKMAGIC; 1752 lp->d_checksum = dkcksum(lp); 1753} 1754 1755/* 1756 * Read the disklabel from a vnd. If one is not present, create a fake one. 1757 */ 1758static void 1759vndgetdisklabel(dev_t dev, struct vnd_softc *sc) 1760{ 1761 const char *errstring; 1762 struct disklabel *lp = sc->sc_dkdev.dk_label; 1763 struct cpu_disklabel *clp = sc->sc_dkdev.dk_cpulabel; 1764 int i; 1765 1766 memset(clp, 0, sizeof(*clp)); 1767 1768 vndgetdefaultlabel(sc, lp); 1769 1770 /* 1771 * Call the generic disklabel extraction routine. 1772 */ 1773 errstring = readdisklabel(VNDLABELDEV(dev), vndstrategy, lp, clp); 1774 if (errstring) { 1775 /* 1776 * Lack of disklabel is common, but we print the warning 1777 * anyway, since it might contain other useful information. 1778 */ 1779 aprint_normal_dev(sc->sc_dev, "%s\n", errstring); 1780 1781 /* 1782 * For historical reasons, if there's no disklabel 1783 * present, all partitions must be FS_BSDFFS and 1784 * occupy the entire disk. 1785 */ 1786 for (i = 0; i < MAXPARTITIONS; i++) { 1787 /* 1788 * Don't wipe out port specific hack (such as 1789 * dos partition hack of i386 port). 1790 */ 1791 if (lp->d_partitions[i].p_size != 0) 1792 continue; 1793 1794 lp->d_partitions[i].p_size = lp->d_secperunit; 1795 lp->d_partitions[i].p_offset = 0; 1796 lp->d_partitions[i].p_fstype = FS_BSDFFS; 1797 } 1798 1799 strncpy(lp->d_packname, "default label", 1800 sizeof(lp->d_packname)); 1801 1802 lp->d_npartitions = MAXPARTITIONS; 1803 lp->d_checksum = dkcksum(lp); 1804 } 1805 1806 /* In-core label now valid. */ 1807 sc->sc_flags |= VNF_VLABEL; 1808} 1809 1810/* 1811 * Wait interruptibly for an exclusive lock. 1812 * 1813 * XXX 1814 * Several drivers do this; it should be abstracted and made MP-safe. 1815 */ 1816static int 1817vndlock(struct vnd_softc *sc) 1818{ 1819 int error; 1820 1821 while ((sc->sc_flags & VNF_LOCKED) != 0) { 1822 sc->sc_flags |= VNF_WANTED; 1823 if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0) 1824 return error; 1825 } 1826 sc->sc_flags |= VNF_LOCKED; 1827 return 0; 1828} 1829 1830/* 1831 * Unlock and wake up any waiters. 1832 */ 1833static void 1834vndunlock(struct vnd_softc *sc) 1835{ 1836 1837 sc->sc_flags &= ~VNF_LOCKED; 1838 if ((sc->sc_flags & VNF_WANTED) != 0) { 1839 sc->sc_flags &= ~VNF_WANTED; 1840 wakeup(sc); 1841 } 1842} 1843 1844#ifdef VND_COMPRESSION 1845/* compressed file read */ 1846static void 1847compstrategy(struct buf *bp, off_t bn) 1848{ 1849 int error; 1850 int unit = vndunit(bp->b_dev); 1851 struct vnd_softc *vnd = 1852 device_lookup_private(&vnd_cd, unit); 1853 u_int32_t comp_block; 1854 struct uio auio; 1855 char *addr; 1856 int s; 1857 1858 /* set up constants for data move */ 1859 auio.uio_rw = UIO_READ; 1860 UIO_SETUP_SYSSPACE(&auio); 1861 1862 /* read, and transfer the data */ 1863 addr = bp->b_data; 1864 bp->b_resid = bp->b_bcount; 1865 s = splbio(); 1866 while (bp->b_resid > 0) { 1867 unsigned length; 1868 size_t length_in_buffer; 1869 u_int32_t offset_in_buffer; 1870 struct iovec aiov; 1871 1872 /* calculate the compressed block number */ 1873 comp_block = bn / (off_t)vnd->sc_comp_blksz; 1874 1875 /* check for good block number */ 1876 if (comp_block >= vnd->sc_comp_numoffs) { 1877 bp->b_error = EINVAL; 1878 splx(s); 1879 return; 1880 } 1881 1882 /* read in the compressed block, if not in buffer */ 1883 if (comp_block != vnd->sc_comp_buffblk) { 1884 length = vnd->sc_comp_offsets[comp_block + 1] - 1885 vnd->sc_comp_offsets[comp_block]; 1886 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1887 error = vn_rdwr(UIO_READ, vnd->sc_vp, vnd->sc_comp_buff, 1888 length, vnd->sc_comp_offsets[comp_block], 1889 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, vnd->sc_cred, 1890 NULL, NULL); 1891 if (error) { 1892 bp->b_error = error; 1893 VOP_UNLOCK(vnd->sc_vp); 1894 splx(s); 1895 return; 1896 } 1897 /* uncompress the buffer */ 1898 vnd->sc_comp_stream.next_in = vnd->sc_comp_buff; 1899 vnd->sc_comp_stream.avail_in = length; 1900 vnd->sc_comp_stream.next_out = vnd->sc_comp_decombuf; 1901 vnd->sc_comp_stream.avail_out = vnd->sc_comp_blksz; 1902 inflateReset(&vnd->sc_comp_stream); 1903 error = inflate(&vnd->sc_comp_stream, Z_FINISH); 1904 if (error != Z_STREAM_END) { 1905 if (vnd->sc_comp_stream.msg) 1906 aprint_normal_dev(vnd->sc_dev, 1907 "compressed file, %s\n", 1908 vnd->sc_comp_stream.msg); 1909 bp->b_error = EBADMSG; 1910 VOP_UNLOCK(vnd->sc_vp); 1911 splx(s); 1912 return; 1913 } 1914 vnd->sc_comp_buffblk = comp_block; 1915 VOP_UNLOCK(vnd->sc_vp); 1916 } 1917 1918 /* transfer the usable uncompressed data */ 1919 offset_in_buffer = bn % (off_t)vnd->sc_comp_blksz; 1920 length_in_buffer = vnd->sc_comp_blksz - offset_in_buffer; 1921 if (length_in_buffer > bp->b_resid) 1922 length_in_buffer = bp->b_resid; 1923 auio.uio_iov = &aiov; 1924 auio.uio_iovcnt = 1; 1925 aiov.iov_base = addr; 1926 aiov.iov_len = length_in_buffer; 1927 auio.uio_resid = aiov.iov_len; 1928 auio.uio_offset = 0; 1929 error = uiomove(vnd->sc_comp_decombuf + offset_in_buffer, 1930 length_in_buffer, &auio); 1931 if (error) { 1932 bp->b_error = error; 1933 splx(s); 1934 return; 1935 } 1936 1937 bn += length_in_buffer; 1938 addr += length_in_buffer; 1939 bp->b_resid -= length_in_buffer; 1940 } 1941 splx(s); 1942} 1943 1944/* compression memory allocation routines */ 1945static void * 1946vnd_alloc(void *aux, u_int items, u_int siz) 1947{ 1948 return malloc(items * siz, M_TEMP, M_NOWAIT); 1949} 1950 1951static void 1952vnd_free(void *aux, void *ptr) 1953{ 1954 free(ptr, M_TEMP); 1955} 1956#endif /* VND_COMPRESSION */ 1957 1958static void 1959vnd_set_properties(struct vnd_softc *vnd) 1960{ 1961 prop_dictionary_t disk_info, odisk_info, geom; 1962 1963 disk_info = prop_dictionary_create(); 1964 1965 geom = prop_dictionary_create(); 1966 1967 prop_dictionary_set_uint64(geom, "sectors-per-unit", 1968 vnd->sc_geom.vng_nsectors * vnd->sc_geom.vng_ntracks * 1969 vnd->sc_geom.vng_ncylinders); 1970 1971 prop_dictionary_set_uint32(geom, "sector-size", 1972 vnd->sc_geom.vng_secsize); 1973 1974 prop_dictionary_set_uint16(geom, "sectors-per-track", 1975 vnd->sc_geom.vng_nsectors); 1976 1977 prop_dictionary_set_uint16(geom, "tracks-per-cylinder", 1978 vnd->sc_geom.vng_ntracks); 1979 1980 prop_dictionary_set_uint64(geom, "cylinders-per-unit", 1981 vnd->sc_geom.vng_ncylinders); 1982 1983 prop_dictionary_set(disk_info, "geometry", geom); 1984 prop_object_release(geom); 1985 1986 prop_dictionary_set(device_properties(vnd->sc_dev), 1987 "disk-info", disk_info); 1988 1989 /* 1990 * Don't release disk_info here; we keep a reference to it. 1991 * disk_detach() will release it when we go away. 1992 */ 1993 1994 odisk_info = vnd->sc_dkdev.dk_info; 1995 vnd->sc_dkdev.dk_info = disk_info; 1996 if (odisk_info) 1997 prop_object_release(odisk_info); 1998} 1999 2000#ifdef _MODULE 2001 2002#include <sys/module.h> 2003 2004MODULE(MODULE_CLASS_DRIVER, vnd, NULL); 2005CFDRIVER_DECL(vnd, DV_DISK, NULL); 2006 2007static int 2008vnd_modcmd(modcmd_t cmd, void *arg) 2009{ 2010 int bmajor = -1, cmajor = -1, error = 0; 2011 2012 switch (cmd) { 2013 case MODULE_CMD_INIT: 2014 error = config_cfdriver_attach(&vnd_cd); 2015 if (error) 2016 break; 2017 2018 error = config_cfattach_attach(vnd_cd.cd_name, &vnd_ca); 2019 if (error) { 2020 config_cfdriver_detach(&vnd_cd); 2021 aprint_error("%s: unable to register cfattach\n", 2022 vnd_cd.cd_name); 2023 break; 2024 } 2025 2026 error = devsw_attach("vnd", &vnd_bdevsw, &bmajor, 2027 &vnd_cdevsw, &cmajor); 2028 if (error) { 2029 config_cfattach_detach(vnd_cd.cd_name, &vnd_ca); 2030 config_cfdriver_detach(&vnd_cd); 2031 break; 2032 } 2033 2034 break; 2035 2036 case MODULE_CMD_FINI: 2037 error = config_cfattach_detach(vnd_cd.cd_name, &vnd_ca); 2038 if (error) 2039 break; 2040 config_cfdriver_detach(&vnd_cd); 2041 devsw_detach(&vnd_bdevsw, &vnd_cdevsw); 2042 break; 2043 2044 case MODULE_CMD_STAT: 2045 return ENOTTY; 2046 2047 default: 2048 return ENOTTY; 2049 } 2050 2051 return error; 2052} 2053 2054#endif 2055