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