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