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