1 /* $NetBSD: vnd.c,v 1.114 2005/03/31 18:02:16 bouyer Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997, 1998 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1990, 1993 41 * The Regents of the University of California. All rights reserved. 42 * 43 * This code is derived from software contributed to Berkeley by 44 * the Systems Programming Group of the University of Utah Computer 45 * Science Department. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * from: Utah $Hdr: vn.c 1.13 94/04/02$ 72 * 73 * @(#)vn.c 8.9 (Berkeley) 5/14/95 74 */ 75 76 /* 77 * Copyright (c) 1988 University of Utah. 78 * 79 * This code is derived from software contributed to Berkeley by 80 * the Systems Programming Group of the University of Utah Computer 81 * Science Department. 82 * 83 * Redistribution and use in source and binary forms, with or without 84 * modification, are permitted provided that the following conditions 85 * are met: 86 * 1. Redistributions of source code must retain the above copyright 87 * notice, this list of conditions and the following disclaimer. 88 * 2. Redistributions in binary form must reproduce the above copyright 89 * notice, this list of conditions and the following disclaimer in the 90 * documentation and/or other materials provided with the distribution. 91 * 3. All advertising materials mentioning features or use of this software 92 * must display the following acknowledgement: 93 * This product includes software developed by the University of 94 * California, Berkeley and its contributors. 95 * 4. Neither the name of the University nor the names of its contributors 96 * may be used to endorse or promote products derived from this software 97 * without specific prior written permission. 98 * 99 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 100 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 101 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 102 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 103 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 104 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 105 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 106 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 107 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 108 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 109 * SUCH DAMAGE. 110 * 111 * from: Utah $Hdr: vn.c 1.13 94/04/02$ 112 * 113 * @(#)vn.c 8.9 (Berkeley) 5/14/95 114 */ 115 116 /* 117 * Vnode disk driver. 118 * 119 * Block/character interface to a vnode. Allows one to treat a file 120 * as a disk (e.g. build a filesystem in it, mount it, etc.). 121 * 122 * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode 123 * instead of a simple VOP_RDWR. We do this to avoid distorting the 124 * local buffer cache. 125 * 126 * NOTE 2: There is a security issue involved with this driver. 127 * Once mounted all access to the contents of the "mapped" file via 128 * the special file is controlled by the permissions on the special 129 * file, the protection of the mapped file is ignored (effectively, 130 * by using root credentials in all transactions). 131 * 132 * NOTE 3: Doesn't interact with leases, should it? 133 */ 134 135 #include <sys/cdefs.h> 136 __KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.114 2005/03/31 18:02:16 bouyer Exp $"); 137 138 #if defined(_KERNEL_OPT) 139 #include "fs_nfs.h" 140 #endif 141 142 #include <sys/param.h> 143 #include <sys/systm.h> 144 #include <sys/namei.h> 145 #include <sys/proc.h> 146 #include <sys/kthread.h> 147 #include <sys/errno.h> 148 #include <sys/buf.h> 149 #include <sys/bufq.h> 150 #include <sys/malloc.h> 151 #include <sys/ioctl.h> 152 #include <sys/disklabel.h> 153 #include <sys/device.h> 154 #include <sys/disk.h> 155 #include <sys/stat.h> 156 #include <sys/mount.h> 157 #include <sys/vnode.h> 158 #include <sys/file.h> 159 #include <sys/uio.h> 160 #include <sys/conf.h> 161 162 #include <miscfs/specfs/specdev.h> 163 164 #include <dev/vndvar.h> 165 166 #if defined(VNDDEBUG) && !defined(DEBUG) 167 #define DEBUG 168 #endif 169 170 #ifdef DEBUG 171 int dovndcluster = 1; 172 #define VDB_FOLLOW 0x01 173 #define VDB_INIT 0x02 174 #define VDB_IO 0x04 175 #define VDB_LABEL 0x08 176 int vnddebug = 0x00; 177 #endif 178 179 #define vndunit(x) DISKUNIT(x) 180 181 struct vndxfer { 182 struct buf *vx_bp; /* Pointer to parent buffer */ 183 int vx_error; 184 int vx_pending; /* # of pending aux buffers */ 185 int vx_flags; 186 #define VX_BUSY 1 187 }; 188 189 struct vndbuf { 190 struct buf vb_buf; 191 struct vndxfer *vb_xfer; 192 }; 193 194 #define VND_GETXFER(vnd) pool_get(&(vnd)->sc_vxpool, PR_WAITOK) 195 #define VND_PUTXFER(vnd, vx) pool_put(&(vnd)->sc_vxpool, (vx)) 196 197 #define VND_GETBUF(vnd) pool_get(&(vnd)->sc_vbpool, PR_WAITOK) 198 #define VND_PUTBUF(vnd, vb) pool_put(&(vnd)->sc_vbpool, (vb)) 199 200 struct vnd_softc *vnd_softc; 201 int numvnd = 0; 202 203 #define VNDLABELDEV(dev) \ 204 (MAKEDISKDEV(major((dev)), vndunit((dev)), RAW_PART)) 205 206 /* called by main() at boot time (XXX: and the LKM driver) */ 207 void vndattach(int); 208 int vnddetach(void); 209 210 static void vndclear(struct vnd_softc *, int); 211 static int vndsetcred(struct vnd_softc *, struct ucred *); 212 static void vndthrottle(struct vnd_softc *, struct vnode *); 213 static void vndiodone(struct buf *); 214 #if 0 215 static void vndshutdown(void); 216 #endif 217 218 static void vndgetdefaultlabel(struct vnd_softc *, struct disklabel *); 219 static void vndgetdisklabel(dev_t); 220 221 static int vndlock(struct vnd_softc *); 222 static void vndunlock(struct vnd_softc *); 223 224 void vndthread(void *); 225 226 static dev_type_open(vndopen); 227 static dev_type_close(vndclose); 228 static dev_type_read(vndread); 229 static dev_type_write(vndwrite); 230 static dev_type_ioctl(vndioctl); 231 static dev_type_strategy(vndstrategy); 232 static dev_type_dump(vnddump); 233 static dev_type_size(vndsize); 234 235 const struct bdevsw vnd_bdevsw = { 236 vndopen, vndclose, vndstrategy, vndioctl, vnddump, vndsize, D_DISK 237 }; 238 239 const struct cdevsw vnd_cdevsw = { 240 vndopen, vndclose, vndread, vndwrite, vndioctl, 241 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 242 }; 243 244 static int vndattached; 245 246 void 247 vndattach(int num) 248 { 249 int i; 250 char *mem; 251 252 if (vndattached) 253 return; 254 vndattached = 1; 255 if (num <= 0) 256 return; 257 i = num * sizeof(struct vnd_softc); 258 mem = malloc(i, M_DEVBUF, M_NOWAIT|M_ZERO); 259 if (mem == NULL) { 260 printf("WARNING: no memory for vnode disks\n"); 261 return; 262 } 263 vnd_softc = (struct vnd_softc *)mem; 264 numvnd = num; 265 266 for (i = 0; i < numvnd; i++) { 267 vnd_softc[i].sc_unit = i; 268 bufq_alloc(&vnd_softc[i].sc_tab, 269 BUFQ_DISKSORT|BUFQ_SORT_RAWBLOCK); 270 } 271 } 272 273 int 274 vnddetach(void) 275 { 276 int i; 277 278 /* First check we aren't in use. */ 279 for (i = 0; i < numvnd; i++) 280 if (vnd_softc[i].sc_flags & VNF_INITED) 281 return (EBUSY); 282 283 for (i = 0; i < numvnd; i++) 284 bufq_free(&vnd_softc[i].sc_tab); 285 286 free(vnd_softc, M_DEVBUF); 287 vndattached = 0; 288 289 return (0); 290 } 291 292 static int 293 vndopen(dev_t dev, int flags, int mode, struct proc *p) 294 { 295 int unit = vndunit(dev); 296 struct vnd_softc *sc; 297 int error = 0, part, pmask; 298 struct disklabel *lp; 299 300 #ifdef DEBUG 301 if (vnddebug & VDB_FOLLOW) 302 printf("vndopen(0x%x, 0x%x, 0x%x, %p)\n", dev, flags, mode, p); 303 #endif 304 if (unit >= numvnd) 305 return (ENXIO); 306 sc = &vnd_softc[unit]; 307 308 if ((error = vndlock(sc)) != 0) 309 return (error); 310 311 lp = sc->sc_dkdev.dk_label; 312 313 part = DISKPART(dev); 314 pmask = (1 << part); 315 316 /* 317 * If we're initialized, check to see if there are any other 318 * open partitions. If not, then it's safe to update the 319 * in-core disklabel. Only read the disklabel if it is 320 * not realdy valid. 321 */ 322 if ((sc->sc_flags & (VNF_INITED|VNF_VLABEL)) == VNF_INITED && 323 sc->sc_dkdev.dk_openmask == 0) 324 vndgetdisklabel(dev); 325 326 /* Check that the partitions exists. */ 327 if (part != RAW_PART) { 328 if (((sc->sc_flags & VNF_INITED) == 0) || 329 ((part >= lp->d_npartitions) || 330 (lp->d_partitions[part].p_fstype == FS_UNUSED))) { 331 error = ENXIO; 332 goto done; 333 } 334 } 335 336 /* Prevent our unit from being unconfigured while open. */ 337 switch (mode) { 338 case S_IFCHR: 339 sc->sc_dkdev.dk_copenmask |= pmask; 340 break; 341 342 case S_IFBLK: 343 sc->sc_dkdev.dk_bopenmask |= pmask; 344 break; 345 } 346 sc->sc_dkdev.dk_openmask = 347 sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask; 348 349 done: 350 vndunlock(sc); 351 return (error); 352 } 353 354 static int 355 vndclose(dev_t dev, int flags, int mode, struct proc *p) 356 { 357 int unit = vndunit(dev); 358 struct vnd_softc *sc; 359 int error = 0, part; 360 361 #ifdef DEBUG 362 if (vnddebug & VDB_FOLLOW) 363 printf("vndclose(0x%x, 0x%x, 0x%x, %p)\n", dev, flags, mode, p); 364 #endif 365 366 if (unit >= numvnd) 367 return (ENXIO); 368 sc = &vnd_softc[unit]; 369 370 if ((error = vndlock(sc)) != 0) 371 return (error); 372 373 part = DISKPART(dev); 374 375 /* ...that much closer to allowing unconfiguration... */ 376 switch (mode) { 377 case S_IFCHR: 378 sc->sc_dkdev.dk_copenmask &= ~(1 << part); 379 break; 380 381 case S_IFBLK: 382 sc->sc_dkdev.dk_bopenmask &= ~(1 << part); 383 break; 384 } 385 sc->sc_dkdev.dk_openmask = 386 sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask; 387 388 if (sc->sc_dkdev.dk_openmask == 0) { 389 if ((sc->sc_flags & VNF_KLABEL) == 0) 390 sc->sc_flags &= ~VNF_VLABEL; 391 } 392 393 vndunlock(sc); 394 return (0); 395 } 396 397 /* 398 * Qeue the request, and wakeup the kernel thread to handle it. 399 */ 400 static void 401 vndstrategy(struct buf *bp) 402 { 403 int unit = vndunit(bp->b_dev); 404 struct vnd_softc *vnd = &vnd_softc[unit]; 405 struct disklabel *lp = vnd->sc_dkdev.dk_label; 406 int s = splbio(); 407 408 bp->b_resid = bp->b_bcount; 409 410 if ((vnd->sc_flags & VNF_INITED) == 0) { 411 bp->b_error = ENXIO; 412 bp->b_flags |= B_ERROR; 413 goto done; 414 } 415 416 /* 417 * The transfer must be a whole number of blocks. 418 */ 419 if ((bp->b_bcount % lp->d_secsize) != 0) { 420 bp->b_error = EINVAL; 421 bp->b_flags |= B_ERROR; 422 goto done; 423 } 424 425 /* 426 * check if we're read-only. 427 */ 428 if ((vnd->sc_flags & VNF_READONLY) && !(bp->b_flags & B_READ)) { 429 bp->b_error = EACCES; 430 bp->b_flags |= B_ERROR; 431 goto done; 432 } 433 434 /* 435 * Do bounds checking and adjust transfer. If there's an error, 436 * the bounds check will flag that for us. 437 */ 438 if (DISKPART(bp->b_dev) != RAW_PART) { 439 if (bounds_check_with_label(&vnd->sc_dkdev, 440 bp, vnd->sc_flags & (VNF_WLABEL|VNF_LABELLING)) <= 0) 441 goto done; 442 } 443 444 /* If it's a nil transfer, wake up the top half now. */ 445 if (bp->b_bcount == 0) 446 goto done; 447 #ifdef DEBUG 448 if (vnddebug & VDB_FOLLOW) 449 printf("vndstrategy(%p): unit %d\n", bp, unit); 450 #endif 451 BUFQ_PUT(&vnd->sc_tab, bp); 452 wakeup(&vnd->sc_tab); 453 splx(s); 454 return; 455 done: 456 biodone(bp); 457 splx(s); 458 } 459 460 void 461 vndthread(void *arg) 462 { 463 struct vnd_softc *vnd = arg; 464 struct buf *bp; 465 struct vndxfer *vnx; 466 struct mount *mp; 467 int s, bsize, resid; 468 off_t bn; 469 caddr_t addr; 470 int sz, flags, error; 471 struct disklabel *lp; 472 struct partition *pp; 473 474 s = splbio(); 475 vnd->sc_flags |= VNF_KTHREAD; 476 wakeup(&vnd->sc_kthread); 477 478 /* 479 * Dequeue requests, break them into bsize pieces and submit using 480 * VOP_BMAP/VOP_STRATEGY. 481 */ 482 while ((vnd->sc_flags & VNF_VUNCONF) == 0) { 483 bp = BUFQ_GET(&vnd->sc_tab); 484 if (bp == NULL) { 485 tsleep(&vnd->sc_tab, PRIBIO, "vndbp", 0); 486 continue; 487 }; 488 splx(s); 489 490 #ifdef DEBUG 491 if (vnddebug & VDB_FOLLOW) 492 printf("vndthread(%p\n", bp); 493 #endif 494 lp = vnd->sc_dkdev.dk_label; 495 bp->b_resid = bp->b_bcount; 496 497 /* 498 * Put the block number in terms of the logical blocksize 499 * of the "device". 500 */ 501 bn = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); 502 503 /* 504 * Translate the partition-relative block number to an absolute. 505 */ 506 if (DISKPART(bp->b_dev) != RAW_PART) { 507 pp = &vnd->sc_dkdev.dk_label->d_partitions[ 508 DISKPART(bp->b_dev)]; 509 bn += pp->p_offset; 510 } 511 512 /* ...and convert to a byte offset within the file. */ 513 bn *= lp->d_secsize; 514 515 if (vnd->sc_vp->v_mount == NULL) { 516 bp->b_error = ENXIO; 517 bp->b_flags |= B_ERROR; 518 goto done; 519 } 520 bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize; 521 addr = bp->b_data; 522 flags = (bp->b_flags & (B_READ|B_ASYNC)) | B_CALL; 523 524 /* 525 * Allocate a header for this transfer and link it to the 526 * buffer 527 */ 528 s = splbio(); 529 vnx = VND_GETXFER(vnd); 530 splx(s); 531 vnx->vx_flags = VX_BUSY; 532 vnx->vx_error = 0; 533 vnx->vx_pending = 0; 534 vnx->vx_bp = bp; 535 536 if ((flags & B_READ) == 0) 537 vn_start_write(vnd->sc_vp, &mp, V_WAIT); 538 539 /* 540 * Feed requests sequentially. 541 * We do it this way to keep from flooding NFS servers if we 542 * are connected to an NFS file. This places the burden on 543 * the client rather than the server. 544 */ 545 for (resid = bp->b_resid; resid; resid -= sz) { 546 struct vndbuf *nbp; 547 struct vnode *vp; 548 daddr_t nbn; 549 int off, nra; 550 551 nra = 0; 552 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE); 553 error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra); 554 VOP_UNLOCK(vnd->sc_vp, 0); 555 556 if (error == 0 && (long)nbn == -1) 557 error = EIO; 558 559 /* 560 * If there was an error or a hole in the file...punt. 561 * Note that we may have to wait for any operations 562 * that we have already fired off before releasing 563 * the buffer. 564 * 565 * XXX we could deal with holes here but it would be 566 * a hassle (in the write case). 567 */ 568 if (error) { 569 s = splbio(); 570 vnx->vx_error = error; 571 goto out; 572 } 573 574 #ifdef DEBUG 575 if (!dovndcluster) 576 nra = 0; 577 #endif 578 579 if ((off = bn % bsize) != 0) 580 sz = bsize - off; 581 else 582 sz = (1 + nra) * bsize; 583 if (resid < sz) 584 sz = resid; 585 #ifdef DEBUG 586 if (vnddebug & VDB_IO) 587 printf("vndstrategy: vp %p/%p bn 0x%qx/0x%" PRIx64 588 " sz 0x%x\n", 589 vnd->sc_vp, vp, (long long)bn, nbn, sz); 590 #endif 591 592 s = splbio(); 593 while (vnd->sc_active >= vnd->sc_maxactive) { 594 tsleep(&vnd->sc_tab, PRIBIO, "vndac", 0); 595 } 596 vnd->sc_active++; 597 nbp = VND_GETBUF(vnd); 598 splx(s); 599 BUF_INIT(&nbp->vb_buf); 600 nbp->vb_buf.b_flags = flags; 601 nbp->vb_buf.b_bcount = sz; 602 nbp->vb_buf.b_bufsize = round_page((ulong)addr + sz) 603 - trunc_page((ulong) addr); 604 nbp->vb_buf.b_error = 0; 605 nbp->vb_buf.b_data = addr; 606 nbp->vb_buf.b_blkno = nbp->vb_buf.b_rawblkno = nbn + btodb(off); 607 nbp->vb_buf.b_proc = bp->b_proc; 608 nbp->vb_buf.b_iodone = vndiodone; 609 nbp->vb_buf.b_vp = vp; 610 611 nbp->vb_xfer = vnx; 612 613 BIO_COPYPRIO(&nbp->vb_buf, bp); 614 615 /* 616 * Just sort by block number 617 */ 618 s = splbio(); 619 if (vnx->vx_error != 0) { 620 VND_PUTBUF(vnd, nbp); 621 goto out; 622 } 623 vnx->vx_pending++; 624 #ifdef DEBUG 625 if (vnddebug & VDB_IO) 626 printf("vndstart(%ld): bp %p vp %p blkno " 627 "0x%" PRIx64 " flags %x addr %p cnt 0x%x\n", 628 (long) (vnd-vnd_softc), &nbp->vb_buf, 629 nbp->vb_buf.b_vp, nbp->vb_buf.b_blkno, 630 nbp->vb_buf.b_flags, nbp->vb_buf.b_data, 631 nbp->vb_buf.b_bcount); 632 #endif 633 634 /* Instrumentation. */ 635 disk_busy(&vnd->sc_dkdev); 636 637 if ((nbp->vb_buf.b_flags & B_READ) == 0) 638 vp->v_numoutput++; 639 VOP_STRATEGY(vp, &nbp->vb_buf); 640 641 splx(s); 642 bn += sz; 643 addr += sz; 644 } 645 646 s = splbio(); 647 648 out: /* Arrive here at splbio */ 649 if ((flags & B_READ) == 0) 650 vn_finished_write(mp, 0); 651 vnx->vx_flags &= ~VX_BUSY; 652 if (vnx->vx_pending == 0) { 653 if (vnx->vx_error != 0) { 654 bp->b_error = vnx->vx_error; 655 bp->b_flags |= B_ERROR; 656 } 657 VND_PUTXFER(vnd, vnx); 658 biodone(bp); 659 } 660 continue; 661 done: 662 biodone(bp); 663 s = splbio(); 664 } 665 666 vnd->sc_flags &= (~VNF_KTHREAD | VNF_VUNCONF); 667 wakeup(&vnd->sc_kthread); 668 splx(s); 669 kthread_exit(0); 670 } 671 672 673 static void 674 vndiodone(struct buf *bp) 675 { 676 struct vndbuf *vbp = (struct vndbuf *) bp; 677 struct vndxfer *vnx = (struct vndxfer *)vbp->vb_xfer; 678 struct buf *pbp = vnx->vx_bp; 679 struct vnd_softc *vnd = &vnd_softc[vndunit(pbp->b_dev)]; 680 int s, resid; 681 682 s = splbio(); 683 #ifdef DEBUG 684 if (vnddebug & VDB_IO) 685 printf("vndiodone(%ld): vbp %p vp %p blkno 0x%" PRIx64 686 " addr %p cnt 0x%x\n", 687 (long) (vnd-vnd_softc), vbp, vbp->vb_buf.b_vp, 688 vbp->vb_buf.b_blkno, vbp->vb_buf.b_data, 689 vbp->vb_buf.b_bcount); 690 #endif 691 692 resid = vbp->vb_buf.b_bcount - vbp->vb_buf.b_resid; 693 pbp->b_resid -= resid; 694 disk_unbusy(&vnd->sc_dkdev, resid, (pbp->b_flags & B_READ)); 695 vnx->vx_pending--; 696 697 if (vbp->vb_buf.b_error) { 698 #ifdef DEBUG 699 if (vnddebug & VDB_IO) 700 printf("vndiodone: vbp %p error %d\n", vbp, 701 vbp->vb_buf.b_error); 702 #endif 703 vnx->vx_error = vbp->vb_buf.b_error; 704 } 705 706 VND_PUTBUF(vnd, vbp); 707 708 /* 709 * Wrap up this transaction if it has run to completion or, in 710 * case of an error, when all auxiliary buffers have returned. 711 */ 712 if (vnx->vx_error != 0) { 713 pbp->b_flags |= B_ERROR; 714 pbp->b_error = vnx->vx_error; 715 if ((vnx->vx_flags & VX_BUSY) == 0 && vnx->vx_pending == 0) { 716 717 #ifdef DEBUG 718 if (vnddebug & VDB_IO) 719 printf("vndiodone: pbp %p iodone: error %d\n", 720 pbp, vnx->vx_error); 721 #endif 722 VND_PUTXFER(vnd, vnx); 723 biodone(pbp); 724 } 725 } else if (pbp->b_resid == 0) { 726 727 #ifdef DIAGNOSTIC 728 if (vnx->vx_pending != 0) 729 panic("vndiodone: vnx pending: %d", vnx->vx_pending); 730 #endif 731 732 if ((vnx->vx_flags & VX_BUSY) == 0) { 733 #ifdef DEBUG 734 if (vnddebug & VDB_IO) 735 printf("vndiodone: pbp %p iodone\n", pbp); 736 #endif 737 VND_PUTXFER(vnd, vnx); 738 biodone(pbp); 739 } 740 } 741 742 vnd->sc_active--; 743 wakeup(&vnd->sc_tab); 744 splx(s); 745 } 746 747 /* ARGSUSED */ 748 static int 749 vndread(dev_t dev, struct uio *uio, int flags) 750 { 751 int unit = vndunit(dev); 752 struct vnd_softc *sc; 753 754 #ifdef DEBUG 755 if (vnddebug & VDB_FOLLOW) 756 printf("vndread(0x%x, %p)\n", dev, uio); 757 #endif 758 759 if (unit >= numvnd) 760 return (ENXIO); 761 sc = &vnd_softc[unit]; 762 763 if ((sc->sc_flags & VNF_INITED) == 0) 764 return (ENXIO); 765 766 return (physio(vndstrategy, NULL, dev, B_READ, minphys, uio)); 767 } 768 769 /* ARGSUSED */ 770 static int 771 vndwrite(dev_t dev, struct uio *uio, int flags) 772 { 773 int unit = vndunit(dev); 774 struct vnd_softc *sc; 775 776 #ifdef DEBUG 777 if (vnddebug & VDB_FOLLOW) 778 printf("vndwrite(0x%x, %p)\n", dev, uio); 779 #endif 780 781 if (unit >= numvnd) 782 return (ENXIO); 783 sc = &vnd_softc[unit]; 784 785 if ((sc->sc_flags & VNF_INITED) == 0) 786 return (ENXIO); 787 788 return (physio(vndstrategy, NULL, dev, B_WRITE, minphys, uio)); 789 } 790 791 /* ARGSUSED */ 792 static int 793 vndioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 794 { 795 int unit = vndunit(dev); 796 struct vnd_softc *vnd; 797 struct vnd_ioctl *vio; 798 struct vattr vattr; 799 struct nameidata nd; 800 int error, part, pmask; 801 size_t geomsize; 802 int fflags; 803 #ifdef __HAVE_OLD_DISKLABEL 804 struct disklabel newlabel; 805 #endif 806 807 #ifdef DEBUG 808 if (vnddebug & VDB_FOLLOW) 809 printf("vndioctl(0x%x, 0x%lx, %p, 0x%x, %p): unit %d\n", 810 dev, cmd, data, flag, p, unit); 811 #endif 812 if (unit >= numvnd) 813 return (ENXIO); 814 815 vnd = &vnd_softc[unit]; 816 vio = (struct vnd_ioctl *)data; 817 818 /* Must be open for writes for these commands... */ 819 switch (cmd) { 820 case VNDIOCSET: 821 case VNDIOCCLR: 822 case DIOCSDINFO: 823 case DIOCWDINFO: 824 #ifdef __HAVE_OLD_DISKLABEL 825 case ODIOCSDINFO: 826 case ODIOCWDINFO: 827 #endif 828 case DIOCKLABEL: 829 case DIOCWLABEL: 830 if ((flag & FWRITE) == 0) 831 return (EBADF); 832 } 833 834 /* Must be initialized for these... */ 835 switch (cmd) { 836 case VNDIOCCLR: 837 case DIOCGDINFO: 838 case DIOCSDINFO: 839 case DIOCWDINFO: 840 case DIOCGPART: 841 case DIOCKLABEL: 842 case DIOCWLABEL: 843 case DIOCGDEFLABEL: 844 #ifdef __HAVE_OLD_DISKLABEL 845 case ODIOCGDINFO: 846 case ODIOCSDINFO: 847 case ODIOCWDINFO: 848 case ODIOCGDEFLABEL: 849 #endif 850 if ((vnd->sc_flags & VNF_INITED) == 0) 851 return (ENXIO); 852 } 853 854 switch (cmd) { 855 case VNDIOCSET: 856 if (vnd->sc_flags & VNF_INITED) 857 return (EBUSY); 858 859 if ((error = vndlock(vnd)) != 0) 860 return (error); 861 862 fflags = FREAD; 863 if ((vio->vnd_flags & VNDIOF_READONLY) == 0) 864 fflags |= FWRITE; 865 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p); 866 if ((error = vn_open(&nd, fflags, 0)) != 0) 867 goto unlock_and_exit; 868 error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p); 869 VOP_UNLOCK(nd.ni_vp, 0); 870 if (!error && nd.ni_vp->v_type != VREG) 871 error = EOPNOTSUPP; 872 if (error) 873 goto close_and_exit; 874 vnd->sc_vp = nd.ni_vp; 875 vnd->sc_size = btodb(vattr.va_size); /* note truncation */ 876 877 /* 878 * Use pseudo-geometry specified. If none was provided, 879 * use "standard" Adaptec fictitious geometry. 880 */ 881 if (vio->vnd_flags & VNDIOF_HASGEOM) { 882 883 memcpy(&vnd->sc_geom, &vio->vnd_geom, 884 sizeof(vio->vnd_geom)); 885 886 /* 887 * Sanity-check the sector size. 888 * XXX Don't allow secsize < DEV_BSIZE. Should 889 * XXX we? 890 */ 891 if (vnd->sc_geom.vng_secsize < DEV_BSIZE || 892 (vnd->sc_geom.vng_secsize % DEV_BSIZE) != 0 || 893 vnd->sc_geom.vng_ncylinders == 0 || 894 (vnd->sc_geom.vng_ntracks * 895 vnd->sc_geom.vng_nsectors) == 0) { 896 error = EINVAL; 897 goto close_and_exit; 898 } 899 900 /* 901 * Compute the size (in DEV_BSIZE blocks) specified 902 * by the geometry. 903 */ 904 geomsize = (vnd->sc_geom.vng_nsectors * 905 vnd->sc_geom.vng_ntracks * 906 vnd->sc_geom.vng_ncylinders) * 907 (vnd->sc_geom.vng_secsize / DEV_BSIZE); 908 909 /* 910 * Sanity-check the size against the specified 911 * geometry. 912 */ 913 if (vnd->sc_size < geomsize) { 914 error = EINVAL; 915 goto close_and_exit; 916 } 917 } else { 918 /* 919 * Size must be at least 2048 DEV_BSIZE blocks 920 * (1M) in order to use this geometry. 921 */ 922 if (vnd->sc_size < (32 * 64)) { 923 error = EINVAL; 924 goto close_and_exit; 925 } 926 927 vnd->sc_geom.vng_secsize = DEV_BSIZE; 928 vnd->sc_geom.vng_nsectors = 32; 929 vnd->sc_geom.vng_ntracks = 64; 930 vnd->sc_geom.vng_ncylinders = vnd->sc_size / (64 * 32); 931 } 932 933 if (vio->vnd_flags & VNDIOF_READONLY) { 934 vnd->sc_flags |= VNF_READONLY; 935 } 936 937 if ((error = vndsetcred(vnd, p->p_ucred)) != 0) 938 goto close_and_exit; 939 940 memset(vnd->sc_xname, 0, sizeof(vnd->sc_xname)); /* XXX */ 941 snprintf(vnd->sc_xname, sizeof(vnd->sc_xname), "vnd%d", unit); 942 943 944 vndthrottle(vnd, vnd->sc_vp); 945 vio->vnd_size = dbtob(vnd->sc_size); 946 vnd->sc_flags |= VNF_INITED; 947 948 /* create the kernel thread, wait for it to be up */ 949 error = kthread_create1(vndthread, vnd, &vnd->sc_kthread, 950 vnd->sc_xname); 951 if (error) 952 goto close_and_exit; 953 while ((vnd->sc_flags & VNF_KTHREAD) == 0) { 954 tsleep(&vnd->sc_kthread, PRIBIO, "vndthr", 0); 955 } 956 #ifdef DEBUG 957 if (vnddebug & VDB_INIT) 958 printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n", 959 vnd->sc_vp, (unsigned long) vnd->sc_size, 960 vnd->sc_geom.vng_secsize, 961 vnd->sc_geom.vng_nsectors, 962 vnd->sc_geom.vng_ntracks, 963 vnd->sc_geom.vng_ncylinders); 964 #endif 965 966 /* Attach the disk. */ 967 vnd->sc_dkdev.dk_name = vnd->sc_xname; 968 disk_attach(&vnd->sc_dkdev); 969 970 /* Initialize the xfer and buffer pools. */ 971 pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0, 972 0, 0, "vndxpl", NULL); 973 pool_init(&vnd->sc_vbpool, sizeof(struct vndbuf), 0, 974 0, 0, "vndbpl", NULL); 975 976 /* Try and read the disklabel. */ 977 vndgetdisklabel(dev); 978 979 vndunlock(vnd); 980 981 break; 982 983 close_and_exit: 984 (void) vn_close(nd.ni_vp, fflags, p->p_ucred, p); 985 unlock_and_exit: 986 vndunlock(vnd); 987 return (error); 988 989 case VNDIOCCLR: 990 if ((error = vndlock(vnd)) != 0) 991 return (error); 992 993 /* 994 * Don't unconfigure if any other partitions are open 995 * or if both the character and block flavors of this 996 * partition are open. 997 */ 998 part = DISKPART(dev); 999 pmask = (1 << part); 1000 if (((vnd->sc_dkdev.dk_openmask & ~pmask) || 1001 ((vnd->sc_dkdev.dk_bopenmask & pmask) && 1002 (vnd->sc_dkdev.dk_copenmask & pmask))) && 1003 !(vio->vnd_flags & VNDIOF_FORCE)) { 1004 vndunlock(vnd); 1005 return (EBUSY); 1006 } 1007 1008 /* 1009 * XXX vndclear() might call vndclose() implicitely; 1010 * release lock to avoid recursion 1011 */ 1012 vndunlock(vnd); 1013 vndclear(vnd, minor(dev)); 1014 #ifdef DEBUG 1015 if (vnddebug & VDB_INIT) 1016 printf("vndioctl: CLRed\n"); 1017 #endif 1018 1019 /* Destroy the xfer and buffer pools. */ 1020 pool_destroy(&vnd->sc_vxpool); 1021 pool_destroy(&vnd->sc_vbpool); 1022 1023 /* Detatch the disk. */ 1024 disk_detach(&vnd->sc_dkdev); 1025 1026 break; 1027 1028 case VNDIOCGET: { 1029 struct vnd_user *vnu; 1030 struct vattr va; 1031 1032 vnu = (struct vnd_user *)data; 1033 1034 if (vnu->vnu_unit == -1) 1035 vnu->vnu_unit = unit; 1036 if (vnu->vnu_unit >= numvnd) 1037 return (ENXIO); 1038 if (vnu->vnu_unit < 0) 1039 return (EINVAL); 1040 1041 vnd = &vnd_softc[vnu->vnu_unit]; 1042 1043 if (vnd->sc_flags & VNF_INITED) { 1044 error = VOP_GETATTR(vnd->sc_vp, &va, p->p_ucred, p); 1045 if (error) 1046 return (error); 1047 vnu->vnu_dev = va.va_fsid; 1048 vnu->vnu_ino = va.va_fileid; 1049 } 1050 else { 1051 /* unused is not an error */ 1052 vnu->vnu_dev = 0; 1053 vnu->vnu_ino = 0; 1054 } 1055 1056 break; 1057 } 1058 1059 case DIOCGDINFO: 1060 *(struct disklabel *)data = *(vnd->sc_dkdev.dk_label); 1061 break; 1062 1063 #ifdef __HAVE_OLD_DISKLABEL 1064 case ODIOCGDINFO: 1065 newlabel = *(vnd->sc_dkdev.dk_label); 1066 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1067 return ENOTTY; 1068 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1069 break; 1070 #endif 1071 1072 case DIOCGPART: 1073 ((struct partinfo *)data)->disklab = vnd->sc_dkdev.dk_label; 1074 ((struct partinfo *)data)->part = 1075 &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(dev)]; 1076 break; 1077 1078 case DIOCWDINFO: 1079 case DIOCSDINFO: 1080 #ifdef __HAVE_OLD_DISKLABEL 1081 case ODIOCWDINFO: 1082 case ODIOCSDINFO: 1083 #endif 1084 { 1085 struct disklabel *lp; 1086 1087 if ((error = vndlock(vnd)) != 0) 1088 return (error); 1089 1090 vnd->sc_flags |= VNF_LABELLING; 1091 1092 #ifdef __HAVE_OLD_DISKLABEL 1093 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 1094 memset(&newlabel, 0, sizeof newlabel); 1095 memcpy(&newlabel, data, sizeof (struct olddisklabel)); 1096 lp = &newlabel; 1097 } else 1098 #endif 1099 lp = (struct disklabel *)data; 1100 1101 error = setdisklabel(vnd->sc_dkdev.dk_label, 1102 lp, 0, vnd->sc_dkdev.dk_cpulabel); 1103 if (error == 0) { 1104 if (cmd == DIOCWDINFO 1105 #ifdef __HAVE_OLD_DISKLABEL 1106 || cmd == ODIOCWDINFO 1107 #endif 1108 ) 1109 error = writedisklabel(VNDLABELDEV(dev), 1110 vndstrategy, vnd->sc_dkdev.dk_label, 1111 vnd->sc_dkdev.dk_cpulabel); 1112 } 1113 1114 vnd->sc_flags &= ~VNF_LABELLING; 1115 1116 vndunlock(vnd); 1117 1118 if (error) 1119 return (error); 1120 break; 1121 } 1122 1123 case DIOCKLABEL: 1124 if (*(int *)data != 0) 1125 vnd->sc_flags |= VNF_KLABEL; 1126 else 1127 vnd->sc_flags &= ~VNF_KLABEL; 1128 break; 1129 1130 case DIOCWLABEL: 1131 if (*(int *)data != 0) 1132 vnd->sc_flags |= VNF_WLABEL; 1133 else 1134 vnd->sc_flags &= ~VNF_WLABEL; 1135 break; 1136 1137 case DIOCGDEFLABEL: 1138 vndgetdefaultlabel(vnd, (struct disklabel *)data); 1139 break; 1140 1141 #ifdef __HAVE_OLD_DISKLABEL 1142 case ODIOCGDEFLABEL: 1143 vndgetdefaultlabel(vnd, &newlabel); 1144 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1145 return ENOTTY; 1146 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1147 break; 1148 #endif 1149 1150 default: 1151 return (ENOTTY); 1152 } 1153 1154 return (0); 1155 } 1156 1157 /* 1158 * Duplicate the current processes' credentials. Since we are called only 1159 * as the result of a SET ioctl and only root can do that, any future access 1160 * to this "disk" is essentially as root. Note that credentials may change 1161 * if some other uid can write directly to the mapped file (NFS). 1162 */ 1163 static int 1164 vndsetcred(struct vnd_softc *vnd, struct ucred *cred) 1165 { 1166 struct uio auio; 1167 struct iovec aiov; 1168 char *tmpbuf; 1169 int error; 1170 1171 vnd->sc_cred = crdup(cred); 1172 tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK); 1173 1174 /* XXX: Horrible kludge to establish credentials for NFS */ 1175 aiov.iov_base = tmpbuf; 1176 aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size)); 1177 auio.uio_iov = &aiov; 1178 auio.uio_iovcnt = 1; 1179 auio.uio_offset = 0; 1180 auio.uio_rw = UIO_READ; 1181 auio.uio_segflg = UIO_SYSSPACE; 1182 auio.uio_resid = aiov.iov_len; 1183 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); 1184 error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred); 1185 if (error == 0) { 1186 /* 1187 * Because vnd does all IO directly through the vnode 1188 * we need to flush (at least) the buffer from the above 1189 * VOP_READ from the buffer cache to prevent cache 1190 * incoherencies. Also, be careful to write dirty 1191 * buffers back to stable storage. 1192 */ 1193 error = vinvalbuf(vnd->sc_vp, V_SAVE, vnd->sc_cred, 1194 curproc, 0, 0); 1195 } 1196 VOP_UNLOCK(vnd->sc_vp, 0); 1197 1198 free(tmpbuf, M_TEMP); 1199 return (error); 1200 } 1201 1202 /* 1203 * Set maxactive based on FS type 1204 */ 1205 static void 1206 vndthrottle(struct vnd_softc *vnd, struct vnode *vp) 1207 { 1208 #ifdef NFS 1209 extern int (**nfsv2_vnodeop_p)(void *); 1210 1211 if (vp->v_op == nfsv2_vnodeop_p) 1212 vnd->sc_maxactive = 2; 1213 else 1214 #endif 1215 vnd->sc_maxactive = 8; 1216 1217 if (vnd->sc_maxactive < 1) 1218 vnd->sc_maxactive = 1; 1219 } 1220 1221 #if 0 1222 static void 1223 vndshutdown(void) 1224 { 1225 struct vnd_softc *vnd; 1226 1227 for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++) 1228 if (vnd->sc_flags & VNF_INITED) 1229 vndclear(vnd); 1230 } 1231 #endif 1232 1233 static void 1234 vndclear(struct vnd_softc *vnd, int myminor) 1235 { 1236 struct vnode *vp = vnd->sc_vp; 1237 struct proc *p = curproc; /* XXX */ 1238 int fflags = FREAD; 1239 int bmaj, cmaj, i, mn; 1240 int s; 1241 1242 #ifdef DEBUG 1243 if (vnddebug & VDB_FOLLOW) 1244 printf("vndclear(%p): vp %p\n", vnd, vp); 1245 #endif 1246 /* locate the major number */ 1247 bmaj = bdevsw_lookup_major(&vnd_bdevsw); 1248 cmaj = cdevsw_lookup_major(&vnd_cdevsw); 1249 1250 /* Nuke the vnodes for any open instances */ 1251 for (i = 0; i < MAXPARTITIONS; i++) { 1252 mn = DISKMINOR(vnd->sc_unit, i); 1253 vdevgone(bmaj, mn, mn, VBLK); 1254 if (mn != myminor) /* XXX avoid to kill own vnode */ 1255 vdevgone(cmaj, mn, mn, VCHR); 1256 } 1257 1258 if ((vnd->sc_flags & VNF_READONLY) == 0) 1259 fflags |= FWRITE; 1260 1261 s = splbio(); 1262 bufq_drain(&vnd->sc_tab); 1263 splx(s); 1264 1265 vnd->sc_flags |= VNF_VUNCONF; 1266 wakeup(&vnd->sc_tab); 1267 while (vnd->sc_flags & VNF_KTHREAD) 1268 tsleep(&vnd->sc_kthread, PRIBIO, "vnthr", 0); 1269 1270 vnd->sc_flags &= 1271 ~(VNF_INITED | VNF_READONLY | VNF_VLABEL | VNF_VUNCONF); 1272 if (vp == (struct vnode *)0) 1273 panic("vndclear: null vp"); 1274 (void) vn_close(vp, fflags, vnd->sc_cred, p); 1275 crfree(vnd->sc_cred); 1276 vnd->sc_vp = (struct vnode *)0; 1277 vnd->sc_cred = (struct ucred *)0; 1278 vnd->sc_size = 0; 1279 } 1280 1281 static int 1282 vndsize(dev_t dev) 1283 { 1284 struct vnd_softc *sc; 1285 struct disklabel *lp; 1286 int part, unit, omask; 1287 int size; 1288 1289 unit = vndunit(dev); 1290 if (unit >= numvnd) 1291 return (-1); 1292 sc = &vnd_softc[unit]; 1293 1294 if ((sc->sc_flags & VNF_INITED) == 0) 1295 return (-1); 1296 1297 part = DISKPART(dev); 1298 omask = sc->sc_dkdev.dk_openmask & (1 << part); 1299 lp = sc->sc_dkdev.dk_label; 1300 1301 if (omask == 0 && vndopen(dev, 0, S_IFBLK, curproc)) 1302 return (-1); 1303 1304 if (lp->d_partitions[part].p_fstype != FS_SWAP) 1305 size = -1; 1306 else 1307 size = lp->d_partitions[part].p_size * 1308 (lp->d_secsize / DEV_BSIZE); 1309 1310 if (omask == 0 && vndclose(dev, 0, S_IFBLK, curproc)) 1311 return (-1); 1312 1313 return (size); 1314 } 1315 1316 static int 1317 vnddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) 1318 { 1319 1320 /* Not implemented. */ 1321 return ENXIO; 1322 } 1323 1324 static void 1325 vndgetdefaultlabel(struct vnd_softc *sc, struct disklabel *lp) 1326 { 1327 struct vndgeom *vng = &sc->sc_geom; 1328 struct partition *pp; 1329 1330 memset(lp, 0, sizeof(*lp)); 1331 1332 lp->d_secperunit = sc->sc_size / (vng->vng_secsize / DEV_BSIZE); 1333 lp->d_secsize = vng->vng_secsize; 1334 lp->d_nsectors = vng->vng_nsectors; 1335 lp->d_ntracks = vng->vng_ntracks; 1336 lp->d_ncylinders = vng->vng_ncylinders; 1337 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1338 1339 strncpy(lp->d_typename, "vnd", sizeof(lp->d_typename)); 1340 lp->d_type = DTYPE_VND; 1341 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1342 lp->d_rpm = 3600; 1343 lp->d_interleave = 1; 1344 lp->d_flags = 0; 1345 1346 pp = &lp->d_partitions[RAW_PART]; 1347 pp->p_offset = 0; 1348 pp->p_size = lp->d_secperunit; 1349 pp->p_fstype = FS_UNUSED; 1350 lp->d_npartitions = RAW_PART + 1; 1351 1352 lp->d_magic = DISKMAGIC; 1353 lp->d_magic2 = DISKMAGIC; 1354 lp->d_checksum = dkcksum(lp); 1355 } 1356 1357 /* 1358 * Read the disklabel from a vnd. If one is not present, create a fake one. 1359 */ 1360 static void 1361 vndgetdisklabel(dev_t dev) 1362 { 1363 struct vnd_softc *sc = &vnd_softc[vndunit(dev)]; 1364 const char *errstring; 1365 struct disklabel *lp = sc->sc_dkdev.dk_label; 1366 struct cpu_disklabel *clp = sc->sc_dkdev.dk_cpulabel; 1367 int i; 1368 1369 memset(clp, 0, sizeof(*clp)); 1370 1371 vndgetdefaultlabel(sc, lp); 1372 1373 /* 1374 * Call the generic disklabel extraction routine. 1375 */ 1376 errstring = readdisklabel(VNDLABELDEV(dev), vndstrategy, lp, clp); 1377 if (errstring) { 1378 /* 1379 * Lack of disklabel is common, but we print the warning 1380 * anyway, since it might contain other useful information. 1381 */ 1382 printf("%s: %s\n", sc->sc_xname, errstring); 1383 1384 /* 1385 * For historical reasons, if there's no disklabel 1386 * present, all partitions must be FS_BSDFFS and 1387 * occupy the entire disk. 1388 */ 1389 for (i = 0; i < MAXPARTITIONS; i++) { 1390 /* 1391 * Don't wipe out port specific hack (such as 1392 * dos partition hack of i386 port). 1393 */ 1394 if (lp->d_partitions[i].p_size != 0) 1395 continue; 1396 1397 lp->d_partitions[i].p_size = lp->d_secperunit; 1398 lp->d_partitions[i].p_offset = 0; 1399 lp->d_partitions[i].p_fstype = FS_BSDFFS; 1400 } 1401 1402 strncpy(lp->d_packname, "default label", 1403 sizeof(lp->d_packname)); 1404 1405 lp->d_npartitions = MAXPARTITIONS; 1406 lp->d_checksum = dkcksum(lp); 1407 } 1408 1409 /* In-core label now valid. */ 1410 sc->sc_flags |= VNF_VLABEL; 1411 } 1412 1413 /* 1414 * Wait interruptibly for an exclusive lock. 1415 * 1416 * XXX 1417 * Several drivers do this; it should be abstracted and made MP-safe. 1418 */ 1419 static int 1420 vndlock(struct vnd_softc *sc) 1421 { 1422 int error; 1423 1424 while ((sc->sc_flags & VNF_LOCKED) != 0) { 1425 sc->sc_flags |= VNF_WANTED; 1426 if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0) 1427 return (error); 1428 } 1429 sc->sc_flags |= VNF_LOCKED; 1430 return (0); 1431 } 1432 1433 /* 1434 * Unlock and wake up any waiters. 1435 */ 1436 static void 1437 vndunlock(struct vnd_softc *sc) 1438 { 1439 1440 sc->sc_flags &= ~VNF_LOCKED; 1441 if ((sc->sc_flags & VNF_WANTED) != 0) { 1442 sc->sc_flags &= ~VNF_WANTED; 1443 wakeup(sc); 1444 } 1445 } 1446