1e770bc6bSMatt Jacob /*- 2e6afd72bSAlexander Motin * Copyright (c) 2011-2013 Alexander Motin <mav@FreeBSD.org> 3e770bc6bSMatt Jacob * Copyright (c) 2006-2007 Matthew Jacob <mjacob@FreeBSD.org> 4e770bc6bSMatt Jacob * All rights reserved. 5e770bc6bSMatt Jacob * 6e770bc6bSMatt Jacob * Redistribution and use in source and binary forms, with or without 7e770bc6bSMatt Jacob * modification, are permitted provided that the following conditions 8e770bc6bSMatt Jacob * are met: 9e770bc6bSMatt Jacob * 1. Redistributions of source code must retain the above copyright 10e770bc6bSMatt Jacob * notice, this list of conditions and the following disclaimer. 11e770bc6bSMatt Jacob * 2. Redistributions in binary form must reproduce the above copyright 12e770bc6bSMatt Jacob * notice, this list of conditions and the following disclaimer in the 13e770bc6bSMatt Jacob * documentation and/or other materials provided with the distribution. 14e770bc6bSMatt Jacob * 15e770bc6bSMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16e770bc6bSMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17e770bc6bSMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18e770bc6bSMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19e770bc6bSMatt Jacob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20e770bc6bSMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21e770bc6bSMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22e770bc6bSMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23e770bc6bSMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24e770bc6bSMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25e770bc6bSMatt Jacob * SUCH DAMAGE. 26e770bc6bSMatt Jacob */ 27e770bc6bSMatt Jacob /* 28e770bc6bSMatt Jacob * Based upon work by Pawel Jakub Dawidek <pjd@FreeBSD.org> for all of the 29e770bc6bSMatt Jacob * fine geom examples, and by Poul Henning Kamp <phk@FreeBSD.org> for GEOM 30e770bc6bSMatt Jacob * itself, all of which is most gratefully acknowledged. 31e770bc6bSMatt Jacob */ 32e770bc6bSMatt Jacob 33e770bc6bSMatt Jacob #include <sys/cdefs.h> 34e770bc6bSMatt Jacob __FBSDID("$FreeBSD$"); 35e770bc6bSMatt Jacob #include <sys/param.h> 36e770bc6bSMatt Jacob #include <sys/systm.h> 37e770bc6bSMatt Jacob #include <sys/kernel.h> 38e770bc6bSMatt Jacob #include <sys/module.h> 39e6afd72bSAlexander Motin #include <sys/limits.h> 40e770bc6bSMatt Jacob #include <sys/lock.h> 41e770bc6bSMatt Jacob #include <sys/mutex.h> 42e770bc6bSMatt Jacob #include <sys/bio.h> 435d807a0eSAndrey V. Elsukov #include <sys/sbuf.h> 44e770bc6bSMatt Jacob #include <sys/sysctl.h> 45e770bc6bSMatt Jacob #include <sys/kthread.h> 46e770bc6bSMatt Jacob #include <sys/malloc.h> 47e770bc6bSMatt Jacob #include <geom/geom.h> 48e770bc6bSMatt Jacob #include <geom/multipath/g_multipath.h> 49e770bc6bSMatt Jacob 50cb08c2ccSAlexander Leidinger FEATURE(geom_multipath, "GEOM multipath support"); 51e770bc6bSMatt Jacob 52e770bc6bSMatt Jacob SYSCTL_DECL(_kern_geom); 536472ac3dSEd Schouten static SYSCTL_NODE(_kern_geom, OID_AUTO, multipath, CTLFLAG_RW, 0, 54e770bc6bSMatt Jacob "GEOM_MULTIPATH tunables"); 55e770bc6bSMatt Jacob static u_int g_multipath_debug = 0; 56e770bc6bSMatt Jacob SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, debug, CTLFLAG_RW, 57e770bc6bSMatt Jacob &g_multipath_debug, 0, "Debug level"); 580c883cefSAlexander Motin static u_int g_multipath_exclusive = 1; 590c883cefSAlexander Motin SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, exclusive, CTLFLAG_RW, 600c883cefSAlexander Motin &g_multipath_exclusive, 0, "Exclusively open providers"); 61e770bc6bSMatt Jacob 62e770bc6bSMatt Jacob static enum { 63e770bc6bSMatt Jacob GKT_NIL, 64e770bc6bSMatt Jacob GKT_RUN, 65e770bc6bSMatt Jacob GKT_DIE 66e770bc6bSMatt Jacob } g_multipath_kt_state; 67e770bc6bSMatt Jacob static struct bio_queue_head gmtbq; 68e770bc6bSMatt Jacob static struct mtx gmtbq_mtx; 69e770bc6bSMatt Jacob 70f8c79813SAlexander Motin static int g_multipath_read_metadata(struct g_consumer *cp, 71f8c79813SAlexander Motin struct g_multipath_metadata *md); 72f8c79813SAlexander Motin static int g_multipath_write_metadata(struct g_consumer *cp, 73f8c79813SAlexander Motin struct g_multipath_metadata *md); 74f8c79813SAlexander Motin 75e770bc6bSMatt Jacob static void g_multipath_orphan(struct g_consumer *); 76e6afd72bSAlexander Motin static void g_multipath_resize(struct g_consumer *); 77e770bc6bSMatt Jacob static void g_multipath_start(struct bio *); 78e770bc6bSMatt Jacob static void g_multipath_done(struct bio *); 79e770bc6bSMatt Jacob static void g_multipath_done_error(struct bio *); 80e770bc6bSMatt Jacob static void g_multipath_kt(void *); 81e770bc6bSMatt Jacob 82e770bc6bSMatt Jacob static int g_multipath_destroy(struct g_geom *); 83e770bc6bSMatt Jacob static int 84e770bc6bSMatt Jacob g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *); 85e770bc6bSMatt Jacob 862b4969ffSMatt Jacob static struct g_geom *g_multipath_find_geom(struct g_class *, const char *); 87b5dce617SMatt Jacob static int g_multipath_rotate(struct g_geom *); 88b5dce617SMatt Jacob 89e770bc6bSMatt Jacob static g_taste_t g_multipath_taste; 90e770bc6bSMatt Jacob static g_ctl_req_t g_multipath_config; 91e770bc6bSMatt Jacob static g_init_t g_multipath_init; 92e770bc6bSMatt Jacob static g_fini_t g_multipath_fini; 930c883cefSAlexander Motin static g_dumpconf_t g_multipath_dumpconf; 94e770bc6bSMatt Jacob 95e770bc6bSMatt Jacob struct g_class g_multipath_class = { 96e770bc6bSMatt Jacob .name = G_MULTIPATH_CLASS_NAME, 97e770bc6bSMatt Jacob .version = G_VERSION, 98e770bc6bSMatt Jacob .ctlreq = g_multipath_config, 99e770bc6bSMatt Jacob .taste = g_multipath_taste, 100e770bc6bSMatt Jacob .destroy_geom = g_multipath_destroy_geom, 101e770bc6bSMatt Jacob .init = g_multipath_init, 102e770bc6bSMatt Jacob .fini = g_multipath_fini 103e770bc6bSMatt Jacob }; 104e770bc6bSMatt Jacob 1050c883cefSAlexander Motin #define MP_FAIL 0x00000001 1060c883cefSAlexander Motin #define MP_LOST 0x00000002 1070c883cefSAlexander Motin #define MP_NEW 0x00000004 1080c883cefSAlexander Motin #define MP_POSTED 0x00000008 1090c883cefSAlexander Motin #define MP_BAD (MP_FAIL | MP_LOST | MP_NEW) 1100c883cefSAlexander Motin #define MP_IDLE 0x00000010 1110c883cefSAlexander Motin #define MP_IDLE_MASK 0xfffffff0 1120c883cefSAlexander Motin 1130c883cefSAlexander Motin static int 1140c883cefSAlexander Motin g_multipath_good(struct g_geom *gp) 1150c883cefSAlexander Motin { 1160c883cefSAlexander Motin struct g_consumer *cp; 1170c883cefSAlexander Motin int n = 0; 1180c883cefSAlexander Motin 1190c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 1200c883cefSAlexander Motin if ((cp->index & MP_BAD) == 0) 1210c883cefSAlexander Motin n++; 1220c883cefSAlexander Motin } 1230c883cefSAlexander Motin return (n); 1240c883cefSAlexander Motin } 1250c883cefSAlexander Motin 1260c883cefSAlexander Motin static void 1270c883cefSAlexander Motin g_multipath_fault(struct g_consumer *cp, int cause) 1280c883cefSAlexander Motin { 1290c883cefSAlexander Motin struct g_multipath_softc *sc; 1300c883cefSAlexander Motin struct g_consumer *lcp; 1310c883cefSAlexander Motin struct g_geom *gp; 1320c883cefSAlexander Motin 1330c883cefSAlexander Motin gp = cp->geom; 1340c883cefSAlexander Motin sc = gp->softc; 1350c883cefSAlexander Motin cp->index |= cause; 1360c883cefSAlexander Motin if (g_multipath_good(gp) == 0 && sc->sc_ndisks > 0) { 1370c883cefSAlexander Motin LIST_FOREACH(lcp, &gp->consumer, consumer) { 1380c883cefSAlexander Motin if (lcp->provider == NULL || 1390c883cefSAlexander Motin (lcp->index & (MP_LOST | MP_NEW))) 1400c883cefSAlexander Motin continue; 1410c883cefSAlexander Motin if (sc->sc_ndisks > 1 && lcp == cp) 1420c883cefSAlexander Motin continue; 1430c883cefSAlexander Motin printf("GEOM_MULTIPATH: " 1440c883cefSAlexander Motin "all paths in %s were marked FAIL, restore %s\n", 1450c883cefSAlexander Motin sc->sc_name, lcp->provider->name); 1460c883cefSAlexander Motin lcp->index &= ~MP_FAIL; 1470c883cefSAlexander Motin } 1480c883cefSAlexander Motin } 1490c883cefSAlexander Motin if (cp != sc->sc_active) 1500c883cefSAlexander Motin return; 1510c883cefSAlexander Motin sc->sc_active = NULL; 1520c883cefSAlexander Motin LIST_FOREACH(lcp, &gp->consumer, consumer) { 1530c883cefSAlexander Motin if ((lcp->index & MP_BAD) == 0) { 1540c883cefSAlexander Motin sc->sc_active = lcp; 1550c883cefSAlexander Motin break; 1560c883cefSAlexander Motin } 1570c883cefSAlexander Motin } 1580c883cefSAlexander Motin if (sc->sc_active == NULL) { 1590c883cefSAlexander Motin printf("GEOM_MULTIPATH: out of providers for %s\n", 1600c883cefSAlexander Motin sc->sc_name); 16163297dfdSAlexander Motin } else if (sc->sc_active_active != 1) { 1620c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 1630c883cefSAlexander Motin sc->sc_active->provider->name, sc->sc_name); 1640c883cefSAlexander Motin } 1650c883cefSAlexander Motin } 1660c883cefSAlexander Motin 1670c883cefSAlexander Motin static struct g_consumer * 16863297dfdSAlexander Motin g_multipath_choose(struct g_geom *gp, struct bio *bp) 1690c883cefSAlexander Motin { 1700c883cefSAlexander Motin struct g_multipath_softc *sc; 1710c883cefSAlexander Motin struct g_consumer *best, *cp; 1720c883cefSAlexander Motin 1730c883cefSAlexander Motin sc = gp->softc; 17463297dfdSAlexander Motin if (sc->sc_active_active == 0 || 17563297dfdSAlexander Motin (sc->sc_active_active == 2 && bp->bio_cmd != BIO_READ)) 1760c883cefSAlexander Motin return (sc->sc_active); 1770c883cefSAlexander Motin best = NULL; 1780c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 1790c883cefSAlexander Motin if (cp->index & MP_BAD) 1800c883cefSAlexander Motin continue; 1810c883cefSAlexander Motin cp->index += MP_IDLE; 1820c883cefSAlexander Motin if (best == NULL || cp->private < best->private || 1830c883cefSAlexander Motin (cp->private == best->private && cp->index > best->index)) 1840c883cefSAlexander Motin best = cp; 1850c883cefSAlexander Motin } 1860c883cefSAlexander Motin if (best != NULL) 1870c883cefSAlexander Motin best->index &= ~MP_IDLE_MASK; 1880c883cefSAlexander Motin return (best); 1890c883cefSAlexander Motin } 190e770bc6bSMatt Jacob 191e770bc6bSMatt Jacob static void 192e770bc6bSMatt Jacob g_mpd(void *arg, int flags __unused) 193e770bc6bSMatt Jacob { 1940c883cefSAlexander Motin struct g_geom *gp; 1950c883cefSAlexander Motin struct g_multipath_softc *sc; 196e770bc6bSMatt Jacob struct g_consumer *cp; 1970c883cefSAlexander Motin int w; 198e770bc6bSMatt Jacob 199e770bc6bSMatt Jacob g_topology_assert(); 200e770bc6bSMatt Jacob cp = arg; 2010c883cefSAlexander Motin gp = cp->geom; 2020c883cefSAlexander Motin if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) { 2030c883cefSAlexander Motin w = cp->acw; 204e770bc6bSMatt Jacob g_access(cp, -cp->acr, -cp->acw, -cp->ace); 2050c883cefSAlexander Motin if (w > 0 && cp->provider != NULL && 2060c883cefSAlexander Motin (cp->provider->geom->flags & G_GEOM_WITHER) == 0) { 2070c883cefSAlexander Motin g_post_event(g_mpd, cp, M_WAITOK, NULL); 2080c883cefSAlexander Motin return; 2090c883cefSAlexander Motin } 2100c883cefSAlexander Motin } 2110c883cefSAlexander Motin sc = gp->softc; 2120c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 213e770bc6bSMatt Jacob if (cp->provider) { 214e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: %s removed from %s\n", 2150c883cefSAlexander Motin cp->provider->name, gp->name); 216e770bc6bSMatt Jacob g_detach(cp); 217e770bc6bSMatt Jacob } 218e770bc6bSMatt Jacob g_destroy_consumer(cp); 2190c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 2200c883cefSAlexander Motin if (LIST_EMPTY(&gp->consumer)) 2210c883cefSAlexander Motin g_multipath_destroy(gp); 222e770bc6bSMatt Jacob } 223e770bc6bSMatt Jacob 224e770bc6bSMatt Jacob static void 225e770bc6bSMatt Jacob g_multipath_orphan(struct g_consumer *cp) 226e770bc6bSMatt Jacob { 2270c883cefSAlexander Motin struct g_multipath_softc *sc; 2280c883cefSAlexander Motin uintptr_t *cnt; 2290c883cefSAlexander Motin 2300c883cefSAlexander Motin g_topology_assert(); 2310c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s in %s was disconnected\n", 232e770bc6bSMatt Jacob cp->provider->name, cp->geom->name); 2330c883cefSAlexander Motin sc = cp->geom->softc; 2340c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 2350c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 2360c883cefSAlexander Motin sc->sc_ndisks--; 2370c883cefSAlexander Motin g_multipath_fault(cp, MP_LOST); 2380c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_POSTED) == 0) { 2390c883cefSAlexander Motin cp->index |= MP_POSTED; 2400c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 241e770bc6bSMatt Jacob g_mpd(cp, 0); 2420c883cefSAlexander Motin } else 2430c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 244e770bc6bSMatt Jacob } 245e770bc6bSMatt Jacob 246e770bc6bSMatt Jacob static void 247e6afd72bSAlexander Motin g_multipath_resize(struct g_consumer *cp) 248e6afd72bSAlexander Motin { 249e6afd72bSAlexander Motin struct g_multipath_softc *sc; 250e6afd72bSAlexander Motin struct g_geom *gp; 251f8c79813SAlexander Motin struct g_consumer *cp1; 252e6afd72bSAlexander Motin struct g_provider *pp; 253e6afd72bSAlexander Motin struct g_multipath_metadata md; 254e6afd72bSAlexander Motin off_t size, psize, ssize; 255e6afd72bSAlexander Motin int error; 256e6afd72bSAlexander Motin 257e6afd72bSAlexander Motin g_topology_assert(); 258e6afd72bSAlexander Motin 259e6afd72bSAlexander Motin gp = cp->geom; 260e6afd72bSAlexander Motin pp = cp->provider; 261e6afd72bSAlexander Motin sc = gp->softc; 262e6afd72bSAlexander Motin 263e6afd72bSAlexander Motin if (sc->sc_stopping) 264e6afd72bSAlexander Motin return; 265e6afd72bSAlexander Motin 266e6afd72bSAlexander Motin if (pp->mediasize < sc->sc_size) { 267e6afd72bSAlexander Motin size = pp->mediasize; 268e6afd72bSAlexander Motin ssize = pp->sectorsize; 269e6afd72bSAlexander Motin } else { 270e6afd72bSAlexander Motin size = ssize = OFF_MAX; 271e6afd72bSAlexander Motin mtx_lock(&sc->sc_mtx); 272f8c79813SAlexander Motin LIST_FOREACH(cp1, &gp->consumer, consumer) { 273f8c79813SAlexander Motin pp = cp1->provider; 274e6afd72bSAlexander Motin if (pp == NULL) 275e6afd72bSAlexander Motin continue; 276e6afd72bSAlexander Motin if (pp->mediasize < size) { 277e6afd72bSAlexander Motin size = pp->mediasize; 278e6afd72bSAlexander Motin ssize = pp->sectorsize; 279e6afd72bSAlexander Motin } 280e6afd72bSAlexander Motin } 281e6afd72bSAlexander Motin mtx_unlock(&sc->sc_mtx); 282e6afd72bSAlexander Motin if (size == OFF_MAX || size == sc->sc_size) 283e6afd72bSAlexander Motin return; 284e6afd72bSAlexander Motin } 285e6afd72bSAlexander Motin psize = size - ((sc->sc_uuid[0] != 0) ? ssize : 0); 286e6afd72bSAlexander Motin printf("GEOM_MULTIPATH: %s size changed from %jd to %jd\n", 287e6afd72bSAlexander Motin sc->sc_name, sc->sc_pp->mediasize, psize); 288f8c79813SAlexander Motin if (sc->sc_uuid[0] != 0 && size < sc->sc_size) { 289f8c79813SAlexander Motin error = g_multipath_read_metadata(cp, &md); 290f8c79813SAlexander Motin if (error || 291f8c79813SAlexander Motin (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) || 292f8c79813SAlexander Motin (memcmp(md.md_uuid, sc->sc_uuid, sizeof(sc->sc_uuid)) != 0) || 293f8c79813SAlexander Motin (strcmp(md.md_name, sc->sc_name) != 0) || 294f8c79813SAlexander Motin (md.md_size != 0 && md.md_size != size) || 295f8c79813SAlexander Motin (md.md_sectorsize != 0 && md.md_sectorsize != ssize)) { 296e6afd72bSAlexander Motin g_multipath_destroy(gp); 297e6afd72bSAlexander Motin return; 298e6afd72bSAlexander Motin } 299f8c79813SAlexander Motin } 300e6afd72bSAlexander Motin sc->sc_size = size; 301e6afd72bSAlexander Motin g_resize_provider(sc->sc_pp, psize); 302e6afd72bSAlexander Motin 303f8c79813SAlexander Motin if (sc->sc_uuid[0] != 0) { 304e6afd72bSAlexander Motin pp = cp->provider; 305e6afd72bSAlexander Motin strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 306e6afd72bSAlexander Motin memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid)); 307e6afd72bSAlexander Motin strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name)); 308e6afd72bSAlexander Motin md.md_version = G_MULTIPATH_VERSION; 309e6afd72bSAlexander Motin md.md_size = size; 310f8c79813SAlexander Motin md.md_sectorsize = ssize; 311e6afd72bSAlexander Motin md.md_active_active = sc->sc_active_active; 312f8c79813SAlexander Motin error = g_multipath_write_metadata(cp, &md); 313e6afd72bSAlexander Motin if (error != 0) 314e6afd72bSAlexander Motin printf("GEOM_MULTIPATH: Can't update metadata on %s " 315e6afd72bSAlexander Motin "(%d)\n", pp->name, error); 316e6afd72bSAlexander Motin } 317e6afd72bSAlexander Motin } 318e6afd72bSAlexander Motin 319e6afd72bSAlexander Motin static void 320e770bc6bSMatt Jacob g_multipath_start(struct bio *bp) 321e770bc6bSMatt Jacob { 322e770bc6bSMatt Jacob struct g_multipath_softc *sc; 323e770bc6bSMatt Jacob struct g_geom *gp; 324e770bc6bSMatt Jacob struct g_consumer *cp; 325e770bc6bSMatt Jacob struct bio *cbp; 3260c883cefSAlexander Motin uintptr_t *cnt; 327e770bc6bSMatt Jacob 328e770bc6bSMatt Jacob gp = bp->bio_to->geom; 329e770bc6bSMatt Jacob sc = gp->softc; 330e770bc6bSMatt Jacob KASSERT(sc != NULL, ("NULL sc")); 331e770bc6bSMatt Jacob cbp = g_clone_bio(bp); 332e770bc6bSMatt Jacob if (cbp == NULL) { 333e770bc6bSMatt Jacob g_io_deliver(bp, ENOMEM); 334e770bc6bSMatt Jacob return; 335e770bc6bSMatt Jacob } 3360c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 33763297dfdSAlexander Motin cp = g_multipath_choose(gp, bp); 3380c883cefSAlexander Motin if (cp == NULL) { 3390c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 3400c883cefSAlexander Motin g_destroy_bio(cbp); 3410c883cefSAlexander Motin g_io_deliver(bp, ENXIO); 3420c883cefSAlexander Motin return; 3430c883cefSAlexander Motin } 3440c883cefSAlexander Motin if ((uintptr_t)bp->bio_driver1 < sc->sc_ndisks) 3450c883cefSAlexander Motin bp->bio_driver1 = (void *)(uintptr_t)sc->sc_ndisks; 3460c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 3470c883cefSAlexander Motin (*cnt)++; 3480c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 349e770bc6bSMatt Jacob cbp->bio_done = g_multipath_done; 350e770bc6bSMatt Jacob g_io_request(cbp, cp); 351e770bc6bSMatt Jacob } 352e770bc6bSMatt Jacob 353e770bc6bSMatt Jacob static void 354e770bc6bSMatt Jacob g_multipath_done(struct bio *bp) 355e770bc6bSMatt Jacob { 3560c883cefSAlexander Motin struct g_multipath_softc *sc; 3570c883cefSAlexander Motin struct g_consumer *cp; 3580c883cefSAlexander Motin uintptr_t *cnt; 3590c883cefSAlexander Motin 360e770bc6bSMatt Jacob if (bp->bio_error == ENXIO || bp->bio_error == EIO) { 361e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 362e770bc6bSMatt Jacob bioq_insert_tail(&gmtbq, bp); 363e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 3640c883cefSAlexander Motin wakeup(&g_multipath_kt_state); 365e770bc6bSMatt Jacob } else { 3660c883cefSAlexander Motin cp = bp->bio_from; 3670c883cefSAlexander Motin sc = cp->geom->softc; 3680c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 3690c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 3700c883cefSAlexander Motin (*cnt)--; 3710c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_LOST)) { 372*0ada3afcSAlexander Motin if (g_post_event(g_mpd, cp, M_NOWAIT, NULL) == 0) 3730c883cefSAlexander Motin cp->index |= MP_POSTED; 3740c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 3750c883cefSAlexander Motin } else 3760c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 377e770bc6bSMatt Jacob g_std_done(bp); 378e770bc6bSMatt Jacob } 379e770bc6bSMatt Jacob } 380e770bc6bSMatt Jacob 381e770bc6bSMatt Jacob static void 382e770bc6bSMatt Jacob g_multipath_done_error(struct bio *bp) 383e770bc6bSMatt Jacob { 384e770bc6bSMatt Jacob struct bio *pbp; 385e770bc6bSMatt Jacob struct g_geom *gp; 386e770bc6bSMatt Jacob struct g_multipath_softc *sc; 387e770bc6bSMatt Jacob struct g_consumer *cp; 388e770bc6bSMatt Jacob struct g_provider *pp; 3890c883cefSAlexander Motin uintptr_t *cnt; 390e770bc6bSMatt Jacob 391e770bc6bSMatt Jacob /* 392e770bc6bSMatt Jacob * If we had a failure, we have to check first to see 393e770bc6bSMatt Jacob * whether the consumer it failed on was the currently 394e770bc6bSMatt Jacob * active consumer (i.e., this is the first in perhaps 395e770bc6bSMatt Jacob * a number of failures). If so, we then switch consumers 396e770bc6bSMatt Jacob * to the next available consumer. 397e770bc6bSMatt Jacob */ 398e770bc6bSMatt Jacob 399e770bc6bSMatt Jacob pbp = bp->bio_parent; 400e770bc6bSMatt Jacob gp = pbp->bio_to->geom; 401e770bc6bSMatt Jacob sc = gp->softc; 402e770bc6bSMatt Jacob cp = bp->bio_from; 403e770bc6bSMatt Jacob pp = cp->provider; 4040c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 405e770bc6bSMatt Jacob 4060c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 40763297dfdSAlexander Motin if ((cp->index & MP_FAIL) == 0) { 4080c883cefSAlexander Motin printf("GEOM_MULTIPATH: Error %d, %s in %s marked FAIL\n", 4090c883cefSAlexander Motin bp->bio_error, pp->name, sc->sc_name); 4100c883cefSAlexander Motin g_multipath_fault(cp, MP_FAIL); 41163297dfdSAlexander Motin } 4120c883cefSAlexander Motin (*cnt)--; 4130c883cefSAlexander Motin if (*cnt == 0 && (cp->index & (MP_LOST | MP_POSTED)) == MP_LOST) { 414e770bc6bSMatt Jacob cp->index |= MP_POSTED; 4150c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 4160c883cefSAlexander Motin g_post_event(g_mpd, cp, M_WAITOK, NULL); 4170c883cefSAlexander Motin } else 4180c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 419e770bc6bSMatt Jacob 420e770bc6bSMatt Jacob /* 421e770bc6bSMatt Jacob * If we can fruitfully restart the I/O, do so. 422e770bc6bSMatt Jacob */ 4230c883cefSAlexander Motin if (pbp->bio_children < (uintptr_t)pbp->bio_driver1) { 4240c883cefSAlexander Motin pbp->bio_inbed++; 425e770bc6bSMatt Jacob g_destroy_bio(bp); 426e770bc6bSMatt Jacob g_multipath_start(pbp); 427e770bc6bSMatt Jacob } else { 428e770bc6bSMatt Jacob g_std_done(bp); 429e770bc6bSMatt Jacob } 430e770bc6bSMatt Jacob } 431e770bc6bSMatt Jacob 432e770bc6bSMatt Jacob static void 433e770bc6bSMatt Jacob g_multipath_kt(void *arg) 434e770bc6bSMatt Jacob { 43512f35a61SPawel Jakub Dawidek 436e770bc6bSMatt Jacob g_multipath_kt_state = GKT_RUN; 437e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 438e770bc6bSMatt Jacob while (g_multipath_kt_state == GKT_RUN) { 439e770bc6bSMatt Jacob for (;;) { 440e770bc6bSMatt Jacob struct bio *bp; 44112f35a61SPawel Jakub Dawidek 442e770bc6bSMatt Jacob bp = bioq_takefirst(&gmtbq); 44312f35a61SPawel Jakub Dawidek if (bp == NULL) 444e770bc6bSMatt Jacob break; 445e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 446e770bc6bSMatt Jacob g_multipath_done_error(bp); 447e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 448e770bc6bSMatt Jacob } 44963297dfdSAlexander Motin if (g_multipath_kt_state != GKT_RUN) 45063297dfdSAlexander Motin break; 451e770bc6bSMatt Jacob msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO, 45263297dfdSAlexander Motin "gkt:wait", 0); 453e770bc6bSMatt Jacob } 454e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 455e770bc6bSMatt Jacob wakeup(&g_multipath_kt_state); 4563745c395SJulian Elischer kproc_exit(0); 457e770bc6bSMatt Jacob } 458e770bc6bSMatt Jacob 459e770bc6bSMatt Jacob 460e770bc6bSMatt Jacob static int 461e770bc6bSMatt Jacob g_multipath_access(struct g_provider *pp, int dr, int dw, int de) 462e770bc6bSMatt Jacob { 463e770bc6bSMatt Jacob struct g_geom *gp; 464e770bc6bSMatt Jacob struct g_consumer *cp, *badcp = NULL; 4650c883cefSAlexander Motin struct g_multipath_softc *sc; 466e770bc6bSMatt Jacob int error; 467e770bc6bSMatt Jacob 468e770bc6bSMatt Jacob gp = pp->geom; 469e770bc6bSMatt Jacob 470e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 471e770bc6bSMatt Jacob error = g_access(cp, dr, dw, de); 472e770bc6bSMatt Jacob if (error) { 473e770bc6bSMatt Jacob badcp = cp; 474e770bc6bSMatt Jacob goto fail; 475e770bc6bSMatt Jacob } 476e770bc6bSMatt Jacob } 4770c883cefSAlexander Motin sc = gp->softc; 4780c883cefSAlexander Motin sc->sc_opened += dr + dw + de; 4790c883cefSAlexander Motin if (sc->sc_stopping && sc->sc_opened == 0) 4800c883cefSAlexander Motin g_multipath_destroy(gp); 481e770bc6bSMatt Jacob return (0); 482e770bc6bSMatt Jacob 483e770bc6bSMatt Jacob fail: 484e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 48512f35a61SPawel Jakub Dawidek if (cp == badcp) 486e770bc6bSMatt Jacob break; 487e770bc6bSMatt Jacob (void) g_access(cp, -dr, -dw, -de); 488e770bc6bSMatt Jacob } 489e770bc6bSMatt Jacob return (error); 490e770bc6bSMatt Jacob } 491e770bc6bSMatt Jacob 492e770bc6bSMatt Jacob static struct g_geom * 493e770bc6bSMatt Jacob g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md) 494e770bc6bSMatt Jacob { 495e770bc6bSMatt Jacob struct g_multipath_softc *sc; 496e770bc6bSMatt Jacob struct g_geom *gp; 497e770bc6bSMatt Jacob struct g_provider *pp; 498e770bc6bSMatt Jacob 499e770bc6bSMatt Jacob g_topology_assert(); 500e770bc6bSMatt Jacob 501e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 5020c883cefSAlexander Motin sc = gp->softc; 5030c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 5040c883cefSAlexander Motin continue; 505e770bc6bSMatt Jacob if (strcmp(gp->name, md->md_name) == 0) { 506e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: name %s already exists\n", 507e770bc6bSMatt Jacob md->md_name); 508e770bc6bSMatt Jacob return (NULL); 509e770bc6bSMatt Jacob } 510e770bc6bSMatt Jacob } 511e770bc6bSMatt Jacob 51202c62349SJaakko Heinonen gp = g_new_geomf(mp, "%s", md->md_name); 513e770bc6bSMatt Jacob sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); 5140c883cefSAlexander Motin mtx_init(&sc->sc_mtx, "multipath", NULL, MTX_DEF); 5150c883cefSAlexander Motin memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid)); 5160c883cefSAlexander Motin memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name)); 5170c883cefSAlexander Motin sc->sc_active_active = md->md_active_active; 518e6afd72bSAlexander Motin sc->sc_size = md->md_size; 519e770bc6bSMatt Jacob gp->softc = sc; 520e770bc6bSMatt Jacob gp->start = g_multipath_start; 521e770bc6bSMatt Jacob gp->orphan = g_multipath_orphan; 522e6afd72bSAlexander Motin gp->resize = g_multipath_resize; 523e770bc6bSMatt Jacob gp->access = g_multipath_access; 5240c883cefSAlexander Motin gp->dumpconf = g_multipath_dumpconf; 525e770bc6bSMatt Jacob 526e770bc6bSMatt Jacob pp = g_new_providerf(gp, "multipath/%s", md->md_name); 52740ea77a0SAlexander Motin pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; 5280c883cefSAlexander Motin if (md->md_size != 0) { 5290c883cefSAlexander Motin pp->mediasize = md->md_size - 5300c883cefSAlexander Motin ((md->md_uuid[0] != 0) ? md->md_sectorsize : 0); 531e770bc6bSMatt Jacob pp->sectorsize = md->md_sectorsize; 5320c883cefSAlexander Motin } 5330c883cefSAlexander Motin sc->sc_pp = pp; 534e770bc6bSMatt Jacob g_error_provider(pp, 0); 5350c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s created\n", gp->name); 536e770bc6bSMatt Jacob return (gp); 537e770bc6bSMatt Jacob } 538e770bc6bSMatt Jacob 539e770bc6bSMatt Jacob static int 540e770bc6bSMatt Jacob g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp) 541e770bc6bSMatt Jacob { 542e770bc6bSMatt Jacob struct g_multipath_softc *sc; 543e770bc6bSMatt Jacob struct g_consumer *cp, *nxtcp; 5440c883cefSAlexander Motin int error, acr, acw, ace; 545e770bc6bSMatt Jacob 546e770bc6bSMatt Jacob g_topology_assert(); 547e770bc6bSMatt Jacob 548e770bc6bSMatt Jacob sc = gp->softc; 549e770bc6bSMatt Jacob KASSERT(sc, ("no softc")); 550e770bc6bSMatt Jacob 551e770bc6bSMatt Jacob /* 552e770bc6bSMatt Jacob * Make sure that the passed provider isn't already attached 553e770bc6bSMatt Jacob */ 554e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 55512f35a61SPawel Jakub Dawidek if (cp->provider == pp) 556e770bc6bSMatt Jacob break; 557e770bc6bSMatt Jacob } 558e770bc6bSMatt Jacob if (cp) { 559e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: provider %s already attached to %s\n", 560e770bc6bSMatt Jacob pp->name, gp->name); 561e770bc6bSMatt Jacob return (EEXIST); 562e770bc6bSMatt Jacob } 563e770bc6bSMatt Jacob nxtcp = LIST_FIRST(&gp->consumer); 564e770bc6bSMatt Jacob cp = g_new_consumer(gp); 56540ea77a0SAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 5660c883cefSAlexander Motin cp->private = NULL; 5670c883cefSAlexander Motin cp->index = MP_NEW; 568e770bc6bSMatt Jacob error = g_attach(cp, pp); 569e770bc6bSMatt Jacob if (error != 0) { 570e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot attach %s to %s", 571e770bc6bSMatt Jacob pp->name, sc->sc_name); 572e770bc6bSMatt Jacob g_destroy_consumer(cp); 573e770bc6bSMatt Jacob return (error); 574e770bc6bSMatt Jacob } 575e770bc6bSMatt Jacob 576e770bc6bSMatt Jacob /* 577e770bc6bSMatt Jacob * Set access permissions on new consumer to match other consumers 578e770bc6bSMatt Jacob */ 5790c883cefSAlexander Motin if (sc->sc_pp) { 5800c883cefSAlexander Motin acr = sc->sc_pp->acr; 5810c883cefSAlexander Motin acw = sc->sc_pp->acw; 5820c883cefSAlexander Motin ace = sc->sc_pp->ace; 5830c883cefSAlexander Motin } else 5840c883cefSAlexander Motin acr = acw = ace = 0; 5850c883cefSAlexander Motin if (g_multipath_exclusive) { 5860c883cefSAlexander Motin acr++; 5870c883cefSAlexander Motin acw++; 5880c883cefSAlexander Motin ace++; 5890c883cefSAlexander Motin } 5900c883cefSAlexander Motin error = g_access(cp, acr, acw, ace); 591e770bc6bSMatt Jacob if (error) { 592e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot set access in " 5930c883cefSAlexander Motin "attaching %s to %s (%d)\n", 5940c883cefSAlexander Motin pp->name, sc->sc_name, error); 595e770bc6bSMatt Jacob g_detach(cp); 596e770bc6bSMatt Jacob g_destroy_consumer(cp); 597e770bc6bSMatt Jacob return (error); 598e770bc6bSMatt Jacob } 599e6afd72bSAlexander Motin if (sc->sc_size == 0) { 600e6afd72bSAlexander Motin sc->sc_size = pp->mediasize - 6010c883cefSAlexander Motin ((sc->sc_uuid[0] != 0) ? pp->sectorsize : 0); 602e6afd72bSAlexander Motin sc->sc_pp->mediasize = sc->sc_size; 6030c883cefSAlexander Motin sc->sc_pp->sectorsize = pp->sectorsize; 604e770bc6bSMatt Jacob } 605e6afd72bSAlexander Motin if (sc->sc_pp->stripesize == 0 && sc->sc_pp->stripeoffset == 0) { 6060c883cefSAlexander Motin sc->sc_pp->stripesize = pp->stripesize; 6070c883cefSAlexander Motin sc->sc_pp->stripeoffset = pp->stripeoffset; 6080c883cefSAlexander Motin } 609f4673017SAlexander Motin sc->sc_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED; 6100c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 6110c883cefSAlexander Motin cp->index = 0; 6120c883cefSAlexander Motin sc->sc_ndisks++; 6130c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 6140c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s added to %s\n", 6150c883cefSAlexander Motin pp->name, sc->sc_name); 6160c883cefSAlexander Motin if (sc->sc_active == NULL) { 6170c883cefSAlexander Motin sc->sc_active = cp; 61863297dfdSAlexander Motin if (sc->sc_active_active != 1) 6190c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 620e770bc6bSMatt Jacob pp->name, sc->sc_name); 621e770bc6bSMatt Jacob } 622e770bc6bSMatt Jacob return (0); 623e770bc6bSMatt Jacob } 624e770bc6bSMatt Jacob 625e770bc6bSMatt Jacob static int 626e770bc6bSMatt Jacob g_multipath_destroy(struct g_geom *gp) 627e770bc6bSMatt Jacob { 6280c883cefSAlexander Motin struct g_multipath_softc *sc; 6290c883cefSAlexander Motin struct g_consumer *cp, *cp1; 630e770bc6bSMatt Jacob 631e770bc6bSMatt Jacob g_topology_assert(); 63212f35a61SPawel Jakub Dawidek if (gp->softc == NULL) 633e770bc6bSMatt Jacob return (ENXIO); 6340c883cefSAlexander Motin sc = gp->softc; 6350c883cefSAlexander Motin if (!sc->sc_stopping) { 636e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: destroying %s\n", gp->name); 6370c883cefSAlexander Motin sc->sc_stopping = 1; 6380c883cefSAlexander Motin } 6390c883cefSAlexander Motin if (sc->sc_opened != 0) { 6400c883cefSAlexander Motin g_wither_provider(sc->sc_pp, ENXIO); 6410c883cefSAlexander Motin sc->sc_pp = NULL; 6420c883cefSAlexander Motin return (EINPROGRESS); 6430c883cefSAlexander Motin } 6440c883cefSAlexander Motin LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 6450c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 6460c883cefSAlexander Motin if ((cp->index & MP_POSTED) == 0) { 6470c883cefSAlexander Motin cp->index |= MP_POSTED; 6480c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 6490c883cefSAlexander Motin g_mpd(cp, 0); 6500c883cefSAlexander Motin if (cp1 == NULL) 6510c883cefSAlexander Motin return(0); /* Recursion happened. */ 6520c883cefSAlexander Motin } else 6530c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 6540c883cefSAlexander Motin } 6550c883cefSAlexander Motin if (!LIST_EMPTY(&gp->consumer)) 6560c883cefSAlexander Motin return (EINPROGRESS); 6570c883cefSAlexander Motin mtx_destroy(&sc->sc_mtx); 658e770bc6bSMatt Jacob g_free(gp->softc); 659e770bc6bSMatt Jacob gp->softc = NULL; 6600c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s destroyed\n", gp->name); 661e770bc6bSMatt Jacob g_wither_geom(gp, ENXIO); 662e770bc6bSMatt Jacob return (0); 663e770bc6bSMatt Jacob } 664e770bc6bSMatt Jacob 665e770bc6bSMatt Jacob static int 666e770bc6bSMatt Jacob g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp, 667e770bc6bSMatt Jacob struct g_geom *gp) 668e770bc6bSMatt Jacob { 66912f35a61SPawel Jakub Dawidek 670e770bc6bSMatt Jacob return (g_multipath_destroy(gp)); 671e770bc6bSMatt Jacob } 672e770bc6bSMatt Jacob 673b5dce617SMatt Jacob static int 674b5dce617SMatt Jacob g_multipath_rotate(struct g_geom *gp) 675b5dce617SMatt Jacob { 6768fb378d6SThomas Quinot struct g_consumer *lcp, *first_good_cp = NULL; 677b5dce617SMatt Jacob struct g_multipath_softc *sc = gp->softc; 6788fb378d6SThomas Quinot int active_cp_seen = 0; 679b5dce617SMatt Jacob 680b5dce617SMatt Jacob g_topology_assert(); 681b5dce617SMatt Jacob if (sc == NULL) 682b5dce617SMatt Jacob return (ENXIO); 683b5dce617SMatt Jacob LIST_FOREACH(lcp, &gp->consumer, consumer) { 684b5dce617SMatt Jacob if ((lcp->index & MP_BAD) == 0) { 6858fb378d6SThomas Quinot if (first_good_cp == NULL) 6868fb378d6SThomas Quinot first_good_cp = lcp; 6878fb378d6SThomas Quinot if (active_cp_seen) 688b5dce617SMatt Jacob break; 689b5dce617SMatt Jacob } 6908fb378d6SThomas Quinot if (sc->sc_active == lcp) 6918fb378d6SThomas Quinot active_cp_seen = 1; 692b5dce617SMatt Jacob } 6938fb378d6SThomas Quinot if (lcp == NULL) 6948fb378d6SThomas Quinot lcp = first_good_cp; 6958fb378d6SThomas Quinot if (lcp && lcp != sc->sc_active) { 6960c883cefSAlexander Motin sc->sc_active = lcp; 69763297dfdSAlexander Motin if (sc->sc_active_active != 1) 6980c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 699b5dce617SMatt Jacob lcp->provider->name, sc->sc_name); 700b5dce617SMatt Jacob } 701b5dce617SMatt Jacob return (0); 702b5dce617SMatt Jacob } 703b5dce617SMatt Jacob 704e770bc6bSMatt Jacob static void 705e770bc6bSMatt Jacob g_multipath_init(struct g_class *mp) 706e770bc6bSMatt Jacob { 707e770bc6bSMatt Jacob bioq_init(&gmtbq); 708e770bc6bSMatt Jacob mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF); 70963297dfdSAlexander Motin kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt"); 710e770bc6bSMatt Jacob } 711e770bc6bSMatt Jacob 712e770bc6bSMatt Jacob static void 713e770bc6bSMatt Jacob g_multipath_fini(struct g_class *mp) 714e770bc6bSMatt Jacob { 715e770bc6bSMatt Jacob if (g_multipath_kt_state == GKT_RUN) { 716e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 717e770bc6bSMatt Jacob g_multipath_kt_state = GKT_DIE; 718e770bc6bSMatt Jacob wakeup(&g_multipath_kt_state); 719e770bc6bSMatt Jacob msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO, 720e770bc6bSMatt Jacob "gmp:fini", 0); 721e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 722e770bc6bSMatt Jacob } 723e770bc6bSMatt Jacob } 724e770bc6bSMatt Jacob 725e770bc6bSMatt Jacob static int 726e770bc6bSMatt Jacob g_multipath_read_metadata(struct g_consumer *cp, 727e770bc6bSMatt Jacob struct g_multipath_metadata *md) 728e770bc6bSMatt Jacob { 729e770bc6bSMatt Jacob struct g_provider *pp; 730e770bc6bSMatt Jacob u_char *buf; 731e770bc6bSMatt Jacob int error; 732e770bc6bSMatt Jacob 733e770bc6bSMatt Jacob g_topology_assert(); 734e770bc6bSMatt Jacob error = g_access(cp, 1, 0, 0); 73512f35a61SPawel Jakub Dawidek if (error != 0) 736e770bc6bSMatt Jacob return (error); 737e770bc6bSMatt Jacob pp = cp->provider; 738e770bc6bSMatt Jacob g_topology_unlock(); 739e770bc6bSMatt Jacob buf = g_read_data(cp, pp->mediasize - pp->sectorsize, 740e770bc6bSMatt Jacob pp->sectorsize, &error); 741e770bc6bSMatt Jacob g_topology_lock(); 742e770bc6bSMatt Jacob g_access(cp, -1, 0, 0); 74312f35a61SPawel Jakub Dawidek if (buf == NULL) 744e770bc6bSMatt Jacob return (error); 745e770bc6bSMatt Jacob multipath_metadata_decode(buf, md); 746e770bc6bSMatt Jacob g_free(buf); 747e770bc6bSMatt Jacob return (0); 748e770bc6bSMatt Jacob } 749e770bc6bSMatt Jacob 750f8c79813SAlexander Motin static int 751f8c79813SAlexander Motin g_multipath_write_metadata(struct g_consumer *cp, 752f8c79813SAlexander Motin struct g_multipath_metadata *md) 753f8c79813SAlexander Motin { 754f8c79813SAlexander Motin struct g_provider *pp; 755f8c79813SAlexander Motin u_char *buf; 756f8c79813SAlexander Motin int error; 757f8c79813SAlexander Motin 758f8c79813SAlexander Motin g_topology_assert(); 759f8c79813SAlexander Motin error = g_access(cp, 1, 1, 1); 760f8c79813SAlexander Motin if (error != 0) 761f8c79813SAlexander Motin return (error); 762f8c79813SAlexander Motin pp = cp->provider; 763f8c79813SAlexander Motin g_topology_unlock(); 764f8c79813SAlexander Motin buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 765f8c79813SAlexander Motin multipath_metadata_encode(md, buf); 766f8c79813SAlexander Motin error = g_write_data(cp, pp->mediasize - pp->sectorsize, 767f8c79813SAlexander Motin buf, pp->sectorsize); 768f8c79813SAlexander Motin g_topology_lock(); 769f8c79813SAlexander Motin g_access(cp, -1, -1, -1); 770f8c79813SAlexander Motin g_free(buf); 771f8c79813SAlexander Motin return (error); 772f8c79813SAlexander Motin } 773f8c79813SAlexander Motin 774e770bc6bSMatt Jacob static struct g_geom * 775e770bc6bSMatt Jacob g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 776e770bc6bSMatt Jacob { 777e770bc6bSMatt Jacob struct g_multipath_metadata md; 778e770bc6bSMatt Jacob struct g_multipath_softc *sc; 779e770bc6bSMatt Jacob struct g_consumer *cp; 780e770bc6bSMatt Jacob struct g_geom *gp, *gp1; 781e770bc6bSMatt Jacob int error, isnew; 782e770bc6bSMatt Jacob 783e770bc6bSMatt Jacob g_topology_assert(); 784e770bc6bSMatt Jacob 785e770bc6bSMatt Jacob gp = g_new_geomf(mp, "multipath:taste"); 786e770bc6bSMatt Jacob gp->start = g_multipath_start; 787e770bc6bSMatt Jacob gp->access = g_multipath_access; 788e770bc6bSMatt Jacob gp->orphan = g_multipath_orphan; 789e770bc6bSMatt Jacob cp = g_new_consumer(gp); 790e770bc6bSMatt Jacob g_attach(cp, pp); 791e770bc6bSMatt Jacob error = g_multipath_read_metadata(cp, &md); 792e770bc6bSMatt Jacob g_detach(cp); 793e770bc6bSMatt Jacob g_destroy_consumer(cp); 794e770bc6bSMatt Jacob g_destroy_geom(gp); 79512f35a61SPawel Jakub Dawidek if (error != 0) 796e770bc6bSMatt Jacob return (NULL); 797e770bc6bSMatt Jacob gp = NULL; 798e770bc6bSMatt Jacob 799e770bc6bSMatt Jacob if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) { 80012f35a61SPawel Jakub Dawidek if (g_multipath_debug) 801e770bc6bSMatt Jacob printf("%s is not MULTIPATH\n", pp->name); 802e770bc6bSMatt Jacob return (NULL); 803e770bc6bSMatt Jacob } 804e770bc6bSMatt Jacob if (md.md_version != G_MULTIPATH_VERSION) { 805e770bc6bSMatt Jacob printf("%s has version %d multipath id- this module is version " 806e770bc6bSMatt Jacob " %d: rejecting\n", pp->name, md.md_version, 807e770bc6bSMatt Jacob G_MULTIPATH_VERSION); 808e770bc6bSMatt Jacob return (NULL); 809e770bc6bSMatt Jacob } 8100c883cefSAlexander Motin if (md.md_size != 0 && md.md_size != pp->mediasize) 8110c883cefSAlexander Motin return (NULL); 8120c883cefSAlexander Motin if (md.md_sectorsize != 0 && md.md_sectorsize != pp->sectorsize) 8130c883cefSAlexander Motin return (NULL); 81412f35a61SPawel Jakub Dawidek if (g_multipath_debug) 815e770bc6bSMatt Jacob printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid); 816e770bc6bSMatt Jacob 817e770bc6bSMatt Jacob /* 818e770bc6bSMatt Jacob * Let's check if such a device already is present. We check against 819e770bc6bSMatt Jacob * uuid alone first because that's the true distinguishor. If that 820e770bc6bSMatt Jacob * passes, then we check for name conflicts. If there are conflicts, 821e770bc6bSMatt Jacob * modify the name. 822e770bc6bSMatt Jacob * 823e770bc6bSMatt Jacob * The whole purpose of this is to solve the problem that people don't 824e770bc6bSMatt Jacob * pick good unique names, but good unique names (like uuids) are a 825e770bc6bSMatt Jacob * pain to use. So, we allow people to build GEOMs with friendly names 826e770bc6bSMatt Jacob * and uuids, and modify the names in case there's a collision. 827e770bc6bSMatt Jacob */ 828e770bc6bSMatt Jacob sc = NULL; 829e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 830e770bc6bSMatt Jacob sc = gp->softc; 8310c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 832e770bc6bSMatt Jacob continue; 83312f35a61SPawel Jakub Dawidek if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0) 834e770bc6bSMatt Jacob break; 835e770bc6bSMatt Jacob } 836e770bc6bSMatt Jacob 837e770bc6bSMatt Jacob LIST_FOREACH(gp1, &mp->geom, geom) { 83812f35a61SPawel Jakub Dawidek if (gp1 == gp) 839e770bc6bSMatt Jacob continue; 840e770bc6bSMatt Jacob sc = gp1->softc; 8410c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 842e770bc6bSMatt Jacob continue; 84312f35a61SPawel Jakub Dawidek if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0) 844e770bc6bSMatt Jacob break; 845e770bc6bSMatt Jacob } 846e770bc6bSMatt Jacob 847e770bc6bSMatt Jacob /* 848e770bc6bSMatt Jacob * If gp is NULL, we had no extant MULTIPATH geom with this uuid. 849e770bc6bSMatt Jacob * 850e770bc6bSMatt Jacob * If gp1 is *not* NULL, that means we have a MULTIPATH geom extant 851e770bc6bSMatt Jacob * with the same name (but a different UUID). 852e770bc6bSMatt Jacob * 853e770bc6bSMatt Jacob * If gp is NULL, then modify the name with a random number and 854e770bc6bSMatt Jacob * complain, but allow the creation of the geom to continue. 855e770bc6bSMatt Jacob * 856e770bc6bSMatt Jacob * If gp is *not* NULL, just use the geom's name as we're attaching 857e770bc6bSMatt Jacob * this disk to the (previously generated) name. 858e770bc6bSMatt Jacob */ 859e770bc6bSMatt Jacob 860e770bc6bSMatt Jacob if (gp1) { 861e770bc6bSMatt Jacob sc = gp1->softc; 862e770bc6bSMatt Jacob if (gp == NULL) { 863e770bc6bSMatt Jacob char buf[16]; 864e770bc6bSMatt Jacob u_long rand = random(); 865e770bc6bSMatt Jacob 866e770bc6bSMatt Jacob snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand); 867e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: geom %s/%s exists already\n", 868e770bc6bSMatt Jacob sc->sc_name, sc->sc_uuid); 869e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n", 870e770bc6bSMatt Jacob md.md_uuid, buf); 871e770bc6bSMatt Jacob strlcpy(md.md_name, buf, sizeof(md.md_name)); 872e770bc6bSMatt Jacob } else { 873e770bc6bSMatt Jacob strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name)); 874e770bc6bSMatt Jacob } 875e770bc6bSMatt Jacob } 876e770bc6bSMatt Jacob 877e770bc6bSMatt Jacob if (gp == NULL) { 878e770bc6bSMatt Jacob gp = g_multipath_create(mp, &md); 879e770bc6bSMatt Jacob if (gp == NULL) { 880e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot create geom %s/%s\n", 881e770bc6bSMatt Jacob md.md_name, md.md_uuid); 882e770bc6bSMatt Jacob return (NULL); 883e770bc6bSMatt Jacob } 884e770bc6bSMatt Jacob isnew = 1; 885e770bc6bSMatt Jacob } else { 886e770bc6bSMatt Jacob isnew = 0; 887e770bc6bSMatt Jacob } 888e770bc6bSMatt Jacob 889e770bc6bSMatt Jacob sc = gp->softc; 890e770bc6bSMatt Jacob KASSERT(sc != NULL, ("sc is NULL")); 891e770bc6bSMatt Jacob error = g_multipath_add_disk(gp, pp); 892e770bc6bSMatt Jacob if (error != 0) { 89312f35a61SPawel Jakub Dawidek if (isnew) 894e770bc6bSMatt Jacob g_multipath_destroy(gp); 895e770bc6bSMatt Jacob return (NULL); 896e770bc6bSMatt Jacob } 897e770bc6bSMatt Jacob return (gp); 898e770bc6bSMatt Jacob } 899e770bc6bSMatt Jacob 900e770bc6bSMatt Jacob static void 9010c883cefSAlexander Motin g_multipath_ctl_add_name(struct gctl_req *req, struct g_class *mp, 9020c883cefSAlexander Motin const char *name) 903e770bc6bSMatt Jacob { 9040c883cefSAlexander Motin struct g_multipath_softc *sc; 905e770bc6bSMatt Jacob struct g_geom *gp; 9062b4969ffSMatt Jacob struct g_consumer *cp; 9070c883cefSAlexander Motin struct g_provider *pp; 9080c883cefSAlexander Motin const char *mpname; 909e770bc6bSMatt Jacob static const char devpf[6] = "/dev/"; 910e770bc6bSMatt Jacob 911e770bc6bSMatt Jacob g_topology_assert(); 912e770bc6bSMatt Jacob 913e770bc6bSMatt Jacob mpname = gctl_get_asciiparam(req, "arg0"); 914e770bc6bSMatt Jacob if (mpname == NULL) { 915e770bc6bSMatt Jacob gctl_error(req, "No 'arg0' argument"); 916e770bc6bSMatt Jacob return; 917e770bc6bSMatt Jacob } 9182b4969ffSMatt Jacob gp = g_multipath_find_geom(mp, mpname); 9192b4969ffSMatt Jacob if (gp == NULL) { 9202b4969ffSMatt Jacob gctl_error(req, "Device %s is invalid", mpname); 921e770bc6bSMatt Jacob return; 922e770bc6bSMatt Jacob } 9230c883cefSAlexander Motin sc = gp->softc; 924e770bc6bSMatt Jacob 92512f35a61SPawel Jakub Dawidek if (strncmp(name, devpf, 5) == 0) 926e770bc6bSMatt Jacob name += 5; 9272b4969ffSMatt Jacob pp = g_provider_by_name(name); 9282b4969ffSMatt Jacob if (pp == NULL) { 929e770bc6bSMatt Jacob gctl_error(req, "Provider %s is invalid", name); 930e770bc6bSMatt Jacob return; 931e770bc6bSMatt Jacob } 932e770bc6bSMatt Jacob 933e770bc6bSMatt Jacob /* 9340c883cefSAlexander Motin * Check to make sure parameters match. 935e770bc6bSMatt Jacob */ 9360c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 9370c883cefSAlexander Motin if (cp->provider == pp) { 9380c883cefSAlexander Motin gctl_error(req, "provider %s is already there", 9390c883cefSAlexander Motin pp->name); 940e770bc6bSMatt Jacob return; 941e770bc6bSMatt Jacob } 9420c883cefSAlexander Motin } 943e6afd72bSAlexander Motin if (sc->sc_pp->mediasize != 0 && 9440c883cefSAlexander Motin sc->sc_pp->mediasize + (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0) 9450c883cefSAlexander Motin != pp->mediasize) { 9460c883cefSAlexander Motin gctl_error(req, "Providers size mismatch %jd != %jd", 9470c883cefSAlexander Motin (intmax_t) sc->sc_pp->mediasize + 9480c883cefSAlexander Motin (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0), 9490c883cefSAlexander Motin (intmax_t) pp->mediasize); 950e770bc6bSMatt Jacob return; 951e770bc6bSMatt Jacob } 952e6afd72bSAlexander Motin if (sc->sc_pp->sectorsize != 0 && 9530c883cefSAlexander Motin sc->sc_pp->sectorsize != pp->sectorsize) { 9540c883cefSAlexander Motin gctl_error(req, "Providers sectorsize mismatch %u != %u", 9550c883cefSAlexander Motin sc->sc_pp->sectorsize, pp->sectorsize); 956e770bc6bSMatt Jacob return; 957e770bc6bSMatt Jacob } 958e770bc6bSMatt Jacob 959e770bc6bSMatt Jacob /* 9602b4969ffSMatt Jacob * Now add.... 961e770bc6bSMatt Jacob */ 9622b4969ffSMatt Jacob (void) g_multipath_add_disk(gp, pp); 963e770bc6bSMatt Jacob } 964e770bc6bSMatt Jacob 9650c883cefSAlexander Motin static void 96671ee4ef0SThomas Quinot g_multipath_ctl_prefer(struct gctl_req *req, struct g_class *mp) 96771ee4ef0SThomas Quinot { 96871ee4ef0SThomas Quinot struct g_geom *gp; 96971ee4ef0SThomas Quinot struct g_multipath_softc *sc; 97071ee4ef0SThomas Quinot struct g_consumer *cp; 97171ee4ef0SThomas Quinot const char *name, *mpname; 97271ee4ef0SThomas Quinot static const char devpf[6] = "/dev/"; 97371ee4ef0SThomas Quinot int *nargs; 97471ee4ef0SThomas Quinot 97571ee4ef0SThomas Quinot g_topology_assert(); 97671ee4ef0SThomas Quinot 97771ee4ef0SThomas Quinot mpname = gctl_get_asciiparam(req, "arg0"); 97871ee4ef0SThomas Quinot if (mpname == NULL) { 97971ee4ef0SThomas Quinot gctl_error(req, "No 'arg0' argument"); 98071ee4ef0SThomas Quinot return; 98171ee4ef0SThomas Quinot } 98271ee4ef0SThomas Quinot gp = g_multipath_find_geom(mp, mpname); 98371ee4ef0SThomas Quinot if (gp == NULL) { 98471ee4ef0SThomas Quinot gctl_error(req, "Device %s is invalid", mpname); 98571ee4ef0SThomas Quinot return; 98671ee4ef0SThomas Quinot } 98771ee4ef0SThomas Quinot sc = gp->softc; 98871ee4ef0SThomas Quinot 98971ee4ef0SThomas Quinot nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 99071ee4ef0SThomas Quinot if (nargs == NULL) { 99171ee4ef0SThomas Quinot gctl_error(req, "No 'nargs' argument"); 99271ee4ef0SThomas Quinot return; 99371ee4ef0SThomas Quinot } 99471ee4ef0SThomas Quinot if (*nargs != 2) { 99571ee4ef0SThomas Quinot gctl_error(req, "missing device"); 99671ee4ef0SThomas Quinot return; 99771ee4ef0SThomas Quinot } 99871ee4ef0SThomas Quinot 99971ee4ef0SThomas Quinot name = gctl_get_asciiparam(req, "arg1"); 100071ee4ef0SThomas Quinot if (name == NULL) { 100171ee4ef0SThomas Quinot gctl_error(req, "No 'arg1' argument"); 100271ee4ef0SThomas Quinot return; 100371ee4ef0SThomas Quinot } 100471ee4ef0SThomas Quinot if (strncmp(name, devpf, 5) == 0) { 100571ee4ef0SThomas Quinot name += 5; 100671ee4ef0SThomas Quinot } 100771ee4ef0SThomas Quinot 100871ee4ef0SThomas Quinot LIST_FOREACH(cp, &gp->consumer, consumer) { 100971ee4ef0SThomas Quinot if (cp->provider != NULL 101071ee4ef0SThomas Quinot && strcmp(cp->provider->name, name) == 0) 101171ee4ef0SThomas Quinot break; 101271ee4ef0SThomas Quinot } 101371ee4ef0SThomas Quinot 101471ee4ef0SThomas Quinot if (cp == NULL) { 101571ee4ef0SThomas Quinot gctl_error(req, "Provider %s not found", name); 101671ee4ef0SThomas Quinot return; 101771ee4ef0SThomas Quinot } 101871ee4ef0SThomas Quinot 101971ee4ef0SThomas Quinot mtx_lock(&sc->sc_mtx); 102071ee4ef0SThomas Quinot 102171ee4ef0SThomas Quinot if (cp->index & MP_BAD) { 102271ee4ef0SThomas Quinot gctl_error(req, "Consumer %s is invalid", name); 102371ee4ef0SThomas Quinot mtx_unlock(&sc->sc_mtx); 102471ee4ef0SThomas Quinot return; 102571ee4ef0SThomas Quinot } 102671ee4ef0SThomas Quinot 102771ee4ef0SThomas Quinot /* Here when the consumer is present and in good shape */ 102871ee4ef0SThomas Quinot 102971ee4ef0SThomas Quinot sc->sc_active = cp; 103071ee4ef0SThomas Quinot if (!sc->sc_active_active) 103171ee4ef0SThomas Quinot printf("GEOM_MULTIPATH: %s now active path in %s\n", 103271ee4ef0SThomas Quinot sc->sc_active->provider->name, sc->sc_name); 103371ee4ef0SThomas Quinot 103471ee4ef0SThomas Quinot mtx_unlock(&sc->sc_mtx); 103571ee4ef0SThomas Quinot } 103671ee4ef0SThomas Quinot 103771ee4ef0SThomas Quinot static void 10380c883cefSAlexander Motin g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp) 10390c883cefSAlexander Motin { 10400c883cefSAlexander Motin struct g_multipath_softc *sc; 10410c883cefSAlexander Motin struct g_geom *gp; 10420c883cefSAlexander Motin const char *mpname, *name; 10430c883cefSAlexander Motin 10440c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 10450c883cefSAlexander Motin if (mpname == NULL) { 10460c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 10470c883cefSAlexander Motin return; 10480c883cefSAlexander Motin } 10490c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 10500c883cefSAlexander Motin if (gp == NULL) { 10510c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 10520c883cefSAlexander Motin return; 10530c883cefSAlexander Motin } 10540c883cefSAlexander Motin sc = gp->softc; 10550c883cefSAlexander Motin 10560c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 10570c883cefSAlexander Motin if (name == NULL) { 10580c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 10590c883cefSAlexander Motin return; 10600c883cefSAlexander Motin } 10610c883cefSAlexander Motin g_multipath_ctl_add_name(req, mp, name); 10620c883cefSAlexander Motin } 10630c883cefSAlexander Motin 10640c883cefSAlexander Motin static void 10650c883cefSAlexander Motin g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp) 10660c883cefSAlexander Motin { 10670c883cefSAlexander Motin struct g_multipath_metadata md; 10680c883cefSAlexander Motin struct g_multipath_softc *sc; 10690c883cefSAlexander Motin struct g_geom *gp; 10700c883cefSAlexander Motin const char *mpname, *name; 10710c883cefSAlexander Motin char param[16]; 107263297dfdSAlexander Motin int *nargs, i, *val; 10730c883cefSAlexander Motin 10740c883cefSAlexander Motin g_topology_assert(); 10750c883cefSAlexander Motin 10760c883cefSAlexander Motin nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 10770c883cefSAlexander Motin if (*nargs < 2) { 10780c883cefSAlexander Motin gctl_error(req, "wrong number of arguments."); 10790c883cefSAlexander Motin return; 10800c883cefSAlexander Motin } 10810c883cefSAlexander Motin 10820c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 10830c883cefSAlexander Motin if (mpname == NULL) { 10840c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 10850c883cefSAlexander Motin return; 10860c883cefSAlexander Motin } 10870c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 10880c883cefSAlexander Motin if (gp != NULL) { 10890c883cefSAlexander Motin gctl_error(req, "Device %s already exist", mpname); 10900c883cefSAlexander Motin return; 10910c883cefSAlexander Motin } 10920c883cefSAlexander Motin 10930c883cefSAlexander Motin memset(&md, 0, sizeof(md)); 10940c883cefSAlexander Motin strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 10950c883cefSAlexander Motin md.md_version = G_MULTIPATH_VERSION; 10960c883cefSAlexander Motin strlcpy(md.md_name, mpname, sizeof(md.md_name)); 10970c883cefSAlexander Motin md.md_size = 0; 10980c883cefSAlexander Motin md.md_sectorsize = 0; 10990c883cefSAlexander Motin md.md_uuid[0] = 0; 110063297dfdSAlexander Motin md.md_active_active = 0; 110163297dfdSAlexander Motin val = gctl_get_paraml(req, "active_active", sizeof(*val)); 110263297dfdSAlexander Motin if (val != NULL && *val != 0) 110363297dfdSAlexander Motin md.md_active_active = 1; 110463297dfdSAlexander Motin val = gctl_get_paraml(req, "active_read", sizeof(*val)); 110563297dfdSAlexander Motin if (val != NULL && *val != 0) 110663297dfdSAlexander Motin md.md_active_active = 2; 11070c883cefSAlexander Motin gp = g_multipath_create(mp, &md); 11080c883cefSAlexander Motin if (gp == NULL) { 11090c883cefSAlexander Motin gctl_error(req, "GEOM_MULTIPATH: cannot create geom %s/%s\n", 11100c883cefSAlexander Motin md.md_name, md.md_uuid); 11110c883cefSAlexander Motin return; 11120c883cefSAlexander Motin } 11130c883cefSAlexander Motin sc = gp->softc; 11140c883cefSAlexander Motin 11150c883cefSAlexander Motin for (i = 1; i < *nargs; i++) { 11160c883cefSAlexander Motin snprintf(param, sizeof(param), "arg%d", i); 11170c883cefSAlexander Motin name = gctl_get_asciiparam(req, param); 11180c883cefSAlexander Motin g_multipath_ctl_add_name(req, mp, name); 11190c883cefSAlexander Motin } 11200c883cefSAlexander Motin 11210c883cefSAlexander Motin if (sc->sc_ndisks != (*nargs - 1)) 11220c883cefSAlexander Motin g_multipath_destroy(gp); 11230c883cefSAlexander Motin } 11240c883cefSAlexander Motin 11250c883cefSAlexander Motin static void 112663297dfdSAlexander Motin g_multipath_ctl_configure(struct gctl_req *req, struct g_class *mp) 112763297dfdSAlexander Motin { 112863297dfdSAlexander Motin struct g_multipath_softc *sc; 112963297dfdSAlexander Motin struct g_geom *gp; 113063297dfdSAlexander Motin struct g_consumer *cp; 113163297dfdSAlexander Motin struct g_provider *pp; 1132c0b1ef66SAlexander Motin struct g_multipath_metadata md; 113363297dfdSAlexander Motin const char *name; 113463297dfdSAlexander Motin int error, *val; 113563297dfdSAlexander Motin 113663297dfdSAlexander Motin g_topology_assert(); 113763297dfdSAlexander Motin 113863297dfdSAlexander Motin name = gctl_get_asciiparam(req, "arg0"); 113963297dfdSAlexander Motin if (name == NULL) { 114063297dfdSAlexander Motin gctl_error(req, "No 'arg0' argument"); 114163297dfdSAlexander Motin return; 114263297dfdSAlexander Motin } 114363297dfdSAlexander Motin gp = g_multipath_find_geom(mp, name); 114463297dfdSAlexander Motin if (gp == NULL) { 114563297dfdSAlexander Motin gctl_error(req, "Device %s is invalid", name); 114663297dfdSAlexander Motin return; 114763297dfdSAlexander Motin } 114863297dfdSAlexander Motin sc = gp->softc; 114963297dfdSAlexander Motin val = gctl_get_paraml(req, "active_active", sizeof(*val)); 115063297dfdSAlexander Motin if (val != NULL && *val != 0) 115163297dfdSAlexander Motin sc->sc_active_active = 1; 115263297dfdSAlexander Motin val = gctl_get_paraml(req, "active_read", sizeof(*val)); 115363297dfdSAlexander Motin if (val != NULL && *val != 0) 115463297dfdSAlexander Motin sc->sc_active_active = 2; 115563297dfdSAlexander Motin val = gctl_get_paraml(req, "active_passive", sizeof(*val)); 115663297dfdSAlexander Motin if (val != NULL && *val != 0) 115763297dfdSAlexander Motin sc->sc_active_active = 0; 115863297dfdSAlexander Motin if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) { 115963297dfdSAlexander Motin cp = sc->sc_active; 116063297dfdSAlexander Motin pp = cp->provider; 1161c0b1ef66SAlexander Motin strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 1162c0b1ef66SAlexander Motin memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid)); 1163c0b1ef66SAlexander Motin strlcpy(md.md_name, name, sizeof(md.md_name)); 1164c0b1ef66SAlexander Motin md.md_version = G_MULTIPATH_VERSION; 1165c0b1ef66SAlexander Motin md.md_size = pp->mediasize; 1166c0b1ef66SAlexander Motin md.md_sectorsize = pp->sectorsize; 1167c0b1ef66SAlexander Motin md.md_active_active = sc->sc_active_active; 1168f8c79813SAlexander Motin error = g_multipath_write_metadata(cp, &md); 116963297dfdSAlexander Motin if (error != 0) 117063297dfdSAlexander Motin gctl_error(req, "Can't update metadata on %s (%d)", 117163297dfdSAlexander Motin pp->name, error); 117263297dfdSAlexander Motin } 117363297dfdSAlexander Motin } 117463297dfdSAlexander Motin 117563297dfdSAlexander Motin static void 11760c883cefSAlexander Motin g_multipath_ctl_fail(struct gctl_req *req, struct g_class *mp, int fail) 11770c883cefSAlexander Motin { 11780c883cefSAlexander Motin struct g_multipath_softc *sc; 11790c883cefSAlexander Motin struct g_geom *gp; 11800c883cefSAlexander Motin struct g_consumer *cp; 11810c883cefSAlexander Motin const char *mpname, *name; 11820c883cefSAlexander Motin int found; 11830c883cefSAlexander Motin 11840c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 11850c883cefSAlexander Motin if (mpname == NULL) { 11860c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 11870c883cefSAlexander Motin return; 11880c883cefSAlexander Motin } 11890c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 11900c883cefSAlexander Motin if (gp == NULL) { 11910c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 11920c883cefSAlexander Motin return; 11930c883cefSAlexander Motin } 11940c883cefSAlexander Motin sc = gp->softc; 11950c883cefSAlexander Motin 11960c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 11970c883cefSAlexander Motin if (name == NULL) { 11980c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 11990c883cefSAlexander Motin return; 12000c883cefSAlexander Motin } 12010c883cefSAlexander Motin 12020c883cefSAlexander Motin found = 0; 12030c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 12040c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 12050c883cefSAlexander Motin if (cp->provider != NULL && 12060c883cefSAlexander Motin strcmp(cp->provider->name, name) == 0 && 12070c883cefSAlexander Motin (cp->index & MP_LOST) == 0) { 12080c883cefSAlexander Motin found = 1; 120963297dfdSAlexander Motin if (!fail == !(cp->index & MP_FAIL)) 121063297dfdSAlexander Motin continue; 12110c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s in %s is marked %s.\n", 12120c883cefSAlexander Motin name, sc->sc_name, fail ? "FAIL" : "OK"); 12130c883cefSAlexander Motin if (fail) { 12140c883cefSAlexander Motin g_multipath_fault(cp, MP_FAIL); 12150c883cefSAlexander Motin } else { 12160c883cefSAlexander Motin cp->index &= ~MP_FAIL; 12170c883cefSAlexander Motin } 12180c883cefSAlexander Motin } 12190c883cefSAlexander Motin } 12200c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 12210c883cefSAlexander Motin if (found == 0) 12220c883cefSAlexander Motin gctl_error(req, "Provider %s not found", name); 12230c883cefSAlexander Motin } 12240c883cefSAlexander Motin 12250c883cefSAlexander Motin static void 12260c883cefSAlexander Motin g_multipath_ctl_remove(struct gctl_req *req, struct g_class *mp) 12270c883cefSAlexander Motin { 12280c883cefSAlexander Motin struct g_multipath_softc *sc; 12290c883cefSAlexander Motin struct g_geom *gp; 12300c883cefSAlexander Motin struct g_consumer *cp, *cp1; 12310c883cefSAlexander Motin const char *mpname, *name; 12320c883cefSAlexander Motin uintptr_t *cnt; 12330c883cefSAlexander Motin int found; 12340c883cefSAlexander Motin 12350c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 12360c883cefSAlexander Motin if (mpname == NULL) { 12370c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 12380c883cefSAlexander Motin return; 12390c883cefSAlexander Motin } 12400c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 12410c883cefSAlexander Motin if (gp == NULL) { 12420c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 12430c883cefSAlexander Motin return; 12440c883cefSAlexander Motin } 12450c883cefSAlexander Motin sc = gp->softc; 12460c883cefSAlexander Motin 12470c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 12480c883cefSAlexander Motin if (name == NULL) { 12490c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 12500c883cefSAlexander Motin return; 12510c883cefSAlexander Motin } 12520c883cefSAlexander Motin 12530c883cefSAlexander Motin found = 0; 12540c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 12550c883cefSAlexander Motin LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 12560c883cefSAlexander Motin if (cp->provider != NULL && 12570c883cefSAlexander Motin strcmp(cp->provider->name, name) == 0 && 12580c883cefSAlexander Motin (cp->index & MP_LOST) == 0) { 12590c883cefSAlexander Motin found = 1; 12600c883cefSAlexander Motin printf("GEOM_MULTIPATH: removing %s from %s\n", 12610c883cefSAlexander Motin cp->provider->name, cp->geom->name); 12620c883cefSAlexander Motin sc->sc_ndisks--; 12630c883cefSAlexander Motin g_multipath_fault(cp, MP_LOST); 12640c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 12650c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_POSTED) == 0) { 12660c883cefSAlexander Motin cp->index |= MP_POSTED; 12670c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 12680c883cefSAlexander Motin g_mpd(cp, 0); 12690c883cefSAlexander Motin if (cp1 == NULL) 12700c883cefSAlexander Motin return; /* Recursion happened. */ 12710c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 12720c883cefSAlexander Motin } 12730c883cefSAlexander Motin } 12740c883cefSAlexander Motin } 12750c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 12760c883cefSAlexander Motin if (found == 0) 12770c883cefSAlexander Motin gctl_error(req, "Provider %s not found", name); 12780c883cefSAlexander Motin } 12790c883cefSAlexander Motin 1280e770bc6bSMatt Jacob static struct g_geom * 1281e770bc6bSMatt Jacob g_multipath_find_geom(struct g_class *mp, const char *name) 1282e770bc6bSMatt Jacob { 1283e770bc6bSMatt Jacob struct g_geom *gp; 12840c883cefSAlexander Motin struct g_multipath_softc *sc; 1285e770bc6bSMatt Jacob 1286e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 12870c883cefSAlexander Motin sc = gp->softc; 12880c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 12890c883cefSAlexander Motin continue; 12900c883cefSAlexander Motin if (strcmp(gp->name, name) == 0) 1291e770bc6bSMatt Jacob return (gp); 1292e770bc6bSMatt Jacob } 1293e770bc6bSMatt Jacob return (NULL); 1294e770bc6bSMatt Jacob } 1295e770bc6bSMatt Jacob 1296e770bc6bSMatt Jacob static void 12970c883cefSAlexander Motin g_multipath_ctl_stop(struct gctl_req *req, struct g_class *mp) 1298e770bc6bSMatt Jacob { 1299e770bc6bSMatt Jacob struct g_geom *gp; 1300e770bc6bSMatt Jacob const char *name; 1301e770bc6bSMatt Jacob int error; 1302e770bc6bSMatt Jacob 1303e770bc6bSMatt Jacob g_topology_assert(); 1304e770bc6bSMatt Jacob 1305e770bc6bSMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1306e770bc6bSMatt Jacob if (name == NULL) { 1307e770bc6bSMatt Jacob gctl_error(req, "No 'arg0' argument"); 1308e770bc6bSMatt Jacob return; 1309e770bc6bSMatt Jacob } 1310e770bc6bSMatt Jacob gp = g_multipath_find_geom(mp, name); 1311e770bc6bSMatt Jacob if (gp == NULL) { 1312e770bc6bSMatt Jacob gctl_error(req, "Device %s is invalid", name); 1313e770bc6bSMatt Jacob return; 1314e770bc6bSMatt Jacob } 1315e770bc6bSMatt Jacob error = g_multipath_destroy(gp); 13160c883cefSAlexander Motin if (error != 0 && error != EINPROGRESS) 13170c883cefSAlexander Motin gctl_error(req, "failed to stop %s (err=%d)", name, error); 1318e770bc6bSMatt Jacob } 13190c883cefSAlexander Motin 13200c883cefSAlexander Motin static void 13210c883cefSAlexander Motin g_multipath_ctl_destroy(struct gctl_req *req, struct g_class *mp) 13220c883cefSAlexander Motin { 13230c883cefSAlexander Motin struct g_geom *gp; 13240c883cefSAlexander Motin struct g_multipath_softc *sc; 13250c883cefSAlexander Motin struct g_consumer *cp; 13260c883cefSAlexander Motin struct g_provider *pp; 13270c883cefSAlexander Motin const char *name; 13280c883cefSAlexander Motin uint8_t *buf; 13290c883cefSAlexander Motin int error; 13300c883cefSAlexander Motin 13310c883cefSAlexander Motin g_topology_assert(); 13320c883cefSAlexander Motin 13330c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg0"); 13340c883cefSAlexander Motin if (name == NULL) { 13350c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 13360c883cefSAlexander Motin return; 13370c883cefSAlexander Motin } 13380c883cefSAlexander Motin gp = g_multipath_find_geom(mp, name); 13390c883cefSAlexander Motin if (gp == NULL) { 13400c883cefSAlexander Motin gctl_error(req, "Device %s is invalid", name); 13410c883cefSAlexander Motin return; 13420c883cefSAlexander Motin } 13430c883cefSAlexander Motin sc = gp->softc; 13440c883cefSAlexander Motin 13450c883cefSAlexander Motin if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) { 13460c883cefSAlexander Motin cp = sc->sc_active; 13470c883cefSAlexander Motin pp = cp->provider; 13480c883cefSAlexander Motin error = g_access(cp, 1, 1, 1); 13490c883cefSAlexander Motin if (error != 0) { 13500c883cefSAlexander Motin gctl_error(req, "Can't open %s (%d)", pp->name, error); 13510c883cefSAlexander Motin goto destroy; 13520c883cefSAlexander Motin } 13530c883cefSAlexander Motin g_topology_unlock(); 13540c883cefSAlexander Motin buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 13550c883cefSAlexander Motin error = g_write_data(cp, pp->mediasize - pp->sectorsize, 13560c883cefSAlexander Motin buf, pp->sectorsize); 13570c883cefSAlexander Motin g_topology_lock(); 13580c883cefSAlexander Motin g_access(cp, -1, -1, -1); 13590c883cefSAlexander Motin if (error != 0) 13600c883cefSAlexander Motin gctl_error(req, "Can't erase metadata on %s (%d)", 13610c883cefSAlexander Motin pp->name, error); 13620c883cefSAlexander Motin } 13630c883cefSAlexander Motin 13640c883cefSAlexander Motin destroy: 13650c883cefSAlexander Motin error = g_multipath_destroy(gp); 13660c883cefSAlexander Motin if (error != 0 && error != EINPROGRESS) 13670c883cefSAlexander Motin gctl_error(req, "failed to destroy %s (err=%d)", name, error); 1368e770bc6bSMatt Jacob } 1369e770bc6bSMatt Jacob 1370e770bc6bSMatt Jacob static void 1371b5dce617SMatt Jacob g_multipath_ctl_rotate(struct gctl_req *req, struct g_class *mp) 1372b5dce617SMatt Jacob { 1373b5dce617SMatt Jacob struct g_geom *gp; 1374b5dce617SMatt Jacob const char *name; 1375b5dce617SMatt Jacob int error; 1376b5dce617SMatt Jacob 1377b5dce617SMatt Jacob g_topology_assert(); 1378b5dce617SMatt Jacob 1379b5dce617SMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1380b5dce617SMatt Jacob if (name == NULL) { 1381b5dce617SMatt Jacob gctl_error(req, "No 'arg0' argument"); 1382b5dce617SMatt Jacob return; 1383b5dce617SMatt Jacob } 1384b5dce617SMatt Jacob gp = g_multipath_find_geom(mp, name); 1385b5dce617SMatt Jacob if (gp == NULL) { 1386b5dce617SMatt Jacob gctl_error(req, "Device %s is invalid", name); 1387b5dce617SMatt Jacob return; 1388b5dce617SMatt Jacob } 1389b5dce617SMatt Jacob error = g_multipath_rotate(gp); 1390b5dce617SMatt Jacob if (error != 0) { 1391b5dce617SMatt Jacob gctl_error(req, "failed to rotate %s (err=%d)", name, error); 1392b5dce617SMatt Jacob } 1393b5dce617SMatt Jacob } 1394b5dce617SMatt Jacob 1395b5dce617SMatt Jacob static void 1396b5dce617SMatt Jacob g_multipath_ctl_getactive(struct gctl_req *req, struct g_class *mp) 1397b5dce617SMatt Jacob { 1398b5dce617SMatt Jacob struct sbuf *sb; 1399b5dce617SMatt Jacob struct g_geom *gp; 1400b5dce617SMatt Jacob struct g_multipath_softc *sc; 14010c883cefSAlexander Motin struct g_consumer *cp; 1402b5dce617SMatt Jacob const char *name; 14030c883cefSAlexander Motin int empty; 1404b5dce617SMatt Jacob 1405b5dce617SMatt Jacob sb = sbuf_new_auto(); 1406b5dce617SMatt Jacob 1407b5dce617SMatt Jacob g_topology_assert(); 1408b5dce617SMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1409b5dce617SMatt Jacob if (name == NULL) { 1410b5dce617SMatt Jacob gctl_error(req, "No 'arg0' argument"); 1411b5dce617SMatt Jacob return; 1412b5dce617SMatt Jacob } 1413b5dce617SMatt Jacob gp = g_multipath_find_geom(mp, name); 1414b5dce617SMatt Jacob if (gp == NULL) { 1415b5dce617SMatt Jacob gctl_error(req, "Device %s is invalid", name); 1416b5dce617SMatt Jacob return; 1417b5dce617SMatt Jacob } 1418b5dce617SMatt Jacob sc = gp->softc; 141963297dfdSAlexander Motin if (sc->sc_active_active == 1) { 14200c883cefSAlexander Motin empty = 1; 14210c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 14220c883cefSAlexander Motin if (cp->index & MP_BAD) 14230c883cefSAlexander Motin continue; 14240c883cefSAlexander Motin if (!empty) 14250c883cefSAlexander Motin sbuf_cat(sb, " "); 14260c883cefSAlexander Motin sbuf_cat(sb, cp->provider->name); 14270c883cefSAlexander Motin empty = 0; 14280c883cefSAlexander Motin } 14290c883cefSAlexander Motin if (empty) 14300c883cefSAlexander Motin sbuf_cat(sb, "none"); 14310c883cefSAlexander Motin sbuf_cat(sb, "\n"); 14320c883cefSAlexander Motin } else if (sc->sc_active && sc->sc_active->provider) { 14330c883cefSAlexander Motin sbuf_printf(sb, "%s\n", sc->sc_active->provider->name); 1434b5dce617SMatt Jacob } else { 1435b5dce617SMatt Jacob sbuf_printf(sb, "none\n"); 1436b5dce617SMatt Jacob } 1437b5dce617SMatt Jacob sbuf_finish(sb); 1438b5dce617SMatt Jacob gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1439b5dce617SMatt Jacob sbuf_delete(sb); 1440b5dce617SMatt Jacob } 1441b5dce617SMatt Jacob 1442b5dce617SMatt Jacob static void 1443e770bc6bSMatt Jacob g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb) 1444e770bc6bSMatt Jacob { 1445e770bc6bSMatt Jacob uint32_t *version; 1446e770bc6bSMatt Jacob g_topology_assert(); 1447e770bc6bSMatt Jacob version = gctl_get_paraml(req, "version", sizeof(*version)); 1448e770bc6bSMatt Jacob if (version == NULL) { 1449e770bc6bSMatt Jacob gctl_error(req, "No 'version' argument"); 1450e770bc6bSMatt Jacob } else if (*version != G_MULTIPATH_VERSION) { 1451e770bc6bSMatt Jacob gctl_error(req, "Userland and kernel parts are out of sync"); 14522b4969ffSMatt Jacob } else if (strcmp(verb, "add") == 0) { 14532b4969ffSMatt Jacob g_multipath_ctl_add(req, mp); 145471ee4ef0SThomas Quinot } else if (strcmp(verb, "prefer") == 0) { 145571ee4ef0SThomas Quinot g_multipath_ctl_prefer(req, mp); 14560c883cefSAlexander Motin } else if (strcmp(verb, "create") == 0) { 14570c883cefSAlexander Motin g_multipath_ctl_create(req, mp); 145863297dfdSAlexander Motin } else if (strcmp(verb, "configure") == 0) { 145963297dfdSAlexander Motin g_multipath_ctl_configure(req, mp); 14600c883cefSAlexander Motin } else if (strcmp(verb, "stop") == 0) { 14610c883cefSAlexander Motin g_multipath_ctl_stop(req, mp); 1462e770bc6bSMatt Jacob } else if (strcmp(verb, "destroy") == 0) { 1463e770bc6bSMatt Jacob g_multipath_ctl_destroy(req, mp); 14640c883cefSAlexander Motin } else if (strcmp(verb, "fail") == 0) { 14650c883cefSAlexander Motin g_multipath_ctl_fail(req, mp, 1); 14660c883cefSAlexander Motin } else if (strcmp(verb, "restore") == 0) { 14670c883cefSAlexander Motin g_multipath_ctl_fail(req, mp, 0); 14680c883cefSAlexander Motin } else if (strcmp(verb, "remove") == 0) { 14690c883cefSAlexander Motin g_multipath_ctl_remove(req, mp); 1470b5dce617SMatt Jacob } else if (strcmp(verb, "rotate") == 0) { 1471b5dce617SMatt Jacob g_multipath_ctl_rotate(req, mp); 1472b5dce617SMatt Jacob } else if (strcmp(verb, "getactive") == 0) { 1473b5dce617SMatt Jacob g_multipath_ctl_getactive(req, mp); 1474e770bc6bSMatt Jacob } else { 1475e770bc6bSMatt Jacob gctl_error(req, "Unknown verb %s", verb); 1476e770bc6bSMatt Jacob } 1477e770bc6bSMatt Jacob } 14780c883cefSAlexander Motin 14790c883cefSAlexander Motin static void 14800c883cefSAlexander Motin g_multipath_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 14810c883cefSAlexander Motin struct g_consumer *cp, struct g_provider *pp) 14820c883cefSAlexander Motin { 14830c883cefSAlexander Motin struct g_multipath_softc *sc; 14840c883cefSAlexander Motin int good; 14850c883cefSAlexander Motin 14860c883cefSAlexander Motin g_topology_assert(); 14870c883cefSAlexander Motin 14880c883cefSAlexander Motin sc = gp->softc; 14890c883cefSAlexander Motin if (sc == NULL) 14900c883cefSAlexander Motin return; 14910c883cefSAlexander Motin if (cp != NULL) { 1492a839e332SAlexander Motin sbuf_printf(sb, "%s<State>%s</State>\n", indent, 14930c883cefSAlexander Motin (cp->index & MP_NEW) ? "NEW" : 14940c883cefSAlexander Motin (cp->index & MP_LOST) ? "LOST" : 14950c883cefSAlexander Motin (cp->index & MP_FAIL) ? "FAIL" : 149663297dfdSAlexander Motin (sc->sc_active_active == 1 || sc->sc_active == cp) ? 149763297dfdSAlexander Motin "ACTIVE" : 149863297dfdSAlexander Motin sc->sc_active_active == 2 ? "READ" : "PASSIVE"); 14990c883cefSAlexander Motin } else { 15000c883cefSAlexander Motin good = g_multipath_good(gp); 1501a839e332SAlexander Motin sbuf_printf(sb, "%s<State>%s</State>\n", indent, 15020c883cefSAlexander Motin good == 0 ? "BROKEN" : 15030c883cefSAlexander Motin (good != sc->sc_ndisks || sc->sc_ndisks == 1) ? 15040c883cefSAlexander Motin "DEGRADED" : "OPTIMAL"); 15050c883cefSAlexander Motin } 15060c883cefSAlexander Motin if (cp == NULL && pp == NULL) { 1507a839e332SAlexander Motin sbuf_printf(sb, "%s<UUID>%s</UUID>\n", indent, sc->sc_uuid); 1508a839e332SAlexander Motin sbuf_printf(sb, "%s<Mode>Active/%s</Mode>\n", indent, 150963297dfdSAlexander Motin sc->sc_active_active == 2 ? "Read" : 151063297dfdSAlexander Motin sc->sc_active_active == 1 ? "Active" : "Passive"); 1511a839e332SAlexander Motin sbuf_printf(sb, "%s<Type>%s</Type>\n", indent, 15120c883cefSAlexander Motin sc->sc_uuid[0] == 0 ? "MANUAL" : "AUTOMATIC"); 15130c883cefSAlexander Motin } 15140c883cefSAlexander Motin } 15150c883cefSAlexander Motin 1516e770bc6bSMatt Jacob DECLARE_GEOM_CLASS(g_multipath_class, g_multipath); 1517