1 /*- 2 * Copyright (c) 2011-2013 Alexander Motin <mav@FreeBSD.org> 3 * Copyright (c) 2006-2007 Matthew Jacob <mjacob@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 /* 28 * Based upon work by Pawel Jakub Dawidek <pjd@FreeBSD.org> for all of the 29 * fine geom examples, and by Poul Henning Kamp <phk@FreeBSD.org> for GEOM 30 * itself, all of which is most gratefully acknowledged. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/module.h> 39 #include <sys/limits.h> 40 #include <sys/lock.h> 41 #include <sys/mutex.h> 42 #include <sys/bio.h> 43 #include <sys/sbuf.h> 44 #include <sys/sysctl.h> 45 #include <sys/kthread.h> 46 #include <sys/malloc.h> 47 #include <geom/geom.h> 48 #include <geom/multipath/g_multipath.h> 49 50 FEATURE(geom_multipath, "GEOM multipath support"); 51 52 SYSCTL_DECL(_kern_geom); 53 static SYSCTL_NODE(_kern_geom, OID_AUTO, multipath, CTLFLAG_RW, 0, 54 "GEOM_MULTIPATH tunables"); 55 static u_int g_multipath_debug = 0; 56 SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, debug, CTLFLAG_RW, 57 &g_multipath_debug, 0, "Debug level"); 58 static u_int g_multipath_exclusive = 1; 59 SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, exclusive, CTLFLAG_RW, 60 &g_multipath_exclusive, 0, "Exclusively open providers"); 61 62 static enum { 63 GKT_NIL, 64 GKT_RUN, 65 GKT_DIE 66 } g_multipath_kt_state; 67 static struct bio_queue_head gmtbq; 68 static struct mtx gmtbq_mtx; 69 70 static int g_multipath_read_metadata(struct g_consumer *cp, 71 struct g_multipath_metadata *md); 72 static int g_multipath_write_metadata(struct g_consumer *cp, 73 struct g_multipath_metadata *md); 74 75 static void g_multipath_orphan(struct g_consumer *); 76 static void g_multipath_resize(struct g_consumer *); 77 static void g_multipath_start(struct bio *); 78 static void g_multipath_done(struct bio *); 79 static void g_multipath_done_error(struct bio *); 80 static void g_multipath_kt(void *); 81 82 static int g_multipath_destroy(struct g_geom *); 83 static int 84 g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *); 85 86 static struct g_geom *g_multipath_find_geom(struct g_class *, const char *); 87 static int g_multipath_rotate(struct g_geom *); 88 89 static g_taste_t g_multipath_taste; 90 static g_ctl_req_t g_multipath_config; 91 static g_init_t g_multipath_init; 92 static g_fini_t g_multipath_fini; 93 static g_dumpconf_t g_multipath_dumpconf; 94 95 struct g_class g_multipath_class = { 96 .name = G_MULTIPATH_CLASS_NAME, 97 .version = G_VERSION, 98 .ctlreq = g_multipath_config, 99 .taste = g_multipath_taste, 100 .destroy_geom = g_multipath_destroy_geom, 101 .init = g_multipath_init, 102 .fini = g_multipath_fini 103 }; 104 105 #define MP_FAIL 0x00000001 106 #define MP_LOST 0x00000002 107 #define MP_NEW 0x00000004 108 #define MP_POSTED 0x00000008 109 #define MP_BAD (MP_FAIL | MP_LOST | MP_NEW) 110 #define MP_IDLE 0x00000010 111 #define MP_IDLE_MASK 0xfffffff0 112 113 static int 114 g_multipath_good(struct g_geom *gp) 115 { 116 struct g_consumer *cp; 117 int n = 0; 118 119 LIST_FOREACH(cp, &gp->consumer, consumer) { 120 if ((cp->index & MP_BAD) == 0) 121 n++; 122 } 123 return (n); 124 } 125 126 static void 127 g_multipath_fault(struct g_consumer *cp, int cause) 128 { 129 struct g_multipath_softc *sc; 130 struct g_consumer *lcp; 131 struct g_geom *gp; 132 133 gp = cp->geom; 134 sc = gp->softc; 135 cp->index |= cause; 136 if (g_multipath_good(gp) == 0 && sc->sc_ndisks > 0) { 137 LIST_FOREACH(lcp, &gp->consumer, consumer) { 138 if (lcp->provider == NULL || 139 (lcp->index & (MP_LOST | MP_NEW))) 140 continue; 141 if (sc->sc_ndisks > 1 && lcp == cp) 142 continue; 143 printf("GEOM_MULTIPATH: " 144 "all paths in %s were marked FAIL, restore %s\n", 145 sc->sc_name, lcp->provider->name); 146 lcp->index &= ~MP_FAIL; 147 } 148 } 149 if (cp != sc->sc_active) 150 return; 151 sc->sc_active = NULL; 152 LIST_FOREACH(lcp, &gp->consumer, consumer) { 153 if ((lcp->index & MP_BAD) == 0) { 154 sc->sc_active = lcp; 155 break; 156 } 157 } 158 if (sc->sc_active == NULL) { 159 printf("GEOM_MULTIPATH: out of providers for %s\n", 160 sc->sc_name); 161 } else if (sc->sc_active_active != 1) { 162 printf("GEOM_MULTIPATH: %s is now active path in %s\n", 163 sc->sc_active->provider->name, sc->sc_name); 164 } 165 } 166 167 static struct g_consumer * 168 g_multipath_choose(struct g_geom *gp, struct bio *bp) 169 { 170 struct g_multipath_softc *sc; 171 struct g_consumer *best, *cp; 172 173 sc = gp->softc; 174 if (sc->sc_active_active == 0 || 175 (sc->sc_active_active == 2 && bp->bio_cmd != BIO_READ)) 176 return (sc->sc_active); 177 best = NULL; 178 LIST_FOREACH(cp, &gp->consumer, consumer) { 179 if (cp->index & MP_BAD) 180 continue; 181 cp->index += MP_IDLE; 182 if (best == NULL || cp->private < best->private || 183 (cp->private == best->private && cp->index > best->index)) 184 best = cp; 185 } 186 if (best != NULL) 187 best->index &= ~MP_IDLE_MASK; 188 return (best); 189 } 190 191 static void 192 g_mpd(void *arg, int flags __unused) 193 { 194 struct g_geom *gp; 195 struct g_multipath_softc *sc; 196 struct g_consumer *cp; 197 int w; 198 199 g_topology_assert(); 200 cp = arg; 201 gp = cp->geom; 202 if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) { 203 w = cp->acw; 204 g_access(cp, -cp->acr, -cp->acw, -cp->ace); 205 if (w > 0 && cp->provider != NULL && 206 (cp->provider->geom->flags & G_GEOM_WITHER) == 0) { 207 g_post_event(g_mpd, cp, M_WAITOK, NULL); 208 return; 209 } 210 } 211 sc = gp->softc; 212 mtx_lock(&sc->sc_mtx); 213 if (cp->provider) { 214 printf("GEOM_MULTIPATH: %s removed from %s\n", 215 cp->provider->name, gp->name); 216 g_detach(cp); 217 } 218 g_destroy_consumer(cp); 219 mtx_unlock(&sc->sc_mtx); 220 if (LIST_EMPTY(&gp->consumer)) 221 g_multipath_destroy(gp); 222 } 223 224 static void 225 g_multipath_orphan(struct g_consumer *cp) 226 { 227 struct g_multipath_softc *sc; 228 uintptr_t *cnt; 229 230 g_topology_assert(); 231 printf("GEOM_MULTIPATH: %s in %s was disconnected\n", 232 cp->provider->name, cp->geom->name); 233 sc = cp->geom->softc; 234 cnt = (uintptr_t *)&cp->private; 235 mtx_lock(&sc->sc_mtx); 236 sc->sc_ndisks--; 237 g_multipath_fault(cp, MP_LOST); 238 if (*cnt == 0 && (cp->index & MP_POSTED) == 0) { 239 cp->index |= MP_POSTED; 240 mtx_unlock(&sc->sc_mtx); 241 g_mpd(cp, 0); 242 } else 243 mtx_unlock(&sc->sc_mtx); 244 } 245 246 static void 247 g_multipath_resize(struct g_consumer *cp) 248 { 249 struct g_multipath_softc *sc; 250 struct g_geom *gp; 251 struct g_consumer *cp1; 252 struct g_provider *pp; 253 struct g_multipath_metadata md; 254 off_t size, psize, ssize; 255 int error; 256 257 g_topology_assert(); 258 259 gp = cp->geom; 260 pp = cp->provider; 261 sc = gp->softc; 262 263 if (sc->sc_stopping) 264 return; 265 266 if (pp->mediasize < sc->sc_size) { 267 size = pp->mediasize; 268 ssize = pp->sectorsize; 269 } else { 270 size = ssize = OFF_MAX; 271 mtx_lock(&sc->sc_mtx); 272 LIST_FOREACH(cp1, &gp->consumer, consumer) { 273 pp = cp1->provider; 274 if (pp == NULL) 275 continue; 276 if (pp->mediasize < size) { 277 size = pp->mediasize; 278 ssize = pp->sectorsize; 279 } 280 } 281 mtx_unlock(&sc->sc_mtx); 282 if (size == OFF_MAX || size == sc->sc_size) 283 return; 284 } 285 psize = size - ((sc->sc_uuid[0] != 0) ? ssize : 0); 286 printf("GEOM_MULTIPATH: %s size changed from %jd to %jd\n", 287 sc->sc_name, sc->sc_pp->mediasize, psize); 288 if (sc->sc_uuid[0] != 0 && size < sc->sc_size) { 289 error = g_multipath_read_metadata(cp, &md); 290 if (error || 291 (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) || 292 (memcmp(md.md_uuid, sc->sc_uuid, sizeof(sc->sc_uuid)) != 0) || 293 (strcmp(md.md_name, sc->sc_name) != 0) || 294 (md.md_size != 0 && md.md_size != size) || 295 (md.md_sectorsize != 0 && md.md_sectorsize != ssize)) { 296 g_multipath_destroy(gp); 297 return; 298 } 299 } 300 sc->sc_size = size; 301 g_resize_provider(sc->sc_pp, psize); 302 303 if (sc->sc_uuid[0] != 0) { 304 pp = cp->provider; 305 strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 306 memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid)); 307 strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name)); 308 md.md_version = G_MULTIPATH_VERSION; 309 md.md_size = size; 310 md.md_sectorsize = ssize; 311 md.md_active_active = sc->sc_active_active; 312 error = g_multipath_write_metadata(cp, &md); 313 if (error != 0) 314 printf("GEOM_MULTIPATH: Can't update metadata on %s " 315 "(%d)\n", pp->name, error); 316 } 317 } 318 319 static void 320 g_multipath_start(struct bio *bp) 321 { 322 struct g_multipath_softc *sc; 323 struct g_geom *gp; 324 struct g_consumer *cp; 325 struct bio *cbp; 326 uintptr_t *cnt; 327 328 gp = bp->bio_to->geom; 329 sc = gp->softc; 330 KASSERT(sc != NULL, ("NULL sc")); 331 cbp = g_clone_bio(bp); 332 if (cbp == NULL) { 333 g_io_deliver(bp, ENOMEM); 334 return; 335 } 336 mtx_lock(&sc->sc_mtx); 337 cp = g_multipath_choose(gp, bp); 338 if (cp == NULL) { 339 mtx_unlock(&sc->sc_mtx); 340 g_destroy_bio(cbp); 341 g_io_deliver(bp, ENXIO); 342 return; 343 } 344 if ((uintptr_t)bp->bio_driver1 < sc->sc_ndisks) 345 bp->bio_driver1 = (void *)(uintptr_t)sc->sc_ndisks; 346 cnt = (uintptr_t *)&cp->private; 347 (*cnt)++; 348 mtx_unlock(&sc->sc_mtx); 349 cbp->bio_done = g_multipath_done; 350 g_io_request(cbp, cp); 351 } 352 353 static void 354 g_multipath_done(struct bio *bp) 355 { 356 struct g_multipath_softc *sc; 357 struct g_consumer *cp; 358 uintptr_t *cnt; 359 360 if (bp->bio_error == ENXIO || bp->bio_error == EIO) { 361 mtx_lock(&gmtbq_mtx); 362 bioq_insert_tail(&gmtbq, bp); 363 mtx_unlock(&gmtbq_mtx); 364 wakeup(&g_multipath_kt_state); 365 } else { 366 cp = bp->bio_from; 367 sc = cp->geom->softc; 368 cnt = (uintptr_t *)&cp->private; 369 mtx_lock(&sc->sc_mtx); 370 (*cnt)--; 371 if (*cnt == 0 && (cp->index & MP_LOST)) { 372 cp->index |= MP_POSTED; 373 mtx_unlock(&sc->sc_mtx); 374 g_post_event(g_mpd, cp, M_WAITOK, NULL); 375 } else 376 mtx_unlock(&sc->sc_mtx); 377 g_std_done(bp); 378 } 379 } 380 381 static void 382 g_multipath_done_error(struct bio *bp) 383 { 384 struct bio *pbp; 385 struct g_geom *gp; 386 struct g_multipath_softc *sc; 387 struct g_consumer *cp; 388 struct g_provider *pp; 389 uintptr_t *cnt; 390 391 /* 392 * If we had a failure, we have to check first to see 393 * whether the consumer it failed on was the currently 394 * active consumer (i.e., this is the first in perhaps 395 * a number of failures). If so, we then switch consumers 396 * to the next available consumer. 397 */ 398 399 pbp = bp->bio_parent; 400 gp = pbp->bio_to->geom; 401 sc = gp->softc; 402 cp = bp->bio_from; 403 pp = cp->provider; 404 cnt = (uintptr_t *)&cp->private; 405 406 mtx_lock(&sc->sc_mtx); 407 if ((cp->index & MP_FAIL) == 0) { 408 printf("GEOM_MULTIPATH: Error %d, %s in %s marked FAIL\n", 409 bp->bio_error, pp->name, sc->sc_name); 410 g_multipath_fault(cp, MP_FAIL); 411 } 412 (*cnt)--; 413 if (*cnt == 0 && (cp->index & (MP_LOST | MP_POSTED)) == MP_LOST) { 414 cp->index |= MP_POSTED; 415 mtx_unlock(&sc->sc_mtx); 416 g_post_event(g_mpd, cp, M_WAITOK, NULL); 417 } else 418 mtx_unlock(&sc->sc_mtx); 419 420 /* 421 * If we can fruitfully restart the I/O, do so. 422 */ 423 if (pbp->bio_children < (uintptr_t)pbp->bio_driver1) { 424 pbp->bio_inbed++; 425 g_destroy_bio(bp); 426 g_multipath_start(pbp); 427 } else { 428 g_std_done(bp); 429 } 430 } 431 432 static void 433 g_multipath_kt(void *arg) 434 { 435 436 g_multipath_kt_state = GKT_RUN; 437 mtx_lock(&gmtbq_mtx); 438 while (g_multipath_kt_state == GKT_RUN) { 439 for (;;) { 440 struct bio *bp; 441 442 bp = bioq_takefirst(&gmtbq); 443 if (bp == NULL) 444 break; 445 mtx_unlock(&gmtbq_mtx); 446 g_multipath_done_error(bp); 447 mtx_lock(&gmtbq_mtx); 448 } 449 if (g_multipath_kt_state != GKT_RUN) 450 break; 451 msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO, 452 "gkt:wait", 0); 453 } 454 mtx_unlock(&gmtbq_mtx); 455 wakeup(&g_multipath_kt_state); 456 kproc_exit(0); 457 } 458 459 460 static int 461 g_multipath_access(struct g_provider *pp, int dr, int dw, int de) 462 { 463 struct g_geom *gp; 464 struct g_consumer *cp, *badcp = NULL; 465 struct g_multipath_softc *sc; 466 int error; 467 468 gp = pp->geom; 469 470 LIST_FOREACH(cp, &gp->consumer, consumer) { 471 error = g_access(cp, dr, dw, de); 472 if (error) { 473 badcp = cp; 474 goto fail; 475 } 476 } 477 sc = gp->softc; 478 sc->sc_opened += dr + dw + de; 479 if (sc->sc_stopping && sc->sc_opened == 0) 480 g_multipath_destroy(gp); 481 return (0); 482 483 fail: 484 LIST_FOREACH(cp, &gp->consumer, consumer) { 485 if (cp == badcp) 486 break; 487 (void) g_access(cp, -dr, -dw, -de); 488 } 489 return (error); 490 } 491 492 static struct g_geom * 493 g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md) 494 { 495 struct g_multipath_softc *sc; 496 struct g_geom *gp; 497 struct g_provider *pp; 498 499 g_topology_assert(); 500 501 LIST_FOREACH(gp, &mp->geom, geom) { 502 sc = gp->softc; 503 if (sc == NULL || sc->sc_stopping) 504 continue; 505 if (strcmp(gp->name, md->md_name) == 0) { 506 printf("GEOM_MULTIPATH: name %s already exists\n", 507 md->md_name); 508 return (NULL); 509 } 510 } 511 512 gp = g_new_geomf(mp, "%s", md->md_name); 513 sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); 514 mtx_init(&sc->sc_mtx, "multipath", NULL, MTX_DEF); 515 memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid)); 516 memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name)); 517 sc->sc_active_active = md->md_active_active; 518 sc->sc_size = md->md_size; 519 gp->softc = sc; 520 gp->start = g_multipath_start; 521 gp->orphan = g_multipath_orphan; 522 gp->resize = g_multipath_resize; 523 gp->access = g_multipath_access; 524 gp->dumpconf = g_multipath_dumpconf; 525 526 pp = g_new_providerf(gp, "multipath/%s", md->md_name); 527 pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; 528 if (md->md_size != 0) { 529 pp->mediasize = md->md_size - 530 ((md->md_uuid[0] != 0) ? md->md_sectorsize : 0); 531 pp->sectorsize = md->md_sectorsize; 532 } 533 sc->sc_pp = pp; 534 g_error_provider(pp, 0); 535 printf("GEOM_MULTIPATH: %s created\n", gp->name); 536 return (gp); 537 } 538 539 static int 540 g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp) 541 { 542 struct g_multipath_softc *sc; 543 struct g_consumer *cp, *nxtcp; 544 int error, acr, acw, ace; 545 546 g_topology_assert(); 547 548 sc = gp->softc; 549 KASSERT(sc, ("no softc")); 550 551 /* 552 * Make sure that the passed provider isn't already attached 553 */ 554 LIST_FOREACH(cp, &gp->consumer, consumer) { 555 if (cp->provider == pp) 556 break; 557 } 558 if (cp) { 559 printf("GEOM_MULTIPATH: provider %s already attached to %s\n", 560 pp->name, gp->name); 561 return (EEXIST); 562 } 563 nxtcp = LIST_FIRST(&gp->consumer); 564 cp = g_new_consumer(gp); 565 cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 566 cp->private = NULL; 567 cp->index = MP_NEW; 568 error = g_attach(cp, pp); 569 if (error != 0) { 570 printf("GEOM_MULTIPATH: cannot attach %s to %s", 571 pp->name, sc->sc_name); 572 g_destroy_consumer(cp); 573 return (error); 574 } 575 576 /* 577 * Set access permissions on new consumer to match other consumers 578 */ 579 if (sc->sc_pp) { 580 acr = sc->sc_pp->acr; 581 acw = sc->sc_pp->acw; 582 ace = sc->sc_pp->ace; 583 } else 584 acr = acw = ace = 0; 585 if (g_multipath_exclusive) { 586 acr++; 587 acw++; 588 ace++; 589 } 590 error = g_access(cp, acr, acw, ace); 591 if (error) { 592 printf("GEOM_MULTIPATH: cannot set access in " 593 "attaching %s to %s (%d)\n", 594 pp->name, sc->sc_name, error); 595 g_detach(cp); 596 g_destroy_consumer(cp); 597 return (error); 598 } 599 if (sc->sc_size == 0) { 600 sc->sc_size = pp->mediasize - 601 ((sc->sc_uuid[0] != 0) ? pp->sectorsize : 0); 602 sc->sc_pp->mediasize = sc->sc_size; 603 sc->sc_pp->sectorsize = pp->sectorsize; 604 } 605 if (sc->sc_pp->stripesize == 0 && sc->sc_pp->stripeoffset == 0) { 606 sc->sc_pp->stripesize = pp->stripesize; 607 sc->sc_pp->stripeoffset = pp->stripeoffset; 608 } 609 sc->sc_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED; 610 mtx_lock(&sc->sc_mtx); 611 cp->index = 0; 612 sc->sc_ndisks++; 613 mtx_unlock(&sc->sc_mtx); 614 printf("GEOM_MULTIPATH: %s added to %s\n", 615 pp->name, sc->sc_name); 616 if (sc->sc_active == NULL) { 617 sc->sc_active = cp; 618 if (sc->sc_active_active != 1) 619 printf("GEOM_MULTIPATH: %s is now active path in %s\n", 620 pp->name, sc->sc_name); 621 } 622 return (0); 623 } 624 625 static int 626 g_multipath_destroy(struct g_geom *gp) 627 { 628 struct g_multipath_softc *sc; 629 struct g_consumer *cp, *cp1; 630 631 g_topology_assert(); 632 if (gp->softc == NULL) 633 return (ENXIO); 634 sc = gp->softc; 635 if (!sc->sc_stopping) { 636 printf("GEOM_MULTIPATH: destroying %s\n", gp->name); 637 sc->sc_stopping = 1; 638 } 639 if (sc->sc_opened != 0) { 640 g_wither_provider(sc->sc_pp, ENXIO); 641 sc->sc_pp = NULL; 642 return (EINPROGRESS); 643 } 644 LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 645 mtx_lock(&sc->sc_mtx); 646 if ((cp->index & MP_POSTED) == 0) { 647 cp->index |= MP_POSTED; 648 mtx_unlock(&sc->sc_mtx); 649 g_mpd(cp, 0); 650 if (cp1 == NULL) 651 return(0); /* Recursion happened. */ 652 } else 653 mtx_unlock(&sc->sc_mtx); 654 } 655 if (!LIST_EMPTY(&gp->consumer)) 656 return (EINPROGRESS); 657 mtx_destroy(&sc->sc_mtx); 658 g_free(gp->softc); 659 gp->softc = NULL; 660 printf("GEOM_MULTIPATH: %s destroyed\n", gp->name); 661 g_wither_geom(gp, ENXIO); 662 return (0); 663 } 664 665 static int 666 g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp, 667 struct g_geom *gp) 668 { 669 670 return (g_multipath_destroy(gp)); 671 } 672 673 static int 674 g_multipath_rotate(struct g_geom *gp) 675 { 676 struct g_consumer *lcp, *first_good_cp = NULL; 677 struct g_multipath_softc *sc = gp->softc; 678 int active_cp_seen = 0; 679 680 g_topology_assert(); 681 if (sc == NULL) 682 return (ENXIO); 683 LIST_FOREACH(lcp, &gp->consumer, consumer) { 684 if ((lcp->index & MP_BAD) == 0) { 685 if (first_good_cp == NULL) 686 first_good_cp = lcp; 687 if (active_cp_seen) 688 break; 689 } 690 if (sc->sc_active == lcp) 691 active_cp_seen = 1; 692 } 693 if (lcp == NULL) 694 lcp = first_good_cp; 695 if (lcp && lcp != sc->sc_active) { 696 sc->sc_active = lcp; 697 if (sc->sc_active_active != 1) 698 printf("GEOM_MULTIPATH: %s is now active path in %s\n", 699 lcp->provider->name, sc->sc_name); 700 } 701 return (0); 702 } 703 704 static void 705 g_multipath_init(struct g_class *mp) 706 { 707 bioq_init(&gmtbq); 708 mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF); 709 kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt"); 710 } 711 712 static void 713 g_multipath_fini(struct g_class *mp) 714 { 715 if (g_multipath_kt_state == GKT_RUN) { 716 mtx_lock(&gmtbq_mtx); 717 g_multipath_kt_state = GKT_DIE; 718 wakeup(&g_multipath_kt_state); 719 msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO, 720 "gmp:fini", 0); 721 mtx_unlock(&gmtbq_mtx); 722 } 723 } 724 725 static int 726 g_multipath_read_metadata(struct g_consumer *cp, 727 struct g_multipath_metadata *md) 728 { 729 struct g_provider *pp; 730 u_char *buf; 731 int error; 732 733 g_topology_assert(); 734 error = g_access(cp, 1, 0, 0); 735 if (error != 0) 736 return (error); 737 pp = cp->provider; 738 g_topology_unlock(); 739 buf = g_read_data(cp, pp->mediasize - pp->sectorsize, 740 pp->sectorsize, &error); 741 g_topology_lock(); 742 g_access(cp, -1, 0, 0); 743 if (buf == NULL) 744 return (error); 745 multipath_metadata_decode(buf, md); 746 g_free(buf); 747 return (0); 748 } 749 750 static int 751 g_multipath_write_metadata(struct g_consumer *cp, 752 struct g_multipath_metadata *md) 753 { 754 struct g_provider *pp; 755 u_char *buf; 756 int error; 757 758 g_topology_assert(); 759 error = g_access(cp, 1, 1, 1); 760 if (error != 0) 761 return (error); 762 pp = cp->provider; 763 g_topology_unlock(); 764 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 765 multipath_metadata_encode(md, buf); 766 error = g_write_data(cp, pp->mediasize - pp->sectorsize, 767 buf, pp->sectorsize); 768 g_topology_lock(); 769 g_access(cp, -1, -1, -1); 770 g_free(buf); 771 return (error); 772 } 773 774 static struct g_geom * 775 g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 776 { 777 struct g_multipath_metadata md; 778 struct g_multipath_softc *sc; 779 struct g_consumer *cp; 780 struct g_geom *gp, *gp1; 781 int error, isnew; 782 783 g_topology_assert(); 784 785 gp = g_new_geomf(mp, "multipath:taste"); 786 gp->start = g_multipath_start; 787 gp->access = g_multipath_access; 788 gp->orphan = g_multipath_orphan; 789 cp = g_new_consumer(gp); 790 g_attach(cp, pp); 791 error = g_multipath_read_metadata(cp, &md); 792 g_detach(cp); 793 g_destroy_consumer(cp); 794 g_destroy_geom(gp); 795 if (error != 0) 796 return (NULL); 797 gp = NULL; 798 799 if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) { 800 if (g_multipath_debug) 801 printf("%s is not MULTIPATH\n", pp->name); 802 return (NULL); 803 } 804 if (md.md_version != G_MULTIPATH_VERSION) { 805 printf("%s has version %d multipath id- this module is version " 806 " %d: rejecting\n", pp->name, md.md_version, 807 G_MULTIPATH_VERSION); 808 return (NULL); 809 } 810 if (md.md_size != 0 && md.md_size != pp->mediasize) 811 return (NULL); 812 if (md.md_sectorsize != 0 && md.md_sectorsize != pp->sectorsize) 813 return (NULL); 814 if (g_multipath_debug) 815 printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid); 816 817 /* 818 * Let's check if such a device already is present. We check against 819 * uuid alone first because that's the true distinguishor. If that 820 * passes, then we check for name conflicts. If there are conflicts, 821 * modify the name. 822 * 823 * The whole purpose of this is to solve the problem that people don't 824 * pick good unique names, but good unique names (like uuids) are a 825 * pain to use. So, we allow people to build GEOMs with friendly names 826 * and uuids, and modify the names in case there's a collision. 827 */ 828 sc = NULL; 829 LIST_FOREACH(gp, &mp->geom, geom) { 830 sc = gp->softc; 831 if (sc == NULL || sc->sc_stopping) 832 continue; 833 if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0) 834 break; 835 } 836 837 LIST_FOREACH(gp1, &mp->geom, geom) { 838 if (gp1 == gp) 839 continue; 840 sc = gp1->softc; 841 if (sc == NULL || sc->sc_stopping) 842 continue; 843 if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0) 844 break; 845 } 846 847 /* 848 * If gp is NULL, we had no extant MULTIPATH geom with this uuid. 849 * 850 * If gp1 is *not* NULL, that means we have a MULTIPATH geom extant 851 * with the same name (but a different UUID). 852 * 853 * If gp is NULL, then modify the name with a random number and 854 * complain, but allow the creation of the geom to continue. 855 * 856 * If gp is *not* NULL, just use the geom's name as we're attaching 857 * this disk to the (previously generated) name. 858 */ 859 860 if (gp1) { 861 sc = gp1->softc; 862 if (gp == NULL) { 863 char buf[16]; 864 u_long rand = random(); 865 866 snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand); 867 printf("GEOM_MULTIPATH: geom %s/%s exists already\n", 868 sc->sc_name, sc->sc_uuid); 869 printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n", 870 md.md_uuid, buf); 871 strlcpy(md.md_name, buf, sizeof(md.md_name)); 872 } else { 873 strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name)); 874 } 875 } 876 877 if (gp == NULL) { 878 gp = g_multipath_create(mp, &md); 879 if (gp == NULL) { 880 printf("GEOM_MULTIPATH: cannot create geom %s/%s\n", 881 md.md_name, md.md_uuid); 882 return (NULL); 883 } 884 isnew = 1; 885 } else { 886 isnew = 0; 887 } 888 889 sc = gp->softc; 890 KASSERT(sc != NULL, ("sc is NULL")); 891 error = g_multipath_add_disk(gp, pp); 892 if (error != 0) { 893 if (isnew) 894 g_multipath_destroy(gp); 895 return (NULL); 896 } 897 return (gp); 898 } 899 900 static void 901 g_multipath_ctl_add_name(struct gctl_req *req, struct g_class *mp, 902 const char *name) 903 { 904 struct g_multipath_softc *sc; 905 struct g_geom *gp; 906 struct g_consumer *cp; 907 struct g_provider *pp; 908 const char *mpname; 909 static const char devpf[6] = "/dev/"; 910 911 g_topology_assert(); 912 913 mpname = gctl_get_asciiparam(req, "arg0"); 914 if (mpname == NULL) { 915 gctl_error(req, "No 'arg0' argument"); 916 return; 917 } 918 gp = g_multipath_find_geom(mp, mpname); 919 if (gp == NULL) { 920 gctl_error(req, "Device %s is invalid", mpname); 921 return; 922 } 923 sc = gp->softc; 924 925 if (strncmp(name, devpf, 5) == 0) 926 name += 5; 927 pp = g_provider_by_name(name); 928 if (pp == NULL) { 929 gctl_error(req, "Provider %s is invalid", name); 930 return; 931 } 932 933 /* 934 * Check to make sure parameters match. 935 */ 936 LIST_FOREACH(cp, &gp->consumer, consumer) { 937 if (cp->provider == pp) { 938 gctl_error(req, "provider %s is already there", 939 pp->name); 940 return; 941 } 942 } 943 if (sc->sc_pp->mediasize != 0 && 944 sc->sc_pp->mediasize + (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0) 945 != pp->mediasize) { 946 gctl_error(req, "Providers size mismatch %jd != %jd", 947 (intmax_t) sc->sc_pp->mediasize + 948 (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0), 949 (intmax_t) pp->mediasize); 950 return; 951 } 952 if (sc->sc_pp->sectorsize != 0 && 953 sc->sc_pp->sectorsize != pp->sectorsize) { 954 gctl_error(req, "Providers sectorsize mismatch %u != %u", 955 sc->sc_pp->sectorsize, pp->sectorsize); 956 return; 957 } 958 959 /* 960 * Now add.... 961 */ 962 (void) g_multipath_add_disk(gp, pp); 963 } 964 965 static void 966 g_multipath_ctl_prefer(struct gctl_req *req, struct g_class *mp) 967 { 968 struct g_geom *gp; 969 struct g_multipath_softc *sc; 970 struct g_consumer *cp; 971 const char *name, *mpname; 972 static const char devpf[6] = "/dev/"; 973 int *nargs; 974 975 g_topology_assert(); 976 977 mpname = gctl_get_asciiparam(req, "arg0"); 978 if (mpname == NULL) { 979 gctl_error(req, "No 'arg0' argument"); 980 return; 981 } 982 gp = g_multipath_find_geom(mp, mpname); 983 if (gp == NULL) { 984 gctl_error(req, "Device %s is invalid", mpname); 985 return; 986 } 987 sc = gp->softc; 988 989 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 990 if (nargs == NULL) { 991 gctl_error(req, "No 'nargs' argument"); 992 return; 993 } 994 if (*nargs != 2) { 995 gctl_error(req, "missing device"); 996 return; 997 } 998 999 name = gctl_get_asciiparam(req, "arg1"); 1000 if (name == NULL) { 1001 gctl_error(req, "No 'arg1' argument"); 1002 return; 1003 } 1004 if (strncmp(name, devpf, 5) == 0) { 1005 name += 5; 1006 } 1007 1008 LIST_FOREACH(cp, &gp->consumer, consumer) { 1009 if (cp->provider != NULL 1010 && strcmp(cp->provider->name, name) == 0) 1011 break; 1012 } 1013 1014 if (cp == NULL) { 1015 gctl_error(req, "Provider %s not found", name); 1016 return; 1017 } 1018 1019 mtx_lock(&sc->sc_mtx); 1020 1021 if (cp->index & MP_BAD) { 1022 gctl_error(req, "Consumer %s is invalid", name); 1023 mtx_unlock(&sc->sc_mtx); 1024 return; 1025 } 1026 1027 /* Here when the consumer is present and in good shape */ 1028 1029 sc->sc_active = cp; 1030 if (!sc->sc_active_active) 1031 printf("GEOM_MULTIPATH: %s now active path in %s\n", 1032 sc->sc_active->provider->name, sc->sc_name); 1033 1034 mtx_unlock(&sc->sc_mtx); 1035 } 1036 1037 static void 1038 g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp) 1039 { 1040 struct g_multipath_softc *sc; 1041 struct g_geom *gp; 1042 const char *mpname, *name; 1043 1044 mpname = gctl_get_asciiparam(req, "arg0"); 1045 if (mpname == NULL) { 1046 gctl_error(req, "No 'arg0' argument"); 1047 return; 1048 } 1049 gp = g_multipath_find_geom(mp, mpname); 1050 if (gp == NULL) { 1051 gctl_error(req, "Device %s not found", mpname); 1052 return; 1053 } 1054 sc = gp->softc; 1055 1056 name = gctl_get_asciiparam(req, "arg1"); 1057 if (name == NULL) { 1058 gctl_error(req, "No 'arg1' argument"); 1059 return; 1060 } 1061 g_multipath_ctl_add_name(req, mp, name); 1062 } 1063 1064 static void 1065 g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp) 1066 { 1067 struct g_multipath_metadata md; 1068 struct g_multipath_softc *sc; 1069 struct g_geom *gp; 1070 const char *mpname, *name; 1071 char param[16]; 1072 int *nargs, i, *val; 1073 1074 g_topology_assert(); 1075 1076 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1077 if (*nargs < 2) { 1078 gctl_error(req, "wrong number of arguments."); 1079 return; 1080 } 1081 1082 mpname = gctl_get_asciiparam(req, "arg0"); 1083 if (mpname == NULL) { 1084 gctl_error(req, "No 'arg0' argument"); 1085 return; 1086 } 1087 gp = g_multipath_find_geom(mp, mpname); 1088 if (gp != NULL) { 1089 gctl_error(req, "Device %s already exist", mpname); 1090 return; 1091 } 1092 sc = gp->softc; 1093 1094 memset(&md, 0, sizeof(md)); 1095 strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 1096 md.md_version = G_MULTIPATH_VERSION; 1097 strlcpy(md.md_name, mpname, sizeof(md.md_name)); 1098 md.md_size = 0; 1099 md.md_sectorsize = 0; 1100 md.md_uuid[0] = 0; 1101 md.md_active_active = 0; 1102 val = gctl_get_paraml(req, "active_active", sizeof(*val)); 1103 if (val != NULL && *val != 0) 1104 md.md_active_active = 1; 1105 val = gctl_get_paraml(req, "active_read", sizeof(*val)); 1106 if (val != NULL && *val != 0) 1107 md.md_active_active = 2; 1108 gp = g_multipath_create(mp, &md); 1109 if (gp == NULL) { 1110 gctl_error(req, "GEOM_MULTIPATH: cannot create geom %s/%s\n", 1111 md.md_name, md.md_uuid); 1112 return; 1113 } 1114 sc = gp->softc; 1115 1116 for (i = 1; i < *nargs; i++) { 1117 snprintf(param, sizeof(param), "arg%d", i); 1118 name = gctl_get_asciiparam(req, param); 1119 g_multipath_ctl_add_name(req, mp, name); 1120 } 1121 1122 if (sc->sc_ndisks != (*nargs - 1)) 1123 g_multipath_destroy(gp); 1124 } 1125 1126 static void 1127 g_multipath_ctl_configure(struct gctl_req *req, struct g_class *mp) 1128 { 1129 struct g_multipath_softc *sc; 1130 struct g_geom *gp; 1131 struct g_consumer *cp; 1132 struct g_provider *pp; 1133 struct g_multipath_metadata md; 1134 const char *name; 1135 int error, *val; 1136 1137 g_topology_assert(); 1138 1139 name = gctl_get_asciiparam(req, "arg0"); 1140 if (name == NULL) { 1141 gctl_error(req, "No 'arg0' argument"); 1142 return; 1143 } 1144 gp = g_multipath_find_geom(mp, name); 1145 if (gp == NULL) { 1146 gctl_error(req, "Device %s is invalid", name); 1147 return; 1148 } 1149 sc = gp->softc; 1150 val = gctl_get_paraml(req, "active_active", sizeof(*val)); 1151 if (val != NULL && *val != 0) 1152 sc->sc_active_active = 1; 1153 val = gctl_get_paraml(req, "active_read", sizeof(*val)); 1154 if (val != NULL && *val != 0) 1155 sc->sc_active_active = 2; 1156 val = gctl_get_paraml(req, "active_passive", sizeof(*val)); 1157 if (val != NULL && *val != 0) 1158 sc->sc_active_active = 0; 1159 if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) { 1160 cp = sc->sc_active; 1161 pp = cp->provider; 1162 strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 1163 memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid)); 1164 strlcpy(md.md_name, name, sizeof(md.md_name)); 1165 md.md_version = G_MULTIPATH_VERSION; 1166 md.md_size = pp->mediasize; 1167 md.md_sectorsize = pp->sectorsize; 1168 md.md_active_active = sc->sc_active_active; 1169 error = g_multipath_write_metadata(cp, &md); 1170 if (error != 0) 1171 gctl_error(req, "Can't update metadata on %s (%d)", 1172 pp->name, error); 1173 } 1174 } 1175 1176 static void 1177 g_multipath_ctl_fail(struct gctl_req *req, struct g_class *mp, int fail) 1178 { 1179 struct g_multipath_softc *sc; 1180 struct g_geom *gp; 1181 struct g_consumer *cp; 1182 const char *mpname, *name; 1183 int found; 1184 1185 mpname = gctl_get_asciiparam(req, "arg0"); 1186 if (mpname == NULL) { 1187 gctl_error(req, "No 'arg0' argument"); 1188 return; 1189 } 1190 gp = g_multipath_find_geom(mp, mpname); 1191 if (gp == NULL) { 1192 gctl_error(req, "Device %s not found", mpname); 1193 return; 1194 } 1195 sc = gp->softc; 1196 1197 name = gctl_get_asciiparam(req, "arg1"); 1198 if (name == NULL) { 1199 gctl_error(req, "No 'arg1' argument"); 1200 return; 1201 } 1202 1203 found = 0; 1204 mtx_lock(&sc->sc_mtx); 1205 LIST_FOREACH(cp, &gp->consumer, consumer) { 1206 if (cp->provider != NULL && 1207 strcmp(cp->provider->name, name) == 0 && 1208 (cp->index & MP_LOST) == 0) { 1209 found = 1; 1210 if (!fail == !(cp->index & MP_FAIL)) 1211 continue; 1212 printf("GEOM_MULTIPATH: %s in %s is marked %s.\n", 1213 name, sc->sc_name, fail ? "FAIL" : "OK"); 1214 if (fail) { 1215 g_multipath_fault(cp, MP_FAIL); 1216 } else { 1217 cp->index &= ~MP_FAIL; 1218 } 1219 } 1220 } 1221 mtx_unlock(&sc->sc_mtx); 1222 if (found == 0) 1223 gctl_error(req, "Provider %s not found", name); 1224 } 1225 1226 static void 1227 g_multipath_ctl_remove(struct gctl_req *req, struct g_class *mp) 1228 { 1229 struct g_multipath_softc *sc; 1230 struct g_geom *gp; 1231 struct g_consumer *cp, *cp1; 1232 const char *mpname, *name; 1233 uintptr_t *cnt; 1234 int found; 1235 1236 mpname = gctl_get_asciiparam(req, "arg0"); 1237 if (mpname == NULL) { 1238 gctl_error(req, "No 'arg0' argument"); 1239 return; 1240 } 1241 gp = g_multipath_find_geom(mp, mpname); 1242 if (gp == NULL) { 1243 gctl_error(req, "Device %s not found", mpname); 1244 return; 1245 } 1246 sc = gp->softc; 1247 1248 name = gctl_get_asciiparam(req, "arg1"); 1249 if (name == NULL) { 1250 gctl_error(req, "No 'arg1' argument"); 1251 return; 1252 } 1253 1254 found = 0; 1255 mtx_lock(&sc->sc_mtx); 1256 LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 1257 if (cp->provider != NULL && 1258 strcmp(cp->provider->name, name) == 0 && 1259 (cp->index & MP_LOST) == 0) { 1260 found = 1; 1261 printf("GEOM_MULTIPATH: removing %s from %s\n", 1262 cp->provider->name, cp->geom->name); 1263 sc->sc_ndisks--; 1264 g_multipath_fault(cp, MP_LOST); 1265 cnt = (uintptr_t *)&cp->private; 1266 if (*cnt == 0 && (cp->index & MP_POSTED) == 0) { 1267 cp->index |= MP_POSTED; 1268 mtx_unlock(&sc->sc_mtx); 1269 g_mpd(cp, 0); 1270 if (cp1 == NULL) 1271 return; /* Recursion happened. */ 1272 mtx_lock(&sc->sc_mtx); 1273 } 1274 } 1275 } 1276 mtx_unlock(&sc->sc_mtx); 1277 if (found == 0) 1278 gctl_error(req, "Provider %s not found", name); 1279 } 1280 1281 static struct g_geom * 1282 g_multipath_find_geom(struct g_class *mp, const char *name) 1283 { 1284 struct g_geom *gp; 1285 struct g_multipath_softc *sc; 1286 1287 LIST_FOREACH(gp, &mp->geom, geom) { 1288 sc = gp->softc; 1289 if (sc == NULL || sc->sc_stopping) 1290 continue; 1291 if (strcmp(gp->name, name) == 0) 1292 return (gp); 1293 } 1294 return (NULL); 1295 } 1296 1297 static void 1298 g_multipath_ctl_stop(struct gctl_req *req, struct g_class *mp) 1299 { 1300 struct g_geom *gp; 1301 const char *name; 1302 int error; 1303 1304 g_topology_assert(); 1305 1306 name = gctl_get_asciiparam(req, "arg0"); 1307 if (name == NULL) { 1308 gctl_error(req, "No 'arg0' argument"); 1309 return; 1310 } 1311 gp = g_multipath_find_geom(mp, name); 1312 if (gp == NULL) { 1313 gctl_error(req, "Device %s is invalid", name); 1314 return; 1315 } 1316 error = g_multipath_destroy(gp); 1317 if (error != 0 && error != EINPROGRESS) 1318 gctl_error(req, "failed to stop %s (err=%d)", name, error); 1319 } 1320 1321 static void 1322 g_multipath_ctl_destroy(struct gctl_req *req, struct g_class *mp) 1323 { 1324 struct g_geom *gp; 1325 struct g_multipath_softc *sc; 1326 struct g_consumer *cp; 1327 struct g_provider *pp; 1328 const char *name; 1329 uint8_t *buf; 1330 int error; 1331 1332 g_topology_assert(); 1333 1334 name = gctl_get_asciiparam(req, "arg0"); 1335 if (name == NULL) { 1336 gctl_error(req, "No 'arg0' argument"); 1337 return; 1338 } 1339 gp = g_multipath_find_geom(mp, name); 1340 if (gp == NULL) { 1341 gctl_error(req, "Device %s is invalid", name); 1342 return; 1343 } 1344 sc = gp->softc; 1345 1346 if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) { 1347 cp = sc->sc_active; 1348 pp = cp->provider; 1349 error = g_access(cp, 1, 1, 1); 1350 if (error != 0) { 1351 gctl_error(req, "Can't open %s (%d)", pp->name, error); 1352 goto destroy; 1353 } 1354 g_topology_unlock(); 1355 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 1356 error = g_write_data(cp, pp->mediasize - pp->sectorsize, 1357 buf, pp->sectorsize); 1358 g_topology_lock(); 1359 g_access(cp, -1, -1, -1); 1360 if (error != 0) 1361 gctl_error(req, "Can't erase metadata on %s (%d)", 1362 pp->name, error); 1363 } 1364 1365 destroy: 1366 error = g_multipath_destroy(gp); 1367 if (error != 0 && error != EINPROGRESS) 1368 gctl_error(req, "failed to destroy %s (err=%d)", name, error); 1369 } 1370 1371 static void 1372 g_multipath_ctl_rotate(struct gctl_req *req, struct g_class *mp) 1373 { 1374 struct g_geom *gp; 1375 const char *name; 1376 int error; 1377 1378 g_topology_assert(); 1379 1380 name = gctl_get_asciiparam(req, "arg0"); 1381 if (name == NULL) { 1382 gctl_error(req, "No 'arg0' argument"); 1383 return; 1384 } 1385 gp = g_multipath_find_geom(mp, name); 1386 if (gp == NULL) { 1387 gctl_error(req, "Device %s is invalid", name); 1388 return; 1389 } 1390 error = g_multipath_rotate(gp); 1391 if (error != 0) { 1392 gctl_error(req, "failed to rotate %s (err=%d)", name, error); 1393 } 1394 } 1395 1396 static void 1397 g_multipath_ctl_getactive(struct gctl_req *req, struct g_class *mp) 1398 { 1399 struct sbuf *sb; 1400 struct g_geom *gp; 1401 struct g_multipath_softc *sc; 1402 struct g_consumer *cp; 1403 const char *name; 1404 int empty; 1405 1406 sb = sbuf_new_auto(); 1407 1408 g_topology_assert(); 1409 name = gctl_get_asciiparam(req, "arg0"); 1410 if (name == NULL) { 1411 gctl_error(req, "No 'arg0' argument"); 1412 return; 1413 } 1414 gp = g_multipath_find_geom(mp, name); 1415 if (gp == NULL) { 1416 gctl_error(req, "Device %s is invalid", name); 1417 return; 1418 } 1419 sc = gp->softc; 1420 if (sc->sc_active_active == 1) { 1421 empty = 1; 1422 LIST_FOREACH(cp, &gp->consumer, consumer) { 1423 if (cp->index & MP_BAD) 1424 continue; 1425 if (!empty) 1426 sbuf_cat(sb, " "); 1427 sbuf_cat(sb, cp->provider->name); 1428 empty = 0; 1429 } 1430 if (empty) 1431 sbuf_cat(sb, "none"); 1432 sbuf_cat(sb, "\n"); 1433 } else if (sc->sc_active && sc->sc_active->provider) { 1434 sbuf_printf(sb, "%s\n", sc->sc_active->provider->name); 1435 } else { 1436 sbuf_printf(sb, "none\n"); 1437 } 1438 sbuf_finish(sb); 1439 gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1440 sbuf_delete(sb); 1441 } 1442 1443 static void 1444 g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb) 1445 { 1446 uint32_t *version; 1447 g_topology_assert(); 1448 version = gctl_get_paraml(req, "version", sizeof(*version)); 1449 if (version == NULL) { 1450 gctl_error(req, "No 'version' argument"); 1451 } else if (*version != G_MULTIPATH_VERSION) { 1452 gctl_error(req, "Userland and kernel parts are out of sync"); 1453 } else if (strcmp(verb, "add") == 0) { 1454 g_multipath_ctl_add(req, mp); 1455 } else if (strcmp(verb, "prefer") == 0) { 1456 g_multipath_ctl_prefer(req, mp); 1457 } else if (strcmp(verb, "create") == 0) { 1458 g_multipath_ctl_create(req, mp); 1459 } else if (strcmp(verb, "configure") == 0) { 1460 g_multipath_ctl_configure(req, mp); 1461 } else if (strcmp(verb, "stop") == 0) { 1462 g_multipath_ctl_stop(req, mp); 1463 } else if (strcmp(verb, "destroy") == 0) { 1464 g_multipath_ctl_destroy(req, mp); 1465 } else if (strcmp(verb, "fail") == 0) { 1466 g_multipath_ctl_fail(req, mp, 1); 1467 } else if (strcmp(verb, "restore") == 0) { 1468 g_multipath_ctl_fail(req, mp, 0); 1469 } else if (strcmp(verb, "remove") == 0) { 1470 g_multipath_ctl_remove(req, mp); 1471 } else if (strcmp(verb, "rotate") == 0) { 1472 g_multipath_ctl_rotate(req, mp); 1473 } else if (strcmp(verb, "getactive") == 0) { 1474 g_multipath_ctl_getactive(req, mp); 1475 } else { 1476 gctl_error(req, "Unknown verb %s", verb); 1477 } 1478 } 1479 1480 static void 1481 g_multipath_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1482 struct g_consumer *cp, struct g_provider *pp) 1483 { 1484 struct g_multipath_softc *sc; 1485 int good; 1486 1487 g_topology_assert(); 1488 1489 sc = gp->softc; 1490 if (sc == NULL) 1491 return; 1492 if (cp != NULL) { 1493 sbuf_printf(sb, "%s<State>%s</State>\n", indent, 1494 (cp->index & MP_NEW) ? "NEW" : 1495 (cp->index & MP_LOST) ? "LOST" : 1496 (cp->index & MP_FAIL) ? "FAIL" : 1497 (sc->sc_active_active == 1 || sc->sc_active == cp) ? 1498 "ACTIVE" : 1499 sc->sc_active_active == 2 ? "READ" : "PASSIVE"); 1500 } else { 1501 good = g_multipath_good(gp); 1502 sbuf_printf(sb, "%s<State>%s</State>\n", indent, 1503 good == 0 ? "BROKEN" : 1504 (good != sc->sc_ndisks || sc->sc_ndisks == 1) ? 1505 "DEGRADED" : "OPTIMAL"); 1506 } 1507 if (cp == NULL && pp == NULL) { 1508 sbuf_printf(sb, "%s<UUID>%s</UUID>\n", indent, sc->sc_uuid); 1509 sbuf_printf(sb, "%s<Mode>Active/%s</Mode>\n", indent, 1510 sc->sc_active_active == 2 ? "Read" : 1511 sc->sc_active_active == 1 ? "Active" : "Passive"); 1512 sbuf_printf(sb, "%s<Type>%s</Type>\n", indent, 1513 sc->sc_uuid[0] == 0 ? "MANUAL" : "AUTOMATIC"); 1514 } 1515 } 1516 1517 DECLARE_GEOM_CLASS(g_multipath_class, g_multipath); 1518