1 /* $NetBSD: dk.c,v 1.175 2026/05/26 14:57:25 simonb 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.175 2026/05/26 14:57:25 simonb Exp $"); 34 35 #ifdef _KERNEL_OPT 36 #include "opt_dkwedge.h" 37 #endif 38 39 #include <sys/param.h> 40 #include <sys/types.h> 41 42 #include <sys/buf.h> 43 #include <sys/bufq.h> 44 #include <sys/callout.h> 45 #include <sys/conf.h> 46 #include <sys/device.h> 47 #include <sys/disk.h> 48 #include <sys/disklabel.h> 49 #include <sys/errno.h> 50 #include <sys/fcntl.h> 51 #include <sys/ioctl.h> 52 #include <sys/kauth.h> 53 #include <sys/kernel.h> 54 #include <sys/malloc.h> 55 #include <sys/pool.h> 56 #include <sys/proc.h> 57 #include <sys/rwlock.h> 58 #include <sys/stat.h> 59 #include <sys/systm.h> 60 #include <sys/vnode.h> 61 62 #include <miscfs/specfs/specdev.h> 63 64 MALLOC_DEFINE(M_DKWEDGE, "dkwedge", "Disk wedge structures"); 65 66 typedef enum { 67 DKW_STATE_LARVAL = 0, 68 DKW_STATE_RUNNING = 1, 69 DKW_STATE_DYING = 2, 70 DKW_STATE_DEAD = 666 71 } dkwedge_state_t; 72 73 /* 74 * Lock order: 75 * 76 * sc->sc_dk.dk_openlock 77 * => sc->sc_parent->dk_rawlock 78 * => sc->sc_parent->dk_openlock 79 * => dkwedges_lock 80 * => sc->sc_sizelock 81 * 82 * Locking notes: 83 * 84 * W dkwedges_lock 85 * D device reference 86 * O sc->sc_dk.dk_openlock 87 * P sc->sc_parent->dk_openlock 88 * R sc->sc_parent->dk_rawlock 89 * S sc->sc_sizelock 90 * I sc->sc_iolock 91 * $ stable after initialization 92 * 1 used only by a single thread 93 * 94 * x&y means both x and y must be held to write (with a write lock if 95 * one is rwlock), and either x or y must be held to read. 96 */ 97 98 struct dkwedge_softc { 99 device_t sc_dev; /* P&W: pointer to our pseudo-device */ 100 /* sc_dev is also stable while device is referenced */ 101 struct cfdata sc_cfdata; /* 1: our cfdata structure */ 102 uint8_t sc_wname[128]; /* $: wedge name (Unicode, UTF-8) */ 103 104 dkwedge_state_t sc_state; /* state this wedge is in */ 105 /* stable while device is referenced */ 106 /* used only in assertions when stable, and in dump in ddb */ 107 108 struct disk *sc_parent; /* $: parent disk */ 109 /* P: sc_parent->dk_openmask */ 110 /* P: sc_parent->dk_nwedges */ 111 /* P: sc_parent->dk_wedges */ 112 /* R: sc_parent->dk_rawopens */ 113 /* R: sc_parent->dk_rawvp (also stable while wedge is open) */ 114 daddr_t sc_offset; /* $: LBA offset of wedge in parent */ 115 krwlock_t sc_sizelock; 116 uint64_t sc_size; /* S: size of wedge in blocks */ 117 char sc_ptype[32]; /* $: partition type */ 118 dev_t sc_pdev; /* $: cached parent's dev_t */ 119 /* P: link on parent's wedge list */ 120 LIST_ENTRY(dkwedge_softc) sc_plink; 121 122 struct disk sc_dk; /* our own disk structure */ 123 /* O&R: sc_dk.dk_bopenmask */ 124 /* O&R: sc_dk.dk_copenmask */ 125 /* O&R: sc_dk.dk_openmask */ 126 struct bufq_state *sc_bufq; /* $: buffer queue */ 127 struct callout sc_restart_ch; /* I: callout to restart I/O */ 128 129 kmutex_t sc_iolock; 130 bool sc_iostop; /* I: don't schedule restart */ 131 int sc_mode; /* O&R: parent open mode */ 132 }; 133 134 static int dkwedge_match(device_t, cfdata_t, void *); 135 static void dkwedge_attach(device_t, device_t, void *); 136 static int dkwedge_detach(device_t, int); 137 138 static void dk_set_geometry(struct dkwedge_softc *, struct disk *); 139 140 static void dkstart(struct dkwedge_softc *); 141 static void dkiodone(struct buf *); 142 static void dkrestart(void *); 143 static void dkminphys(struct buf *); 144 145 static int dkfirstopen(struct dkwedge_softc *, int); 146 static void dklastclose(struct dkwedge_softc *); 147 static int dkwedge_detach(device_t, int); 148 static void dkwedge_delall1(struct disk *, bool); 149 static int dkwedge_del1(struct dkwedge_info *, int); 150 static int dk_open_parent(dev_t, int, struct vnode **); 151 static int dk_close_parent(struct vnode *, int); 152 153 static device_t dkwedge_rootspec_hook(const char *); 154 static void dkwedge_rootspec_print(void); 155 static void dkwedge_rootspec_noprint(void); 156 157 static dev_type_open(dkopen); 158 static dev_type_close(dkclose); 159 static dev_type_cancel(dkcancel); 160 static dev_type_read(dkread); 161 static dev_type_write(dkwrite); 162 static dev_type_ioctl(dkioctl); 163 static dev_type_strategy(dkstrategy); 164 static dev_type_dump(dkdump); 165 static dev_type_size(dksize); 166 static dev_type_discard(dkdiscard); 167 168 CFDRIVER_DECL(dk, DV_DISK, NULL); 169 CFATTACH_DECL3_NEW(dk, 0, 170 dkwedge_match, dkwedge_attach, dkwedge_detach, NULL, NULL, NULL, 171 DVF_DETACH_SHUTDOWN | DVF_NO_PARTITIONS); 172 173 const struct bdevsw dk_bdevsw = { 174 .d_open = dkopen, 175 .d_close = dkclose, 176 .d_cancel = dkcancel, 177 .d_strategy = dkstrategy, 178 .d_ioctl = dkioctl, 179 .d_dump = dkdump, 180 .d_psize = dksize, 181 .d_discard = dkdiscard, 182 .d_cfdriver = &dk_cd, 183 .d_devtounit = dev_minor_unit, 184 .d_flag = D_DISK | D_MPSAFE 185 }; 186 187 const struct cdevsw dk_cdevsw = { 188 .d_open = dkopen, 189 .d_close = dkclose, 190 .d_cancel = dkcancel, 191 .d_read = dkread, 192 .d_write = dkwrite, 193 .d_ioctl = dkioctl, 194 .d_stop = nostop, 195 .d_tty = notty, 196 .d_poll = nopoll, 197 .d_mmap = nommap, 198 .d_kqfilter = nokqfilter, 199 .d_discard = dkdiscard, 200 .d_cfdriver = &dk_cd, 201 .d_devtounit = dev_minor_unit, 202 .d_flag = D_DISK | D_MPSAFE 203 }; 204 205 static struct dkwedge_softc **dkwedges; 206 static u_int ndkwedges; 207 static krwlock_t dkwedges_lock; 208 209 static LIST_HEAD(, dkwedge_discovery_method) dkwedge_discovery_methods; 210 static krwlock_t dkwedge_discovery_methods_lock; 211 212 /* 213 * dkwedge_match: 214 * 215 * Autoconfiguration match function for pseudo-device glue. 216 */ 217 static int 218 dkwedge_match(device_t parent, cfdata_t match, void *aux) 219 { 220 221 /* Pseudo-device; always present. */ 222 return 1; 223 } 224 225 /* 226 * dkwedge_attach: 227 * 228 * Autoconfiguration attach function for pseudo-device glue. 229 */ 230 static void 231 dkwedge_attach(device_t parent, device_t self, void *aux) 232 { 233 struct dkwedge_softc *sc = aux; 234 struct disk *pdk = sc->sc_parent; 235 int unit = device_unit(self); 236 237 KASSERTMSG(unit >= 0, "unit=%d", unit); 238 239 if (!pmf_device_register(self, NULL, NULL)) 240 aprint_error_dev(self, "couldn't establish power handler\n"); 241 242 mutex_enter(&pdk->dk_openlock); 243 rw_enter(&dkwedges_lock, RW_WRITER); 244 KASSERTMSG(unit < ndkwedges, "unit=%d ndkwedges=%u", unit, ndkwedges); 245 KASSERTMSG(sc == dkwedges[unit], "sc=%p dkwedges[%d]=%p", 246 sc, unit, dkwedges[unit]); 247 KASSERTMSG(sc->sc_dev == NULL, "sc=%p sc->sc_dev=%p", sc, sc->sc_dev); 248 sc->sc_dev = self; 249 rw_exit(&dkwedges_lock); 250 mutex_exit(&pdk->dk_openlock); 251 252 disk_init(&sc->sc_dk, device_xname(sc->sc_dev), NULL); 253 mutex_enter(&pdk->dk_openlock); 254 dk_set_geometry(sc, pdk); 255 mutex_exit(&pdk->dk_openlock); 256 disk_attach(&sc->sc_dk); 257 258 /* Disk wedge is ready for use! */ 259 device_set_private(self, sc); 260 sc->sc_state = DKW_STATE_RUNNING; 261 } 262 263 /* 264 * dkwedge_compute_pdev: 265 * 266 * Compute the parent disk's dev_t. 267 */ 268 static int 269 dkwedge_compute_pdev(const char *pname, dev_t *pdevp, enum vtype type) 270 { 271 const char *name, *cp; 272 devmajor_t pmaj; 273 int punit; 274 char devname[16]; 275 276 name = pname; 277 switch (type) { 278 case VBLK: 279 pmaj = devsw_name2blk(name, devname, sizeof(devname)); 280 break; 281 case VCHR: 282 pmaj = devsw_name2chr(name, devname, sizeof(devname)); 283 break; 284 default: 285 pmaj = NODEVMAJOR; 286 break; 287 } 288 if (pmaj == NODEVMAJOR) 289 return ENXIO; 290 291 name += strlen(devname); 292 for (cp = name, punit = 0; *cp >= '0' && *cp <= '9'; cp++) 293 punit = (punit * 10) + (*cp - '0'); 294 if (cp == name) { 295 /* Invalid parent disk name. */ 296 return ENXIO; 297 } 298 299 *pdevp = MAKEDISKDEV(pmaj, punit, RAW_PART); 300 301 return 0; 302 } 303 304 /* 305 * dkwedge_array_expand: 306 * 307 * Expand the dkwedges array. 308 * 309 * Releases and reacquires dkwedges_lock as a writer. 310 */ 311 static int 312 dkwedge_array_expand(void) 313 { 314 315 const unsigned incr = 16; 316 unsigned newcnt, oldcnt; 317 struct dkwedge_softc **newarray = NULL, **oldarray = NULL; 318 319 KASSERT(rw_write_held(&dkwedges_lock)); 320 321 oldcnt = ndkwedges; 322 oldarray = dkwedges; 323 324 if (oldcnt >= INT_MAX - incr) 325 return ENFILE; /* XXX */ 326 newcnt = oldcnt + incr; 327 328 rw_exit(&dkwedges_lock); 329 newarray = malloc(newcnt * sizeof(*newarray), M_DKWEDGE, 330 M_WAITOK|M_ZERO); 331 rw_enter(&dkwedges_lock, RW_WRITER); 332 333 if (ndkwedges != oldcnt || dkwedges != oldarray) { 334 oldarray = NULL; /* already recycled */ 335 goto out; 336 } 337 338 if (oldarray != NULL) 339 memcpy(newarray, dkwedges, ndkwedges * sizeof(*newarray)); 340 dkwedges = newarray; 341 newarray = NULL; /* transferred to dkwedges */ 342 ndkwedges = newcnt; 343 344 out: rw_exit(&dkwedges_lock); 345 if (oldarray != NULL) 346 free(oldarray, M_DKWEDGE); 347 if (newarray != NULL) 348 free(newarray, M_DKWEDGE); 349 rw_enter(&dkwedges_lock, RW_WRITER); 350 return 0; 351 } 352 353 static void 354 dkwedge_size_init(struct dkwedge_softc *sc, uint64_t size) 355 { 356 357 rw_init(&sc->sc_sizelock); 358 sc->sc_size = size; 359 } 360 361 static void 362 dkwedge_size_fini(struct dkwedge_softc *sc) 363 { 364 365 rw_destroy(&sc->sc_sizelock); 366 } 367 368 static uint64_t 369 dkwedge_size(struct dkwedge_softc *sc) 370 { 371 uint64_t size; 372 373 rw_enter(&sc->sc_sizelock, RW_READER); 374 size = sc->sc_size; 375 rw_exit(&sc->sc_sizelock); 376 377 return size; 378 } 379 380 static void 381 dkwedge_size_increase(struct dkwedge_softc *sc, uint64_t size) 382 { 383 384 KASSERT(mutex_owned(&sc->sc_parent->dk_openlock)); 385 386 rw_enter(&sc->sc_sizelock, RW_WRITER); 387 KASSERTMSG(size >= sc->sc_size, 388 "decreasing dkwedge size from %"PRIu64" to %"PRIu64, 389 sc->sc_size, size); 390 sc->sc_size = size; 391 rw_exit(&sc->sc_sizelock); 392 } 393 394 static void 395 dk_set_geometry(struct dkwedge_softc *sc, struct disk *pdk) 396 { 397 struct disk *dk = &sc->sc_dk; 398 struct disk_geom *dg = &dk->dk_geom; 399 uint32_t r, lspps; 400 401 KASSERT(mutex_owned(&pdk->dk_openlock)); 402 403 memset(dg, 0, sizeof(*dg)); 404 405 dg->dg_secperunit = dkwedge_size(sc); 406 dg->dg_secsize = DEV_BSIZE << pdk->dk_blkshift; 407 408 /* fake numbers, 1 cylinder is 1 MB with default sector size */ 409 dg->dg_nsectors = 32; 410 dg->dg_ntracks = 64; 411 dg->dg_ncylinders = 412 dg->dg_secperunit / (dg->dg_nsectors * dg->dg_ntracks); 413 414 dg->dg_physsecsize = pdk->dk_geom.dg_physsecsize; 415 dg->dg_alignedsec = pdk->dk_geom.dg_alignedsec; 416 lspps = MAX(1u, dg->dg_physsecsize / dg->dg_secsize); 417 r = sc->sc_offset % lspps; 418 if (r > dg->dg_alignedsec) 419 dg->dg_alignedsec += lspps; 420 dg->dg_alignedsec -= r; 421 dg->dg_alignedsec %= lspps; 422 423 disk_set_info(sc->sc_dev, dk, NULL); 424 } 425 426 /* 427 * dkwedge_add: [exported function] 428 * 429 * Add a disk wedge based on the provided information. 430 * 431 * The incoming dkw_devname[] is ignored, instead being 432 * filled in and returned to the caller. 433 */ 434 int 435 dkwedge_add(struct dkwedge_info *dkw) 436 { 437 struct dkwedge_softc *sc, *lsc; 438 struct disk *pdk; 439 u_int unit; 440 int error; 441 dev_t pdev; 442 device_t dev __diagused; 443 444 dkw->dkw_parent[sizeof(dkw->dkw_parent) - 1] = '\0'; 445 pdk = disk_find(dkw->dkw_parent); 446 if (pdk == NULL) 447 return ENXIO; 448 449 error = dkwedge_compute_pdev(pdk->dk_name, &pdev, VBLK); 450 if (error) 451 return error; 452 453 if (dkw->dkw_offset < 0) 454 return EINVAL; 455 456 /* 457 * Check for an existing wedge at the same disk offset. Allow 458 * updating a wedge if the only change is the size, and the new 459 * size is larger than the old. 460 */ 461 sc = NULL; 462 mutex_enter(&pdk->dk_openlock); 463 LIST_FOREACH(lsc, &pdk->dk_wedges, sc_plink) { 464 if (lsc->sc_offset != dkw->dkw_offset) 465 continue; 466 if (strcmp(lsc->sc_wname, dkw->dkw_wname) != 0) 467 break; 468 if (strcmp(lsc->sc_ptype, dkw->dkw_ptype) != 0) 469 break; 470 if (dkwedge_size(lsc) > dkw->dkw_size) 471 break; 472 if (lsc->sc_dev == NULL) 473 break; 474 475 sc = lsc; 476 device_acquire(sc->sc_dev); 477 dkwedge_size_increase(sc, dkw->dkw_size); 478 dk_set_geometry(sc, pdk); 479 480 break; 481 } 482 mutex_exit(&pdk->dk_openlock); 483 484 if (sc != NULL) 485 goto announce; 486 487 sc = malloc(sizeof(*sc), M_DKWEDGE, M_WAITOK|M_ZERO); 488 sc->sc_state = DKW_STATE_LARVAL; 489 sc->sc_parent = pdk; 490 sc->sc_pdev = pdev; 491 sc->sc_offset = dkw->dkw_offset; 492 dkwedge_size_init(sc, dkw->dkw_size); 493 494 memcpy(sc->sc_wname, dkw->dkw_wname, sizeof(sc->sc_wname)); 495 sc->sc_wname[sizeof(sc->sc_wname) - 1] = '\0'; 496 497 memcpy(sc->sc_ptype, dkw->dkw_ptype, sizeof(sc->sc_ptype)); 498 sc->sc_ptype[sizeof(sc->sc_ptype) - 1] = '\0'; 499 500 bufq_alloc(&sc->sc_bufq, "fcfs", 0); 501 502 callout_init(&sc->sc_restart_ch, 0); 503 callout_setfunc(&sc->sc_restart_ch, dkrestart, sc); 504 505 mutex_init(&sc->sc_iolock, MUTEX_DEFAULT, IPL_BIO); 506 507 /* 508 * Wedge will be added; increment the wedge count for the parent. 509 * Only allow this to happen if RAW_PART is the only thing open. 510 */ 511 mutex_enter(&pdk->dk_openlock); 512 if (pdk->dk_openmask & ~(1 << RAW_PART)) 513 error = EBUSY; 514 else { 515 /* Check for wedge overlap. */ 516 LIST_FOREACH(lsc, &pdk->dk_wedges, sc_plink) { 517 /* XXX arithmetic overflow */ 518 uint64_t size = dkwedge_size(sc); 519 uint64_t lsize = dkwedge_size(lsc); 520 daddr_t lastblk = sc->sc_offset + size - 1; 521 daddr_t llastblk = lsc->sc_offset + lsize - 1; 522 523 if (sc->sc_offset >= lsc->sc_offset && 524 sc->sc_offset <= llastblk) { 525 /* Overlaps the tail of the existing wedge. */ 526 break; 527 } 528 if (lastblk >= lsc->sc_offset && 529 lastblk <= llastblk) { 530 /* Overlaps the head of the existing wedge. */ 531 break; 532 } 533 } 534 if (lsc != NULL) { 535 if (sc->sc_offset == lsc->sc_offset && 536 dkwedge_size(sc) == dkwedge_size(lsc) && 537 strcmp(sc->sc_wname, lsc->sc_wname) == 0) 538 error = EEXIST; 539 else 540 error = EINVAL; 541 } else { 542 pdk->dk_nwedges++; 543 LIST_INSERT_HEAD(&pdk->dk_wedges, sc, sc_plink); 544 } 545 } 546 mutex_exit(&pdk->dk_openlock); 547 if (error) { 548 mutex_destroy(&sc->sc_iolock); 549 bufq_free(sc->sc_bufq); 550 dkwedge_size_fini(sc); 551 free(sc, M_DKWEDGE); 552 return error; 553 } 554 555 /* Fill in our cfdata for the pseudo-device glue. */ 556 sc->sc_cfdata.cf_name = dk_cd.cd_name; 557 sc->sc_cfdata.cf_atname = dk_ca.ca_name; 558 /* sc->sc_cfdata.cf_unit set below */ 559 sc->sc_cfdata.cf_fstate = FSTATE_NOTFOUND; /* use chosen cf_unit */ 560 561 /* Insert the larval wedge into the array. */ 562 rw_enter(&dkwedges_lock, RW_WRITER); 563 for (error = 0;;) { 564 struct dkwedge_softc **scpp; 565 566 /* 567 * Check for a duplicate wname while searching for 568 * a slot. 569 */ 570 for (scpp = NULL, unit = 0; unit < ndkwedges; unit++) { 571 if (dkwedges[unit] == NULL) { 572 if (scpp == NULL) { 573 scpp = &dkwedges[unit]; 574 sc->sc_cfdata.cf_unit = unit; 575 } 576 } else { 577 /* XXX Unicode. */ 578 if (strcmp(dkwedges[unit]->sc_wname, 579 sc->sc_wname) == 0) { 580 error = EEXIST; 581 break; 582 } 583 } 584 } 585 if (error) 586 break; 587 KASSERT(unit == ndkwedges); 588 if (scpp == NULL) { 589 error = dkwedge_array_expand(); 590 if (error) 591 break; 592 } else { 593 KASSERT(scpp == &dkwedges[sc->sc_cfdata.cf_unit]); 594 *scpp = sc; 595 break; 596 } 597 } 598 rw_exit(&dkwedges_lock); 599 if (error) { 600 mutex_enter(&pdk->dk_openlock); 601 pdk->dk_nwedges--; 602 LIST_REMOVE(sc, sc_plink); 603 mutex_exit(&pdk->dk_openlock); 604 605 mutex_destroy(&sc->sc_iolock); 606 bufq_free(sc->sc_bufq); 607 dkwedge_size_fini(sc); 608 free(sc, M_DKWEDGE); 609 return error; 610 } 611 612 /* 613 * Now that we know the unit #, attach a pseudo-device for 614 * this wedge instance. This will provide us with the 615 * device_t necessary for glue to other parts of the system. 616 * 617 * This should never fail, unless we're almost totally out of 618 * memory. 619 */ 620 if ((dev = config_attach_pseudo_acquire(&sc->sc_cfdata, sc)) == NULL) { 621 aprint_error("%s%u: unable to attach pseudo-device\n", 622 sc->sc_cfdata.cf_name, sc->sc_cfdata.cf_unit); 623 624 rw_enter(&dkwedges_lock, RW_WRITER); 625 KASSERT(dkwedges[sc->sc_cfdata.cf_unit] == sc); 626 dkwedges[sc->sc_cfdata.cf_unit] = NULL; 627 rw_exit(&dkwedges_lock); 628 629 mutex_enter(&pdk->dk_openlock); 630 pdk->dk_nwedges--; 631 LIST_REMOVE(sc, sc_plink); 632 mutex_exit(&pdk->dk_openlock); 633 634 mutex_destroy(&sc->sc_iolock); 635 bufq_free(sc->sc_bufq); 636 dkwedge_size_fini(sc); 637 free(sc, M_DKWEDGE); 638 return ENOMEM; 639 } 640 641 KASSERT(dev == sc->sc_dev); 642 643 announce: 644 /* Announce our arrival. */ 645 aprint_normal( 646 "%s at %s: \"%s\", %"PRIu64" blocks at %"PRId64", type: %s\n", 647 device_xname(sc->sc_dev), pdk->dk_name, 648 sc->sc_wname, /* XXX Unicode */ 649 dkwedge_size(sc), sc->sc_offset, 650 sc->sc_ptype[0] == '\0' ? "<unknown>" : sc->sc_ptype); 651 652 /* Return the devname to the caller. */ 653 strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev), 654 sizeof(dkw->dkw_devname)); 655 656 device_release(sc->sc_dev); 657 return 0; 658 } 659 660 /* 661 * dkwedge_find_acquire: 662 * 663 * Lookup a disk wedge based on the provided information. 664 * NOTE: We look up the wedge based on the wedge devname, 665 * not wname. 666 * 667 * Return NULL if the wedge is not found, otherwise return 668 * the wedge's softc. Assign the wedge's unit number to unitp 669 * if unitp is not NULL. The wedge's sc_dev is referenced and 670 * must be released by device_release or equivalent. 671 */ 672 static struct dkwedge_softc * 673 dkwedge_find_acquire(struct dkwedge_info *dkw, u_int *unitp) 674 { 675 struct dkwedge_softc *sc = NULL; 676 u_int unit; 677 678 /* Find our softc. */ 679 dkw->dkw_devname[sizeof(dkw->dkw_devname) - 1] = '\0'; 680 rw_enter(&dkwedges_lock, RW_READER); 681 for (unit = 0; unit < ndkwedges; unit++) { 682 if ((sc = dkwedges[unit]) != NULL && 683 sc->sc_dev != NULL && 684 strcmp(device_xname(sc->sc_dev), dkw->dkw_devname) == 0 && 685 strcmp(sc->sc_parent->dk_name, dkw->dkw_parent) == 0) { 686 device_acquire(sc->sc_dev); 687 break; 688 } 689 } 690 rw_exit(&dkwedges_lock); 691 if (sc == NULL) 692 return NULL; 693 694 if (unitp != NULL) 695 *unitp = unit; 696 697 return sc; 698 } 699 700 /* 701 * dkwedge_del: [exported function] 702 * 703 * Delete a disk wedge based on the provided information. 704 * NOTE: We look up the wedge based on the wedge devname, 705 * not wname. 706 */ 707 int 708 dkwedge_del(struct dkwedge_info *dkw) 709 { 710 711 return dkwedge_del1(dkw, 0); 712 } 713 714 int 715 dkwedge_del1(struct dkwedge_info *dkw, int flags) 716 { 717 struct dkwedge_softc *sc = NULL; 718 719 /* Find our softc. */ 720 if ((sc = dkwedge_find_acquire(dkw, NULL)) == NULL) 721 return ESRCH; 722 723 return config_detach_release(sc->sc_dev, flags); 724 } 725 726 /* 727 * dkwedge_detach: 728 * 729 * Autoconfiguration detach function for pseudo-device glue. 730 */ 731 static int 732 dkwedge_detach(device_t self, int flags) 733 { 734 struct dkwedge_softc *const sc = device_private(self); 735 const u_int unit = device_unit(self); 736 int bmaj, cmaj, error; 737 738 error = disk_begindetach(&sc->sc_dk, /*lastclose*/NULL, self, flags); 739 if (error) 740 return error; 741 742 /* Mark the wedge as dying. */ 743 sc->sc_state = DKW_STATE_DYING; 744 745 pmf_device_deregister(self); 746 747 /* Kill any pending restart. */ 748 mutex_enter(&sc->sc_iolock); 749 sc->sc_iostop = true; 750 mutex_exit(&sc->sc_iolock); 751 callout_halt(&sc->sc_restart_ch, NULL); 752 753 /* Locate the wedge major numbers. */ 754 bmaj = bdevsw_lookup_major(&dk_bdevsw); 755 cmaj = cdevsw_lookup_major(&dk_cdevsw); 756 757 /* Nuke the vnodes for any open instances. */ 758 vdevgone(bmaj, unit, unit, VBLK); 759 vdevgone(cmaj, unit, unit, VCHR); 760 761 /* 762 * At this point, all block device opens have been closed, 763 * synchronously flushing any buffered writes; and all 764 * character device I/O operations have completed 765 * synchronously, and character device opens have been closed. 766 * 767 * So there can be no more opens or queued buffers by now. 768 */ 769 KASSERT(sc->sc_dk.dk_openmask == 0); 770 KASSERT(bufq_peek(sc->sc_bufq) == NULL); 771 bufq_drain(sc->sc_bufq); 772 773 /* Announce our departure. */ 774 aprint_normal("%s at %s (%s) deleted\n", device_xname(sc->sc_dev), 775 sc->sc_parent->dk_name, 776 sc->sc_wname); /* XXX Unicode */ 777 778 mutex_enter(&sc->sc_parent->dk_openlock); 779 sc->sc_parent->dk_nwedges--; 780 LIST_REMOVE(sc, sc_plink); 781 mutex_exit(&sc->sc_parent->dk_openlock); 782 783 /* Delete our buffer queue. */ 784 bufq_free(sc->sc_bufq); 785 786 /* Detach from the disk list. */ 787 disk_detach(&sc->sc_dk); 788 disk_destroy(&sc->sc_dk); 789 790 /* Poof. */ 791 rw_enter(&dkwedges_lock, RW_WRITER); 792 KASSERT(dkwedges[unit] == sc); 793 dkwedges[unit] = NULL; 794 sc->sc_state = DKW_STATE_DEAD; 795 rw_exit(&dkwedges_lock); 796 797 mutex_destroy(&sc->sc_iolock); 798 dkwedge_size_fini(sc); 799 800 free(sc, M_DKWEDGE); 801 802 return 0; 803 } 804 805 /* 806 * dkwedge_delall: [exported function] 807 * 808 * Forcibly delete all of the wedges on the specified disk. Used 809 * when a disk is being detached. 810 */ 811 void 812 dkwedge_delall(struct disk *pdk) 813 { 814 815 dkwedge_delall1(pdk, /*idleonly*/false); 816 } 817 818 /* 819 * dkwedge_delidle: [exported function] 820 * 821 * Delete all of the wedges on the specified disk if idle. Used 822 * by ioctl(DIOCRMWEDGES). 823 */ 824 void 825 dkwedge_delidle(struct disk *pdk) 826 { 827 828 dkwedge_delall1(pdk, /*idleonly*/true); 829 } 830 831 static void 832 dkwedge_delall1(struct disk *pdk, bool idleonly) 833 { 834 struct dkwedge_softc *sc; 835 int flags; 836 837 flags = DETACH_QUIET; 838 if (!idleonly) 839 flags |= DETACH_FORCE; 840 841 for (;;) { 842 mutex_enter(&pdk->dk_rawlock); /* for sc->sc_dk.dk_openmask */ 843 mutex_enter(&pdk->dk_openlock); 844 LIST_FOREACH(sc, &pdk->dk_wedges, sc_plink) { 845 /* 846 * Wedge is not yet created. This is a race -- 847 * it may as well have been added just after we 848 * deleted all the wedges, so pretend it's not 849 * here yet. 850 */ 851 if (sc->sc_dev == NULL) 852 continue; 853 if (!idleonly || sc->sc_dk.dk_openmask == 0) { 854 device_acquire(sc->sc_dev); 855 break; 856 } 857 } 858 if (sc == NULL) { 859 KASSERT(idleonly || pdk->dk_nwedges == 0); 860 mutex_exit(&pdk->dk_openlock); 861 mutex_exit(&pdk->dk_rawlock); 862 return; 863 } 864 mutex_exit(&pdk->dk_openlock); 865 mutex_exit(&pdk->dk_rawlock); 866 (void)config_detach_release(sc->sc_dev, flags); 867 } 868 } 869 870 /* 871 * dkwedge_list: [exported function] 872 * 873 * List all of the wedges on a particular disk. 874 */ 875 int 876 dkwedge_list(struct disk *pdk, struct dkwedge_list *dkwl, struct lwp *l) 877 { 878 struct uio uio; 879 struct iovec iov; 880 struct dkwedge_softc *sc; 881 struct dkwedge_info dkw; 882 int error = 0; 883 884 iov.iov_base = dkwl->dkwl_buf; 885 iov.iov_len = dkwl->dkwl_bufsize; 886 887 uio.uio_iov = &iov; 888 uio.uio_iovcnt = 1; 889 uio.uio_offset = 0; 890 uio.uio_resid = dkwl->dkwl_bufsize; 891 uio.uio_rw = UIO_READ; 892 KASSERT(l == curlwp); 893 uio.uio_vmspace = l->l_proc->p_vmspace; 894 895 dkwl->dkwl_ncopied = 0; 896 897 mutex_enter(&pdk->dk_openlock); 898 LIST_FOREACH(sc, &pdk->dk_wedges, sc_plink) { 899 if (uio.uio_resid < sizeof(dkw)) 900 break; 901 902 if (sc->sc_dev == NULL) 903 continue; 904 905 strlcpy(dkw.dkw_devname, device_xname(sc->sc_dev), 906 sizeof(dkw.dkw_devname)); 907 memcpy(dkw.dkw_wname, sc->sc_wname, sizeof(dkw.dkw_wname)); 908 dkw.dkw_wname[sizeof(dkw.dkw_wname) - 1] = '\0'; 909 strlcpy(dkw.dkw_parent, sc->sc_parent->dk_name, 910 sizeof(dkw.dkw_parent)); 911 dkw.dkw_offset = sc->sc_offset; 912 dkw.dkw_size = dkwedge_size(sc); 913 strlcpy(dkw.dkw_ptype, sc->sc_ptype, sizeof(dkw.dkw_ptype)); 914 915 /* 916 * Acquire a device reference so this wedge doesn't go 917 * away before our next iteration in LIST_FOREACH, and 918 * then release the lock for uiomove. 919 */ 920 device_acquire(sc->sc_dev); 921 mutex_exit(&pdk->dk_openlock); 922 error = uiomove(&dkw, sizeof(dkw), &uio); 923 mutex_enter(&pdk->dk_openlock); 924 device_release(sc->sc_dev); 925 if (error) 926 break; 927 928 dkwl->dkwl_ncopied++; 929 } 930 dkwl->dkwl_nwedges = pdk->dk_nwedges; 931 mutex_exit(&pdk->dk_openlock); 932 933 return error; 934 } 935 936 static device_t 937 dkwedge_find_by_wname_acquire(const char *wname) 938 { 939 device_t dv = NULL; 940 struct dkwedge_softc *sc; 941 int i; 942 943 rw_enter(&dkwedges_lock, RW_READER); 944 for (i = 0; i < ndkwedges; i++) { 945 if ((sc = dkwedges[i]) == NULL || sc->sc_dev == NULL) 946 continue; 947 if (strcmp(sc->sc_wname, wname) == 0) { 948 if (dv != NULL) { 949 printf( 950 "WARNING: double match for wedge name %s " 951 "(%s, %s)\n", wname, device_xname(dv), 952 device_xname(sc->sc_dev)); 953 continue; 954 } 955 device_acquire(sc->sc_dev); 956 dv = sc->sc_dev; 957 } 958 } 959 rw_exit(&dkwedges_lock); 960 return dv; 961 } 962 963 static device_t 964 dkwedge_find_by_parent_acquire(const char *name, size_t *i) 965 { 966 967 rw_enter(&dkwedges_lock, RW_READER); 968 for (; *i < (size_t)ndkwedges; (*i)++) { 969 struct dkwedge_softc *sc; 970 if ((sc = dkwedges[*i]) == NULL || sc->sc_dev == NULL) 971 continue; 972 if (strcmp(sc->sc_parent->dk_name, name) != 0) 973 continue; 974 device_acquire(sc->sc_dev); 975 rw_exit(&dkwedges_lock); 976 return sc->sc_dev; 977 } 978 rw_exit(&dkwedges_lock); 979 return NULL; 980 } 981 982 /* XXX unsafe */ 983 device_t 984 dkwedge_find_by_wname(const char *wname) 985 { 986 device_t dv; 987 988 if ((dv = dkwedge_find_by_wname_acquire(wname)) == NULL) 989 return NULL; 990 device_release(dv); 991 return dv; 992 } 993 994 /* XXX unsafe */ 995 device_t 996 dkwedge_find_by_parent(const char *name, size_t *i) 997 { 998 device_t dv; 999 1000 if ((dv = dkwedge_find_by_parent_acquire(name, i)) == NULL) 1001 return NULL; 1002 device_release(dv); 1003 return dv; 1004 } 1005 1006 static device_t 1007 dkwedge_rootspec_hook(const char *spec) 1008 { 1009 device_t dv; 1010 1011 dv = dkwedge_find_by_wname(spec); 1012 return dv; 1013 } 1014 1015 static void 1016 dkwedge_rootspec_print(void) 1017 { 1018 struct dkwedge_softc *sc; 1019 int i; 1020 1021 rw_enter(&dkwedges_lock, RW_READER); 1022 for (i = 0; i < ndkwedges; i++) { 1023 if ((sc = dkwedges[i]) == NULL || sc->sc_dev == NULL) 1024 continue; 1025 printf(" wedge:%s", sc->sc_wname); 1026 } 1027 rw_exit(&dkwedges_lock); 1028 } 1029 1030 /* 1031 * Only list the device names for the wedge:xxx root spec hook. 1032 * For the NAME= root spec hook don't print anything otherwise 1033 * we just get the same wedge device list twice. 1034 */ 1035 static void 1036 dkwedge_rootspec_noprint(void) 1037 { 1038 /* nothing */ 1039 } 1040 1041 /* 1042 * We need a dummy object to stuff into the dkwedge discovery method link 1043 * set to ensure that there is always at least one object in the set. 1044 */ 1045 static struct dkwedge_discovery_method dummy_discovery_method; 1046 __link_set_add_bss(dkwedge_methods, dummy_discovery_method); 1047 1048 /* 1049 * dkwedge_init: 1050 * 1051 * Initialize the disk wedge subsystem. 1052 */ 1053 void 1054 dkwedge_init(void) 1055 { 1056 __link_set_decl(dkwedge_methods, struct dkwedge_discovery_method); 1057 struct dkwedge_discovery_method * const *ddmp; 1058 struct dkwedge_discovery_method *lddm, *ddm; 1059 1060 rw_init(&dkwedges_lock); 1061 rw_init(&dkwedge_discovery_methods_lock); 1062 1063 if (config_cfdriver_attach(&dk_cd) != 0) 1064 panic("dkwedge: unable to attach cfdriver"); 1065 if (config_cfattach_attach(dk_cd.cd_name, &dk_ca) != 0) 1066 panic("dkwedge: unable to attach cfattach"); 1067 1068 rw_enter(&dkwedge_discovery_methods_lock, RW_WRITER); 1069 1070 LIST_INIT(&dkwedge_discovery_methods); 1071 1072 __link_set_foreach(ddmp, dkwedge_methods) { 1073 ddm = *ddmp; 1074 if (ddm == &dummy_discovery_method) 1075 continue; 1076 if (LIST_EMPTY(&dkwedge_discovery_methods)) { 1077 LIST_INSERT_HEAD(&dkwedge_discovery_methods, 1078 ddm, ddm_list); 1079 continue; 1080 } 1081 LIST_FOREACH(lddm, &dkwedge_discovery_methods, ddm_list) { 1082 if (ddm->ddm_priority == lddm->ddm_priority) { 1083 aprint_error("dk-method-%s: method \"%s\" " 1084 "already exists at priority %d\n", 1085 ddm->ddm_name, lddm->ddm_name, 1086 lddm->ddm_priority); 1087 /* Not inserted. */ 1088 break; 1089 } 1090 if (ddm->ddm_priority < lddm->ddm_priority) { 1091 /* Higher priority; insert before. */ 1092 LIST_INSERT_BEFORE(lddm, ddm, ddm_list); 1093 break; 1094 } 1095 if (LIST_NEXT(lddm, ddm_list) == NULL) { 1096 /* Last one; insert after. */ 1097 KASSERT(lddm->ddm_priority < ddm->ddm_priority); 1098 LIST_INSERT_AFTER(lddm, ddm, ddm_list); 1099 break; 1100 } 1101 } 1102 } 1103 1104 rw_exit(&dkwedge_discovery_methods_lock); 1105 1106 /* never unloaded, so don't need to save the hook establish cookies */ 1107 rootspechook_establish("wedge:", dkwedge_rootspec_hook, 1108 dkwedge_rootspec_print); 1109 rootspechook_establish("NAME=", dkwedge_rootspec_hook, 1110 dkwedge_rootspec_noprint); 1111 } 1112 1113 #ifdef DKWEDGE_AUTODISCOVER 1114 int dkwedge_autodiscover = 1; 1115 #else 1116 int dkwedge_autodiscover = 0; 1117 #endif 1118 1119 /* 1120 * dkwedge_discover: [exported function] 1121 * 1122 * Discover the wedges on a newly attached disk. 1123 * Remove all unused wedges on the disk first. 1124 */ 1125 void 1126 dkwedge_discover(struct disk *pdk) 1127 { 1128 struct dkwedge_discovery_method *ddm; 1129 struct vnode *vp; 1130 int error; 1131 dev_t pdev; 1132 1133 /* 1134 * Require people playing with wedges to enable this explicitly. 1135 */ 1136 if (dkwedge_autodiscover == 0) 1137 return; 1138 1139 rw_enter(&dkwedge_discovery_methods_lock, RW_READER); 1140 1141 /* 1142 * Use the character device for scanning, the block device 1143 * is busy if there are already wedges attached. 1144 */ 1145 error = dkwedge_compute_pdev(pdk->dk_name, &pdev, VCHR); 1146 if (error) { 1147 aprint_error("%s: unable to compute pdev, error = %d\n", 1148 pdk->dk_name, error); 1149 goto out; 1150 } 1151 1152 error = cdevvp(pdev, &vp); 1153 if (error) { 1154 aprint_error("%s: unable to find vnode for pdev, error = %d\n", 1155 pdk->dk_name, error); 1156 goto out; 1157 } 1158 1159 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1160 if (error) { 1161 aprint_error("%s: unable to lock vnode for pdev, error = %d\n", 1162 pdk->dk_name, error); 1163 vrele(vp); 1164 goto out; 1165 } 1166 1167 error = VOP_OPEN(vp, FREAD | FSILENT, NOCRED); 1168 if (error) { 1169 if (error != ENXIO) 1170 aprint_error("%s: unable to open device, error = %d\n", 1171 pdk->dk_name, error); 1172 vput(vp); 1173 goto out; 1174 } 1175 VOP_UNLOCK(vp); 1176 1177 /* 1178 * Remove unused wedges 1179 */ 1180 dkwedge_delidle(pdk); 1181 1182 /* 1183 * For each supported partition map type, look to see if 1184 * this map type exists. If so, parse it and add the 1185 * corresponding wedges. 1186 */ 1187 LIST_FOREACH(ddm, &dkwedge_discovery_methods, ddm_list) { 1188 error = (*ddm->ddm_discover)(pdk, vp); 1189 if (error == 0) { 1190 /* Successfully created wedges; we're done. */ 1191 break; 1192 } 1193 } 1194 1195 error = vn_close(vp, FREAD, NOCRED); 1196 if (error) { 1197 aprint_error("%s: unable to close device, error = %d\n", 1198 pdk->dk_name, error); 1199 /* We'll just assume the vnode has been cleaned up. */ 1200 } 1201 1202 out: 1203 rw_exit(&dkwedge_discovery_methods_lock); 1204 } 1205 1206 /* 1207 * dkwedge_read: 1208 * 1209 * Read some data from the specified disk, used for 1210 * partition discovery. 1211 */ 1212 int 1213 dkwedge_read(struct disk *pdk, struct vnode *vp, daddr_t blkno, 1214 void *tbuf, size_t len) 1215 { 1216 buf_t *bp; 1217 int error; 1218 bool isopen; 1219 dev_t bdev; 1220 struct vnode *bdvp; 1221 1222 /* 1223 * The kernel cannot read from a character device vnode 1224 * as physio() only handles user memory. 1225 * 1226 * If the block device has already been opened by a wedge 1227 * use that vnode and temporarily bump the open counter. 1228 * 1229 * Otherwise try to open the block device. 1230 */ 1231 1232 bdev = devsw_chr2blk(vp->v_rdev); 1233 1234 mutex_enter(&pdk->dk_rawlock); 1235 if (pdk->dk_rawopens != 0) { 1236 KASSERT(pdk->dk_rawvp != NULL); 1237 isopen = true; 1238 ++pdk->dk_rawopens; 1239 bdvp = pdk->dk_rawvp; 1240 error = 0; 1241 } else { 1242 isopen = false; 1243 error = dk_open_parent(bdev, FREAD, &bdvp); 1244 } 1245 mutex_exit(&pdk->dk_rawlock); 1246 1247 if (error) 1248 return error; 1249 1250 bp = getiobuf(bdvp, true); 1251 bp->b_flags = B_READ; 1252 bp->b_cflags = BC_BUSY; 1253 bp->b_dev = bdev; 1254 bp->b_data = tbuf; 1255 bp->b_bufsize = bp->b_bcount = len; 1256 bp->b_blkno = blkno; 1257 bp->b_cylinder = 0; 1258 bp->b_error = 0; 1259 1260 VOP_STRATEGY(bdvp, bp); 1261 error = biowait(bp); 1262 putiobuf(bp); 1263 1264 mutex_enter(&pdk->dk_rawlock); 1265 if (isopen) { 1266 --pdk->dk_rawopens; 1267 } else { 1268 dk_close_parent(bdvp, FREAD); 1269 } 1270 mutex_exit(&pdk->dk_rawlock); 1271 1272 return error; 1273 } 1274 1275 /* 1276 * dkwedge_lookup: 1277 * 1278 * Look up a dkwedge_softc based on the provided dev_t. 1279 * 1280 * Caller must guarantee the wedge is referenced. 1281 */ 1282 static struct dkwedge_softc * 1283 dkwedge_lookup(dev_t dev) 1284 { 1285 1286 return device_lookup_private(&dk_cd, minor(dev)); 1287 } 1288 1289 static struct dkwedge_softc * 1290 dkwedge_lookup_acquire(dev_t dev) 1291 { 1292 device_t dv = device_lookup_acquire(&dk_cd, minor(dev)); 1293 1294 if (dv == NULL) 1295 return NULL; 1296 return device_private(dv); 1297 } 1298 1299 static int 1300 dk_open_parent(dev_t dev, int mode, struct vnode **vpp) 1301 { 1302 struct vnode *vp; 1303 int error; 1304 1305 error = bdevvp(dev, &vp); 1306 if (error) 1307 return error; 1308 1309 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1310 if (error) { 1311 vrele(vp); 1312 return error; 1313 } 1314 error = VOP_OPEN(vp, mode, NOCRED); 1315 if (error) { 1316 vput(vp); 1317 return error; 1318 } 1319 1320 /* VOP_OPEN() doesn't do this for us. */ 1321 if (mode & FWRITE) { 1322 mutex_enter(vp->v_interlock); 1323 vp->v_writecount++; 1324 mutex_exit(vp->v_interlock); 1325 } 1326 1327 VOP_UNLOCK(vp); 1328 1329 *vpp = vp; 1330 1331 return 0; 1332 } 1333 1334 static int 1335 dk_close_parent(struct vnode *vp, int mode) 1336 { 1337 int error; 1338 1339 error = vn_close(vp, mode, NOCRED); 1340 return error; 1341 } 1342 1343 /* 1344 * dkopen: [devsw entry point] 1345 * 1346 * Open a wedge. 1347 */ 1348 static int 1349 dkopen(dev_t dev, int flags, int fmt, struct lwp *l) 1350 { 1351 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1352 int error = 0; 1353 1354 if (sc == NULL) 1355 return ENXIO; 1356 KASSERT(sc->sc_dev != NULL); 1357 KASSERT(sc->sc_state == DKW_STATE_RUNNING); 1358 1359 /* 1360 * We go through a complicated little dance to only open the parent 1361 * vnode once per wedge, no matter how many times the wedge is 1362 * opened. The reason? We see one dkopen() per open call, but 1363 * only dkclose() on the last close. 1364 */ 1365 mutex_enter(&sc->sc_dk.dk_openlock); 1366 mutex_enter(&sc->sc_parent->dk_rawlock); 1367 if (sc->sc_dk.dk_openmask == 0) { 1368 error = dkfirstopen(sc, flags); 1369 if (error) 1370 goto out; 1371 } else if (flags & ~sc->sc_mode & FWRITE) { 1372 /* 1373 * The parent is already open, but the previous attempt 1374 * to open it read/write failed and fell back to 1375 * read-only. In that case, we assume the medium is 1376 * read-only and fail to open the wedge read/write. 1377 */ 1378 error = EROFS; 1379 goto out; 1380 } 1381 KASSERT(sc->sc_mode != 0); 1382 KASSERTMSG(sc->sc_mode & FREAD, "%s: sc_mode=%x", 1383 device_xname(sc->sc_dev), sc->sc_mode); 1384 KASSERTMSG((flags & FWRITE) ? (sc->sc_mode & FWRITE) : 1, 1385 "%s: flags=%x sc_mode=%x", 1386 device_xname(sc->sc_dev), flags, sc->sc_mode); 1387 if (fmt == S_IFCHR) 1388 sc->sc_dk.dk_copenmask |= 1; 1389 else 1390 sc->sc_dk.dk_bopenmask |= 1; 1391 sc->sc_dk.dk_openmask = 1392 sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; 1393 1394 out: mutex_exit(&sc->sc_parent->dk_rawlock); 1395 mutex_exit(&sc->sc_dk.dk_openlock); 1396 return error; 1397 } 1398 1399 static int 1400 dkfirstopen(struct dkwedge_softc *sc, int flags) 1401 { 1402 struct dkwedge_softc *nsc; 1403 struct vnode *vp; 1404 int mode; 1405 int error; 1406 1407 KASSERT(mutex_owned(&sc->sc_dk.dk_openlock)); 1408 KASSERT(mutex_owned(&sc->sc_parent->dk_rawlock)); 1409 1410 if (sc->sc_parent->dk_rawopens == 0) { 1411 KASSERT(sc->sc_parent->dk_rawvp == NULL); 1412 /* 1413 * Try open read-write. If this fails for EROFS 1414 * and wedge is read-only, retry to open read-only. 1415 */ 1416 mode = FREAD | FWRITE; 1417 error = dk_open_parent(sc->sc_pdev, mode, &vp); 1418 if (error == EROFS && (flags & FWRITE) == 0) { 1419 mode &= ~FWRITE; 1420 error = dk_open_parent(sc->sc_pdev, mode, &vp); 1421 } 1422 if (error) 1423 return error; 1424 KASSERT(vp != NULL); 1425 sc->sc_parent->dk_rawvp = vp; 1426 } else { 1427 /* 1428 * Retrieve mode from an already opened wedge. 1429 * 1430 * At this point, dk_rawopens is bounded by the number 1431 * of dkwedge devices in the system, which is limited 1432 * by autoconf device numbering to INT_MAX. Since 1433 * dk_rawopens is unsigned, this can't overflow. 1434 */ 1435 KASSERT(sc->sc_parent->dk_rawopens < UINT_MAX); 1436 KASSERT(sc->sc_parent->dk_rawvp != NULL); 1437 mode = 0; 1438 mutex_enter(&sc->sc_parent->dk_openlock); 1439 LIST_FOREACH(nsc, &sc->sc_parent->dk_wedges, sc_plink) { 1440 if (nsc == sc || nsc->sc_dk.dk_openmask == 0) 1441 continue; 1442 mode = nsc->sc_mode; 1443 break; 1444 } 1445 mutex_exit(&sc->sc_parent->dk_openlock); 1446 } 1447 sc->sc_mode = mode; 1448 sc->sc_parent->dk_rawopens++; 1449 1450 return 0; 1451 } 1452 1453 static void 1454 dklastclose(struct dkwedge_softc *sc) 1455 { 1456 1457 KASSERT(mutex_owned(&sc->sc_dk.dk_openlock)); 1458 KASSERT(mutex_owned(&sc->sc_parent->dk_rawlock)); 1459 KASSERT(sc->sc_parent->dk_rawopens > 0); 1460 KASSERT(sc->sc_parent->dk_rawvp != NULL); 1461 1462 if (--sc->sc_parent->dk_rawopens == 0) { 1463 struct vnode *const vp = sc->sc_parent->dk_rawvp; 1464 const int mode = sc->sc_mode; 1465 1466 sc->sc_parent->dk_rawvp = NULL; 1467 sc->sc_mode = 0; 1468 1469 dk_close_parent(vp, mode); 1470 } 1471 } 1472 1473 /* 1474 * dkclose: [devsw entry point] 1475 * 1476 * Close a wedge. 1477 */ 1478 static int 1479 dkclose(dev_t dev, int flags, int fmt, struct lwp *l) 1480 { 1481 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1482 1483 /* 1484 * dkclose can be called even if dkopen didn't succeed, so we 1485 * have to handle the same possibility that the wedge may not 1486 * exist. 1487 */ 1488 if (sc == NULL) 1489 return ENXIO; 1490 KASSERT(sc->sc_dev != NULL); 1491 KASSERT(sc->sc_state != DKW_STATE_LARVAL); 1492 KASSERT(sc->sc_state != DKW_STATE_DEAD); 1493 1494 mutex_enter(&sc->sc_dk.dk_openlock); 1495 mutex_enter(&sc->sc_parent->dk_rawlock); 1496 1497 KASSERT(sc->sc_dk.dk_openmask != 0); 1498 1499 if (fmt == S_IFCHR) 1500 sc->sc_dk.dk_copenmask &= ~1; 1501 else 1502 sc->sc_dk.dk_bopenmask &= ~1; 1503 sc->sc_dk.dk_openmask = 1504 sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; 1505 1506 if (sc->sc_dk.dk_openmask == 0) { 1507 dklastclose(sc); 1508 } 1509 1510 mutex_exit(&sc->sc_parent->dk_rawlock); 1511 mutex_exit(&sc->sc_dk.dk_openlock); 1512 1513 return 0; 1514 } 1515 1516 /* 1517 * dkcancel: [devsw entry point] 1518 * 1519 * Cancel any pending I/O operations waiting on a wedge. 1520 */ 1521 static int 1522 dkcancel(dev_t dev, int flags, int fmt, struct lwp *l) 1523 { 1524 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1525 1526 KASSERT(sc != NULL); 1527 KASSERT(sc->sc_dev != NULL); 1528 KASSERT(sc->sc_state != DKW_STATE_LARVAL); 1529 KASSERT(sc->sc_state != DKW_STATE_DEAD); 1530 1531 /* 1532 * Disk I/O is expected to complete or fail within a reasonable 1533 * timeframe -- it's storage, not communication. Further, the 1534 * character and block device interface guarantees that prior 1535 * reads and writes have completed or failed by the time close 1536 * returns -- we are not to cancel them here. If the parent 1537 * device's hardware is gone, the parent driver can make them 1538 * fail. Nothing for dk(4) itself to do. 1539 */ 1540 1541 return 0; 1542 } 1543 1544 /* 1545 * dkstrategy: [devsw entry point] 1546 * 1547 * Perform I/O based on the wedge I/O strategy. 1548 */ 1549 static void 1550 dkstrategy(struct buf *bp) 1551 { 1552 struct dkwedge_softc *sc = dkwedge_lookup(bp->b_dev); 1553 uint64_t p_size, p_offset; 1554 1555 KASSERT(sc != NULL); 1556 KASSERT(sc->sc_dev != NULL); 1557 KASSERT(sc->sc_state != DKW_STATE_LARVAL); 1558 KASSERT(sc->sc_state != DKW_STATE_DEAD); 1559 KASSERT(sc->sc_parent->dk_rawvp != NULL); 1560 1561 /* If it's an empty transfer, wake up the top half now. */ 1562 if (bp->b_bcount == 0) 1563 goto done; 1564 1565 p_offset = sc->sc_offset << sc->sc_parent->dk_blkshift; 1566 p_size = dkwedge_size(sc) << sc->sc_parent->dk_blkshift; 1567 1568 /* Make sure it's in-range. */ 1569 if (bounds_check_with_mediasize(bp, DEV_BSIZE, p_size) <= 0) 1570 goto done; 1571 1572 /* Translate it to the parent's raw LBA. */ 1573 bp->b_rawblkno = bp->b_blkno + p_offset; 1574 1575 /* Place it in the queue and start I/O on the unit. */ 1576 mutex_enter(&sc->sc_iolock); 1577 disk_wait(&sc->sc_dk); 1578 bufq_put(sc->sc_bufq, bp); 1579 mutex_exit(&sc->sc_iolock); 1580 1581 dkstart(sc); 1582 return; 1583 1584 done: 1585 bp->b_resid = bp->b_bcount; 1586 biodone(bp); 1587 } 1588 1589 /* 1590 * dkstart: 1591 * 1592 * Start I/O that has been enqueued on the wedge. 1593 */ 1594 static void 1595 dkstart(struct dkwedge_softc *sc) 1596 { 1597 struct vnode *vp; 1598 struct buf *bp, *nbp; 1599 1600 mutex_enter(&sc->sc_iolock); 1601 1602 /* Do as much work as has been enqueued. */ 1603 while ((bp = bufq_peek(sc->sc_bufq)) != NULL) { 1604 if (sc->sc_iostop) { 1605 (void) bufq_get(sc->sc_bufq); 1606 mutex_exit(&sc->sc_iolock); 1607 bp->b_error = ENXIO; 1608 bp->b_resid = bp->b_bcount; 1609 biodone(bp); 1610 mutex_enter(&sc->sc_iolock); 1611 continue; 1612 } 1613 1614 /* fetch an I/O buf with sc_iolock dropped */ 1615 mutex_exit(&sc->sc_iolock); 1616 nbp = getiobuf(sc->sc_parent->dk_rawvp, false); 1617 mutex_enter(&sc->sc_iolock); 1618 if (nbp == NULL) { 1619 /* 1620 * No resources to run this request; leave the 1621 * buffer queued up, and schedule a timer to 1622 * restart the queue in 1/2 a second. 1623 */ 1624 if (!sc->sc_iostop) 1625 callout_schedule(&sc->sc_restart_ch, hz/2); 1626 break; 1627 } 1628 1629 /* 1630 * fetch buf, this can fail if another thread 1631 * has already processed the queue, it can also 1632 * return a completely different buf. 1633 */ 1634 bp = bufq_get(sc->sc_bufq); 1635 if (bp == NULL) { 1636 mutex_exit(&sc->sc_iolock); 1637 putiobuf(nbp); 1638 mutex_enter(&sc->sc_iolock); 1639 continue; 1640 } 1641 1642 /* Instrumentation. */ 1643 disk_busy(&sc->sc_dk); 1644 1645 /* release lock for VOP_STRATEGY */ 1646 mutex_exit(&sc->sc_iolock); 1647 1648 nbp->b_data = bp->b_data; 1649 nbp->b_flags = bp->b_flags; 1650 nbp->b_oflags = bp->b_oflags; 1651 nbp->b_cflags = bp->b_cflags; 1652 nbp->b_iodone = dkiodone; 1653 nbp->b_proc = bp->b_proc; 1654 nbp->b_blkno = bp->b_rawblkno; 1655 nbp->b_dev = sc->sc_parent->dk_rawvp->v_rdev; 1656 nbp->b_bcount = bp->b_bcount; 1657 nbp->b_private = bp; 1658 BIO_COPYPRIO(nbp, bp); 1659 1660 vp = nbp->b_vp; 1661 if ((nbp->b_flags & B_READ) == 0) { 1662 mutex_enter(vp->v_interlock); 1663 vp->v_numoutput++; 1664 mutex_exit(vp->v_interlock); 1665 } 1666 VOP_STRATEGY(vp, nbp); 1667 1668 mutex_enter(&sc->sc_iolock); 1669 } 1670 1671 mutex_exit(&sc->sc_iolock); 1672 } 1673 1674 /* 1675 * dkiodone: 1676 * 1677 * I/O to a wedge has completed; alert the top half. 1678 */ 1679 static void 1680 dkiodone(struct buf *bp) 1681 { 1682 struct buf *obp = bp->b_private; 1683 struct dkwedge_softc *sc = dkwedge_lookup(obp->b_dev); 1684 1685 KASSERT(sc != NULL); 1686 KASSERT(sc->sc_dev != NULL); 1687 1688 if (bp->b_error != 0) 1689 obp->b_error = bp->b_error; 1690 obp->b_resid = bp->b_resid; 1691 putiobuf(bp); 1692 1693 mutex_enter(&sc->sc_iolock); 1694 disk_unbusy(&sc->sc_dk, obp->b_bcount - obp->b_resid, 1695 obp->b_flags & B_READ); 1696 mutex_exit(&sc->sc_iolock); 1697 1698 biodone(obp); 1699 1700 /* Kick the queue in case there is more work we can do. */ 1701 dkstart(sc); 1702 } 1703 1704 /* 1705 * dkrestart: 1706 * 1707 * Restart the work queue after it was stalled due to 1708 * a resource shortage. Invoked via a callout. 1709 */ 1710 static void 1711 dkrestart(void *v) 1712 { 1713 struct dkwedge_softc *sc = v; 1714 1715 dkstart(sc); 1716 } 1717 1718 /* 1719 * dkminphys: 1720 * 1721 * Call parent's minphys function. 1722 */ 1723 static void 1724 dkminphys(struct buf *bp) 1725 { 1726 struct dkwedge_softc *sc = dkwedge_lookup(bp->b_dev); 1727 dev_t dev; 1728 1729 KASSERT(sc != NULL); 1730 KASSERT(sc->sc_dev != NULL); 1731 1732 dev = bp->b_dev; 1733 bp->b_dev = sc->sc_pdev; 1734 if (sc->sc_parent->dk_driver && sc->sc_parent->dk_driver->d_minphys) 1735 (*sc->sc_parent->dk_driver->d_minphys)(bp); 1736 else 1737 minphys(bp); 1738 bp->b_dev = dev; 1739 } 1740 1741 /* 1742 * dkread: [devsw entry point] 1743 * 1744 * Read from a wedge. 1745 */ 1746 static int 1747 dkread(dev_t dev, struct uio *uio, int flags) 1748 { 1749 struct dkwedge_softc *sc __diagused = dkwedge_lookup(dev); 1750 1751 KASSERT(sc != NULL); 1752 KASSERT(sc->sc_dev != NULL); 1753 KASSERT(sc->sc_state != DKW_STATE_LARVAL); 1754 KASSERT(sc->sc_state != DKW_STATE_DEAD); 1755 1756 return physio(dkstrategy, NULL, dev, B_READ, dkminphys, uio); 1757 } 1758 1759 /* 1760 * dkwrite: [devsw entry point] 1761 * 1762 * Write to a wedge. 1763 */ 1764 static int 1765 dkwrite(dev_t dev, struct uio *uio, int flags) 1766 { 1767 struct dkwedge_softc *sc __diagused = dkwedge_lookup(dev); 1768 1769 KASSERT(sc != NULL); 1770 KASSERT(sc->sc_dev != NULL); 1771 KASSERT(sc->sc_state != DKW_STATE_LARVAL); 1772 KASSERT(sc->sc_state != DKW_STATE_DEAD); 1773 1774 return physio(dkstrategy, NULL, dev, B_WRITE, dkminphys, uio); 1775 } 1776 1777 /* 1778 * dkioctl: [devsw entry point] 1779 * 1780 * Perform an ioctl request on a wedge. 1781 */ 1782 static int 1783 dkioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1784 { 1785 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1786 int error = 0; 1787 1788 KASSERT(sc != NULL); 1789 KASSERT(sc->sc_dev != NULL); 1790 KASSERT(sc->sc_state != DKW_STATE_LARVAL); 1791 KASSERT(sc->sc_state != DKW_STATE_DEAD); 1792 KASSERT(sc->sc_parent->dk_rawvp != NULL); 1793 1794 /* 1795 * We pass NODEV instead of our device to indicate we don't 1796 * want to handle disklabel ioctls 1797 */ 1798 error = disk_ioctl(&sc->sc_dk, NODEV, cmd, data, flag, l); 1799 if (error != EPASSTHROUGH) 1800 return error; 1801 1802 error = 0; 1803 1804 switch (cmd) { 1805 case DIOCGSTRATEGY: 1806 case DIOCGCACHE: 1807 case DIOCCACHESYNC: 1808 error = VOP_IOCTL(sc->sc_parent->dk_rawvp, cmd, data, flag, 1809 l != NULL ? l->l_cred : NOCRED); 1810 break; 1811 case DIOCGWEDGEINFO: { 1812 struct dkwedge_info *dkw = data; 1813 1814 strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev), 1815 sizeof(dkw->dkw_devname)); 1816 memcpy(dkw->dkw_wname, sc->sc_wname, sizeof(dkw->dkw_wname)); 1817 dkw->dkw_wname[sizeof(dkw->dkw_wname) - 1] = '\0'; 1818 strlcpy(dkw->dkw_parent, sc->sc_parent->dk_name, 1819 sizeof(dkw->dkw_parent)); 1820 dkw->dkw_offset = sc->sc_offset; 1821 dkw->dkw_size = dkwedge_size(sc); 1822 strlcpy(dkw->dkw_ptype, sc->sc_ptype, sizeof(dkw->dkw_ptype)); 1823 1824 break; 1825 } 1826 case DIOCGSECTORALIGN: { 1827 struct disk_sectoralign *dsa = data; 1828 uint32_t r; 1829 1830 error = VOP_IOCTL(sc->sc_parent->dk_rawvp, cmd, dsa, flag, 1831 l != NULL ? l->l_cred : NOCRED); 1832 if (error) 1833 break; 1834 1835 r = sc->sc_offset % dsa->dsa_alignment; 1836 if (r < dsa->dsa_firstaligned) 1837 dsa->dsa_firstaligned = dsa->dsa_firstaligned - r; 1838 else 1839 dsa->dsa_firstaligned = (dsa->dsa_firstaligned + 1840 dsa->dsa_alignment) - r; 1841 dsa->dsa_firstaligned %= dsa->dsa_alignment; 1842 break; 1843 } 1844 default: 1845 error = ENOTTY; 1846 } 1847 1848 return error; 1849 } 1850 1851 /* 1852 * dkdiscard: [devsw entry point] 1853 * 1854 * Perform a discard-range request on a wedge. 1855 */ 1856 static int 1857 dkdiscard(dev_t dev, off_t pos, off_t len) 1858 { 1859 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1860 uint64_t size = dkwedge_size(sc); 1861 unsigned shift; 1862 off_t offset, maxlen; 1863 int error; 1864 1865 KASSERT(sc != NULL); 1866 KASSERT(sc->sc_dev != NULL); 1867 KASSERT(sc->sc_state != DKW_STATE_LARVAL); 1868 KASSERT(sc->sc_state != DKW_STATE_DEAD); 1869 KASSERT(sc->sc_parent->dk_rawvp != NULL); 1870 1871 /* XXX check bounds on size/offset up front */ 1872 shift = (sc->sc_parent->dk_blkshift + DEV_BSHIFT); 1873 KASSERT(__type_fit(off_t, size)); 1874 KASSERT(__type_fit(off_t, sc->sc_offset)); 1875 KASSERT(0 <= sc->sc_offset); 1876 KASSERT(size <= (__type_max(off_t) >> shift)); 1877 KASSERT(sc->sc_offset <= ((__type_max(off_t) >> shift) - size)); 1878 offset = ((off_t)sc->sc_offset << shift); 1879 maxlen = ((off_t)size << shift); 1880 1881 if (len > maxlen) 1882 return EINVAL; 1883 if (pos > (maxlen - len)) 1884 return EINVAL; 1885 1886 pos += offset; 1887 1888 vn_lock(sc->sc_parent->dk_rawvp, LK_EXCLUSIVE | LK_RETRY); 1889 error = VOP_FDISCARD(sc->sc_parent->dk_rawvp, pos, len); 1890 VOP_UNLOCK(sc->sc_parent->dk_rawvp); 1891 1892 return error; 1893 } 1894 1895 /* 1896 * dksize: [devsw entry point] 1897 * 1898 * Query the size of a wedge for the purpose of performing a dump 1899 * or for swapping to. 1900 */ 1901 static int 1902 dksize(dev_t dev) 1903 { 1904 /* 1905 * Don't bother taking a reference because this is only used 1906 * either (a) while the device is open (for swap), or (b) while 1907 * any multiprocessing is quiescent (for crash dumps). 1908 */ 1909 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1910 uint64_t p_size; 1911 int rv = -1; 1912 1913 if (sc == NULL) 1914 return -1; 1915 if (sc->sc_state != DKW_STATE_RUNNING) 1916 return -1; 1917 1918 /* Our content type is static, no need to open the device. */ 1919 1920 p_size = dkwedge_size(sc) << sc->sc_parent->dk_blkshift; 1921 if (strcmp(sc->sc_ptype, DKW_PTYPE_SWAP) == 0) { 1922 /* Saturate if we are larger than INT_MAX. */ 1923 if (p_size > INT_MAX) 1924 rv = INT_MAX; 1925 else 1926 rv = (int)p_size; 1927 } 1928 1929 return rv; 1930 } 1931 1932 /* 1933 * dkdump: [devsw entry point] 1934 * 1935 * Perform a crash dump to a wedge. 1936 */ 1937 static int 1938 dkdump(dev_t dev, daddr_t blkno, void *va, size_t size) 1939 { 1940 /* 1941 * Don't bother taking a reference because this is only used 1942 * while any multiprocessing is quiescent. 1943 */ 1944 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1945 const struct bdevsw *bdev; 1946 uint64_t p_size, p_offset; 1947 1948 if (sc == NULL) 1949 return ENXIO; 1950 if (sc->sc_state != DKW_STATE_RUNNING) 1951 return ENXIO; 1952 1953 /* Our content type is static, no need to open the device. */ 1954 1955 if (strcmp(sc->sc_ptype, DKW_PTYPE_SWAP) != 0 && 1956 strcmp(sc->sc_ptype, DKW_PTYPE_RAID) != 0 && 1957 strcmp(sc->sc_ptype, DKW_PTYPE_CGD) != 0) 1958 return ENXIO; 1959 if (size % DEV_BSIZE != 0) 1960 return EINVAL; 1961 1962 p_offset = sc->sc_offset << sc->sc_parent->dk_blkshift; 1963 p_size = dkwedge_size(sc) << sc->sc_parent->dk_blkshift; 1964 1965 if (blkno < 0 || blkno + size/DEV_BSIZE > p_size) { 1966 printf("%s: blkno (%" PRIu64 ") + size / DEV_BSIZE (%zu) > " 1967 "p_size (%" PRIu64 ")\n", __func__, blkno, 1968 size/DEV_BSIZE, p_size); 1969 return EINVAL; 1970 } 1971 1972 bdev = bdevsw_lookup(sc->sc_pdev); 1973 return (*bdev->d_dump)(sc->sc_pdev, blkno + p_offset, va, size); 1974 } 1975 1976 /* 1977 * config glue 1978 */ 1979 1980 /* 1981 * dkwedge_find_partition 1982 * 1983 * Find wedge corresponding to the specified parent name 1984 * and offset/length. 1985 */ 1986 static device_t 1987 dkwedge_find_partition_acquire(device_t parent, daddr_t startblk, 1988 uint64_t nblks) 1989 { 1990 struct dkwedge_softc *sc; 1991 int i; 1992 device_t wedge = NULL; 1993 1994 rw_enter(&dkwedges_lock, RW_READER); 1995 for (i = 0; i < ndkwedges; i++) { 1996 if ((sc = dkwedges[i]) == NULL || sc->sc_dev == NULL) 1997 continue; 1998 if (strcmp(sc->sc_parent->dk_name, device_xname(parent)) == 0 && 1999 sc->sc_offset == startblk && 2000 dkwedge_size(sc) == nblks) { 2001 if (wedge) { 2002 printf("WARNING: double match for boot wedge " 2003 "(%s, %s)\n", 2004 device_xname(wedge), 2005 device_xname(sc->sc_dev)); 2006 continue; 2007 } 2008 wedge = sc->sc_dev; 2009 device_acquire(wedge); 2010 } 2011 } 2012 rw_exit(&dkwedges_lock); 2013 2014 return wedge; 2015 } 2016 2017 /* XXX unsafe */ 2018 device_t 2019 dkwedge_find_partition(device_t parent, daddr_t startblk, 2020 uint64_t nblks) 2021 { 2022 device_t dv; 2023 2024 if ((dv = dkwedge_find_partition_acquire(parent, startblk, nblks)) 2025 == NULL) 2026 return NULL; 2027 device_release(dv); 2028 return dv; 2029 } 2030 2031 const char * 2032 dkwedge_get_parent_name(dev_t dev) 2033 { 2034 /* XXX: perhaps do this in lookup? */ 2035 int bmaj = bdevsw_lookup_major(&dk_bdevsw); 2036 int cmaj = cdevsw_lookup_major(&dk_cdevsw); 2037 2038 if (major(dev) != bmaj && major(dev) != cmaj) 2039 return NULL; 2040 2041 struct dkwedge_softc *const sc = dkwedge_lookup_acquire(dev); 2042 if (sc == NULL) 2043 return NULL; 2044 const char *const name = sc->sc_parent->dk_name; 2045 device_release(sc->sc_dev); 2046 return name; 2047 } 2048