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