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