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