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