1 /* $NetBSD: dk.c,v 1.47 2009/07/21 19:41:00 dyoung Exp $ */ 2 3 /*- 4 * Copyright (c) 2004, 2005, 2006, 2007 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.47 2009/07/21 19:41:00 dyoung Exp $"); 34 35 #include "opt_dkwedge.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/proc.h> 40 #include <sys/errno.h> 41 #include <sys/pool.h> 42 #include <sys/ioctl.h> 43 #include <sys/disklabel.h> 44 #include <sys/disk.h> 45 #include <sys/fcntl.h> 46 #include <sys/buf.h> 47 #include <sys/bufq.h> 48 #include <sys/vnode.h> 49 #include <sys/stat.h> 50 #include <sys/conf.h> 51 #include <sys/callout.h> 52 #include <sys/kernel.h> 53 #include <sys/malloc.h> 54 #include <sys/device.h> 55 #include <sys/kauth.h> 56 57 #include <miscfs/specfs/specdev.h> 58 59 MALLOC_DEFINE(M_DKWEDGE, "dkwedge", "Disk wedge structures"); 60 61 typedef enum { 62 DKW_STATE_LARVAL = 0, 63 DKW_STATE_RUNNING = 1, 64 DKW_STATE_DYING = 2, 65 DKW_STATE_DEAD = 666 66 } dkwedge_state_t; 67 68 struct dkwedge_softc { 69 struct device *sc_dev; /* pointer to our pseudo-device */ 70 struct cfdata sc_cfdata; /* our cfdata structure */ 71 uint8_t sc_wname[128]; /* wedge name (Unicode, UTF-8) */ 72 73 dkwedge_state_t sc_state; /* state this wedge is in */ 74 75 struct disk *sc_parent; /* parent disk */ 76 daddr_t sc_offset; /* LBA offset of wedge in parent */ 77 uint64_t sc_size; /* size of wedge in blocks */ 78 char sc_ptype[32]; /* partition type */ 79 dev_t sc_pdev; /* cached parent's dev_t */ 80 /* link on parent's wedge list */ 81 LIST_ENTRY(dkwedge_softc) sc_plink; 82 83 struct disk sc_dk; /* our own disk structure */ 84 struct bufq_state *sc_bufq; /* buffer queue */ 85 struct callout sc_restart_ch; /* callout to restart I/O */ 86 87 u_int sc_iopend; /* I/Os pending */ 88 int sc_flags; /* flags (splbio) */ 89 }; 90 91 #define DK_F_WAIT_DRAIN 0x0001 /* waiting for I/O to drain */ 92 93 static void dkstart(struct dkwedge_softc *); 94 static void dkiodone(struct buf *); 95 static void dkrestart(void *); 96 97 static int dklastclose(struct dkwedge_softc *); 98 static int dkwedge_detach(device_t, int); 99 100 static dev_type_open(dkopen); 101 static dev_type_close(dkclose); 102 static dev_type_read(dkread); 103 static dev_type_write(dkwrite); 104 static dev_type_ioctl(dkioctl); 105 static dev_type_strategy(dkstrategy); 106 static dev_type_dump(dkdump); 107 static dev_type_size(dksize); 108 109 const struct bdevsw dk_bdevsw = { 110 dkopen, dkclose, dkstrategy, dkioctl, dkdump, dksize, D_DISK 111 }; 112 113 const struct cdevsw dk_cdevsw = { 114 dkopen, dkclose, dkread, dkwrite, dkioctl, 115 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 116 }; 117 118 static struct dkwedge_softc **dkwedges; 119 static u_int ndkwedges; 120 static krwlock_t dkwedges_lock; 121 122 static LIST_HEAD(, dkwedge_discovery_method) dkwedge_discovery_methods; 123 static krwlock_t dkwedge_discovery_methods_lock; 124 125 /* 126 * dkwedge_match: 127 * 128 * Autoconfiguration match function for pseudo-device glue. 129 */ 130 static int 131 dkwedge_match(device_t parent, cfdata_t match, 132 void *aux) 133 { 134 135 /* Pseudo-device; always present. */ 136 return (1); 137 } 138 139 /* 140 * dkwedge_attach: 141 * 142 * Autoconfiguration attach function for pseudo-device glue. 143 */ 144 static void 145 dkwedge_attach(device_t parent, device_t self, 146 void *aux) 147 { 148 149 if (!pmf_device_register(self, NULL, NULL)) 150 aprint_error_dev(self, "couldn't establish power handler\n"); 151 } 152 153 CFDRIVER_DECL(dk, DV_DISK, NULL); 154 CFATTACH_DECL3_NEW(dk, 0, 155 dkwedge_match, dkwedge_attach, dkwedge_detach, NULL, NULL, NULL, 156 DVF_DETACH_SHUTDOWN); 157 158 /* 159 * dkwedge_wait_drain: 160 * 161 * Wait for I/O on the wedge to drain. 162 * NOTE: Must be called at splbio()! 163 */ 164 static void 165 dkwedge_wait_drain(struct dkwedge_softc *sc) 166 { 167 168 while (sc->sc_iopend != 0) { 169 sc->sc_flags |= DK_F_WAIT_DRAIN; 170 (void) tsleep(&sc->sc_iopend, PRIBIO, "dkdrn", 0); 171 } 172 } 173 174 /* 175 * dkwedge_compute_pdev: 176 * 177 * Compute the parent disk's dev_t. 178 */ 179 static int 180 dkwedge_compute_pdev(const char *pname, dev_t *pdevp) 181 { 182 const char *name, *cp; 183 int punit, pmaj; 184 char devname[16]; 185 186 name = pname; 187 if ((pmaj = devsw_name2blk(name, devname, sizeof(devname))) == -1) 188 return (ENODEV); 189 190 name += strlen(devname); 191 for (cp = name, punit = 0; *cp >= '0' && *cp <= '9'; cp++) 192 punit = (punit * 10) + (*cp - '0'); 193 if (cp == name) { 194 /* Invalid parent disk name. */ 195 return (ENODEV); 196 } 197 198 *pdevp = MAKEDISKDEV(pmaj, punit, RAW_PART); 199 200 return (0); 201 } 202 203 /* 204 * dkwedge_array_expand: 205 * 206 * Expand the dkwedges array. 207 */ 208 static void 209 dkwedge_array_expand(void) 210 { 211 int newcnt = ndkwedges + 16; 212 struct dkwedge_softc **newarray, **oldarray; 213 214 newarray = malloc(newcnt * sizeof(*newarray), M_DKWEDGE, 215 M_WAITOK|M_ZERO); 216 if ((oldarray = dkwedges) != NULL) 217 memcpy(newarray, dkwedges, ndkwedges * sizeof(*newarray)); 218 dkwedges = newarray; 219 ndkwedges = newcnt; 220 if (oldarray != NULL) 221 free(oldarray, M_DKWEDGE); 222 } 223 224 /* 225 * dkwedge_add: [exported function] 226 * 227 * Add a disk wedge based on the provided information. 228 * 229 * The incoming dkw_devname[] is ignored, instead being 230 * filled in and returned to the caller. 231 */ 232 int 233 dkwedge_add(struct dkwedge_info *dkw) 234 { 235 struct dkwedge_softc *sc, *lsc; 236 struct disk *pdk; 237 u_int unit; 238 int error; 239 dev_t pdev; 240 241 dkw->dkw_parent[sizeof(dkw->dkw_parent) - 1] = '\0'; 242 pdk = disk_find(dkw->dkw_parent); 243 if (pdk == NULL) 244 return (ENODEV); 245 246 error = dkwedge_compute_pdev(pdk->dk_name, &pdev); 247 if (error) 248 return (error); 249 250 if (dkw->dkw_offset < 0) 251 return (EINVAL); 252 253 sc = malloc(sizeof(*sc), M_DKWEDGE, M_WAITOK|M_ZERO); 254 sc->sc_state = DKW_STATE_LARVAL; 255 sc->sc_parent = pdk; 256 sc->sc_pdev = pdev; 257 sc->sc_offset = dkw->dkw_offset; 258 sc->sc_size = dkw->dkw_size; 259 260 memcpy(sc->sc_wname, dkw->dkw_wname, sizeof(sc->sc_wname)); 261 sc->sc_wname[sizeof(sc->sc_wname) - 1] = '\0'; 262 263 memcpy(sc->sc_ptype, dkw->dkw_ptype, sizeof(sc->sc_ptype)); 264 sc->sc_ptype[sizeof(sc->sc_ptype) - 1] = '\0'; 265 266 bufq_alloc(&sc->sc_bufq, "fcfs", 0); 267 268 callout_init(&sc->sc_restart_ch, 0); 269 callout_setfunc(&sc->sc_restart_ch, dkrestart, sc); 270 271 /* 272 * Wedge will be added; increment the wedge count for the parent. 273 * Only allow this to happend if RAW_PART is the only thing open. 274 */ 275 mutex_enter(&pdk->dk_openlock); 276 if (pdk->dk_openmask & ~(1 << RAW_PART)) 277 error = EBUSY; 278 else { 279 /* Check for wedge overlap. */ 280 LIST_FOREACH(lsc, &pdk->dk_wedges, sc_plink) { 281 daddr_t lastblk = sc->sc_offset + sc->sc_size - 1; 282 daddr_t llastblk = lsc->sc_offset + lsc->sc_size - 1; 283 284 if (sc->sc_offset >= lsc->sc_offset && 285 sc->sc_offset <= llastblk) { 286 /* Overlaps the tail of the exsiting wedge. */ 287 break; 288 } 289 if (lastblk >= lsc->sc_offset && 290 lastblk <= llastblk) { 291 /* Overlaps the head of the existing wedge. */ 292 break; 293 } 294 } 295 if (lsc != NULL) 296 error = EINVAL; 297 else { 298 pdk->dk_nwedges++; 299 LIST_INSERT_HEAD(&pdk->dk_wedges, sc, sc_plink); 300 } 301 } 302 mutex_exit(&pdk->dk_openlock); 303 if (error) { 304 bufq_free(sc->sc_bufq); 305 free(sc, M_DKWEDGE); 306 return (error); 307 } 308 309 /* Fill in our cfdata for the pseudo-device glue. */ 310 sc->sc_cfdata.cf_name = dk_cd.cd_name; 311 sc->sc_cfdata.cf_atname = dk_ca.ca_name; 312 /* sc->sc_cfdata.cf_unit set below */ 313 sc->sc_cfdata.cf_fstate = FSTATE_STAR; 314 315 /* Insert the larval wedge into the array. */ 316 rw_enter(&dkwedges_lock, RW_WRITER); 317 for (error = 0;;) { 318 struct dkwedge_softc **scpp; 319 320 /* 321 * Check for a duplicate wname while searching for 322 * a slot. 323 */ 324 for (scpp = NULL, unit = 0; unit < ndkwedges; unit++) { 325 if (dkwedges[unit] == NULL) { 326 if (scpp == NULL) { 327 scpp = &dkwedges[unit]; 328 sc->sc_cfdata.cf_unit = unit; 329 } 330 } else { 331 /* XXX Unicode. */ 332 if (strcmp(dkwedges[unit]->sc_wname, 333 sc->sc_wname) == 0) { 334 error = EEXIST; 335 break; 336 } 337 } 338 } 339 if (error) 340 break; 341 KASSERT(unit == ndkwedges); 342 if (scpp == NULL) 343 dkwedge_array_expand(); 344 else { 345 KASSERT(scpp == &dkwedges[sc->sc_cfdata.cf_unit]); 346 *scpp = sc; 347 break; 348 } 349 } 350 rw_exit(&dkwedges_lock); 351 if (error) { 352 mutex_enter(&pdk->dk_openlock); 353 pdk->dk_nwedges--; 354 LIST_REMOVE(sc, sc_plink); 355 mutex_exit(&pdk->dk_openlock); 356 357 bufq_free(sc->sc_bufq); 358 free(sc, M_DKWEDGE); 359 return (error); 360 } 361 362 /* 363 * Now that we know the unit #, attach a pseudo-device for 364 * this wedge instance. This will provide us with the 365 * "struct device" necessary for glue to other parts of the 366 * system. 367 * 368 * This should never fail, unless we're almost totally out of 369 * memory. 370 */ 371 if ((sc->sc_dev = config_attach_pseudo(&sc->sc_cfdata)) == NULL) { 372 aprint_error("%s%u: unable to attach pseudo-device\n", 373 sc->sc_cfdata.cf_name, sc->sc_cfdata.cf_unit); 374 375 rw_enter(&dkwedges_lock, RW_WRITER); 376 dkwedges[sc->sc_cfdata.cf_unit] = NULL; 377 rw_exit(&dkwedges_lock); 378 379 mutex_enter(&pdk->dk_openlock); 380 pdk->dk_nwedges--; 381 LIST_REMOVE(sc, sc_plink); 382 mutex_exit(&pdk->dk_openlock); 383 384 bufq_free(sc->sc_bufq); 385 free(sc, M_DKWEDGE); 386 return (ENOMEM); 387 } 388 389 /* Return the devname to the caller. */ 390 strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev), 391 sizeof(dkw->dkw_devname)); 392 393 /* 394 * XXX Really ought to make the disk_attach() and the changing 395 * of state to RUNNING atomic. 396 */ 397 398 disk_init(&sc->sc_dk, device_xname(sc->sc_dev), NULL); 399 disk_attach(&sc->sc_dk); 400 401 /* Disk wedge is ready for use! */ 402 sc->sc_state = DKW_STATE_RUNNING; 403 404 /* Announce our arrival. */ 405 aprint_normal("%s at %s: %s\n", device_xname(sc->sc_dev), pdk->dk_name, 406 sc->sc_wname); /* XXX Unicode */ 407 aprint_normal("%s: %"PRIu64" blocks at %"PRId64", type: %s\n", 408 device_xname(sc->sc_dev), sc->sc_size, sc->sc_offset, sc->sc_ptype); 409 410 return (0); 411 } 412 413 /* 414 * dkwedge_find: 415 * 416 * Lookup a disk wedge based on the provided information. 417 * NOTE: We look up the wedge based on the wedge devname, 418 * not wname. 419 * 420 * Return NULL if the wedge is not found, otherwise return 421 * the wedge's softc. Assign the wedge's unit number to unitp 422 * if unitp is not NULL. 423 */ 424 static struct dkwedge_softc * 425 dkwedge_find(struct dkwedge_info *dkw, u_int *unitp) 426 { 427 struct dkwedge_softc *sc = NULL; 428 u_int unit; 429 430 /* Find our softc. */ 431 dkw->dkw_devname[sizeof(dkw->dkw_devname) - 1] = '\0'; 432 rw_enter(&dkwedges_lock, RW_READER); 433 for (unit = 0; unit < ndkwedges; unit++) { 434 if ((sc = dkwedges[unit]) != NULL && 435 strcmp(device_xname(sc->sc_dev), dkw->dkw_devname) == 0 && 436 strcmp(sc->sc_parent->dk_name, dkw->dkw_parent) == 0) { 437 break; 438 } 439 } 440 rw_exit(&dkwedges_lock); 441 if (unit == ndkwedges) 442 return NULL; 443 444 if (unitp != NULL) 445 *unitp = unit; 446 447 return sc; 448 } 449 450 /* 451 * dkwedge_del: [exported function] 452 * 453 * Delete a disk wedge based on the provided information. 454 * NOTE: We look up the wedge based on the wedge devname, 455 * not wname. 456 */ 457 int 458 dkwedge_del(struct dkwedge_info *dkw) 459 { 460 struct dkwedge_softc *sc = NULL; 461 462 /* Find our softc. */ 463 if ((sc = dkwedge_find(dkw, NULL)) == NULL) 464 return (ESRCH); 465 466 return config_detach(sc->sc_dev, DETACH_FORCE | DETACH_QUIET); 467 } 468 469 static int 470 dkwedge_begindetach(struct dkwedge_softc *sc, int flags) 471 { 472 struct disk *dk = &sc->sc_dk; 473 int rc; 474 475 rc = 0; 476 mutex_enter(&dk->dk_openlock); 477 mutex_enter(&sc->sc_parent->dk_rawlock); 478 if (dk->dk_openmask == 0) 479 ; /* nothing to do */ 480 else if ((flags & DETACH_FORCE) == 0) 481 rc = EBUSY; 482 else 483 rc = dklastclose(sc); 484 mutex_exit(&sc->sc_parent->dk_rawlock); 485 mutex_exit(&dk->dk_openlock); 486 487 return rc; 488 } 489 490 /* 491 * dkwedge_detach: 492 * 493 * Autoconfiguration detach function for pseudo-device glue. 494 */ 495 static int 496 dkwedge_detach(device_t self, int flags) 497 { 498 struct dkwedge_softc *sc = NULL; 499 u_int unit; 500 int bmaj, cmaj, rc, s; 501 502 rw_enter(&dkwedges_lock, RW_WRITER); 503 for (unit = 0; unit < ndkwedges; unit++) { 504 if ((sc = dkwedges[unit]) != NULL && sc->sc_dev == self) 505 break; 506 } 507 if (unit == ndkwedges) 508 rc = ENXIO; 509 else if ((rc = dkwedge_begindetach(sc, flags)) == 0) { 510 /* Mark the wedge as dying. */ 511 sc->sc_state = DKW_STATE_DYING; 512 } 513 rw_exit(&dkwedges_lock); 514 515 if (rc != 0) 516 return rc; 517 518 pmf_device_deregister(self); 519 520 /* Locate the wedge major numbers. */ 521 bmaj = bdevsw_lookup_major(&dk_bdevsw); 522 cmaj = cdevsw_lookup_major(&dk_cdevsw); 523 524 /* Kill any pending restart. */ 525 callout_stop(&sc->sc_restart_ch); 526 527 /* 528 * dkstart() will kill any queued buffers now that the 529 * state of the wedge is not RUNNING. Once we've done 530 * that, wait for any other pending I/O to complete. 531 */ 532 s = splbio(); 533 dkstart(sc); 534 dkwedge_wait_drain(sc); 535 splx(s); 536 537 /* Nuke the vnodes for any open instances. */ 538 vdevgone(bmaj, unit, unit, VBLK); 539 vdevgone(cmaj, unit, unit, VCHR); 540 541 /* Clean up the parent. */ 542 mutex_enter(&sc->sc_dk.dk_openlock); 543 mutex_enter(&sc->sc_parent->dk_rawlock); 544 if (sc->sc_dk.dk_openmask) { 545 if (sc->sc_parent->dk_rawopens-- == 1) { 546 KASSERT(sc->sc_parent->dk_rawvp != NULL); 547 (void) vn_close(sc->sc_parent->dk_rawvp, FREAD | FWRITE, 548 NOCRED); 549 sc->sc_parent->dk_rawvp = NULL; 550 } 551 sc->sc_dk.dk_openmask = 0; 552 } 553 mutex_exit(&sc->sc_parent->dk_rawlock); 554 mutex_exit(&sc->sc_dk.dk_openlock); 555 556 /* Announce our departure. */ 557 aprint_normal("%s at %s (%s) deleted\n", device_xname(sc->sc_dev), 558 sc->sc_parent->dk_name, 559 sc->sc_wname); /* XXX Unicode */ 560 561 mutex_enter(&sc->sc_parent->dk_openlock); 562 sc->sc_parent->dk_nwedges--; 563 LIST_REMOVE(sc, sc_plink); 564 mutex_exit(&sc->sc_parent->dk_openlock); 565 566 /* Delete our buffer queue. */ 567 bufq_free(sc->sc_bufq); 568 569 /* Detach from the disk list. */ 570 disk_detach(&sc->sc_dk); 571 disk_destroy(&sc->sc_dk); 572 573 /* Poof. */ 574 rw_enter(&dkwedges_lock, RW_WRITER); 575 dkwedges[unit] = NULL; 576 sc->sc_state = DKW_STATE_DEAD; 577 rw_exit(&dkwedges_lock); 578 579 free(sc, M_DKWEDGE); 580 581 return 0; 582 } 583 584 /* 585 * dkwedge_delall: [exported function] 586 * 587 * Delete all of the wedges on the specified disk. Used when 588 * a disk is being detached. 589 */ 590 void 591 dkwedge_delall(struct disk *pdk) 592 { 593 struct dkwedge_info dkw; 594 struct dkwedge_softc *sc; 595 596 for (;;) { 597 mutex_enter(&pdk->dk_openlock); 598 if ((sc = LIST_FIRST(&pdk->dk_wedges)) == NULL) { 599 KASSERT(pdk->dk_nwedges == 0); 600 mutex_exit(&pdk->dk_openlock); 601 return; 602 } 603 strcpy(dkw.dkw_parent, pdk->dk_name); 604 strlcpy(dkw.dkw_devname, device_xname(sc->sc_dev), 605 sizeof(dkw.dkw_devname)); 606 mutex_exit(&pdk->dk_openlock); 607 (void) dkwedge_del(&dkw); 608 } 609 } 610 611 /* 612 * dkwedge_list: [exported function] 613 * 614 * List all of the wedges on a particular disk. 615 * If p == NULL, the buffer is in kernel space. Otherwise, it is 616 * in user space of the specified process. 617 */ 618 int 619 dkwedge_list(struct disk *pdk, struct dkwedge_list *dkwl, struct lwp *l) 620 { 621 struct uio uio; 622 struct iovec iov; 623 struct dkwedge_softc *sc; 624 struct dkwedge_info dkw; 625 struct vmspace *vm; 626 int error = 0; 627 628 iov.iov_base = dkwl->dkwl_buf; 629 iov.iov_len = dkwl->dkwl_bufsize; 630 631 uio.uio_iov = &iov; 632 uio.uio_iovcnt = 1; 633 uio.uio_offset = 0; 634 uio.uio_resid = dkwl->dkwl_bufsize; 635 uio.uio_rw = UIO_READ; 636 if (l == NULL) { 637 UIO_SETUP_SYSSPACE(&uio); 638 } else { 639 error = proc_vmspace_getref(l->l_proc, &vm); 640 if (error) { 641 return error; 642 } 643 uio.uio_vmspace = vm; 644 } 645 646 dkwl->dkwl_ncopied = 0; 647 648 mutex_enter(&pdk->dk_openlock); 649 LIST_FOREACH(sc, &pdk->dk_wedges, sc_plink) { 650 if (uio.uio_resid < sizeof(dkw)) 651 break; 652 653 if (sc->sc_state != DKW_STATE_RUNNING) 654 continue; 655 656 strlcpy(dkw.dkw_devname, device_xname(sc->sc_dev), 657 sizeof(dkw.dkw_devname)); 658 memcpy(dkw.dkw_wname, sc->sc_wname, sizeof(dkw.dkw_wname)); 659 dkw.dkw_wname[sizeof(dkw.dkw_wname) - 1] = '\0'; 660 strcpy(dkw.dkw_parent, sc->sc_parent->dk_name); 661 dkw.dkw_offset = sc->sc_offset; 662 dkw.dkw_size = sc->sc_size; 663 strcpy(dkw.dkw_ptype, sc->sc_ptype); 664 665 error = uiomove(&dkw, sizeof(dkw), &uio); 666 if (error) 667 break; 668 dkwl->dkwl_ncopied++; 669 } 670 dkwl->dkwl_nwedges = pdk->dk_nwedges; 671 mutex_exit(&pdk->dk_openlock); 672 673 if (l != NULL) { 674 uvmspace_free(vm); 675 } 676 677 return (error); 678 } 679 680 device_t 681 dkwedge_find_by_wname(const char *wname) 682 { 683 device_t dv = NULL; 684 struct dkwedge_softc *sc; 685 int i; 686 687 rw_enter(&dkwedges_lock, RW_WRITER); 688 for (i = 0; i < ndkwedges; i++) { 689 if ((sc = dkwedges[i]) == NULL) 690 continue; 691 if (strcmp(sc->sc_wname, wname) == 0) { 692 if (dv != NULL) { 693 printf( 694 "WARNING: double match for wedge name %s " 695 "(%s, %s)\n", wname, device_xname(dv), 696 device_xname(sc->sc_dev)); 697 continue; 698 } 699 dv = sc->sc_dev; 700 } 701 } 702 rw_exit(&dkwedges_lock); 703 return dv; 704 } 705 706 void 707 dkwedge_print_wnames(void) 708 { 709 struct dkwedge_softc *sc; 710 int i; 711 712 rw_enter(&dkwedges_lock, RW_WRITER); 713 for (i = 0; i < ndkwedges; i++) { 714 if ((sc = dkwedges[i]) == NULL) 715 continue; 716 printf(" wedge:%s", sc->sc_wname); 717 } 718 rw_exit(&dkwedges_lock); 719 } 720 721 /* 722 * dkwedge_set_bootwedge 723 * 724 * Set the booted_wedge global based on the specified parent name 725 * and offset/length. 726 */ 727 void 728 dkwedge_set_bootwedge(device_t parent, daddr_t startblk, uint64_t nblks) 729 { 730 struct dkwedge_softc *sc; 731 int i; 732 733 rw_enter(&dkwedges_lock, RW_WRITER); 734 for (i = 0; i < ndkwedges; i++) { 735 if ((sc = dkwedges[i]) == NULL) 736 continue; 737 if (strcmp(sc->sc_parent->dk_name, device_xname(parent)) == 0 && 738 sc->sc_offset == startblk && 739 sc->sc_size == nblks) { 740 if (booted_wedge) { 741 printf("WARNING: double match for boot wedge " 742 "(%s, %s)\n", 743 device_xname(booted_wedge), 744 device_xname(sc->sc_dev)); 745 continue; 746 } 747 booted_device = parent; 748 booted_wedge = sc->sc_dev; 749 booted_partition = 0; 750 } 751 } 752 /* 753 * XXX What if we don't find one? Should we create a special 754 * XXX root wedge? 755 */ 756 rw_exit(&dkwedges_lock); 757 } 758 759 /* 760 * We need a dummy object to stuff into the dkwedge discovery method link 761 * set to ensure that there is always at least one object in the set. 762 */ 763 static struct dkwedge_discovery_method dummy_discovery_method; 764 __link_set_add_bss(dkwedge_methods, dummy_discovery_method); 765 766 /* 767 * dkwedge_init: 768 * 769 * Initialize the disk wedge subsystem. 770 */ 771 void 772 dkwedge_init(void) 773 { 774 __link_set_decl(dkwedge_methods, struct dkwedge_discovery_method); 775 struct dkwedge_discovery_method * const *ddmp; 776 struct dkwedge_discovery_method *lddm, *ddm; 777 778 rw_init(&dkwedges_lock); 779 rw_init(&dkwedge_discovery_methods_lock); 780 781 if (config_cfdriver_attach(&dk_cd) != 0) 782 panic("dkwedge: unable to attach cfdriver"); 783 if (config_cfattach_attach(dk_cd.cd_name, &dk_ca) != 0) 784 panic("dkwedge: unable to attach cfattach"); 785 786 rw_enter(&dkwedge_discovery_methods_lock, RW_WRITER); 787 788 LIST_INIT(&dkwedge_discovery_methods); 789 790 __link_set_foreach(ddmp, dkwedge_methods) { 791 ddm = *ddmp; 792 if (ddm == &dummy_discovery_method) 793 continue; 794 if (LIST_EMPTY(&dkwedge_discovery_methods)) { 795 LIST_INSERT_HEAD(&dkwedge_discovery_methods, 796 ddm, ddm_list); 797 continue; 798 } 799 LIST_FOREACH(lddm, &dkwedge_discovery_methods, ddm_list) { 800 if (ddm->ddm_priority == lddm->ddm_priority) { 801 aprint_error("dk-method-%s: method \"%s\" " 802 "already exists at priority %d\n", 803 ddm->ddm_name, lddm->ddm_name, 804 lddm->ddm_priority); 805 /* Not inserted. */ 806 break; 807 } 808 if (ddm->ddm_priority < lddm->ddm_priority) { 809 /* Higher priority; insert before. */ 810 LIST_INSERT_BEFORE(lddm, ddm, ddm_list); 811 break; 812 } 813 if (LIST_NEXT(lddm, ddm_list) == NULL) { 814 /* Last one; insert after. */ 815 KASSERT(lddm->ddm_priority < ddm->ddm_priority); 816 LIST_INSERT_AFTER(lddm, ddm, ddm_list); 817 break; 818 } 819 } 820 } 821 822 rw_exit(&dkwedge_discovery_methods_lock); 823 } 824 825 #ifdef DKWEDGE_AUTODISCOVER 826 int dkwedge_autodiscover = 1; 827 #else 828 int dkwedge_autodiscover = 0; 829 #endif 830 831 /* 832 * dkwedge_discover: [exported function] 833 * 834 * Discover the wedges on a newly attached disk. 835 */ 836 void 837 dkwedge_discover(struct disk *pdk) 838 { 839 struct dkwedge_discovery_method *ddm; 840 struct vnode *vp; 841 int error; 842 dev_t pdev; 843 844 /* 845 * Require people playing with wedges to enable this explicitly. 846 */ 847 if (dkwedge_autodiscover == 0) 848 return; 849 850 rw_enter(&dkwedge_discovery_methods_lock, RW_READER); 851 852 error = dkwedge_compute_pdev(pdk->dk_name, &pdev); 853 if (error) { 854 aprint_error("%s: unable to compute pdev, error = %d\n", 855 pdk->dk_name, error); 856 goto out; 857 } 858 859 error = bdevvp(pdev, &vp); 860 if (error) { 861 aprint_error("%s: unable to find vnode for pdev, error = %d\n", 862 pdk->dk_name, error); 863 goto out; 864 } 865 866 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 867 if (error) { 868 aprint_error("%s: unable to lock vnode for pdev, error = %d\n", 869 pdk->dk_name, error); 870 vrele(vp); 871 goto out; 872 } 873 874 error = VOP_OPEN(vp, FREAD, NOCRED); 875 if (error) { 876 aprint_error("%s: unable to open device, error = %d\n", 877 pdk->dk_name, error); 878 vput(vp); 879 goto out; 880 } 881 VOP_UNLOCK(vp, 0); 882 883 /* 884 * For each supported partition map type, look to see if 885 * this map type exists. If so, parse it and add the 886 * corresponding wedges. 887 */ 888 LIST_FOREACH(ddm, &dkwedge_discovery_methods, ddm_list) { 889 error = (*ddm->ddm_discover)(pdk, vp); 890 if (error == 0) { 891 /* Successfully created wedges; we're done. */ 892 break; 893 } 894 } 895 896 error = vn_close(vp, FREAD, NOCRED); 897 if (error) { 898 aprint_error("%s: unable to close device, error = %d\n", 899 pdk->dk_name, error); 900 /* We'll just assume the vnode has been cleaned up. */ 901 } 902 out: 903 rw_exit(&dkwedge_discovery_methods_lock); 904 } 905 906 /* 907 * dkwedge_read: 908 * 909 * Read some data from the specified disk, used for 910 * partition discovery. 911 */ 912 int 913 dkwedge_read(struct disk *pdk, struct vnode *vp, daddr_t blkno, 914 void *tbuf, size_t len) 915 { 916 struct buf *bp; 917 int result; 918 919 bp = getiobuf(vp, true); 920 921 bp->b_dev = vp->v_rdev; 922 bp->b_blkno = blkno; 923 bp->b_bcount = len; 924 bp->b_resid = len; 925 bp->b_flags = B_READ; 926 bp->b_data = tbuf; 927 SET(bp->b_cflags, BC_BUSY); /* mark buffer busy */ 928 929 VOP_STRATEGY(vp, bp); 930 result = biowait(bp); 931 putiobuf(bp); 932 933 return result; 934 } 935 936 /* 937 * dkwedge_lookup: 938 * 939 * Look up a dkwedge_softc based on the provided dev_t. 940 */ 941 static struct dkwedge_softc * 942 dkwedge_lookup(dev_t dev) 943 { 944 int unit = minor(dev); 945 946 if (unit >= ndkwedges) 947 return (NULL); 948 949 KASSERT(dkwedges != NULL); 950 951 return (dkwedges[unit]); 952 } 953 954 /* 955 * dkopen: [devsw entry point] 956 * 957 * Open a wedge. 958 */ 959 static int 960 dkopen(dev_t dev, int flags, int fmt, struct lwp *l) 961 { 962 struct dkwedge_softc *sc = dkwedge_lookup(dev); 963 struct vnode *vp; 964 int error = 0; 965 966 if (sc == NULL) 967 return (ENODEV); 968 969 if (sc->sc_state != DKW_STATE_RUNNING) 970 return (ENXIO); 971 972 /* 973 * We go through a complicated little dance to only open the parent 974 * vnode once per wedge, no matter how many times the wedge is 975 * opened. The reason? We see one dkopen() per open call, but 976 * only dkclose() on the last close. 977 */ 978 mutex_enter(&sc->sc_dk.dk_openlock); 979 mutex_enter(&sc->sc_parent->dk_rawlock); 980 if (sc->sc_dk.dk_openmask == 0) { 981 if (sc->sc_parent->dk_rawopens == 0) { 982 KASSERT(sc->sc_parent->dk_rawvp == NULL); 983 error = bdevvp(sc->sc_pdev, &vp); 984 if (error) 985 goto popen_fail; 986 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 987 if (error) { 988 vrele(vp); 989 goto popen_fail; 990 } 991 error = VOP_OPEN(vp, FREAD | FWRITE, NOCRED); 992 if (error) { 993 vput(vp); 994 goto popen_fail; 995 } 996 /* VOP_OPEN() doesn't do this for us. */ 997 mutex_enter(&vp->v_interlock); 998 vp->v_writecount++; 999 mutex_exit(&vp->v_interlock); 1000 VOP_UNLOCK(vp, 0); 1001 sc->sc_parent->dk_rawvp = vp; 1002 } 1003 sc->sc_parent->dk_rawopens++; 1004 } 1005 if (fmt == S_IFCHR) 1006 sc->sc_dk.dk_copenmask |= 1; 1007 else 1008 sc->sc_dk.dk_bopenmask |= 1; 1009 sc->sc_dk.dk_openmask = 1010 sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; 1011 1012 popen_fail: 1013 mutex_exit(&sc->sc_parent->dk_rawlock); 1014 mutex_exit(&sc->sc_dk.dk_openlock); 1015 return (error); 1016 } 1017 1018 /* 1019 * Caller must hold sc->sc_dk.dk_openlock and sc->sc_parent->dk_rawlock. 1020 */ 1021 static int 1022 dklastclose(struct dkwedge_softc *sc) 1023 { 1024 int error = 0; 1025 1026 if (sc->sc_parent->dk_rawopens-- == 1) { 1027 KASSERT(sc->sc_parent->dk_rawvp != NULL); 1028 error = vn_close(sc->sc_parent->dk_rawvp, 1029 FREAD | FWRITE, NOCRED); 1030 sc->sc_parent->dk_rawvp = NULL; 1031 } 1032 return error; 1033 } 1034 1035 /* 1036 * dkclose: [devsw entry point] 1037 * 1038 * Close a wedge. 1039 */ 1040 static int 1041 dkclose(dev_t dev, int flags, int fmt, struct lwp *l) 1042 { 1043 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1044 int error = 0; 1045 1046 KASSERT(sc->sc_dk.dk_openmask != 0); 1047 1048 mutex_enter(&sc->sc_dk.dk_openlock); 1049 mutex_enter(&sc->sc_parent->dk_rawlock); 1050 1051 if (fmt == S_IFCHR) 1052 sc->sc_dk.dk_copenmask &= ~1; 1053 else 1054 sc->sc_dk.dk_bopenmask &= ~1; 1055 sc->sc_dk.dk_openmask = 1056 sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; 1057 1058 if (sc->sc_dk.dk_openmask == 0) 1059 error = dklastclose(sc); 1060 1061 mutex_exit(&sc->sc_parent->dk_rawlock); 1062 mutex_exit(&sc->sc_dk.dk_openlock); 1063 1064 return (error); 1065 } 1066 1067 /* 1068 * dkstragegy: [devsw entry point] 1069 * 1070 * Perform I/O based on the wedge I/O strategy. 1071 */ 1072 static void 1073 dkstrategy(struct buf *bp) 1074 { 1075 struct dkwedge_softc *sc = dkwedge_lookup(bp->b_dev); 1076 int s; 1077 1078 if (sc->sc_state != DKW_STATE_RUNNING) { 1079 bp->b_error = ENXIO; 1080 goto done; 1081 } 1082 1083 /* If it's an empty transfer, wake up the top half now. */ 1084 if (bp->b_bcount == 0) 1085 goto done; 1086 1087 /* Make sure it's in-range. */ 1088 if (bounds_check_with_mediasize(bp, DEV_BSIZE, sc->sc_size) <= 0) 1089 goto done; 1090 1091 /* Translate it to the parent's raw LBA. */ 1092 bp->b_rawblkno = bp->b_blkno + sc->sc_offset; 1093 1094 /* Place it in the queue and start I/O on the unit. */ 1095 s = splbio(); 1096 sc->sc_iopend++; 1097 bufq_put(sc->sc_bufq, bp); 1098 dkstart(sc); 1099 splx(s); 1100 return; 1101 1102 done: 1103 bp->b_resid = bp->b_bcount; 1104 biodone(bp); 1105 } 1106 1107 /* 1108 * dkstart: 1109 * 1110 * Start I/O that has been enqueued on the wedge. 1111 * NOTE: Must be called at splbio()! 1112 */ 1113 static void 1114 dkstart(struct dkwedge_softc *sc) 1115 { 1116 struct vnode *vp; 1117 struct buf *bp, *nbp; 1118 1119 /* Do as much work as has been enqueued. */ 1120 while ((bp = bufq_peek(sc->sc_bufq)) != NULL) { 1121 if (sc->sc_state != DKW_STATE_RUNNING) { 1122 (void) bufq_get(sc->sc_bufq); 1123 if (sc->sc_iopend-- == 1 && 1124 (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) { 1125 sc->sc_flags &= ~DK_F_WAIT_DRAIN; 1126 wakeup(&sc->sc_iopend); 1127 } 1128 bp->b_error = ENXIO; 1129 bp->b_resid = bp->b_bcount; 1130 biodone(bp); 1131 } 1132 1133 /* Instrumentation. */ 1134 disk_busy(&sc->sc_dk); 1135 1136 nbp = getiobuf(sc->sc_parent->dk_rawvp, false); 1137 if (nbp == NULL) { 1138 /* 1139 * No resources to run this request; leave the 1140 * buffer queued up, and schedule a timer to 1141 * restart the queue in 1/2 a second. 1142 */ 1143 disk_unbusy(&sc->sc_dk, 0, bp->b_flags & B_READ); 1144 callout_schedule(&sc->sc_restart_ch, hz / 2); 1145 return; 1146 } 1147 1148 (void) bufq_get(sc->sc_bufq); 1149 1150 nbp->b_data = bp->b_data; 1151 nbp->b_flags = bp->b_flags; 1152 nbp->b_oflags = bp->b_oflags; 1153 nbp->b_cflags = bp->b_cflags; 1154 nbp->b_iodone = dkiodone; 1155 nbp->b_proc = bp->b_proc; 1156 nbp->b_blkno = bp->b_rawblkno; 1157 nbp->b_dev = sc->sc_parent->dk_rawvp->v_rdev; 1158 nbp->b_bcount = bp->b_bcount; 1159 nbp->b_private = bp; 1160 BIO_COPYPRIO(nbp, bp); 1161 1162 vp = nbp->b_vp; 1163 if ((nbp->b_flags & B_READ) == 0) { 1164 mutex_enter(&vp->v_interlock); 1165 vp->v_numoutput++; 1166 mutex_exit(&vp->v_interlock); 1167 } 1168 VOP_STRATEGY(vp, nbp); 1169 } 1170 } 1171 1172 /* 1173 * dkiodone: 1174 * 1175 * I/O to a wedge has completed; alert the top half. 1176 * NOTE: Must be called at splbio()! 1177 */ 1178 static void 1179 dkiodone(struct buf *bp) 1180 { 1181 struct buf *obp = bp->b_private; 1182 struct dkwedge_softc *sc = dkwedge_lookup(obp->b_dev); 1183 1184 if (bp->b_error != 0) 1185 obp->b_error = bp->b_error; 1186 obp->b_resid = bp->b_resid; 1187 putiobuf(bp); 1188 1189 if (sc->sc_iopend-- == 1 && (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) { 1190 sc->sc_flags &= ~DK_F_WAIT_DRAIN; 1191 wakeup(&sc->sc_iopend); 1192 } 1193 1194 disk_unbusy(&sc->sc_dk, obp->b_bcount - obp->b_resid, 1195 obp->b_flags & B_READ); 1196 1197 biodone(obp); 1198 1199 /* Kick the queue in case there is more work we can do. */ 1200 dkstart(sc); 1201 } 1202 1203 /* 1204 * dkrestart: 1205 * 1206 * Restart the work queue after it was stalled due to 1207 * a resource shortage. Invoked via a callout. 1208 */ 1209 static void 1210 dkrestart(void *v) 1211 { 1212 struct dkwedge_softc *sc = v; 1213 int s; 1214 1215 s = splbio(); 1216 dkstart(sc); 1217 splx(s); 1218 } 1219 1220 /* 1221 * dkread: [devsw entry point] 1222 * 1223 * Read from a wedge. 1224 */ 1225 static int 1226 dkread(dev_t dev, struct uio *uio, int flags) 1227 { 1228 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1229 1230 if (sc->sc_state != DKW_STATE_RUNNING) 1231 return (ENXIO); 1232 1233 return (physio(dkstrategy, NULL, dev, B_READ, 1234 sc->sc_parent->dk_driver->d_minphys, uio)); 1235 } 1236 1237 /* 1238 * dkwrite: [devsw entry point] 1239 * 1240 * Write to a wedge. 1241 */ 1242 static int 1243 dkwrite(dev_t dev, struct uio *uio, int flags) 1244 { 1245 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1246 1247 if (sc->sc_state != DKW_STATE_RUNNING) 1248 return (ENXIO); 1249 1250 return (physio(dkstrategy, NULL, dev, B_WRITE, 1251 sc->sc_parent->dk_driver->d_minphys, uio)); 1252 } 1253 1254 /* 1255 * dkioctl: [devsw entry point] 1256 * 1257 * Perform an ioctl request on a wedge. 1258 */ 1259 static int 1260 dkioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1261 { 1262 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1263 int error = 0; 1264 1265 if (sc->sc_state != DKW_STATE_RUNNING) 1266 return (ENXIO); 1267 1268 switch (cmd) { 1269 case DIOCCACHESYNC: 1270 /* 1271 * XXX Do we really need to care about having a writable 1272 * file descriptor here? 1273 */ 1274 if ((flag & FWRITE) == 0) 1275 error = EBADF; 1276 else 1277 error = VOP_IOCTL(sc->sc_parent->dk_rawvp, 1278 cmd, data, flag, 1279 l != NULL ? l->l_cred : NOCRED); 1280 break; 1281 case DIOCGWEDGEINFO: 1282 { 1283 struct dkwedge_info *dkw = (void *) data; 1284 1285 strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev), 1286 sizeof(dkw->dkw_devname)); 1287 memcpy(dkw->dkw_wname, sc->sc_wname, sizeof(dkw->dkw_wname)); 1288 dkw->dkw_wname[sizeof(dkw->dkw_wname) - 1] = '\0'; 1289 strcpy(dkw->dkw_parent, sc->sc_parent->dk_name); 1290 dkw->dkw_offset = sc->sc_offset; 1291 dkw->dkw_size = sc->sc_size; 1292 strcpy(dkw->dkw_ptype, sc->sc_ptype); 1293 1294 break; 1295 } 1296 1297 default: 1298 error = ENOTTY; 1299 } 1300 1301 return (error); 1302 } 1303 1304 /* 1305 * dksize: [devsw entry point] 1306 * 1307 * Query the size of a wedge for the purpose of performing a dump 1308 * or for swapping to. 1309 */ 1310 static int 1311 dksize(dev_t dev) 1312 { 1313 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1314 int rv = -1; 1315 1316 if (sc == NULL) 1317 return (-1); 1318 1319 if (sc->sc_state != DKW_STATE_RUNNING) 1320 return (ENXIO); 1321 1322 mutex_enter(&sc->sc_dk.dk_openlock); 1323 mutex_enter(&sc->sc_parent->dk_rawlock); 1324 1325 /* Our content type is static, no need to open the device. */ 1326 1327 if (strcmp(sc->sc_ptype, DKW_PTYPE_SWAP) == 0) { 1328 /* Saturate if we are larger than INT_MAX. */ 1329 if (sc->sc_size > INT_MAX) 1330 rv = INT_MAX; 1331 else 1332 rv = (int) sc->sc_size; 1333 } 1334 1335 mutex_exit(&sc->sc_parent->dk_rawlock); 1336 mutex_exit(&sc->sc_dk.dk_openlock); 1337 1338 return (rv); 1339 } 1340 1341 /* 1342 * dkdump: [devsw entry point] 1343 * 1344 * Perform a crash dump to a wedge. 1345 */ 1346 static int 1347 dkdump(dev_t dev, daddr_t blkno, void *va, size_t size) 1348 { 1349 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1350 const struct bdevsw *bdev; 1351 int rv = 0; 1352 1353 if (sc == NULL) 1354 return (-1); 1355 1356 if (sc->sc_state != DKW_STATE_RUNNING) 1357 return (ENXIO); 1358 1359 mutex_enter(&sc->sc_dk.dk_openlock); 1360 mutex_enter(&sc->sc_parent->dk_rawlock); 1361 1362 /* Our content type is static, no need to open the device. */ 1363 1364 if (strcmp(sc->sc_ptype, DKW_PTYPE_SWAP) != 0) { 1365 rv = ENXIO; 1366 goto out; 1367 } 1368 if (size % DEV_BSIZE != 0) { 1369 rv = EINVAL; 1370 goto out; 1371 } 1372 if (blkno + size / DEV_BSIZE > sc->sc_size) { 1373 printf("%s: blkno (%" PRIu64 ") + size / DEV_BSIZE (%zu) > " 1374 "sc->sc_size (%" PRIu64 ")\n", __func__, blkno, 1375 size / DEV_BSIZE, sc->sc_size); 1376 rv = EINVAL; 1377 goto out; 1378 } 1379 1380 bdev = bdevsw_lookup(sc->sc_pdev); 1381 rv = (*bdev->d_dump)(sc->sc_pdev, blkno + sc->sc_offset, va, size); 1382 1383 out: 1384 mutex_exit(&sc->sc_parent->dk_rawlock); 1385 mutex_exit(&sc->sc_dk.dk_openlock); 1386 1387 return rv; 1388 } 1389