1e770bc6bSMatt Jacob /*- 23728855aSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 33728855aSPedro F. Giffuni * 4e6afd72bSAlexander Motin * Copyright (c) 2011-2013 Alexander Motin <mav@FreeBSD.org> 5e770bc6bSMatt Jacob * Copyright (c) 2006-2007 Matthew Jacob <mjacob@FreeBSD.org> 6e770bc6bSMatt Jacob * All rights reserved. 7e770bc6bSMatt Jacob * 8e770bc6bSMatt Jacob * Redistribution and use in source and binary forms, with or without 9e770bc6bSMatt Jacob * modification, are permitted provided that the following conditions 10e770bc6bSMatt Jacob * are met: 11e770bc6bSMatt Jacob * 1. Redistributions of source code must retain the above copyright 12e770bc6bSMatt Jacob * notice, this list of conditions and the following disclaimer. 13e770bc6bSMatt Jacob * 2. Redistributions in binary form must reproduce the above copyright 14e770bc6bSMatt Jacob * notice, this list of conditions and the following disclaimer in the 15e770bc6bSMatt Jacob * documentation and/or other materials provided with the distribution. 16e770bc6bSMatt Jacob * 17e770bc6bSMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18e770bc6bSMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19e770bc6bSMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20e770bc6bSMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21e770bc6bSMatt Jacob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22e770bc6bSMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23e770bc6bSMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24e770bc6bSMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25e770bc6bSMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26e770bc6bSMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27e770bc6bSMatt Jacob * SUCH DAMAGE. 28e770bc6bSMatt Jacob */ 29e770bc6bSMatt Jacob /* 30e770bc6bSMatt Jacob * Based upon work by Pawel Jakub Dawidek <pjd@FreeBSD.org> for all of the 31e770bc6bSMatt Jacob * fine geom examples, and by Poul Henning Kamp <phk@FreeBSD.org> for GEOM 32e770bc6bSMatt Jacob * itself, all of which is most gratefully acknowledged. 33e770bc6bSMatt Jacob */ 34e770bc6bSMatt Jacob 35e770bc6bSMatt Jacob #include <sys/cdefs.h> 36e770bc6bSMatt Jacob __FBSDID("$FreeBSD$"); 37e770bc6bSMatt Jacob #include <sys/param.h> 38e770bc6bSMatt Jacob #include <sys/systm.h> 39e770bc6bSMatt Jacob #include <sys/kernel.h> 40e770bc6bSMatt Jacob #include <sys/module.h> 41e6afd72bSAlexander Motin #include <sys/limits.h> 42e770bc6bSMatt Jacob #include <sys/lock.h> 43e770bc6bSMatt Jacob #include <sys/mutex.h> 44e770bc6bSMatt Jacob #include <sys/bio.h> 455d807a0eSAndrey V. Elsukov #include <sys/sbuf.h> 4667f72211SAlan Somers #include <sys/sdt.h> 47e770bc6bSMatt Jacob #include <sys/sysctl.h> 48e770bc6bSMatt Jacob #include <sys/kthread.h> 49e770bc6bSMatt Jacob #include <sys/malloc.h> 50e770bc6bSMatt Jacob #include <geom/geom.h> 51e770bc6bSMatt Jacob #include <geom/multipath/g_multipath.h> 52e770bc6bSMatt Jacob 53cb08c2ccSAlexander Leidinger FEATURE(geom_multipath, "GEOM multipath support"); 54e770bc6bSMatt Jacob 55e770bc6bSMatt Jacob SYSCTL_DECL(_kern_geom); 567029da5cSPawel Biernacki static SYSCTL_NODE(_kern_geom, OID_AUTO, multipath, 577029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 58e770bc6bSMatt Jacob "GEOM_MULTIPATH tunables"); 59e770bc6bSMatt Jacob static u_int g_multipath_debug = 0; 60e770bc6bSMatt Jacob SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, debug, CTLFLAG_RW, 61e770bc6bSMatt Jacob &g_multipath_debug, 0, "Debug level"); 620c883cefSAlexander Motin static u_int g_multipath_exclusive = 1; 630c883cefSAlexander Motin SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, exclusive, CTLFLAG_RW, 640c883cefSAlexander Motin &g_multipath_exclusive, 0, "Exclusively open providers"); 65e770bc6bSMatt Jacob 6667f72211SAlan Somers SDT_PROVIDER_DECLARE(geom); 6767f72211SAlan Somers SDT_PROBE_DEFINE2(geom, multipath, config, restore, "char*", "char*"); 6867f72211SAlan Somers SDT_PROBE_DEFINE2(geom, multipath, config, remove, "char*", "char*"); 6967f72211SAlan Somers SDT_PROBE_DEFINE2(geom, multipath, config, disconnect, "char*", "char*"); 7067f72211SAlan Somers SDT_PROBE_DEFINE3(geom, multipath, config, fail, "char*", "char*", "int"); 7167f72211SAlan Somers SDT_PROBE_DEFINE2(geom, multipath, config, taste, "char*", "char*"); 7267f72211SAlan Somers SDT_PROBE_DEFINE2(geom, multipath, io, restart, "struct bio*", "struct bio*"); 7367f72211SAlan Somers 74e770bc6bSMatt Jacob static enum { 75e770bc6bSMatt Jacob GKT_NIL, 76e770bc6bSMatt Jacob GKT_RUN, 77e770bc6bSMatt Jacob GKT_DIE 78e770bc6bSMatt Jacob } g_multipath_kt_state; 79e770bc6bSMatt Jacob static struct bio_queue_head gmtbq; 80e770bc6bSMatt Jacob static struct mtx gmtbq_mtx; 81e770bc6bSMatt Jacob 82f8c79813SAlexander Motin static int g_multipath_read_metadata(struct g_consumer *cp, 83f8c79813SAlexander Motin struct g_multipath_metadata *md); 84f8c79813SAlexander Motin static int g_multipath_write_metadata(struct g_consumer *cp, 85f8c79813SAlexander Motin struct g_multipath_metadata *md); 86f8c79813SAlexander Motin 87e770bc6bSMatt Jacob static void g_multipath_orphan(struct g_consumer *); 88e6afd72bSAlexander Motin static void g_multipath_resize(struct g_consumer *); 89e770bc6bSMatt Jacob static void g_multipath_start(struct bio *); 90e770bc6bSMatt Jacob static void g_multipath_done(struct bio *); 91e770bc6bSMatt Jacob static void g_multipath_done_error(struct bio *); 92e770bc6bSMatt Jacob static void g_multipath_kt(void *); 93e770bc6bSMatt Jacob 94e770bc6bSMatt Jacob static int g_multipath_destroy(struct g_geom *); 95e770bc6bSMatt Jacob static int 96e770bc6bSMatt Jacob g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *); 97e770bc6bSMatt Jacob 982b4969ffSMatt Jacob static struct g_geom *g_multipath_find_geom(struct g_class *, const char *); 99b5dce617SMatt Jacob static int g_multipath_rotate(struct g_geom *); 100b5dce617SMatt Jacob 101e770bc6bSMatt Jacob static g_taste_t g_multipath_taste; 102e770bc6bSMatt Jacob static g_ctl_req_t g_multipath_config; 103e770bc6bSMatt Jacob static g_init_t g_multipath_init; 104e770bc6bSMatt Jacob static g_fini_t g_multipath_fini; 1050c883cefSAlexander Motin static g_dumpconf_t g_multipath_dumpconf; 106e770bc6bSMatt Jacob 107e770bc6bSMatt Jacob struct g_class g_multipath_class = { 108e770bc6bSMatt Jacob .name = G_MULTIPATH_CLASS_NAME, 109e770bc6bSMatt Jacob .version = G_VERSION, 110e770bc6bSMatt Jacob .ctlreq = g_multipath_config, 111e770bc6bSMatt Jacob .taste = g_multipath_taste, 112e770bc6bSMatt Jacob .destroy_geom = g_multipath_destroy_geom, 113e770bc6bSMatt Jacob .init = g_multipath_init, 114e770bc6bSMatt Jacob .fini = g_multipath_fini 115e770bc6bSMatt Jacob }; 116e770bc6bSMatt Jacob 1170c883cefSAlexander Motin #define MP_FAIL 0x00000001 1180c883cefSAlexander Motin #define MP_LOST 0x00000002 1190c883cefSAlexander Motin #define MP_NEW 0x00000004 1200c883cefSAlexander Motin #define MP_POSTED 0x00000008 1210c883cefSAlexander Motin #define MP_BAD (MP_FAIL | MP_LOST | MP_NEW) 12225080ac4SSteven Hartland #define MP_WITHER 0x00000010 12325080ac4SSteven Hartland #define MP_IDLE 0x00000020 12425080ac4SSteven Hartland #define MP_IDLE_MASK 0xffffffe0 1250c883cefSAlexander Motin 1260c883cefSAlexander Motin static int 1270c883cefSAlexander Motin g_multipath_good(struct g_geom *gp) 1280c883cefSAlexander Motin { 1290c883cefSAlexander Motin struct g_consumer *cp; 1300c883cefSAlexander Motin int n = 0; 1310c883cefSAlexander Motin 1320c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 1330c883cefSAlexander Motin if ((cp->index & MP_BAD) == 0) 1340c883cefSAlexander Motin n++; 1350c883cefSAlexander Motin } 1360c883cefSAlexander Motin return (n); 1370c883cefSAlexander Motin } 1380c883cefSAlexander Motin 1390c883cefSAlexander Motin static void 1400c883cefSAlexander Motin g_multipath_fault(struct g_consumer *cp, int cause) 1410c883cefSAlexander Motin { 1420c883cefSAlexander Motin struct g_multipath_softc *sc; 1430c883cefSAlexander Motin struct g_consumer *lcp; 1440c883cefSAlexander Motin struct g_geom *gp; 1450c883cefSAlexander Motin 1460c883cefSAlexander Motin gp = cp->geom; 1470c883cefSAlexander Motin sc = gp->softc; 1480c883cefSAlexander Motin cp->index |= cause; 1490c883cefSAlexander Motin if (g_multipath_good(gp) == 0 && sc->sc_ndisks > 0) { 1500c883cefSAlexander Motin LIST_FOREACH(lcp, &gp->consumer, consumer) { 1510c883cefSAlexander Motin if (lcp->provider == NULL || 1520c883cefSAlexander Motin (lcp->index & (MP_LOST | MP_NEW))) 1530c883cefSAlexander Motin continue; 1540c883cefSAlexander Motin if (sc->sc_ndisks > 1 && lcp == cp) 1550c883cefSAlexander Motin continue; 1560c883cefSAlexander Motin printf("GEOM_MULTIPATH: " 1570c883cefSAlexander Motin "all paths in %s were marked FAIL, restore %s\n", 1580c883cefSAlexander Motin sc->sc_name, lcp->provider->name); 15967f72211SAlan Somers SDT_PROBE2(geom, multipath, config, restore, 16067f72211SAlan Somers sc->sc_name, lcp->provider->name); 1610c883cefSAlexander Motin lcp->index &= ~MP_FAIL; 1620c883cefSAlexander Motin } 1630c883cefSAlexander Motin } 1640c883cefSAlexander Motin if (cp != sc->sc_active) 1650c883cefSAlexander Motin return; 1660c883cefSAlexander Motin sc->sc_active = NULL; 1670c883cefSAlexander Motin LIST_FOREACH(lcp, &gp->consumer, consumer) { 1680c883cefSAlexander Motin if ((lcp->index & MP_BAD) == 0) { 1690c883cefSAlexander Motin sc->sc_active = lcp; 1700c883cefSAlexander Motin break; 1710c883cefSAlexander Motin } 1720c883cefSAlexander Motin } 1730c883cefSAlexander Motin if (sc->sc_active == NULL) { 1740c883cefSAlexander Motin printf("GEOM_MULTIPATH: out of providers for %s\n", 1750c883cefSAlexander Motin sc->sc_name); 17663297dfdSAlexander Motin } else if (sc->sc_active_active != 1) { 1770c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 1780c883cefSAlexander Motin sc->sc_active->provider->name, sc->sc_name); 1790c883cefSAlexander Motin } 1800c883cefSAlexander Motin } 1810c883cefSAlexander Motin 1820c883cefSAlexander Motin static struct g_consumer * 18363297dfdSAlexander Motin g_multipath_choose(struct g_geom *gp, struct bio *bp) 1840c883cefSAlexander Motin { 1850c883cefSAlexander Motin struct g_multipath_softc *sc; 1860c883cefSAlexander Motin struct g_consumer *best, *cp; 1870c883cefSAlexander Motin 1880c883cefSAlexander Motin sc = gp->softc; 18963297dfdSAlexander Motin if (sc->sc_active_active == 0 || 19063297dfdSAlexander Motin (sc->sc_active_active == 2 && bp->bio_cmd != BIO_READ)) 1910c883cefSAlexander Motin return (sc->sc_active); 1920c883cefSAlexander Motin best = NULL; 1930c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 1940c883cefSAlexander Motin if (cp->index & MP_BAD) 1950c883cefSAlexander Motin continue; 1960c883cefSAlexander Motin cp->index += MP_IDLE; 1970c883cefSAlexander Motin if (best == NULL || cp->private < best->private || 1980c883cefSAlexander Motin (cp->private == best->private && cp->index > best->index)) 1990c883cefSAlexander Motin best = cp; 2000c883cefSAlexander Motin } 2010c883cefSAlexander Motin if (best != NULL) 2020c883cefSAlexander Motin best->index &= ~MP_IDLE_MASK; 2030c883cefSAlexander Motin return (best); 2040c883cefSAlexander Motin } 205e770bc6bSMatt Jacob 206e770bc6bSMatt Jacob static void 207e770bc6bSMatt Jacob g_mpd(void *arg, int flags __unused) 208e770bc6bSMatt Jacob { 2090c883cefSAlexander Motin struct g_geom *gp; 2100c883cefSAlexander Motin struct g_multipath_softc *sc; 211e770bc6bSMatt Jacob struct g_consumer *cp; 2120c883cefSAlexander Motin int w; 213e770bc6bSMatt Jacob 214e770bc6bSMatt Jacob g_topology_assert(); 215e770bc6bSMatt Jacob cp = arg; 2160c883cefSAlexander Motin gp = cp->geom; 2170c883cefSAlexander Motin if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) { 2180c883cefSAlexander Motin w = cp->acw; 219e770bc6bSMatt Jacob g_access(cp, -cp->acr, -cp->acw, -cp->ace); 2200c883cefSAlexander Motin if (w > 0 && cp->provider != NULL && 2210c883cefSAlexander Motin (cp->provider->geom->flags & G_GEOM_WITHER) == 0) { 22225080ac4SSteven Hartland cp->index |= MP_WITHER; 2230c883cefSAlexander Motin g_post_event(g_mpd, cp, M_WAITOK, NULL); 2240c883cefSAlexander Motin return; 2250c883cefSAlexander Motin } 2260c883cefSAlexander Motin } 2270c883cefSAlexander Motin sc = gp->softc; 2280c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 229e770bc6bSMatt Jacob if (cp->provider) { 230e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: %s removed from %s\n", 2310c883cefSAlexander Motin cp->provider->name, gp->name); 23267f72211SAlan Somers SDT_PROBE2(geom, multipath, config, remove, 23367f72211SAlan Somers gp->name, cp->provider->name); 234e770bc6bSMatt Jacob g_detach(cp); 235e770bc6bSMatt Jacob } 236e770bc6bSMatt Jacob g_destroy_consumer(cp); 2370c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 2380c883cefSAlexander Motin if (LIST_EMPTY(&gp->consumer)) 2390c883cefSAlexander Motin g_multipath_destroy(gp); 240e770bc6bSMatt Jacob } 241e770bc6bSMatt Jacob 242e770bc6bSMatt Jacob static void 243e770bc6bSMatt Jacob g_multipath_orphan(struct g_consumer *cp) 244e770bc6bSMatt Jacob { 2450c883cefSAlexander Motin struct g_multipath_softc *sc; 2460c883cefSAlexander Motin uintptr_t *cnt; 2470c883cefSAlexander Motin 2480c883cefSAlexander Motin g_topology_assert(); 2490c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s in %s was disconnected\n", 250e770bc6bSMatt Jacob cp->provider->name, cp->geom->name); 25167f72211SAlan Somers SDT_PROBE2(geom, multipath, config, disconnect, 25267f72211SAlan Somers cp->geom->name, cp->provider->name); 2530c883cefSAlexander Motin sc = cp->geom->softc; 2540c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 2550c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 2560c883cefSAlexander Motin sc->sc_ndisks--; 2570c883cefSAlexander Motin g_multipath_fault(cp, MP_LOST); 2580c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_POSTED) == 0) { 2590c883cefSAlexander Motin cp->index |= MP_POSTED; 2600c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 261e770bc6bSMatt Jacob g_mpd(cp, 0); 2620c883cefSAlexander Motin } else 2630c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 264e770bc6bSMatt Jacob } 265e770bc6bSMatt Jacob 266e770bc6bSMatt Jacob static void 267e6afd72bSAlexander Motin g_multipath_resize(struct g_consumer *cp) 268e6afd72bSAlexander Motin { 269e6afd72bSAlexander Motin struct g_multipath_softc *sc; 270e6afd72bSAlexander Motin struct g_geom *gp; 271f8c79813SAlexander Motin struct g_consumer *cp1; 272e6afd72bSAlexander Motin struct g_provider *pp; 273e6afd72bSAlexander Motin struct g_multipath_metadata md; 274e6afd72bSAlexander Motin off_t size, psize, ssize; 275e6afd72bSAlexander Motin int error; 276e6afd72bSAlexander Motin 277e6afd72bSAlexander Motin g_topology_assert(); 278e6afd72bSAlexander Motin 279e6afd72bSAlexander Motin gp = cp->geom; 280e6afd72bSAlexander Motin pp = cp->provider; 281e6afd72bSAlexander Motin sc = gp->softc; 282e6afd72bSAlexander Motin 283e6afd72bSAlexander Motin if (sc->sc_stopping) 284e6afd72bSAlexander Motin return; 285e6afd72bSAlexander Motin 286e6afd72bSAlexander Motin if (pp->mediasize < sc->sc_size) { 287e6afd72bSAlexander Motin size = pp->mediasize; 288e6afd72bSAlexander Motin ssize = pp->sectorsize; 289e6afd72bSAlexander Motin } else { 290e6afd72bSAlexander Motin size = ssize = OFF_MAX; 291e6afd72bSAlexander Motin mtx_lock(&sc->sc_mtx); 292f8c79813SAlexander Motin LIST_FOREACH(cp1, &gp->consumer, consumer) { 293f8c79813SAlexander Motin pp = cp1->provider; 294e6afd72bSAlexander Motin if (pp == NULL) 295e6afd72bSAlexander Motin continue; 296e6afd72bSAlexander Motin if (pp->mediasize < size) { 297e6afd72bSAlexander Motin size = pp->mediasize; 298e6afd72bSAlexander Motin ssize = pp->sectorsize; 299e6afd72bSAlexander Motin } 300e6afd72bSAlexander Motin } 301e6afd72bSAlexander Motin mtx_unlock(&sc->sc_mtx); 302e6afd72bSAlexander Motin if (size == OFF_MAX || size == sc->sc_size) 303e6afd72bSAlexander Motin return; 304e6afd72bSAlexander Motin } 305e6afd72bSAlexander Motin psize = size - ((sc->sc_uuid[0] != 0) ? ssize : 0); 306e6afd72bSAlexander Motin printf("GEOM_MULTIPATH: %s size changed from %jd to %jd\n", 307e6afd72bSAlexander Motin sc->sc_name, sc->sc_pp->mediasize, psize); 308f8c79813SAlexander Motin if (sc->sc_uuid[0] != 0 && size < sc->sc_size) { 309f8c79813SAlexander Motin error = g_multipath_read_metadata(cp, &md); 310f8c79813SAlexander Motin if (error || 311f8c79813SAlexander Motin (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) || 312f8c79813SAlexander Motin (memcmp(md.md_uuid, sc->sc_uuid, sizeof(sc->sc_uuid)) != 0) || 313f8c79813SAlexander Motin (strcmp(md.md_name, sc->sc_name) != 0) || 314f8c79813SAlexander Motin (md.md_size != 0 && md.md_size != size) || 315f8c79813SAlexander Motin (md.md_sectorsize != 0 && md.md_sectorsize != ssize)) { 316e6afd72bSAlexander Motin g_multipath_destroy(gp); 317e6afd72bSAlexander Motin return; 318e6afd72bSAlexander Motin } 319f8c79813SAlexander Motin } 320e6afd72bSAlexander Motin sc->sc_size = size; 321e6afd72bSAlexander Motin g_resize_provider(sc->sc_pp, psize); 322e6afd72bSAlexander Motin 323f8c79813SAlexander Motin if (sc->sc_uuid[0] != 0) { 324e6afd72bSAlexander Motin pp = cp->provider; 325e6afd72bSAlexander Motin strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 326e6afd72bSAlexander Motin memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid)); 327e6afd72bSAlexander Motin strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name)); 328e6afd72bSAlexander Motin md.md_version = G_MULTIPATH_VERSION; 329e6afd72bSAlexander Motin md.md_size = size; 330f8c79813SAlexander Motin md.md_sectorsize = ssize; 331e6afd72bSAlexander Motin md.md_active_active = sc->sc_active_active; 332f8c79813SAlexander Motin error = g_multipath_write_metadata(cp, &md); 333e6afd72bSAlexander Motin if (error != 0) 334e6afd72bSAlexander Motin printf("GEOM_MULTIPATH: Can't update metadata on %s " 335e6afd72bSAlexander Motin "(%d)\n", pp->name, error); 336e6afd72bSAlexander Motin } 337e6afd72bSAlexander Motin } 338e6afd72bSAlexander Motin 339e6afd72bSAlexander Motin static void 340e770bc6bSMatt Jacob g_multipath_start(struct bio *bp) 341e770bc6bSMatt Jacob { 342e770bc6bSMatt Jacob struct g_multipath_softc *sc; 343e770bc6bSMatt Jacob struct g_geom *gp; 344e770bc6bSMatt Jacob struct g_consumer *cp; 345e770bc6bSMatt Jacob struct bio *cbp; 3460c883cefSAlexander Motin uintptr_t *cnt; 347e770bc6bSMatt Jacob 348e770bc6bSMatt Jacob gp = bp->bio_to->geom; 349e770bc6bSMatt Jacob sc = gp->softc; 350e770bc6bSMatt Jacob KASSERT(sc != NULL, ("NULL sc")); 351e770bc6bSMatt Jacob cbp = g_clone_bio(bp); 352e770bc6bSMatt Jacob if (cbp == NULL) { 353e770bc6bSMatt Jacob g_io_deliver(bp, ENOMEM); 354e770bc6bSMatt Jacob return; 355e770bc6bSMatt Jacob } 3560c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 35763297dfdSAlexander Motin cp = g_multipath_choose(gp, bp); 3580c883cefSAlexander Motin if (cp == NULL) { 3590c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 3600c883cefSAlexander Motin g_destroy_bio(cbp); 3610c883cefSAlexander Motin g_io_deliver(bp, ENXIO); 3620c883cefSAlexander Motin return; 3630c883cefSAlexander Motin } 3640c883cefSAlexander Motin if ((uintptr_t)bp->bio_driver1 < sc->sc_ndisks) 3650c883cefSAlexander Motin bp->bio_driver1 = (void *)(uintptr_t)sc->sc_ndisks; 3660c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 3670c883cefSAlexander Motin (*cnt)++; 3680c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 369e770bc6bSMatt Jacob cbp->bio_done = g_multipath_done; 370e770bc6bSMatt Jacob g_io_request(cbp, cp); 371e770bc6bSMatt Jacob } 372e770bc6bSMatt Jacob 373e770bc6bSMatt Jacob static void 374e770bc6bSMatt Jacob g_multipath_done(struct bio *bp) 375e770bc6bSMatt Jacob { 3760c883cefSAlexander Motin struct g_multipath_softc *sc; 3770c883cefSAlexander Motin struct g_consumer *cp; 3780c883cefSAlexander Motin uintptr_t *cnt; 3790c883cefSAlexander Motin 380e770bc6bSMatt Jacob if (bp->bio_error == ENXIO || bp->bio_error == EIO) { 381e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 382e770bc6bSMatt Jacob bioq_insert_tail(&gmtbq, bp); 383e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 3840c883cefSAlexander Motin wakeup(&g_multipath_kt_state); 385e770bc6bSMatt Jacob } else { 3860c883cefSAlexander Motin cp = bp->bio_from; 3870c883cefSAlexander Motin sc = cp->geom->softc; 3880c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 3890c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 3900c883cefSAlexander Motin (*cnt)--; 3910c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_LOST)) { 3920ada3afcSAlexander Motin if (g_post_event(g_mpd, cp, M_NOWAIT, NULL) == 0) 3930c883cefSAlexander Motin cp->index |= MP_POSTED; 3940c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 3950c883cefSAlexander Motin } else 3960c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 397420dbe76SAlan Somers if (bp->bio_error == 0 && 398420dbe76SAlan Somers bp->bio_cmd == BIO_GETATTR && 399420dbe76SAlan Somers !strcmp(bp->bio_attribute, "GEOM::physpath")) 400420dbe76SAlan Somers { 401420dbe76SAlan Somers strlcat(bp->bio_data, "/mp", bp->bio_length); 402420dbe76SAlan Somers } 403e770bc6bSMatt Jacob g_std_done(bp); 404e770bc6bSMatt Jacob } 405e770bc6bSMatt Jacob } 406e770bc6bSMatt Jacob 407e770bc6bSMatt Jacob static void 408e770bc6bSMatt Jacob g_multipath_done_error(struct bio *bp) 409e770bc6bSMatt Jacob { 410e770bc6bSMatt Jacob struct bio *pbp; 411e770bc6bSMatt Jacob struct g_geom *gp; 412e770bc6bSMatt Jacob struct g_multipath_softc *sc; 413e770bc6bSMatt Jacob struct g_consumer *cp; 414e770bc6bSMatt Jacob struct g_provider *pp; 4150c883cefSAlexander Motin uintptr_t *cnt; 416e770bc6bSMatt Jacob 417e770bc6bSMatt Jacob /* 418e770bc6bSMatt Jacob * If we had a failure, we have to check first to see 419e770bc6bSMatt Jacob * whether the consumer it failed on was the currently 420e770bc6bSMatt Jacob * active consumer (i.e., this is the first in perhaps 421e770bc6bSMatt Jacob * a number of failures). If so, we then switch consumers 422e770bc6bSMatt Jacob * to the next available consumer. 423e770bc6bSMatt Jacob */ 424e770bc6bSMatt Jacob 425e770bc6bSMatt Jacob pbp = bp->bio_parent; 426e770bc6bSMatt Jacob gp = pbp->bio_to->geom; 427e770bc6bSMatt Jacob sc = gp->softc; 428e770bc6bSMatt Jacob cp = bp->bio_from; 429e770bc6bSMatt Jacob pp = cp->provider; 4300c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 431e770bc6bSMatt Jacob 4320c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 43363297dfdSAlexander Motin if ((cp->index & MP_FAIL) == 0) { 4340c883cefSAlexander Motin printf("GEOM_MULTIPATH: Error %d, %s in %s marked FAIL\n", 4350c883cefSAlexander Motin bp->bio_error, pp->name, sc->sc_name); 43667f72211SAlan Somers SDT_PROBE3(geom, multipath, config, fail, 43767f72211SAlan Somers sc->sc_name, pp->name, bp->bio_error); 4380c883cefSAlexander Motin g_multipath_fault(cp, MP_FAIL); 43963297dfdSAlexander Motin } 4400c883cefSAlexander Motin (*cnt)--; 4410c883cefSAlexander Motin if (*cnt == 0 && (cp->index & (MP_LOST | MP_POSTED)) == MP_LOST) { 442e770bc6bSMatt Jacob cp->index |= MP_POSTED; 4430c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 4440c883cefSAlexander Motin g_post_event(g_mpd, cp, M_WAITOK, NULL); 4450c883cefSAlexander Motin } else 4460c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 447e770bc6bSMatt Jacob 448e770bc6bSMatt Jacob /* 449e770bc6bSMatt Jacob * If we can fruitfully restart the I/O, do so. 450e770bc6bSMatt Jacob */ 4510c883cefSAlexander Motin if (pbp->bio_children < (uintptr_t)pbp->bio_driver1) { 4520c883cefSAlexander Motin pbp->bio_inbed++; 45367f72211SAlan Somers SDT_PROBE2(geom, multipath, io, restart, bp, pbp); 454e770bc6bSMatt Jacob g_destroy_bio(bp); 455e770bc6bSMatt Jacob g_multipath_start(pbp); 456e770bc6bSMatt Jacob } else { 457e770bc6bSMatt Jacob g_std_done(bp); 458e770bc6bSMatt Jacob } 459e770bc6bSMatt Jacob } 460e770bc6bSMatt Jacob 461e770bc6bSMatt Jacob static void 462e770bc6bSMatt Jacob g_multipath_kt(void *arg) 463e770bc6bSMatt Jacob { 46412f35a61SPawel Jakub Dawidek 465e770bc6bSMatt Jacob g_multipath_kt_state = GKT_RUN; 466e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 467e770bc6bSMatt Jacob while (g_multipath_kt_state == GKT_RUN) { 468e770bc6bSMatt Jacob for (;;) { 469e770bc6bSMatt Jacob struct bio *bp; 47012f35a61SPawel Jakub Dawidek 471e770bc6bSMatt Jacob bp = bioq_takefirst(&gmtbq); 47212f35a61SPawel Jakub Dawidek if (bp == NULL) 473e770bc6bSMatt Jacob break; 474e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 475e770bc6bSMatt Jacob g_multipath_done_error(bp); 476e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 477e770bc6bSMatt Jacob } 47863297dfdSAlexander Motin if (g_multipath_kt_state != GKT_RUN) 47963297dfdSAlexander Motin break; 480e770bc6bSMatt Jacob msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO, 48163297dfdSAlexander Motin "gkt:wait", 0); 482e770bc6bSMatt Jacob } 483e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 484e770bc6bSMatt Jacob wakeup(&g_multipath_kt_state); 4853745c395SJulian Elischer kproc_exit(0); 486e770bc6bSMatt Jacob } 487e770bc6bSMatt Jacob 488e770bc6bSMatt Jacob static int 489e770bc6bSMatt Jacob g_multipath_access(struct g_provider *pp, int dr, int dw, int de) 490e770bc6bSMatt Jacob { 491e770bc6bSMatt Jacob struct g_geom *gp; 492e770bc6bSMatt Jacob struct g_consumer *cp, *badcp = NULL; 4930c883cefSAlexander Motin struct g_multipath_softc *sc; 494e770bc6bSMatt Jacob int error; 495e770bc6bSMatt Jacob 496e770bc6bSMatt Jacob gp = pp->geom; 497e770bc6bSMatt Jacob 49825080ac4SSteven Hartland /* Error used if we have no valid consumers. */ 49980f0a89cSAlexander Motin error = (dr > 0 || dw > 0 || de > 0) ? ENXIO : 0; 50025080ac4SSteven Hartland 501e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 50225080ac4SSteven Hartland if (cp->index & MP_WITHER) 50325080ac4SSteven Hartland continue; 50425080ac4SSteven Hartland 505e770bc6bSMatt Jacob error = g_access(cp, dr, dw, de); 506e770bc6bSMatt Jacob if (error) { 507e770bc6bSMatt Jacob badcp = cp; 508e770bc6bSMatt Jacob goto fail; 509e770bc6bSMatt Jacob } 510e770bc6bSMatt Jacob } 51125080ac4SSteven Hartland 51225080ac4SSteven Hartland if (error != 0) 51325080ac4SSteven Hartland return (error); 51425080ac4SSteven Hartland 5150c883cefSAlexander Motin sc = gp->softc; 5160c883cefSAlexander Motin sc->sc_opened += dr + dw + de; 5170c883cefSAlexander Motin if (sc->sc_stopping && sc->sc_opened == 0) 5180c883cefSAlexander Motin g_multipath_destroy(gp); 51925080ac4SSteven Hartland 520e770bc6bSMatt Jacob return (0); 521e770bc6bSMatt Jacob 522e770bc6bSMatt Jacob fail: 523e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 52412f35a61SPawel Jakub Dawidek if (cp == badcp) 525e770bc6bSMatt Jacob break; 52625080ac4SSteven Hartland if (cp->index & MP_WITHER) 52725080ac4SSteven Hartland continue; 52825080ac4SSteven Hartland 529e770bc6bSMatt Jacob (void) g_access(cp, -dr, -dw, -de); 530e770bc6bSMatt Jacob } 531e770bc6bSMatt Jacob return (error); 532e770bc6bSMatt Jacob } 533e770bc6bSMatt Jacob 534e770bc6bSMatt Jacob static struct g_geom * 535e770bc6bSMatt Jacob g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md) 536e770bc6bSMatt Jacob { 537e770bc6bSMatt Jacob struct g_multipath_softc *sc; 538e770bc6bSMatt Jacob struct g_geom *gp; 539e770bc6bSMatt Jacob struct g_provider *pp; 540e770bc6bSMatt Jacob 541e770bc6bSMatt Jacob g_topology_assert(); 542e770bc6bSMatt Jacob 543e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 5440c883cefSAlexander Motin sc = gp->softc; 5450c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 5460c883cefSAlexander Motin continue; 547e770bc6bSMatt Jacob if (strcmp(gp->name, md->md_name) == 0) { 548e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: name %s already exists\n", 549e770bc6bSMatt Jacob md->md_name); 550e770bc6bSMatt Jacob return (NULL); 551e770bc6bSMatt Jacob } 552e770bc6bSMatt Jacob } 553e770bc6bSMatt Jacob 55402c62349SJaakko Heinonen gp = g_new_geomf(mp, "%s", md->md_name); 555e770bc6bSMatt Jacob sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); 5560c883cefSAlexander Motin mtx_init(&sc->sc_mtx, "multipath", NULL, MTX_DEF); 5570c883cefSAlexander Motin memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid)); 5580c883cefSAlexander Motin memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name)); 5590c883cefSAlexander Motin sc->sc_active_active = md->md_active_active; 560e6afd72bSAlexander Motin sc->sc_size = md->md_size; 561e770bc6bSMatt Jacob gp->softc = sc; 562e770bc6bSMatt Jacob gp->start = g_multipath_start; 563e770bc6bSMatt Jacob gp->orphan = g_multipath_orphan; 564e6afd72bSAlexander Motin gp->resize = g_multipath_resize; 565e770bc6bSMatt Jacob gp->access = g_multipath_access; 5660c883cefSAlexander Motin gp->dumpconf = g_multipath_dumpconf; 567e770bc6bSMatt Jacob 568e770bc6bSMatt Jacob pp = g_new_providerf(gp, "multipath/%s", md->md_name); 56940ea77a0SAlexander Motin pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; 5700c883cefSAlexander Motin if (md->md_size != 0) { 5710c883cefSAlexander Motin pp->mediasize = md->md_size - 5720c883cefSAlexander Motin ((md->md_uuid[0] != 0) ? md->md_sectorsize : 0); 573e770bc6bSMatt Jacob pp->sectorsize = md->md_sectorsize; 5740c883cefSAlexander Motin } 5750c883cefSAlexander Motin sc->sc_pp = pp; 576e770bc6bSMatt Jacob g_error_provider(pp, 0); 5770c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s created\n", gp->name); 578e770bc6bSMatt Jacob return (gp); 579e770bc6bSMatt Jacob } 580e770bc6bSMatt Jacob 581e770bc6bSMatt Jacob static int 582e770bc6bSMatt Jacob g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp) 583e770bc6bSMatt Jacob { 584e770bc6bSMatt Jacob struct g_multipath_softc *sc; 585b74fdaafSMateusz Guzik struct g_consumer *cp; 5860c883cefSAlexander Motin int error, acr, acw, ace; 587e770bc6bSMatt Jacob 588e770bc6bSMatt Jacob g_topology_assert(); 589e770bc6bSMatt Jacob 590e770bc6bSMatt Jacob sc = gp->softc; 591e770bc6bSMatt Jacob KASSERT(sc, ("no softc")); 592e770bc6bSMatt Jacob 593e770bc6bSMatt Jacob /* 594e770bc6bSMatt Jacob * Make sure that the passed provider isn't already attached 595e770bc6bSMatt Jacob */ 596e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 59712f35a61SPawel Jakub Dawidek if (cp->provider == pp) 598e770bc6bSMatt Jacob break; 599e770bc6bSMatt Jacob } 600e770bc6bSMatt Jacob if (cp) { 601e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: provider %s already attached to %s\n", 602e770bc6bSMatt Jacob pp->name, gp->name); 603e770bc6bSMatt Jacob return (EEXIST); 604e770bc6bSMatt Jacob } 605e770bc6bSMatt Jacob cp = g_new_consumer(gp); 60640ea77a0SAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 6070c883cefSAlexander Motin cp->private = NULL; 6080c883cefSAlexander Motin cp->index = MP_NEW; 609e770bc6bSMatt Jacob error = g_attach(cp, pp); 610e770bc6bSMatt Jacob if (error != 0) { 611e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot attach %s to %s", 612e770bc6bSMatt Jacob pp->name, sc->sc_name); 613e770bc6bSMatt Jacob g_destroy_consumer(cp); 614e770bc6bSMatt Jacob return (error); 615e770bc6bSMatt Jacob } 616e770bc6bSMatt Jacob 617e770bc6bSMatt Jacob /* 618e770bc6bSMatt Jacob * Set access permissions on new consumer to match other consumers 619e770bc6bSMatt Jacob */ 6200c883cefSAlexander Motin if (sc->sc_pp) { 6210c883cefSAlexander Motin acr = sc->sc_pp->acr; 6220c883cefSAlexander Motin acw = sc->sc_pp->acw; 6230c883cefSAlexander Motin ace = sc->sc_pp->ace; 6240c883cefSAlexander Motin } else 6250c883cefSAlexander Motin acr = acw = ace = 0; 6260c883cefSAlexander Motin if (g_multipath_exclusive) { 6270c883cefSAlexander Motin acr++; 6280c883cefSAlexander Motin acw++; 6290c883cefSAlexander Motin ace++; 6300c883cefSAlexander Motin } 6310c883cefSAlexander Motin error = g_access(cp, acr, acw, ace); 632e770bc6bSMatt Jacob if (error) { 633e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot set access in " 6340c883cefSAlexander Motin "attaching %s to %s (%d)\n", 6350c883cefSAlexander Motin pp->name, sc->sc_name, error); 636e770bc6bSMatt Jacob g_detach(cp); 637e770bc6bSMatt Jacob g_destroy_consumer(cp); 638e770bc6bSMatt Jacob return (error); 639e770bc6bSMatt Jacob } 640e6afd72bSAlexander Motin if (sc->sc_size == 0) { 641e6afd72bSAlexander Motin sc->sc_size = pp->mediasize - 6420c883cefSAlexander Motin ((sc->sc_uuid[0] != 0) ? pp->sectorsize : 0); 643e6afd72bSAlexander Motin sc->sc_pp->mediasize = sc->sc_size; 6440c883cefSAlexander Motin sc->sc_pp->sectorsize = pp->sectorsize; 645e770bc6bSMatt Jacob } 646e6afd72bSAlexander Motin if (sc->sc_pp->stripesize == 0 && sc->sc_pp->stripeoffset == 0) { 6470c883cefSAlexander Motin sc->sc_pp->stripesize = pp->stripesize; 6480c883cefSAlexander Motin sc->sc_pp->stripeoffset = pp->stripeoffset; 6490c883cefSAlexander Motin } 650f4673017SAlexander Motin sc->sc_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED; 6510c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 6520c883cefSAlexander Motin cp->index = 0; 6530c883cefSAlexander Motin sc->sc_ndisks++; 6540c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 6550c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s added to %s\n", 6560c883cefSAlexander Motin pp->name, sc->sc_name); 6570c883cefSAlexander Motin if (sc->sc_active == NULL) { 6580c883cefSAlexander Motin sc->sc_active = cp; 65963297dfdSAlexander Motin if (sc->sc_active_active != 1) 6600c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 661e770bc6bSMatt Jacob pp->name, sc->sc_name); 662e770bc6bSMatt Jacob } 663e770bc6bSMatt Jacob return (0); 664e770bc6bSMatt Jacob } 665e770bc6bSMatt Jacob 666e770bc6bSMatt Jacob static int 667e770bc6bSMatt Jacob g_multipath_destroy(struct g_geom *gp) 668e770bc6bSMatt Jacob { 6690c883cefSAlexander Motin struct g_multipath_softc *sc; 6700c883cefSAlexander Motin struct g_consumer *cp, *cp1; 671e770bc6bSMatt Jacob 672e770bc6bSMatt Jacob g_topology_assert(); 67312f35a61SPawel Jakub Dawidek if (gp->softc == NULL) 674e770bc6bSMatt Jacob return (ENXIO); 6750c883cefSAlexander Motin sc = gp->softc; 6760c883cefSAlexander Motin if (!sc->sc_stopping) { 677e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: destroying %s\n", gp->name); 6780c883cefSAlexander Motin sc->sc_stopping = 1; 6790c883cefSAlexander Motin } 6800c883cefSAlexander Motin if (sc->sc_opened != 0) { 6810c883cefSAlexander Motin g_wither_provider(sc->sc_pp, ENXIO); 6820c883cefSAlexander Motin sc->sc_pp = NULL; 6830c883cefSAlexander Motin return (EINPROGRESS); 6840c883cefSAlexander Motin } 6850c883cefSAlexander Motin LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 6860c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 6870c883cefSAlexander Motin if ((cp->index & MP_POSTED) == 0) { 6880c883cefSAlexander Motin cp->index |= MP_POSTED; 6890c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 6900c883cefSAlexander Motin g_mpd(cp, 0); 6910c883cefSAlexander Motin if (cp1 == NULL) 6920c883cefSAlexander Motin return(0); /* Recursion happened. */ 6930c883cefSAlexander Motin } else 6940c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 6950c883cefSAlexander Motin } 6960c883cefSAlexander Motin if (!LIST_EMPTY(&gp->consumer)) 6970c883cefSAlexander Motin return (EINPROGRESS); 6980c883cefSAlexander Motin mtx_destroy(&sc->sc_mtx); 699e770bc6bSMatt Jacob g_free(gp->softc); 700e770bc6bSMatt Jacob gp->softc = NULL; 7010c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s destroyed\n", gp->name); 702e770bc6bSMatt Jacob g_wither_geom(gp, ENXIO); 703e770bc6bSMatt Jacob return (0); 704e770bc6bSMatt Jacob } 705e770bc6bSMatt Jacob 706e770bc6bSMatt Jacob static int 707e770bc6bSMatt Jacob g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp, 708e770bc6bSMatt Jacob struct g_geom *gp) 709e770bc6bSMatt Jacob { 71012f35a61SPawel Jakub Dawidek 711e770bc6bSMatt Jacob return (g_multipath_destroy(gp)); 712e770bc6bSMatt Jacob } 713e770bc6bSMatt Jacob 714b5dce617SMatt Jacob static int 715b5dce617SMatt Jacob g_multipath_rotate(struct g_geom *gp) 716b5dce617SMatt Jacob { 7178fb378d6SThomas Quinot struct g_consumer *lcp, *first_good_cp = NULL; 718b5dce617SMatt Jacob struct g_multipath_softc *sc = gp->softc; 7198fb378d6SThomas Quinot int active_cp_seen = 0; 720b5dce617SMatt Jacob 721b5dce617SMatt Jacob g_topology_assert(); 722b5dce617SMatt Jacob if (sc == NULL) 723b5dce617SMatt Jacob return (ENXIO); 724b5dce617SMatt Jacob LIST_FOREACH(lcp, &gp->consumer, consumer) { 725b5dce617SMatt Jacob if ((lcp->index & MP_BAD) == 0) { 7268fb378d6SThomas Quinot if (first_good_cp == NULL) 7278fb378d6SThomas Quinot first_good_cp = lcp; 7288fb378d6SThomas Quinot if (active_cp_seen) 729b5dce617SMatt Jacob break; 730b5dce617SMatt Jacob } 7318fb378d6SThomas Quinot if (sc->sc_active == lcp) 7328fb378d6SThomas Quinot active_cp_seen = 1; 733b5dce617SMatt Jacob } 7348fb378d6SThomas Quinot if (lcp == NULL) 7358fb378d6SThomas Quinot lcp = first_good_cp; 7368fb378d6SThomas Quinot if (lcp && lcp != sc->sc_active) { 7370c883cefSAlexander Motin sc->sc_active = lcp; 73863297dfdSAlexander Motin if (sc->sc_active_active != 1) 7390c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 740b5dce617SMatt Jacob lcp->provider->name, sc->sc_name); 741b5dce617SMatt Jacob } 742b5dce617SMatt Jacob return (0); 743b5dce617SMatt Jacob } 744b5dce617SMatt Jacob 745e770bc6bSMatt Jacob static void 746e770bc6bSMatt Jacob g_multipath_init(struct g_class *mp) 747e770bc6bSMatt Jacob { 748e770bc6bSMatt Jacob bioq_init(&gmtbq); 749e770bc6bSMatt Jacob mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF); 75063297dfdSAlexander Motin kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt"); 751e770bc6bSMatt Jacob } 752e770bc6bSMatt Jacob 753e770bc6bSMatt Jacob static void 754e770bc6bSMatt Jacob g_multipath_fini(struct g_class *mp) 755e770bc6bSMatt Jacob { 756e770bc6bSMatt Jacob if (g_multipath_kt_state == GKT_RUN) { 757e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 758e770bc6bSMatt Jacob g_multipath_kt_state = GKT_DIE; 759e770bc6bSMatt Jacob wakeup(&g_multipath_kt_state); 760e770bc6bSMatt Jacob msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO, 761e770bc6bSMatt Jacob "gmp:fini", 0); 762e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 763e770bc6bSMatt Jacob } 764e770bc6bSMatt Jacob } 765e770bc6bSMatt Jacob 766e770bc6bSMatt Jacob static int 767e770bc6bSMatt Jacob g_multipath_read_metadata(struct g_consumer *cp, 768e770bc6bSMatt Jacob struct g_multipath_metadata *md) 769e770bc6bSMatt Jacob { 770e770bc6bSMatt Jacob struct g_provider *pp; 771e770bc6bSMatt Jacob u_char *buf; 772e770bc6bSMatt Jacob int error; 773e770bc6bSMatt Jacob 774e770bc6bSMatt Jacob g_topology_assert(); 775e770bc6bSMatt Jacob error = g_access(cp, 1, 0, 0); 77612f35a61SPawel Jakub Dawidek if (error != 0) 777e770bc6bSMatt Jacob return (error); 778e770bc6bSMatt Jacob pp = cp->provider; 779e770bc6bSMatt Jacob g_topology_unlock(); 780e770bc6bSMatt Jacob buf = g_read_data(cp, pp->mediasize - pp->sectorsize, 781e770bc6bSMatt Jacob pp->sectorsize, &error); 782e770bc6bSMatt Jacob g_topology_lock(); 783e770bc6bSMatt Jacob g_access(cp, -1, 0, 0); 78412f35a61SPawel Jakub Dawidek if (buf == NULL) 785e770bc6bSMatt Jacob return (error); 786e770bc6bSMatt Jacob multipath_metadata_decode(buf, md); 787e770bc6bSMatt Jacob g_free(buf); 788e770bc6bSMatt Jacob return (0); 789e770bc6bSMatt Jacob } 790e770bc6bSMatt Jacob 791f8c79813SAlexander Motin static int 792f8c79813SAlexander Motin g_multipath_write_metadata(struct g_consumer *cp, 793f8c79813SAlexander Motin struct g_multipath_metadata *md) 794f8c79813SAlexander Motin { 795f8c79813SAlexander Motin struct g_provider *pp; 796f8c79813SAlexander Motin u_char *buf; 797f8c79813SAlexander Motin int error; 798f8c79813SAlexander Motin 799f8c79813SAlexander Motin g_topology_assert(); 800f8c79813SAlexander Motin error = g_access(cp, 1, 1, 1); 801f8c79813SAlexander Motin if (error != 0) 802f8c79813SAlexander Motin return (error); 803f8c79813SAlexander Motin pp = cp->provider; 804f8c79813SAlexander Motin g_topology_unlock(); 805f8c79813SAlexander Motin buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 806f8c79813SAlexander Motin multipath_metadata_encode(md, buf); 807f8c79813SAlexander Motin error = g_write_data(cp, pp->mediasize - pp->sectorsize, 808f8c79813SAlexander Motin buf, pp->sectorsize); 809f8c79813SAlexander Motin g_topology_lock(); 810f8c79813SAlexander Motin g_access(cp, -1, -1, -1); 811f8c79813SAlexander Motin g_free(buf); 812f8c79813SAlexander Motin return (error); 813f8c79813SAlexander Motin } 814f8c79813SAlexander Motin 815e770bc6bSMatt Jacob static struct g_geom * 816e770bc6bSMatt Jacob g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 817e770bc6bSMatt Jacob { 818e770bc6bSMatt Jacob struct g_multipath_metadata md; 819e770bc6bSMatt Jacob struct g_multipath_softc *sc; 820e770bc6bSMatt Jacob struct g_consumer *cp; 821e770bc6bSMatt Jacob struct g_geom *gp, *gp1; 822e770bc6bSMatt Jacob int error, isnew; 823e770bc6bSMatt Jacob 824e770bc6bSMatt Jacob g_topology_assert(); 825e770bc6bSMatt Jacob 826e770bc6bSMatt Jacob gp = g_new_geomf(mp, "multipath:taste"); 827e770bc6bSMatt Jacob gp->start = g_multipath_start; 828e770bc6bSMatt Jacob gp->access = g_multipath_access; 829e770bc6bSMatt Jacob gp->orphan = g_multipath_orphan; 830e770bc6bSMatt Jacob cp = g_new_consumer(gp); 831*10ae42ccSAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 832d22ff249SEdward Tomasz Napierala error = g_attach(cp, pp); 833d22ff249SEdward Tomasz Napierala if (error == 0) { 834e770bc6bSMatt Jacob error = g_multipath_read_metadata(cp, &md); 835e770bc6bSMatt Jacob g_detach(cp); 836d22ff249SEdward Tomasz Napierala } 837e770bc6bSMatt Jacob g_destroy_consumer(cp); 838e770bc6bSMatt Jacob g_destroy_geom(gp); 83912f35a61SPawel Jakub Dawidek if (error != 0) 840e770bc6bSMatt Jacob return (NULL); 841e770bc6bSMatt Jacob gp = NULL; 842e770bc6bSMatt Jacob 843e770bc6bSMatt Jacob if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) { 84412f35a61SPawel Jakub Dawidek if (g_multipath_debug) 845e770bc6bSMatt Jacob printf("%s is not MULTIPATH\n", pp->name); 846e770bc6bSMatt Jacob return (NULL); 847e770bc6bSMatt Jacob } 848e770bc6bSMatt Jacob if (md.md_version != G_MULTIPATH_VERSION) { 849e770bc6bSMatt Jacob printf("%s has version %d multipath id- this module is version " 850e770bc6bSMatt Jacob " %d: rejecting\n", pp->name, md.md_version, 851e770bc6bSMatt Jacob G_MULTIPATH_VERSION); 852e770bc6bSMatt Jacob return (NULL); 853e770bc6bSMatt Jacob } 8540c883cefSAlexander Motin if (md.md_size != 0 && md.md_size != pp->mediasize) 8550c883cefSAlexander Motin return (NULL); 8560c883cefSAlexander Motin if (md.md_sectorsize != 0 && md.md_sectorsize != pp->sectorsize) 8570c883cefSAlexander Motin return (NULL); 85812f35a61SPawel Jakub Dawidek if (g_multipath_debug) 859e770bc6bSMatt Jacob printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid); 86067f72211SAlan Somers SDT_PROBE2(geom, multipath, config, taste, md.md_name, md.md_uuid); 861e770bc6bSMatt Jacob 862e770bc6bSMatt Jacob /* 863e770bc6bSMatt Jacob * Let's check if such a device already is present. We check against 864e770bc6bSMatt Jacob * uuid alone first because that's the true distinguishor. If that 865e770bc6bSMatt Jacob * passes, then we check for name conflicts. If there are conflicts, 866e770bc6bSMatt Jacob * modify the name. 867e770bc6bSMatt Jacob * 868e770bc6bSMatt Jacob * The whole purpose of this is to solve the problem that people don't 869e770bc6bSMatt Jacob * pick good unique names, but good unique names (like uuids) are a 870e770bc6bSMatt Jacob * pain to use. So, we allow people to build GEOMs with friendly names 871e770bc6bSMatt Jacob * and uuids, and modify the names in case there's a collision. 872e770bc6bSMatt Jacob */ 873e770bc6bSMatt Jacob sc = NULL; 874e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 875e770bc6bSMatt Jacob sc = gp->softc; 8760c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 877e770bc6bSMatt Jacob continue; 87812f35a61SPawel Jakub Dawidek if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0) 879e770bc6bSMatt Jacob break; 880e770bc6bSMatt Jacob } 881e770bc6bSMatt Jacob 882e770bc6bSMatt Jacob LIST_FOREACH(gp1, &mp->geom, geom) { 88312f35a61SPawel Jakub Dawidek if (gp1 == gp) 884e770bc6bSMatt Jacob continue; 885e770bc6bSMatt Jacob sc = gp1->softc; 8860c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 887e770bc6bSMatt Jacob continue; 88812f35a61SPawel Jakub Dawidek if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0) 889e770bc6bSMatt Jacob break; 890e770bc6bSMatt Jacob } 891e770bc6bSMatt Jacob 892e770bc6bSMatt Jacob /* 893e770bc6bSMatt Jacob * If gp is NULL, we had no extant MULTIPATH geom with this uuid. 894e770bc6bSMatt Jacob * 895e770bc6bSMatt Jacob * If gp1 is *not* NULL, that means we have a MULTIPATH geom extant 896e770bc6bSMatt Jacob * with the same name (but a different UUID). 897e770bc6bSMatt Jacob * 898e770bc6bSMatt Jacob * If gp is NULL, then modify the name with a random number and 899e770bc6bSMatt Jacob * complain, but allow the creation of the geom to continue. 900e770bc6bSMatt Jacob * 901e770bc6bSMatt Jacob * If gp is *not* NULL, just use the geom's name as we're attaching 902e770bc6bSMatt Jacob * this disk to the (previously generated) name. 903e770bc6bSMatt Jacob */ 904e770bc6bSMatt Jacob 905e770bc6bSMatt Jacob if (gp1) { 906e770bc6bSMatt Jacob sc = gp1->softc; 907e770bc6bSMatt Jacob if (gp == NULL) { 908e770bc6bSMatt Jacob char buf[16]; 909e770bc6bSMatt Jacob u_long rand = random(); 910e770bc6bSMatt Jacob 911e770bc6bSMatt Jacob snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand); 912e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: geom %s/%s exists already\n", 913e770bc6bSMatt Jacob sc->sc_name, sc->sc_uuid); 914e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n", 915e770bc6bSMatt Jacob md.md_uuid, buf); 916e770bc6bSMatt Jacob strlcpy(md.md_name, buf, sizeof(md.md_name)); 917e770bc6bSMatt Jacob } else { 918e770bc6bSMatt Jacob strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name)); 919e770bc6bSMatt Jacob } 920e770bc6bSMatt Jacob } 921e770bc6bSMatt Jacob 922e770bc6bSMatt Jacob if (gp == NULL) { 923e770bc6bSMatt Jacob gp = g_multipath_create(mp, &md); 924e770bc6bSMatt Jacob if (gp == NULL) { 925e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot create geom %s/%s\n", 926e770bc6bSMatt Jacob md.md_name, md.md_uuid); 927e770bc6bSMatt Jacob return (NULL); 928e770bc6bSMatt Jacob } 929e770bc6bSMatt Jacob isnew = 1; 930e770bc6bSMatt Jacob } else { 931e770bc6bSMatt Jacob isnew = 0; 932e770bc6bSMatt Jacob } 933e770bc6bSMatt Jacob 934e770bc6bSMatt Jacob sc = gp->softc; 935e770bc6bSMatt Jacob KASSERT(sc != NULL, ("sc is NULL")); 936e770bc6bSMatt Jacob error = g_multipath_add_disk(gp, pp); 937e770bc6bSMatt Jacob if (error != 0) { 93812f35a61SPawel Jakub Dawidek if (isnew) 939e770bc6bSMatt Jacob g_multipath_destroy(gp); 940e770bc6bSMatt Jacob return (NULL); 941e770bc6bSMatt Jacob } 942e770bc6bSMatt Jacob return (gp); 943e770bc6bSMatt Jacob } 944e770bc6bSMatt Jacob 945e770bc6bSMatt Jacob static void 9460c883cefSAlexander Motin g_multipath_ctl_add_name(struct gctl_req *req, struct g_class *mp, 9470c883cefSAlexander Motin const char *name) 948e770bc6bSMatt Jacob { 9490c883cefSAlexander Motin struct g_multipath_softc *sc; 950e770bc6bSMatt Jacob struct g_geom *gp; 9512b4969ffSMatt Jacob struct g_consumer *cp; 9520c883cefSAlexander Motin struct g_provider *pp; 9530c883cefSAlexander Motin const char *mpname; 9548510f61aSXin LI static const char devpf[6] = _PATH_DEV; 955d3fef0a0SAlexander Motin int error; 956e770bc6bSMatt Jacob 957e770bc6bSMatt Jacob g_topology_assert(); 958e770bc6bSMatt Jacob 959e770bc6bSMatt Jacob mpname = gctl_get_asciiparam(req, "arg0"); 960e770bc6bSMatt Jacob if (mpname == NULL) { 961e770bc6bSMatt Jacob gctl_error(req, "No 'arg0' argument"); 962e770bc6bSMatt Jacob return; 963e770bc6bSMatt Jacob } 9642b4969ffSMatt Jacob gp = g_multipath_find_geom(mp, mpname); 9652b4969ffSMatt Jacob if (gp == NULL) { 9662b4969ffSMatt Jacob gctl_error(req, "Device %s is invalid", mpname); 967e770bc6bSMatt Jacob return; 968e770bc6bSMatt Jacob } 9690c883cefSAlexander Motin sc = gp->softc; 970e770bc6bSMatt Jacob 97112f35a61SPawel Jakub Dawidek if (strncmp(name, devpf, 5) == 0) 972e770bc6bSMatt Jacob name += 5; 9732b4969ffSMatt Jacob pp = g_provider_by_name(name); 9742b4969ffSMatt Jacob if (pp == NULL) { 975e770bc6bSMatt Jacob gctl_error(req, "Provider %s is invalid", name); 976e770bc6bSMatt Jacob return; 977e770bc6bSMatt Jacob } 978e770bc6bSMatt Jacob 979e770bc6bSMatt Jacob /* 9800c883cefSAlexander Motin * Check to make sure parameters match. 981e770bc6bSMatt Jacob */ 9820c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 9830c883cefSAlexander Motin if (cp->provider == pp) { 9840c883cefSAlexander Motin gctl_error(req, "provider %s is already there", 9850c883cefSAlexander Motin pp->name); 986e770bc6bSMatt Jacob return; 987e770bc6bSMatt Jacob } 9880c883cefSAlexander Motin } 989e6afd72bSAlexander Motin if (sc->sc_pp->mediasize != 0 && 9900c883cefSAlexander Motin sc->sc_pp->mediasize + (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0) 9910c883cefSAlexander Motin != pp->mediasize) { 9920c883cefSAlexander Motin gctl_error(req, "Providers size mismatch %jd != %jd", 9930c883cefSAlexander Motin (intmax_t) sc->sc_pp->mediasize + 9940c883cefSAlexander Motin (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0), 9950c883cefSAlexander Motin (intmax_t) pp->mediasize); 996e770bc6bSMatt Jacob return; 997e770bc6bSMatt Jacob } 998e6afd72bSAlexander Motin if (sc->sc_pp->sectorsize != 0 && 9990c883cefSAlexander Motin sc->sc_pp->sectorsize != pp->sectorsize) { 10000c883cefSAlexander Motin gctl_error(req, "Providers sectorsize mismatch %u != %u", 10010c883cefSAlexander Motin sc->sc_pp->sectorsize, pp->sectorsize); 1002e770bc6bSMatt Jacob return; 1003e770bc6bSMatt Jacob } 1004e770bc6bSMatt Jacob 1005d3fef0a0SAlexander Motin error = g_multipath_add_disk(gp, pp); 1006d3fef0a0SAlexander Motin if (error != 0) 1007d3fef0a0SAlexander Motin gctl_error(req, "Provider addition error: %d", error); 1008e770bc6bSMatt Jacob } 1009e770bc6bSMatt Jacob 10100c883cefSAlexander Motin static void 101171ee4ef0SThomas Quinot g_multipath_ctl_prefer(struct gctl_req *req, struct g_class *mp) 101271ee4ef0SThomas Quinot { 101371ee4ef0SThomas Quinot struct g_geom *gp; 101471ee4ef0SThomas Quinot struct g_multipath_softc *sc; 101571ee4ef0SThomas Quinot struct g_consumer *cp; 101671ee4ef0SThomas Quinot const char *name, *mpname; 10178510f61aSXin LI static const char devpf[6] = _PATH_DEV; 101871ee4ef0SThomas Quinot int *nargs; 101971ee4ef0SThomas Quinot 102071ee4ef0SThomas Quinot g_topology_assert(); 102171ee4ef0SThomas Quinot 102271ee4ef0SThomas Quinot mpname = gctl_get_asciiparam(req, "arg0"); 102371ee4ef0SThomas Quinot if (mpname == NULL) { 102471ee4ef0SThomas Quinot gctl_error(req, "No 'arg0' argument"); 102571ee4ef0SThomas Quinot return; 102671ee4ef0SThomas Quinot } 102771ee4ef0SThomas Quinot gp = g_multipath_find_geom(mp, mpname); 102871ee4ef0SThomas Quinot if (gp == NULL) { 102971ee4ef0SThomas Quinot gctl_error(req, "Device %s is invalid", mpname); 103071ee4ef0SThomas Quinot return; 103171ee4ef0SThomas Quinot } 103271ee4ef0SThomas Quinot sc = gp->softc; 103371ee4ef0SThomas Quinot 103471ee4ef0SThomas Quinot nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 103571ee4ef0SThomas Quinot if (nargs == NULL) { 103671ee4ef0SThomas Quinot gctl_error(req, "No 'nargs' argument"); 103771ee4ef0SThomas Quinot return; 103871ee4ef0SThomas Quinot } 103971ee4ef0SThomas Quinot if (*nargs != 2) { 104071ee4ef0SThomas Quinot gctl_error(req, "missing device"); 104171ee4ef0SThomas Quinot return; 104271ee4ef0SThomas Quinot } 104371ee4ef0SThomas Quinot 104471ee4ef0SThomas Quinot name = gctl_get_asciiparam(req, "arg1"); 104571ee4ef0SThomas Quinot if (name == NULL) { 104671ee4ef0SThomas Quinot gctl_error(req, "No 'arg1' argument"); 104771ee4ef0SThomas Quinot return; 104871ee4ef0SThomas Quinot } 104971ee4ef0SThomas Quinot if (strncmp(name, devpf, 5) == 0) { 105071ee4ef0SThomas Quinot name += 5; 105171ee4ef0SThomas Quinot } 105271ee4ef0SThomas Quinot 105371ee4ef0SThomas Quinot LIST_FOREACH(cp, &gp->consumer, consumer) { 105471ee4ef0SThomas Quinot if (cp->provider != NULL 105571ee4ef0SThomas Quinot && strcmp(cp->provider->name, name) == 0) 105671ee4ef0SThomas Quinot break; 105771ee4ef0SThomas Quinot } 105871ee4ef0SThomas Quinot 105971ee4ef0SThomas Quinot if (cp == NULL) { 106071ee4ef0SThomas Quinot gctl_error(req, "Provider %s not found", name); 106171ee4ef0SThomas Quinot return; 106271ee4ef0SThomas Quinot } 106371ee4ef0SThomas Quinot 106471ee4ef0SThomas Quinot mtx_lock(&sc->sc_mtx); 106571ee4ef0SThomas Quinot 106671ee4ef0SThomas Quinot if (cp->index & MP_BAD) { 106771ee4ef0SThomas Quinot gctl_error(req, "Consumer %s is invalid", name); 106871ee4ef0SThomas Quinot mtx_unlock(&sc->sc_mtx); 106971ee4ef0SThomas Quinot return; 107071ee4ef0SThomas Quinot } 107171ee4ef0SThomas Quinot 107271ee4ef0SThomas Quinot /* Here when the consumer is present and in good shape */ 107371ee4ef0SThomas Quinot 107471ee4ef0SThomas Quinot sc->sc_active = cp; 107571ee4ef0SThomas Quinot if (!sc->sc_active_active) 107671ee4ef0SThomas Quinot printf("GEOM_MULTIPATH: %s now active path in %s\n", 107771ee4ef0SThomas Quinot sc->sc_active->provider->name, sc->sc_name); 107871ee4ef0SThomas Quinot 107971ee4ef0SThomas Quinot mtx_unlock(&sc->sc_mtx); 108071ee4ef0SThomas Quinot } 108171ee4ef0SThomas Quinot 108271ee4ef0SThomas Quinot static void 10830c883cefSAlexander Motin g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp) 10840c883cefSAlexander Motin { 10850c883cefSAlexander Motin struct g_geom *gp; 10860c883cefSAlexander Motin const char *mpname, *name; 10870c883cefSAlexander Motin 10880c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 10890c883cefSAlexander Motin if (mpname == NULL) { 10900c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 10910c883cefSAlexander Motin return; 10920c883cefSAlexander Motin } 10930c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 10940c883cefSAlexander Motin if (gp == NULL) { 10950c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 10960c883cefSAlexander Motin return; 10970c883cefSAlexander Motin } 10980c883cefSAlexander Motin 10990c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 11000c883cefSAlexander Motin if (name == NULL) { 11010c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 11020c883cefSAlexander Motin return; 11030c883cefSAlexander Motin } 11040c883cefSAlexander Motin g_multipath_ctl_add_name(req, mp, name); 11050c883cefSAlexander Motin } 11060c883cefSAlexander Motin 11070c883cefSAlexander Motin static void 11080c883cefSAlexander Motin g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp) 11090c883cefSAlexander Motin { 11100c883cefSAlexander Motin struct g_multipath_metadata md; 11110c883cefSAlexander Motin struct g_multipath_softc *sc; 11120c883cefSAlexander Motin struct g_geom *gp; 11130c883cefSAlexander Motin const char *mpname, *name; 11140c883cefSAlexander Motin char param[16]; 111563297dfdSAlexander Motin int *nargs, i, *val; 11160c883cefSAlexander Motin 11170c883cefSAlexander Motin g_topology_assert(); 11180c883cefSAlexander Motin 11190c883cefSAlexander Motin nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 11200c883cefSAlexander Motin if (*nargs < 2) { 11210c883cefSAlexander Motin gctl_error(req, "wrong number of arguments."); 11220c883cefSAlexander Motin return; 11230c883cefSAlexander Motin } 11240c883cefSAlexander Motin 11250c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 11260c883cefSAlexander Motin if (mpname == NULL) { 11270c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 11280c883cefSAlexander Motin return; 11290c883cefSAlexander Motin } 11300c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 11310c883cefSAlexander Motin if (gp != NULL) { 11320c883cefSAlexander Motin gctl_error(req, "Device %s already exist", mpname); 11330c883cefSAlexander Motin return; 11340c883cefSAlexander Motin } 11350c883cefSAlexander Motin 11360c883cefSAlexander Motin memset(&md, 0, sizeof(md)); 11370c883cefSAlexander Motin strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 11380c883cefSAlexander Motin md.md_version = G_MULTIPATH_VERSION; 11390c883cefSAlexander Motin strlcpy(md.md_name, mpname, sizeof(md.md_name)); 11400c883cefSAlexander Motin md.md_size = 0; 11410c883cefSAlexander Motin md.md_sectorsize = 0; 11420c883cefSAlexander Motin md.md_uuid[0] = 0; 114363297dfdSAlexander Motin md.md_active_active = 0; 114463297dfdSAlexander Motin val = gctl_get_paraml(req, "active_active", sizeof(*val)); 114563297dfdSAlexander Motin if (val != NULL && *val != 0) 114663297dfdSAlexander Motin md.md_active_active = 1; 114763297dfdSAlexander Motin val = gctl_get_paraml(req, "active_read", sizeof(*val)); 114863297dfdSAlexander Motin if (val != NULL && *val != 0) 114963297dfdSAlexander Motin md.md_active_active = 2; 11500c883cefSAlexander Motin gp = g_multipath_create(mp, &md); 11510c883cefSAlexander Motin if (gp == NULL) { 11520c883cefSAlexander Motin gctl_error(req, "GEOM_MULTIPATH: cannot create geom %s/%s\n", 11530c883cefSAlexander Motin md.md_name, md.md_uuid); 11540c883cefSAlexander Motin return; 11550c883cefSAlexander Motin } 11560c883cefSAlexander Motin sc = gp->softc; 11570c883cefSAlexander Motin 11580c883cefSAlexander Motin for (i = 1; i < *nargs; i++) { 11590c883cefSAlexander Motin snprintf(param, sizeof(param), "arg%d", i); 11600c883cefSAlexander Motin name = gctl_get_asciiparam(req, param); 11610c883cefSAlexander Motin g_multipath_ctl_add_name(req, mp, name); 11620c883cefSAlexander Motin } 11630c883cefSAlexander Motin 11640c883cefSAlexander Motin if (sc->sc_ndisks != (*nargs - 1)) 11650c883cefSAlexander Motin g_multipath_destroy(gp); 11660c883cefSAlexander Motin } 11670c883cefSAlexander Motin 11680c883cefSAlexander Motin static void 116963297dfdSAlexander Motin g_multipath_ctl_configure(struct gctl_req *req, struct g_class *mp) 117063297dfdSAlexander Motin { 117163297dfdSAlexander Motin struct g_multipath_softc *sc; 117263297dfdSAlexander Motin struct g_geom *gp; 117363297dfdSAlexander Motin struct g_consumer *cp; 117463297dfdSAlexander Motin struct g_provider *pp; 1175c0b1ef66SAlexander Motin struct g_multipath_metadata md; 117663297dfdSAlexander Motin const char *name; 117763297dfdSAlexander Motin int error, *val; 117863297dfdSAlexander Motin 117963297dfdSAlexander Motin g_topology_assert(); 118063297dfdSAlexander Motin 118163297dfdSAlexander Motin name = gctl_get_asciiparam(req, "arg0"); 118263297dfdSAlexander Motin if (name == NULL) { 118363297dfdSAlexander Motin gctl_error(req, "No 'arg0' argument"); 118463297dfdSAlexander Motin return; 118563297dfdSAlexander Motin } 118663297dfdSAlexander Motin gp = g_multipath_find_geom(mp, name); 118763297dfdSAlexander Motin if (gp == NULL) { 118863297dfdSAlexander Motin gctl_error(req, "Device %s is invalid", name); 118963297dfdSAlexander Motin return; 119063297dfdSAlexander Motin } 119163297dfdSAlexander Motin sc = gp->softc; 119263297dfdSAlexander Motin val = gctl_get_paraml(req, "active_active", sizeof(*val)); 119363297dfdSAlexander Motin if (val != NULL && *val != 0) 119463297dfdSAlexander Motin sc->sc_active_active = 1; 119563297dfdSAlexander Motin val = gctl_get_paraml(req, "active_read", sizeof(*val)); 119663297dfdSAlexander Motin if (val != NULL && *val != 0) 119763297dfdSAlexander Motin sc->sc_active_active = 2; 119863297dfdSAlexander Motin val = gctl_get_paraml(req, "active_passive", sizeof(*val)); 119963297dfdSAlexander Motin if (val != NULL && *val != 0) 120063297dfdSAlexander Motin sc->sc_active_active = 0; 120163297dfdSAlexander Motin if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) { 120263297dfdSAlexander Motin cp = sc->sc_active; 120363297dfdSAlexander Motin pp = cp->provider; 1204c0b1ef66SAlexander Motin strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 1205c0b1ef66SAlexander Motin memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid)); 1206c0b1ef66SAlexander Motin strlcpy(md.md_name, name, sizeof(md.md_name)); 1207c0b1ef66SAlexander Motin md.md_version = G_MULTIPATH_VERSION; 1208c0b1ef66SAlexander Motin md.md_size = pp->mediasize; 1209c0b1ef66SAlexander Motin md.md_sectorsize = pp->sectorsize; 1210c0b1ef66SAlexander Motin md.md_active_active = sc->sc_active_active; 1211f8c79813SAlexander Motin error = g_multipath_write_metadata(cp, &md); 121263297dfdSAlexander Motin if (error != 0) 121363297dfdSAlexander Motin gctl_error(req, "Can't update metadata on %s (%d)", 121463297dfdSAlexander Motin pp->name, error); 121563297dfdSAlexander Motin } 121663297dfdSAlexander Motin } 121763297dfdSAlexander Motin 121863297dfdSAlexander Motin static void 12190c883cefSAlexander Motin g_multipath_ctl_fail(struct gctl_req *req, struct g_class *mp, int fail) 12200c883cefSAlexander Motin { 12210c883cefSAlexander Motin struct g_multipath_softc *sc; 12220c883cefSAlexander Motin struct g_geom *gp; 12230c883cefSAlexander Motin struct g_consumer *cp; 12240c883cefSAlexander Motin const char *mpname, *name; 12250c883cefSAlexander Motin int found; 12260c883cefSAlexander Motin 12270c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 12280c883cefSAlexander Motin if (mpname == NULL) { 12290c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 12300c883cefSAlexander Motin return; 12310c883cefSAlexander Motin } 12320c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 12330c883cefSAlexander Motin if (gp == NULL) { 12340c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 12350c883cefSAlexander Motin return; 12360c883cefSAlexander Motin } 12370c883cefSAlexander Motin sc = gp->softc; 12380c883cefSAlexander Motin 12390c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 12400c883cefSAlexander Motin if (name == NULL) { 12410c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 12420c883cefSAlexander Motin return; 12430c883cefSAlexander Motin } 12440c883cefSAlexander Motin 12450c883cefSAlexander Motin found = 0; 12460c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 12470c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 12480c883cefSAlexander Motin if (cp->provider != NULL && 12490c883cefSAlexander Motin strcmp(cp->provider->name, name) == 0 && 12500c883cefSAlexander Motin (cp->index & MP_LOST) == 0) { 12510c883cefSAlexander Motin found = 1; 125263297dfdSAlexander Motin if (!fail == !(cp->index & MP_FAIL)) 125363297dfdSAlexander Motin continue; 12540c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s in %s is marked %s.\n", 12550c883cefSAlexander Motin name, sc->sc_name, fail ? "FAIL" : "OK"); 12560c883cefSAlexander Motin if (fail) { 12570c883cefSAlexander Motin g_multipath_fault(cp, MP_FAIL); 125867f72211SAlan Somers SDT_PROBE3(geom, multipath, config, fail, 125967f72211SAlan Somers sc->sc_name, cp->provider->name, 0); 12600c883cefSAlexander Motin } else { 12610c883cefSAlexander Motin cp->index &= ~MP_FAIL; 126267f72211SAlan Somers SDT_PROBE2(geom, multipath, config, restore, 126367f72211SAlan Somers sc->sc_name, cp->provider->name); 12640c883cefSAlexander Motin } 12650c883cefSAlexander Motin } 12660c883cefSAlexander Motin } 12670c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 12680c883cefSAlexander Motin if (found == 0) 12690c883cefSAlexander Motin gctl_error(req, "Provider %s not found", name); 12700c883cefSAlexander Motin } 12710c883cefSAlexander Motin 12720c883cefSAlexander Motin static void 12730c883cefSAlexander Motin g_multipath_ctl_remove(struct gctl_req *req, struct g_class *mp) 12740c883cefSAlexander Motin { 12750c883cefSAlexander Motin struct g_multipath_softc *sc; 12760c883cefSAlexander Motin struct g_geom *gp; 12770c883cefSAlexander Motin struct g_consumer *cp, *cp1; 12780c883cefSAlexander Motin const char *mpname, *name; 12790c883cefSAlexander Motin uintptr_t *cnt; 12800c883cefSAlexander Motin int found; 12810c883cefSAlexander Motin 12820c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 12830c883cefSAlexander Motin if (mpname == NULL) { 12840c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 12850c883cefSAlexander Motin return; 12860c883cefSAlexander Motin } 12870c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 12880c883cefSAlexander Motin if (gp == NULL) { 12890c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 12900c883cefSAlexander Motin return; 12910c883cefSAlexander Motin } 12920c883cefSAlexander Motin sc = gp->softc; 12930c883cefSAlexander Motin 12940c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 12950c883cefSAlexander Motin if (name == NULL) { 12960c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 12970c883cefSAlexander Motin return; 12980c883cefSAlexander Motin } 12990c883cefSAlexander Motin 13000c883cefSAlexander Motin found = 0; 13010c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 13020c883cefSAlexander Motin LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 13030c883cefSAlexander Motin if (cp->provider != NULL && 13040c883cefSAlexander Motin strcmp(cp->provider->name, name) == 0 && 13050c883cefSAlexander Motin (cp->index & MP_LOST) == 0) { 13060c883cefSAlexander Motin found = 1; 13070c883cefSAlexander Motin printf("GEOM_MULTIPATH: removing %s from %s\n", 13080c883cefSAlexander Motin cp->provider->name, cp->geom->name); 130967f72211SAlan Somers SDT_PROBE2(geom, multipath, config, remove, 131067f72211SAlan Somers cp->geom->name, cp->provider->name); 13110c883cefSAlexander Motin sc->sc_ndisks--; 13120c883cefSAlexander Motin g_multipath_fault(cp, MP_LOST); 13130c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 13140c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_POSTED) == 0) { 13150c883cefSAlexander Motin cp->index |= MP_POSTED; 13160c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 13170c883cefSAlexander Motin g_mpd(cp, 0); 13180c883cefSAlexander Motin if (cp1 == NULL) 13190c883cefSAlexander Motin return; /* Recursion happened. */ 13200c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 13210c883cefSAlexander Motin } 13220c883cefSAlexander Motin } 13230c883cefSAlexander Motin } 13240c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 13250c883cefSAlexander Motin if (found == 0) 13260c883cefSAlexander Motin gctl_error(req, "Provider %s not found", name); 13270c883cefSAlexander Motin } 13280c883cefSAlexander Motin 1329e770bc6bSMatt Jacob static struct g_geom * 1330e770bc6bSMatt Jacob g_multipath_find_geom(struct g_class *mp, const char *name) 1331e770bc6bSMatt Jacob { 1332e770bc6bSMatt Jacob struct g_geom *gp; 13330c883cefSAlexander Motin struct g_multipath_softc *sc; 1334e770bc6bSMatt Jacob 1335e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 13360c883cefSAlexander Motin sc = gp->softc; 13370c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 13380c883cefSAlexander Motin continue; 13390c883cefSAlexander Motin if (strcmp(gp->name, name) == 0) 1340e770bc6bSMatt Jacob return (gp); 1341e770bc6bSMatt Jacob } 1342e770bc6bSMatt Jacob return (NULL); 1343e770bc6bSMatt Jacob } 1344e770bc6bSMatt Jacob 1345e770bc6bSMatt Jacob static void 13460c883cefSAlexander Motin g_multipath_ctl_stop(struct gctl_req *req, struct g_class *mp) 1347e770bc6bSMatt Jacob { 1348e770bc6bSMatt Jacob struct g_geom *gp; 1349e770bc6bSMatt Jacob const char *name; 1350e770bc6bSMatt Jacob int error; 1351e770bc6bSMatt Jacob 1352e770bc6bSMatt Jacob g_topology_assert(); 1353e770bc6bSMatt Jacob 1354e770bc6bSMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1355e770bc6bSMatt Jacob if (name == NULL) { 1356e770bc6bSMatt Jacob gctl_error(req, "No 'arg0' argument"); 1357e770bc6bSMatt Jacob return; 1358e770bc6bSMatt Jacob } 1359e770bc6bSMatt Jacob gp = g_multipath_find_geom(mp, name); 1360e770bc6bSMatt Jacob if (gp == NULL) { 1361e770bc6bSMatt Jacob gctl_error(req, "Device %s is invalid", name); 1362e770bc6bSMatt Jacob return; 1363e770bc6bSMatt Jacob } 1364e770bc6bSMatt Jacob error = g_multipath_destroy(gp); 13650c883cefSAlexander Motin if (error != 0 && error != EINPROGRESS) 13660c883cefSAlexander Motin gctl_error(req, "failed to stop %s (err=%d)", name, error); 1367e770bc6bSMatt Jacob } 13680c883cefSAlexander Motin 13690c883cefSAlexander Motin static void 13700c883cefSAlexander Motin g_multipath_ctl_destroy(struct gctl_req *req, struct g_class *mp) 13710c883cefSAlexander Motin { 13720c883cefSAlexander Motin struct g_geom *gp; 13730c883cefSAlexander Motin struct g_multipath_softc *sc; 13740c883cefSAlexander Motin struct g_consumer *cp; 13750c883cefSAlexander Motin struct g_provider *pp; 13760c883cefSAlexander Motin const char *name; 13770c883cefSAlexander Motin uint8_t *buf; 13780c883cefSAlexander Motin int error; 13790c883cefSAlexander Motin 13800c883cefSAlexander Motin g_topology_assert(); 13810c883cefSAlexander Motin 13820c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg0"); 13830c883cefSAlexander Motin if (name == NULL) { 13840c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 13850c883cefSAlexander Motin return; 13860c883cefSAlexander Motin } 13870c883cefSAlexander Motin gp = g_multipath_find_geom(mp, name); 13880c883cefSAlexander Motin if (gp == NULL) { 13890c883cefSAlexander Motin gctl_error(req, "Device %s is invalid", name); 13900c883cefSAlexander Motin return; 13910c883cefSAlexander Motin } 13920c883cefSAlexander Motin sc = gp->softc; 13930c883cefSAlexander Motin 13940c883cefSAlexander Motin if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) { 13950c883cefSAlexander Motin cp = sc->sc_active; 13960c883cefSAlexander Motin pp = cp->provider; 13970c883cefSAlexander Motin error = g_access(cp, 1, 1, 1); 13980c883cefSAlexander Motin if (error != 0) { 13990c883cefSAlexander Motin gctl_error(req, "Can't open %s (%d)", pp->name, error); 14000c883cefSAlexander Motin goto destroy; 14010c883cefSAlexander Motin } 14020c883cefSAlexander Motin g_topology_unlock(); 14030c883cefSAlexander Motin buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 14040c883cefSAlexander Motin error = g_write_data(cp, pp->mediasize - pp->sectorsize, 14050c883cefSAlexander Motin buf, pp->sectorsize); 14060c883cefSAlexander Motin g_topology_lock(); 14070c883cefSAlexander Motin g_access(cp, -1, -1, -1); 14080c883cefSAlexander Motin if (error != 0) 14090c883cefSAlexander Motin gctl_error(req, "Can't erase metadata on %s (%d)", 14100c883cefSAlexander Motin pp->name, error); 14110c883cefSAlexander Motin } 14120c883cefSAlexander Motin 14130c883cefSAlexander Motin destroy: 14140c883cefSAlexander Motin error = g_multipath_destroy(gp); 14150c883cefSAlexander Motin if (error != 0 && error != EINPROGRESS) 14160c883cefSAlexander Motin gctl_error(req, "failed to destroy %s (err=%d)", name, error); 1417e770bc6bSMatt Jacob } 1418e770bc6bSMatt Jacob 1419e770bc6bSMatt Jacob static void 1420b5dce617SMatt Jacob g_multipath_ctl_rotate(struct gctl_req *req, struct g_class *mp) 1421b5dce617SMatt Jacob { 1422b5dce617SMatt Jacob struct g_geom *gp; 1423b5dce617SMatt Jacob const char *name; 1424b5dce617SMatt Jacob int error; 1425b5dce617SMatt Jacob 1426b5dce617SMatt Jacob g_topology_assert(); 1427b5dce617SMatt Jacob 1428b5dce617SMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1429b5dce617SMatt Jacob if (name == NULL) { 1430b5dce617SMatt Jacob gctl_error(req, "No 'arg0' argument"); 1431b5dce617SMatt Jacob return; 1432b5dce617SMatt Jacob } 1433b5dce617SMatt Jacob gp = g_multipath_find_geom(mp, name); 1434b5dce617SMatt Jacob if (gp == NULL) { 1435b5dce617SMatt Jacob gctl_error(req, "Device %s is invalid", name); 1436b5dce617SMatt Jacob return; 1437b5dce617SMatt Jacob } 1438b5dce617SMatt Jacob error = g_multipath_rotate(gp); 1439b5dce617SMatt Jacob if (error != 0) { 1440b5dce617SMatt Jacob gctl_error(req, "failed to rotate %s (err=%d)", name, error); 1441b5dce617SMatt Jacob } 1442b5dce617SMatt Jacob } 1443b5dce617SMatt Jacob 1444b5dce617SMatt Jacob static void 1445b5dce617SMatt Jacob g_multipath_ctl_getactive(struct gctl_req *req, struct g_class *mp) 1446b5dce617SMatt Jacob { 1447b5dce617SMatt Jacob struct sbuf *sb; 1448b5dce617SMatt Jacob struct g_geom *gp; 1449b5dce617SMatt Jacob struct g_multipath_softc *sc; 14500c883cefSAlexander Motin struct g_consumer *cp; 1451b5dce617SMatt Jacob const char *name; 14520c883cefSAlexander Motin int empty; 1453b5dce617SMatt Jacob 1454b5dce617SMatt Jacob sb = sbuf_new_auto(); 1455b5dce617SMatt Jacob 1456b5dce617SMatt Jacob g_topology_assert(); 1457b5dce617SMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1458b5dce617SMatt Jacob if (name == NULL) { 1459b5dce617SMatt Jacob gctl_error(req, "No 'arg0' argument"); 1460b5dce617SMatt Jacob return; 1461b5dce617SMatt Jacob } 1462b5dce617SMatt Jacob gp = g_multipath_find_geom(mp, name); 1463b5dce617SMatt Jacob if (gp == NULL) { 1464b5dce617SMatt Jacob gctl_error(req, "Device %s is invalid", name); 1465b5dce617SMatt Jacob return; 1466b5dce617SMatt Jacob } 1467b5dce617SMatt Jacob sc = gp->softc; 146863297dfdSAlexander Motin if (sc->sc_active_active == 1) { 14690c883cefSAlexander Motin empty = 1; 14700c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 14710c883cefSAlexander Motin if (cp->index & MP_BAD) 14720c883cefSAlexander Motin continue; 14730c883cefSAlexander Motin if (!empty) 14740c883cefSAlexander Motin sbuf_cat(sb, " "); 14750c883cefSAlexander Motin sbuf_cat(sb, cp->provider->name); 14760c883cefSAlexander Motin empty = 0; 14770c883cefSAlexander Motin } 14780c883cefSAlexander Motin if (empty) 14790c883cefSAlexander Motin sbuf_cat(sb, "none"); 14800c883cefSAlexander Motin sbuf_cat(sb, "\n"); 14810c883cefSAlexander Motin } else if (sc->sc_active && sc->sc_active->provider) { 14820c883cefSAlexander Motin sbuf_printf(sb, "%s\n", sc->sc_active->provider->name); 1483b5dce617SMatt Jacob } else { 148449ee0fceSAlexander Motin sbuf_cat(sb, "none\n"); 1485b5dce617SMatt Jacob } 1486b5dce617SMatt Jacob sbuf_finish(sb); 1487b5dce617SMatt Jacob gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1488b5dce617SMatt Jacob sbuf_delete(sb); 1489b5dce617SMatt Jacob } 1490b5dce617SMatt Jacob 1491b5dce617SMatt Jacob static void 1492e770bc6bSMatt Jacob g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb) 1493e770bc6bSMatt Jacob { 1494e770bc6bSMatt Jacob uint32_t *version; 1495e770bc6bSMatt Jacob g_topology_assert(); 1496e770bc6bSMatt Jacob version = gctl_get_paraml(req, "version", sizeof(*version)); 1497e770bc6bSMatt Jacob if (version == NULL) { 1498e770bc6bSMatt Jacob gctl_error(req, "No 'version' argument"); 1499e770bc6bSMatt Jacob } else if (*version != G_MULTIPATH_VERSION) { 1500e770bc6bSMatt Jacob gctl_error(req, "Userland and kernel parts are out of sync"); 15012b4969ffSMatt Jacob } else if (strcmp(verb, "add") == 0) { 15022b4969ffSMatt Jacob g_multipath_ctl_add(req, mp); 150371ee4ef0SThomas Quinot } else if (strcmp(verb, "prefer") == 0) { 150471ee4ef0SThomas Quinot g_multipath_ctl_prefer(req, mp); 15050c883cefSAlexander Motin } else if (strcmp(verb, "create") == 0) { 15060c883cefSAlexander Motin g_multipath_ctl_create(req, mp); 150763297dfdSAlexander Motin } else if (strcmp(verb, "configure") == 0) { 150863297dfdSAlexander Motin g_multipath_ctl_configure(req, mp); 15090c883cefSAlexander Motin } else if (strcmp(verb, "stop") == 0) { 15100c883cefSAlexander Motin g_multipath_ctl_stop(req, mp); 1511e770bc6bSMatt Jacob } else if (strcmp(verb, "destroy") == 0) { 1512e770bc6bSMatt Jacob g_multipath_ctl_destroy(req, mp); 15130c883cefSAlexander Motin } else if (strcmp(verb, "fail") == 0) { 15140c883cefSAlexander Motin g_multipath_ctl_fail(req, mp, 1); 15150c883cefSAlexander Motin } else if (strcmp(verb, "restore") == 0) { 15160c883cefSAlexander Motin g_multipath_ctl_fail(req, mp, 0); 15170c883cefSAlexander Motin } else if (strcmp(verb, "remove") == 0) { 15180c883cefSAlexander Motin g_multipath_ctl_remove(req, mp); 1519b5dce617SMatt Jacob } else if (strcmp(verb, "rotate") == 0) { 1520b5dce617SMatt Jacob g_multipath_ctl_rotate(req, mp); 1521b5dce617SMatt Jacob } else if (strcmp(verb, "getactive") == 0) { 1522b5dce617SMatt Jacob g_multipath_ctl_getactive(req, mp); 1523e770bc6bSMatt Jacob } else { 1524e770bc6bSMatt Jacob gctl_error(req, "Unknown verb %s", verb); 1525e770bc6bSMatt Jacob } 1526e770bc6bSMatt Jacob } 15270c883cefSAlexander Motin 15280c883cefSAlexander Motin static void 15290c883cefSAlexander Motin g_multipath_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 15300c883cefSAlexander Motin struct g_consumer *cp, struct g_provider *pp) 15310c883cefSAlexander Motin { 15320c883cefSAlexander Motin struct g_multipath_softc *sc; 15330c883cefSAlexander Motin int good; 15340c883cefSAlexander Motin 15350c883cefSAlexander Motin g_topology_assert(); 15360c883cefSAlexander Motin 15370c883cefSAlexander Motin sc = gp->softc; 15380c883cefSAlexander Motin if (sc == NULL) 15390c883cefSAlexander Motin return; 15400c883cefSAlexander Motin if (cp != NULL) { 1541a839e332SAlexander Motin sbuf_printf(sb, "%s<State>%s</State>\n", indent, 15420c883cefSAlexander Motin (cp->index & MP_NEW) ? "NEW" : 15430c883cefSAlexander Motin (cp->index & MP_LOST) ? "LOST" : 15440c883cefSAlexander Motin (cp->index & MP_FAIL) ? "FAIL" : 154563297dfdSAlexander Motin (sc->sc_active_active == 1 || sc->sc_active == cp) ? 154663297dfdSAlexander Motin "ACTIVE" : 154763297dfdSAlexander Motin sc->sc_active_active == 2 ? "READ" : "PASSIVE"); 15480c883cefSAlexander Motin } else { 15490c883cefSAlexander Motin good = g_multipath_good(gp); 1550a839e332SAlexander Motin sbuf_printf(sb, "%s<State>%s</State>\n", indent, 15510c883cefSAlexander Motin good == 0 ? "BROKEN" : 15520c883cefSAlexander Motin (good != sc->sc_ndisks || sc->sc_ndisks == 1) ? 15530c883cefSAlexander Motin "DEGRADED" : "OPTIMAL"); 15540c883cefSAlexander Motin } 15550c883cefSAlexander Motin if (cp == NULL && pp == NULL) { 1556a839e332SAlexander Motin sbuf_printf(sb, "%s<UUID>%s</UUID>\n", indent, sc->sc_uuid); 1557a839e332SAlexander Motin sbuf_printf(sb, "%s<Mode>Active/%s</Mode>\n", indent, 155863297dfdSAlexander Motin sc->sc_active_active == 2 ? "Read" : 155963297dfdSAlexander Motin sc->sc_active_active == 1 ? "Active" : "Passive"); 1560a839e332SAlexander Motin sbuf_printf(sb, "%s<Type>%s</Type>\n", indent, 15610c883cefSAlexander Motin sc->sc_uuid[0] == 0 ? "MANUAL" : "AUTOMATIC"); 15620c883cefSAlexander Motin } 15630c883cefSAlexander Motin } 15640c883cefSAlexander Motin 1565e770bc6bSMatt Jacob DECLARE_GEOM_CLASS(g_multipath_class, g_multipath); 156674d6c131SKyle Evans MODULE_VERSION(geom_multipath, 0); 1567