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, "%s", 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 if (sc->sc_pp != NULL) 526 sc->sc_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED; 527 mtx_lock(&sc->sc_mtx); 528 cp->index = 0; 529 sc->sc_ndisks++; 530 mtx_unlock(&sc->sc_mtx); 531 printf("GEOM_MULTIPATH: %s added to %s\n", 532 pp->name, sc->sc_name); 533 if (sc->sc_active == NULL) { 534 sc->sc_active = cp; 535 if (sc->sc_active_active != 1) 536 printf("GEOM_MULTIPATH: %s is now active path in %s\n", 537 pp->name, sc->sc_name); 538 } 539 return (0); 540 } 541 542 static int 543 g_multipath_destroy(struct g_geom *gp) 544 { 545 struct g_multipath_softc *sc; 546 struct g_consumer *cp, *cp1; 547 548 g_topology_assert(); 549 if (gp->softc == NULL) 550 return (ENXIO); 551 sc = gp->softc; 552 if (!sc->sc_stopping) { 553 printf("GEOM_MULTIPATH: destroying %s\n", gp->name); 554 sc->sc_stopping = 1; 555 } 556 if (sc->sc_opened != 0) { 557 if (sc->sc_pp != NULL) { 558 g_wither_provider(sc->sc_pp, ENXIO); 559 sc->sc_pp = NULL; 560 } 561 return (EINPROGRESS); 562 } 563 LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 564 mtx_lock(&sc->sc_mtx); 565 if ((cp->index & MP_POSTED) == 0) { 566 cp->index |= MP_POSTED; 567 mtx_unlock(&sc->sc_mtx); 568 g_mpd(cp, 0); 569 if (cp1 == NULL) 570 return(0); /* Recursion happened. */ 571 } else 572 mtx_unlock(&sc->sc_mtx); 573 } 574 if (!LIST_EMPTY(&gp->consumer)) 575 return (EINPROGRESS); 576 mtx_destroy(&sc->sc_mtx); 577 g_free(gp->softc); 578 gp->softc = NULL; 579 printf("GEOM_MULTIPATH: %s destroyed\n", gp->name); 580 g_wither_geom(gp, ENXIO); 581 return (0); 582 } 583 584 static int 585 g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp, 586 struct g_geom *gp) 587 { 588 589 return (g_multipath_destroy(gp)); 590 } 591 592 static int 593 g_multipath_rotate(struct g_geom *gp) 594 { 595 struct g_consumer *lcp, *first_good_cp = NULL; 596 struct g_multipath_softc *sc = gp->softc; 597 int active_cp_seen = 0; 598 599 g_topology_assert(); 600 if (sc == NULL) 601 return (ENXIO); 602 LIST_FOREACH(lcp, &gp->consumer, consumer) { 603 if ((lcp->index & MP_BAD) == 0) { 604 if (first_good_cp == NULL) 605 first_good_cp = lcp; 606 if (active_cp_seen) 607 break; 608 } 609 if (sc->sc_active == lcp) 610 active_cp_seen = 1; 611 } 612 if (lcp == NULL) 613 lcp = first_good_cp; 614 if (lcp && lcp != sc->sc_active) { 615 sc->sc_active = lcp; 616 if (sc->sc_active_active != 1) 617 printf("GEOM_MULTIPATH: %s is now active path in %s\n", 618 lcp->provider->name, sc->sc_name); 619 } 620 return (0); 621 } 622 623 static void 624 g_multipath_init(struct g_class *mp) 625 { 626 bioq_init(&gmtbq); 627 mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF); 628 kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt"); 629 } 630 631 static void 632 g_multipath_fini(struct g_class *mp) 633 { 634 if (g_multipath_kt_state == GKT_RUN) { 635 mtx_lock(&gmtbq_mtx); 636 g_multipath_kt_state = GKT_DIE; 637 wakeup(&g_multipath_kt_state); 638 msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO, 639 "gmp:fini", 0); 640 mtx_unlock(&gmtbq_mtx); 641 } 642 } 643 644 static int 645 g_multipath_read_metadata(struct g_consumer *cp, 646 struct g_multipath_metadata *md) 647 { 648 struct g_provider *pp; 649 u_char *buf; 650 int error; 651 652 g_topology_assert(); 653 error = g_access(cp, 1, 0, 0); 654 if (error != 0) 655 return (error); 656 pp = cp->provider; 657 g_topology_unlock(); 658 buf = g_read_data(cp, pp->mediasize - pp->sectorsize, 659 pp->sectorsize, &error); 660 g_topology_lock(); 661 g_access(cp, -1, 0, 0); 662 if (buf == NULL) 663 return (error); 664 multipath_metadata_decode(buf, md); 665 g_free(buf); 666 return (0); 667 } 668 669 static struct g_geom * 670 g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 671 { 672 struct g_multipath_metadata md; 673 struct g_multipath_softc *sc; 674 struct g_consumer *cp; 675 struct g_geom *gp, *gp1; 676 int error, isnew; 677 678 g_topology_assert(); 679 680 gp = g_new_geomf(mp, "multipath:taste"); 681 gp->start = g_multipath_start; 682 gp->access = g_multipath_access; 683 gp->orphan = g_multipath_orphan; 684 cp = g_new_consumer(gp); 685 g_attach(cp, pp); 686 error = g_multipath_read_metadata(cp, &md); 687 g_detach(cp); 688 g_destroy_consumer(cp); 689 g_destroy_geom(gp); 690 if (error != 0) 691 return (NULL); 692 gp = NULL; 693 694 if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) { 695 if (g_multipath_debug) 696 printf("%s is not MULTIPATH\n", pp->name); 697 return (NULL); 698 } 699 if (md.md_version != G_MULTIPATH_VERSION) { 700 printf("%s has version %d multipath id- this module is version " 701 " %d: rejecting\n", pp->name, md.md_version, 702 G_MULTIPATH_VERSION); 703 return (NULL); 704 } 705 if (md.md_size != 0 && md.md_size != pp->mediasize) 706 return (NULL); 707 if (md.md_sectorsize != 0 && md.md_sectorsize != pp->sectorsize) 708 return (NULL); 709 if (g_multipath_debug) 710 printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid); 711 712 /* 713 * Let's check if such a device already is present. We check against 714 * uuid alone first because that's the true distinguishor. If that 715 * passes, then we check for name conflicts. If there are conflicts, 716 * modify the name. 717 * 718 * The whole purpose of this is to solve the problem that people don't 719 * pick good unique names, but good unique names (like uuids) are a 720 * pain to use. So, we allow people to build GEOMs with friendly names 721 * and uuids, and modify the names in case there's a collision. 722 */ 723 sc = NULL; 724 LIST_FOREACH(gp, &mp->geom, geom) { 725 sc = gp->softc; 726 if (sc == NULL || sc->sc_stopping) 727 continue; 728 if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0) 729 break; 730 } 731 732 LIST_FOREACH(gp1, &mp->geom, geom) { 733 if (gp1 == gp) 734 continue; 735 sc = gp1->softc; 736 if (sc == NULL || sc->sc_stopping) 737 continue; 738 if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0) 739 break; 740 } 741 742 /* 743 * If gp is NULL, we had no extant MULTIPATH geom with this uuid. 744 * 745 * If gp1 is *not* NULL, that means we have a MULTIPATH geom extant 746 * with the same name (but a different UUID). 747 * 748 * If gp is NULL, then modify the name with a random number and 749 * complain, but allow the creation of the geom to continue. 750 * 751 * If gp is *not* NULL, just use the geom's name as we're attaching 752 * this disk to the (previously generated) name. 753 */ 754 755 if (gp1) { 756 sc = gp1->softc; 757 if (gp == NULL) { 758 char buf[16]; 759 u_long rand = random(); 760 761 snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand); 762 printf("GEOM_MULTIPATH: geom %s/%s exists already\n", 763 sc->sc_name, sc->sc_uuid); 764 printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n", 765 md.md_uuid, buf); 766 strlcpy(md.md_name, buf, sizeof(md.md_name)); 767 } else { 768 strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name)); 769 } 770 } 771 772 if (gp == NULL) { 773 gp = g_multipath_create(mp, &md); 774 if (gp == NULL) { 775 printf("GEOM_MULTIPATH: cannot create geom %s/%s\n", 776 md.md_name, md.md_uuid); 777 return (NULL); 778 } 779 isnew = 1; 780 } else { 781 isnew = 0; 782 } 783 784 sc = gp->softc; 785 KASSERT(sc != NULL, ("sc is NULL")); 786 error = g_multipath_add_disk(gp, pp); 787 if (error != 0) { 788 if (isnew) 789 g_multipath_destroy(gp); 790 return (NULL); 791 } 792 return (gp); 793 } 794 795 static void 796 g_multipath_ctl_add_name(struct gctl_req *req, struct g_class *mp, 797 const char *name) 798 { 799 struct g_multipath_softc *sc; 800 struct g_geom *gp; 801 struct g_consumer *cp; 802 struct g_provider *pp; 803 const char *mpname; 804 static const char devpf[6] = "/dev/"; 805 806 g_topology_assert(); 807 808 mpname = gctl_get_asciiparam(req, "arg0"); 809 if (mpname == NULL) { 810 gctl_error(req, "No 'arg0' argument"); 811 return; 812 } 813 gp = g_multipath_find_geom(mp, mpname); 814 if (gp == NULL) { 815 gctl_error(req, "Device %s is invalid", mpname); 816 return; 817 } 818 sc = gp->softc; 819 820 if (strncmp(name, devpf, 5) == 0) 821 name += 5; 822 pp = g_provider_by_name(name); 823 if (pp == NULL) { 824 gctl_error(req, "Provider %s is invalid", name); 825 return; 826 } 827 828 /* 829 * Check to make sure parameters match. 830 */ 831 LIST_FOREACH(cp, &gp->consumer, consumer) { 832 if (cp->provider == pp) { 833 gctl_error(req, "provider %s is already there", 834 pp->name); 835 return; 836 } 837 } 838 if (sc->sc_pp != NULL && sc->sc_pp->mediasize != 0 && 839 sc->sc_pp->mediasize + (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0) 840 != pp->mediasize) { 841 gctl_error(req, "Providers size mismatch %jd != %jd", 842 (intmax_t) sc->sc_pp->mediasize + 843 (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0), 844 (intmax_t) pp->mediasize); 845 return; 846 } 847 if (sc->sc_pp != NULL && sc->sc_pp->sectorsize != 0 && 848 sc->sc_pp->sectorsize != pp->sectorsize) { 849 gctl_error(req, "Providers sectorsize mismatch %u != %u", 850 sc->sc_pp->sectorsize, pp->sectorsize); 851 return; 852 } 853 854 /* 855 * Now add.... 856 */ 857 (void) g_multipath_add_disk(gp, pp); 858 } 859 860 static void 861 g_multipath_ctl_prefer(struct gctl_req *req, struct g_class *mp) 862 { 863 struct g_geom *gp; 864 struct g_multipath_softc *sc; 865 struct g_consumer *cp; 866 const char *name, *mpname; 867 static const char devpf[6] = "/dev/"; 868 int *nargs; 869 870 g_topology_assert(); 871 872 mpname = gctl_get_asciiparam(req, "arg0"); 873 if (mpname == NULL) { 874 gctl_error(req, "No 'arg0' argument"); 875 return; 876 } 877 gp = g_multipath_find_geom(mp, mpname); 878 if (gp == NULL) { 879 gctl_error(req, "Device %s is invalid", mpname); 880 return; 881 } 882 sc = gp->softc; 883 884 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 885 if (nargs == NULL) { 886 gctl_error(req, "No 'nargs' argument"); 887 return; 888 } 889 if (*nargs != 2) { 890 gctl_error(req, "missing device"); 891 return; 892 } 893 894 name = gctl_get_asciiparam(req, "arg1"); 895 if (name == NULL) { 896 gctl_error(req, "No 'arg1' argument"); 897 return; 898 } 899 if (strncmp(name, devpf, 5) == 0) { 900 name += 5; 901 } 902 903 LIST_FOREACH(cp, &gp->consumer, consumer) { 904 if (cp->provider != NULL 905 && strcmp(cp->provider->name, name) == 0) 906 break; 907 } 908 909 if (cp == NULL) { 910 gctl_error(req, "Provider %s not found", name); 911 return; 912 } 913 914 mtx_lock(&sc->sc_mtx); 915 916 if (cp->index & MP_BAD) { 917 gctl_error(req, "Consumer %s is invalid", name); 918 mtx_unlock(&sc->sc_mtx); 919 return; 920 } 921 922 /* Here when the consumer is present and in good shape */ 923 924 sc->sc_active = cp; 925 if (!sc->sc_active_active) 926 printf("GEOM_MULTIPATH: %s now active path in %s\n", 927 sc->sc_active->provider->name, sc->sc_name); 928 929 mtx_unlock(&sc->sc_mtx); 930 } 931 932 static void 933 g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp) 934 { 935 struct g_multipath_softc *sc; 936 struct g_geom *gp; 937 const char *mpname, *name; 938 939 mpname = gctl_get_asciiparam(req, "arg0"); 940 if (mpname == NULL) { 941 gctl_error(req, "No 'arg0' argument"); 942 return; 943 } 944 gp = g_multipath_find_geom(mp, mpname); 945 if (gp == NULL) { 946 gctl_error(req, "Device %s not found", mpname); 947 return; 948 } 949 sc = gp->softc; 950 951 name = gctl_get_asciiparam(req, "arg1"); 952 if (name == NULL) { 953 gctl_error(req, "No 'arg1' argument"); 954 return; 955 } 956 g_multipath_ctl_add_name(req, mp, name); 957 } 958 959 static void 960 g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp) 961 { 962 struct g_multipath_metadata md; 963 struct g_multipath_softc *sc; 964 struct g_geom *gp; 965 const char *mpname, *name; 966 char param[16]; 967 int *nargs, i, *val; 968 969 g_topology_assert(); 970 971 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 972 if (*nargs < 2) { 973 gctl_error(req, "wrong number of arguments."); 974 return; 975 } 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 already exist", mpname); 985 return; 986 } 987 sc = gp->softc; 988 989 memset(&md, 0, sizeof(md)); 990 strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 991 md.md_version = G_MULTIPATH_VERSION; 992 strlcpy(md.md_name, mpname, sizeof(md.md_name)); 993 md.md_size = 0; 994 md.md_sectorsize = 0; 995 md.md_uuid[0] = 0; 996 md.md_active_active = 0; 997 val = gctl_get_paraml(req, "active_active", sizeof(*val)); 998 if (val != NULL && *val != 0) 999 md.md_active_active = 1; 1000 val = gctl_get_paraml(req, "active_read", sizeof(*val)); 1001 if (val != NULL && *val != 0) 1002 md.md_active_active = 2; 1003 gp = g_multipath_create(mp, &md); 1004 if (gp == NULL) { 1005 gctl_error(req, "GEOM_MULTIPATH: cannot create geom %s/%s\n", 1006 md.md_name, md.md_uuid); 1007 return; 1008 } 1009 sc = gp->softc; 1010 1011 for (i = 1; i < *nargs; i++) { 1012 snprintf(param, sizeof(param), "arg%d", i); 1013 name = gctl_get_asciiparam(req, param); 1014 g_multipath_ctl_add_name(req, mp, name); 1015 } 1016 1017 if (sc->sc_ndisks != (*nargs - 1)) 1018 g_multipath_destroy(gp); 1019 } 1020 1021 static void 1022 g_multipath_ctl_configure(struct gctl_req *req, struct g_class *mp) 1023 { 1024 struct g_multipath_softc *sc; 1025 struct g_geom *gp; 1026 struct g_consumer *cp; 1027 struct g_provider *pp; 1028 struct g_multipath_metadata md; 1029 const char *name; 1030 int error, *val; 1031 void *buf; 1032 1033 g_topology_assert(); 1034 1035 name = gctl_get_asciiparam(req, "arg0"); 1036 if (name == NULL) { 1037 gctl_error(req, "No 'arg0' argument"); 1038 return; 1039 } 1040 gp = g_multipath_find_geom(mp, name); 1041 if (gp == NULL) { 1042 gctl_error(req, "Device %s is invalid", name); 1043 return; 1044 } 1045 sc = gp->softc; 1046 val = gctl_get_paraml(req, "active_active", sizeof(*val)); 1047 if (val != NULL && *val != 0) 1048 sc->sc_active_active = 1; 1049 val = gctl_get_paraml(req, "active_read", sizeof(*val)); 1050 if (val != NULL && *val != 0) 1051 sc->sc_active_active = 2; 1052 val = gctl_get_paraml(req, "active_passive", sizeof(*val)); 1053 if (val != NULL && *val != 0) 1054 sc->sc_active_active = 0; 1055 if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) { 1056 cp = sc->sc_active; 1057 pp = cp->provider; 1058 error = g_access(cp, 1, 1, 1); 1059 if (error != 0) { 1060 gctl_error(req, "Can't open %s (%d)", pp->name, error); 1061 return; 1062 } 1063 g_topology_unlock(); 1064 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 1065 strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 1066 memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid)); 1067 strlcpy(md.md_name, name, sizeof(md.md_name)); 1068 md.md_version = G_MULTIPATH_VERSION; 1069 md.md_size = pp->mediasize; 1070 md.md_sectorsize = pp->sectorsize; 1071 md.md_active_active = sc->sc_active_active; 1072 multipath_metadata_encode(&md, buf); 1073 error = g_write_data(cp, pp->mediasize - pp->sectorsize, 1074 buf, pp->sectorsize); 1075 g_topology_lock(); 1076 g_access(cp, -1, -1, -1); 1077 if (error != 0) 1078 gctl_error(req, "Can't update metadata on %s (%d)", 1079 pp->name, error); 1080 } 1081 } 1082 1083 static void 1084 g_multipath_ctl_fail(struct gctl_req *req, struct g_class *mp, int fail) 1085 { 1086 struct g_multipath_softc *sc; 1087 struct g_geom *gp; 1088 struct g_consumer *cp; 1089 const char *mpname, *name; 1090 int found; 1091 1092 mpname = gctl_get_asciiparam(req, "arg0"); 1093 if (mpname == NULL) { 1094 gctl_error(req, "No 'arg0' argument"); 1095 return; 1096 } 1097 gp = g_multipath_find_geom(mp, mpname); 1098 if (gp == NULL) { 1099 gctl_error(req, "Device %s not found", mpname); 1100 return; 1101 } 1102 sc = gp->softc; 1103 1104 name = gctl_get_asciiparam(req, "arg1"); 1105 if (name == NULL) { 1106 gctl_error(req, "No 'arg1' argument"); 1107 return; 1108 } 1109 1110 found = 0; 1111 mtx_lock(&sc->sc_mtx); 1112 LIST_FOREACH(cp, &gp->consumer, consumer) { 1113 if (cp->provider != NULL && 1114 strcmp(cp->provider->name, name) == 0 && 1115 (cp->index & MP_LOST) == 0) { 1116 found = 1; 1117 if (!fail == !(cp->index & MP_FAIL)) 1118 continue; 1119 printf("GEOM_MULTIPATH: %s in %s is marked %s.\n", 1120 name, sc->sc_name, fail ? "FAIL" : "OK"); 1121 if (fail) { 1122 g_multipath_fault(cp, MP_FAIL); 1123 } else { 1124 cp->index &= ~MP_FAIL; 1125 } 1126 } 1127 } 1128 mtx_unlock(&sc->sc_mtx); 1129 if (found == 0) 1130 gctl_error(req, "Provider %s not found", name); 1131 } 1132 1133 static void 1134 g_multipath_ctl_remove(struct gctl_req *req, struct g_class *mp) 1135 { 1136 struct g_multipath_softc *sc; 1137 struct g_geom *gp; 1138 struct g_consumer *cp, *cp1; 1139 const char *mpname, *name; 1140 uintptr_t *cnt; 1141 int found; 1142 1143 mpname = gctl_get_asciiparam(req, "arg0"); 1144 if (mpname == NULL) { 1145 gctl_error(req, "No 'arg0' argument"); 1146 return; 1147 } 1148 gp = g_multipath_find_geom(mp, mpname); 1149 if (gp == NULL) { 1150 gctl_error(req, "Device %s not found", mpname); 1151 return; 1152 } 1153 sc = gp->softc; 1154 1155 name = gctl_get_asciiparam(req, "arg1"); 1156 if (name == NULL) { 1157 gctl_error(req, "No 'arg1' argument"); 1158 return; 1159 } 1160 1161 found = 0; 1162 mtx_lock(&sc->sc_mtx); 1163 LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 1164 if (cp->provider != NULL && 1165 strcmp(cp->provider->name, name) == 0 && 1166 (cp->index & MP_LOST) == 0) { 1167 found = 1; 1168 printf("GEOM_MULTIPATH: removing %s from %s\n", 1169 cp->provider->name, cp->geom->name); 1170 sc->sc_ndisks--; 1171 g_multipath_fault(cp, MP_LOST); 1172 cnt = (uintptr_t *)&cp->private; 1173 if (*cnt == 0 && (cp->index & MP_POSTED) == 0) { 1174 cp->index |= MP_POSTED; 1175 mtx_unlock(&sc->sc_mtx); 1176 g_mpd(cp, 0); 1177 if (cp1 == NULL) 1178 return; /* Recursion happened. */ 1179 mtx_lock(&sc->sc_mtx); 1180 } 1181 } 1182 } 1183 mtx_unlock(&sc->sc_mtx); 1184 if (found == 0) 1185 gctl_error(req, "Provider %s not found", name); 1186 } 1187 1188 static struct g_geom * 1189 g_multipath_find_geom(struct g_class *mp, const char *name) 1190 { 1191 struct g_geom *gp; 1192 struct g_multipath_softc *sc; 1193 1194 LIST_FOREACH(gp, &mp->geom, geom) { 1195 sc = gp->softc; 1196 if (sc == NULL || sc->sc_stopping) 1197 continue; 1198 if (strcmp(gp->name, name) == 0) 1199 return (gp); 1200 } 1201 return (NULL); 1202 } 1203 1204 static void 1205 g_multipath_ctl_stop(struct gctl_req *req, struct g_class *mp) 1206 { 1207 struct g_geom *gp; 1208 const char *name; 1209 int error; 1210 1211 g_topology_assert(); 1212 1213 name = gctl_get_asciiparam(req, "arg0"); 1214 if (name == NULL) { 1215 gctl_error(req, "No 'arg0' argument"); 1216 return; 1217 } 1218 gp = g_multipath_find_geom(mp, name); 1219 if (gp == NULL) { 1220 gctl_error(req, "Device %s is invalid", name); 1221 return; 1222 } 1223 error = g_multipath_destroy(gp); 1224 if (error != 0 && error != EINPROGRESS) 1225 gctl_error(req, "failed to stop %s (err=%d)", name, error); 1226 } 1227 1228 static void 1229 g_multipath_ctl_destroy(struct gctl_req *req, struct g_class *mp) 1230 { 1231 struct g_geom *gp; 1232 struct g_multipath_softc *sc; 1233 struct g_consumer *cp; 1234 struct g_provider *pp; 1235 const char *name; 1236 uint8_t *buf; 1237 int error; 1238 1239 g_topology_assert(); 1240 1241 name = gctl_get_asciiparam(req, "arg0"); 1242 if (name == NULL) { 1243 gctl_error(req, "No 'arg0' argument"); 1244 return; 1245 } 1246 gp = g_multipath_find_geom(mp, name); 1247 if (gp == NULL) { 1248 gctl_error(req, "Device %s is invalid", name); 1249 return; 1250 } 1251 sc = gp->softc; 1252 1253 if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) { 1254 cp = sc->sc_active; 1255 pp = cp->provider; 1256 error = g_access(cp, 1, 1, 1); 1257 if (error != 0) { 1258 gctl_error(req, "Can't open %s (%d)", pp->name, error); 1259 goto destroy; 1260 } 1261 g_topology_unlock(); 1262 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 1263 error = g_write_data(cp, pp->mediasize - pp->sectorsize, 1264 buf, pp->sectorsize); 1265 g_topology_lock(); 1266 g_access(cp, -1, -1, -1); 1267 if (error != 0) 1268 gctl_error(req, "Can't erase metadata on %s (%d)", 1269 pp->name, error); 1270 } 1271 1272 destroy: 1273 error = g_multipath_destroy(gp); 1274 if (error != 0 && error != EINPROGRESS) 1275 gctl_error(req, "failed to destroy %s (err=%d)", name, error); 1276 } 1277 1278 static void 1279 g_multipath_ctl_rotate(struct gctl_req *req, struct g_class *mp) 1280 { 1281 struct g_geom *gp; 1282 const char *name; 1283 int error; 1284 1285 g_topology_assert(); 1286 1287 name = gctl_get_asciiparam(req, "arg0"); 1288 if (name == NULL) { 1289 gctl_error(req, "No 'arg0' argument"); 1290 return; 1291 } 1292 gp = g_multipath_find_geom(mp, name); 1293 if (gp == NULL) { 1294 gctl_error(req, "Device %s is invalid", name); 1295 return; 1296 } 1297 error = g_multipath_rotate(gp); 1298 if (error != 0) { 1299 gctl_error(req, "failed to rotate %s (err=%d)", name, error); 1300 } 1301 } 1302 1303 static void 1304 g_multipath_ctl_getactive(struct gctl_req *req, struct g_class *mp) 1305 { 1306 struct sbuf *sb; 1307 struct g_geom *gp; 1308 struct g_multipath_softc *sc; 1309 struct g_consumer *cp; 1310 const char *name; 1311 int empty; 1312 1313 sb = sbuf_new_auto(); 1314 1315 g_topology_assert(); 1316 name = gctl_get_asciiparam(req, "arg0"); 1317 if (name == NULL) { 1318 gctl_error(req, "No 'arg0' argument"); 1319 return; 1320 } 1321 gp = g_multipath_find_geom(mp, name); 1322 if (gp == NULL) { 1323 gctl_error(req, "Device %s is invalid", name); 1324 return; 1325 } 1326 sc = gp->softc; 1327 if (sc->sc_active_active == 1) { 1328 empty = 1; 1329 LIST_FOREACH(cp, &gp->consumer, consumer) { 1330 if (cp->index & MP_BAD) 1331 continue; 1332 if (!empty) 1333 sbuf_cat(sb, " "); 1334 sbuf_cat(sb, cp->provider->name); 1335 empty = 0; 1336 } 1337 if (empty) 1338 sbuf_cat(sb, "none"); 1339 sbuf_cat(sb, "\n"); 1340 } else if (sc->sc_active && sc->sc_active->provider) { 1341 sbuf_printf(sb, "%s\n", sc->sc_active->provider->name); 1342 } else { 1343 sbuf_printf(sb, "none\n"); 1344 } 1345 sbuf_finish(sb); 1346 gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1347 sbuf_delete(sb); 1348 } 1349 1350 static void 1351 g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb) 1352 { 1353 uint32_t *version; 1354 g_topology_assert(); 1355 version = gctl_get_paraml(req, "version", sizeof(*version)); 1356 if (version == NULL) { 1357 gctl_error(req, "No 'version' argument"); 1358 } else if (*version != G_MULTIPATH_VERSION) { 1359 gctl_error(req, "Userland and kernel parts are out of sync"); 1360 } else if (strcmp(verb, "add") == 0) { 1361 g_multipath_ctl_add(req, mp); 1362 } else if (strcmp(verb, "prefer") == 0) { 1363 g_multipath_ctl_prefer(req, mp); 1364 } else if (strcmp(verb, "create") == 0) { 1365 g_multipath_ctl_create(req, mp); 1366 } else if (strcmp(verb, "configure") == 0) { 1367 g_multipath_ctl_configure(req, mp); 1368 } else if (strcmp(verb, "stop") == 0) { 1369 g_multipath_ctl_stop(req, mp); 1370 } else if (strcmp(verb, "destroy") == 0) { 1371 g_multipath_ctl_destroy(req, mp); 1372 } else if (strcmp(verb, "fail") == 0) { 1373 g_multipath_ctl_fail(req, mp, 1); 1374 } else if (strcmp(verb, "restore") == 0) { 1375 g_multipath_ctl_fail(req, mp, 0); 1376 } else if (strcmp(verb, "remove") == 0) { 1377 g_multipath_ctl_remove(req, mp); 1378 } else if (strcmp(verb, "rotate") == 0) { 1379 g_multipath_ctl_rotate(req, mp); 1380 } else if (strcmp(verb, "getactive") == 0) { 1381 g_multipath_ctl_getactive(req, mp); 1382 } else { 1383 gctl_error(req, "Unknown verb %s", verb); 1384 } 1385 } 1386 1387 static void 1388 g_multipath_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1389 struct g_consumer *cp, struct g_provider *pp) 1390 { 1391 struct g_multipath_softc *sc; 1392 int good; 1393 1394 g_topology_assert(); 1395 1396 sc = gp->softc; 1397 if (sc == NULL) 1398 return; 1399 if (cp != NULL) { 1400 sbuf_printf(sb, "%s<State>%s</State>\n", indent, 1401 (cp->index & MP_NEW) ? "NEW" : 1402 (cp->index & MP_LOST) ? "LOST" : 1403 (cp->index & MP_FAIL) ? "FAIL" : 1404 (sc->sc_active_active == 1 || sc->sc_active == cp) ? 1405 "ACTIVE" : 1406 sc->sc_active_active == 2 ? "READ" : "PASSIVE"); 1407 } else { 1408 good = g_multipath_good(gp); 1409 sbuf_printf(sb, "%s<State>%s</State>\n", indent, 1410 good == 0 ? "BROKEN" : 1411 (good != sc->sc_ndisks || sc->sc_ndisks == 1) ? 1412 "DEGRADED" : "OPTIMAL"); 1413 } 1414 if (cp == NULL && pp == NULL) { 1415 sbuf_printf(sb, "%s<UUID>%s</UUID>\n", indent, sc->sc_uuid); 1416 sbuf_printf(sb, "%s<Mode>Active/%s</Mode>\n", indent, 1417 sc->sc_active_active == 2 ? "Read" : 1418 sc->sc_active_active == 1 ? "Active" : "Passive"); 1419 sbuf_printf(sb, "%s<Type>%s</Type>\n", indent, 1420 sc->sc_uuid[0] == 0 ? "MANUAL" : "AUTOMATIC"); 1421 } 1422 } 1423 1424 DECLARE_GEOM_CLASS(g_multipath_class, g_multipath); 1425