1e770bc6bSMatt Jacob /*- 20c883cefSAlexander Motin * Copyright (c) 2011 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> 39e770bc6bSMatt Jacob #include <sys/lock.h> 40e770bc6bSMatt Jacob #include <sys/mutex.h> 41e770bc6bSMatt Jacob #include <sys/bio.h> 425d807a0eSAndrey V. Elsukov #include <sys/sbuf.h> 43e770bc6bSMatt Jacob #include <sys/sysctl.h> 44e770bc6bSMatt Jacob #include <sys/kthread.h> 45e770bc6bSMatt Jacob #include <sys/malloc.h> 46e770bc6bSMatt Jacob #include <geom/geom.h> 47e770bc6bSMatt Jacob #include <geom/multipath/g_multipath.h> 48e770bc6bSMatt Jacob 49cb08c2ccSAlexander Leidinger FEATURE(geom_multipath, "GEOM multipath support"); 50e770bc6bSMatt Jacob 51e770bc6bSMatt Jacob SYSCTL_DECL(_kern_geom); 526472ac3dSEd Schouten static SYSCTL_NODE(_kern_geom, OID_AUTO, multipath, CTLFLAG_RW, 0, 53e770bc6bSMatt Jacob "GEOM_MULTIPATH tunables"); 54e770bc6bSMatt Jacob static u_int g_multipath_debug = 0; 55e770bc6bSMatt Jacob SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, debug, CTLFLAG_RW, 56e770bc6bSMatt Jacob &g_multipath_debug, 0, "Debug level"); 570c883cefSAlexander Motin static u_int g_multipath_exclusive = 1; 580c883cefSAlexander Motin SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, exclusive, CTLFLAG_RW, 590c883cefSAlexander Motin &g_multipath_exclusive, 0, "Exclusively open providers"); 60e770bc6bSMatt Jacob 61e770bc6bSMatt Jacob static enum { 62e770bc6bSMatt Jacob GKT_NIL, 63e770bc6bSMatt Jacob GKT_RUN, 64e770bc6bSMatt Jacob GKT_DIE 65e770bc6bSMatt Jacob } g_multipath_kt_state; 66e770bc6bSMatt Jacob static struct bio_queue_head gmtbq; 67e770bc6bSMatt Jacob static struct mtx gmtbq_mtx; 68e770bc6bSMatt Jacob 69e770bc6bSMatt Jacob static void g_multipath_orphan(struct g_consumer *); 70e770bc6bSMatt Jacob static void g_multipath_start(struct bio *); 71e770bc6bSMatt Jacob static void g_multipath_done(struct bio *); 72e770bc6bSMatt Jacob static void g_multipath_done_error(struct bio *); 73e770bc6bSMatt Jacob static void g_multipath_kt(void *); 74e770bc6bSMatt Jacob 75e770bc6bSMatt Jacob static int g_multipath_destroy(struct g_geom *); 76e770bc6bSMatt Jacob static int 77e770bc6bSMatt Jacob g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *); 78e770bc6bSMatt Jacob 792b4969ffSMatt Jacob static struct g_geom *g_multipath_find_geom(struct g_class *, const char *); 80b5dce617SMatt Jacob static int g_multipath_rotate(struct g_geom *); 81b5dce617SMatt Jacob 82e770bc6bSMatt Jacob static g_taste_t g_multipath_taste; 83e770bc6bSMatt Jacob static g_ctl_req_t g_multipath_config; 84e770bc6bSMatt Jacob static g_init_t g_multipath_init; 85e770bc6bSMatt Jacob static g_fini_t g_multipath_fini; 860c883cefSAlexander Motin static g_dumpconf_t g_multipath_dumpconf; 87e770bc6bSMatt Jacob 88e770bc6bSMatt Jacob struct g_class g_multipath_class = { 89e770bc6bSMatt Jacob .name = G_MULTIPATH_CLASS_NAME, 90e770bc6bSMatt Jacob .version = G_VERSION, 91e770bc6bSMatt Jacob .ctlreq = g_multipath_config, 92e770bc6bSMatt Jacob .taste = g_multipath_taste, 93e770bc6bSMatt Jacob .destroy_geom = g_multipath_destroy_geom, 94e770bc6bSMatt Jacob .init = g_multipath_init, 95e770bc6bSMatt Jacob .fini = g_multipath_fini 96e770bc6bSMatt Jacob }; 97e770bc6bSMatt Jacob 980c883cefSAlexander Motin #define MP_FAIL 0x00000001 990c883cefSAlexander Motin #define MP_LOST 0x00000002 1000c883cefSAlexander Motin #define MP_NEW 0x00000004 1010c883cefSAlexander Motin #define MP_POSTED 0x00000008 1020c883cefSAlexander Motin #define MP_BAD (MP_FAIL | MP_LOST | MP_NEW) 1030c883cefSAlexander Motin #define MP_IDLE 0x00000010 1040c883cefSAlexander Motin #define MP_IDLE_MASK 0xfffffff0 1050c883cefSAlexander Motin 1060c883cefSAlexander Motin static int 1070c883cefSAlexander Motin g_multipath_good(struct g_geom *gp) 1080c883cefSAlexander Motin { 1090c883cefSAlexander Motin struct g_consumer *cp; 1100c883cefSAlexander Motin int n = 0; 1110c883cefSAlexander Motin 1120c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 1130c883cefSAlexander Motin if ((cp->index & MP_BAD) == 0) 1140c883cefSAlexander Motin n++; 1150c883cefSAlexander Motin } 1160c883cefSAlexander Motin return (n); 1170c883cefSAlexander Motin } 1180c883cefSAlexander Motin 1190c883cefSAlexander Motin static void 1200c883cefSAlexander Motin g_multipath_fault(struct g_consumer *cp, int cause) 1210c883cefSAlexander Motin { 1220c883cefSAlexander Motin struct g_multipath_softc *sc; 1230c883cefSAlexander Motin struct g_consumer *lcp; 1240c883cefSAlexander Motin struct g_geom *gp; 1250c883cefSAlexander Motin 1260c883cefSAlexander Motin gp = cp->geom; 1270c883cefSAlexander Motin sc = gp->softc; 1280c883cefSAlexander Motin cp->index |= cause; 1290c883cefSAlexander Motin if (g_multipath_good(gp) == 0 && sc->sc_ndisks > 0) { 1300c883cefSAlexander Motin LIST_FOREACH(lcp, &gp->consumer, consumer) { 1310c883cefSAlexander Motin if (lcp->provider == NULL || 1320c883cefSAlexander Motin (lcp->index & (MP_LOST | MP_NEW))) 1330c883cefSAlexander Motin continue; 1340c883cefSAlexander Motin if (sc->sc_ndisks > 1 && lcp == cp) 1350c883cefSAlexander Motin continue; 1360c883cefSAlexander Motin printf("GEOM_MULTIPATH: " 1370c883cefSAlexander Motin "all paths in %s were marked FAIL, restore %s\n", 1380c883cefSAlexander Motin sc->sc_name, lcp->provider->name); 1390c883cefSAlexander Motin lcp->index &= ~MP_FAIL; 1400c883cefSAlexander Motin } 1410c883cefSAlexander Motin } 1420c883cefSAlexander Motin if (cp != sc->sc_active) 1430c883cefSAlexander Motin return; 1440c883cefSAlexander Motin sc->sc_active = NULL; 1450c883cefSAlexander Motin LIST_FOREACH(lcp, &gp->consumer, consumer) { 1460c883cefSAlexander Motin if ((lcp->index & MP_BAD) == 0) { 1470c883cefSAlexander Motin sc->sc_active = lcp; 1480c883cefSAlexander Motin break; 1490c883cefSAlexander Motin } 1500c883cefSAlexander Motin } 1510c883cefSAlexander Motin if (sc->sc_active == NULL) { 1520c883cefSAlexander Motin printf("GEOM_MULTIPATH: out of providers for %s\n", 1530c883cefSAlexander Motin sc->sc_name); 15463297dfdSAlexander Motin } else if (sc->sc_active_active != 1) { 1550c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 1560c883cefSAlexander Motin sc->sc_active->provider->name, sc->sc_name); 1570c883cefSAlexander Motin } 1580c883cefSAlexander Motin } 1590c883cefSAlexander Motin 1600c883cefSAlexander Motin static struct g_consumer * 16163297dfdSAlexander Motin g_multipath_choose(struct g_geom *gp, struct bio *bp) 1620c883cefSAlexander Motin { 1630c883cefSAlexander Motin struct g_multipath_softc *sc; 1640c883cefSAlexander Motin struct g_consumer *best, *cp; 1650c883cefSAlexander Motin 1660c883cefSAlexander Motin sc = gp->softc; 16763297dfdSAlexander Motin if (sc->sc_active_active == 0 || 16863297dfdSAlexander Motin (sc->sc_active_active == 2 && bp->bio_cmd != BIO_READ)) 1690c883cefSAlexander Motin return (sc->sc_active); 1700c883cefSAlexander Motin best = NULL; 1710c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 1720c883cefSAlexander Motin if (cp->index & MP_BAD) 1730c883cefSAlexander Motin continue; 1740c883cefSAlexander Motin cp->index += MP_IDLE; 1750c883cefSAlexander Motin if (best == NULL || cp->private < best->private || 1760c883cefSAlexander Motin (cp->private == best->private && cp->index > best->index)) 1770c883cefSAlexander Motin best = cp; 1780c883cefSAlexander Motin } 1790c883cefSAlexander Motin if (best != NULL) 1800c883cefSAlexander Motin best->index &= ~MP_IDLE_MASK; 1810c883cefSAlexander Motin return (best); 1820c883cefSAlexander Motin } 183e770bc6bSMatt Jacob 184e770bc6bSMatt Jacob static void 185e770bc6bSMatt Jacob g_mpd(void *arg, int flags __unused) 186e770bc6bSMatt Jacob { 1870c883cefSAlexander Motin struct g_geom *gp; 1880c883cefSAlexander Motin struct g_multipath_softc *sc; 189e770bc6bSMatt Jacob struct g_consumer *cp; 1900c883cefSAlexander Motin int w; 191e770bc6bSMatt Jacob 192e770bc6bSMatt Jacob g_topology_assert(); 193e770bc6bSMatt Jacob cp = arg; 1940c883cefSAlexander Motin gp = cp->geom; 1950c883cefSAlexander Motin if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) { 1960c883cefSAlexander Motin w = cp->acw; 197e770bc6bSMatt Jacob g_access(cp, -cp->acr, -cp->acw, -cp->ace); 1980c883cefSAlexander Motin if (w > 0 && cp->provider != NULL && 1990c883cefSAlexander Motin (cp->provider->geom->flags & G_GEOM_WITHER) == 0) { 2000c883cefSAlexander Motin g_post_event(g_mpd, cp, M_WAITOK, NULL); 2010c883cefSAlexander Motin return; 2020c883cefSAlexander Motin } 2030c883cefSAlexander Motin } 2040c883cefSAlexander Motin sc = gp->softc; 2050c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 206e770bc6bSMatt Jacob if (cp->provider) { 207e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: %s removed from %s\n", 2080c883cefSAlexander Motin cp->provider->name, gp->name); 209e770bc6bSMatt Jacob g_detach(cp); 210e770bc6bSMatt Jacob } 211e770bc6bSMatt Jacob g_destroy_consumer(cp); 2120c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 2130c883cefSAlexander Motin if (LIST_EMPTY(&gp->consumer)) 2140c883cefSAlexander Motin g_multipath_destroy(gp); 215e770bc6bSMatt Jacob } 216e770bc6bSMatt Jacob 217e770bc6bSMatt Jacob static void 218e770bc6bSMatt Jacob g_multipath_orphan(struct g_consumer *cp) 219e770bc6bSMatt Jacob { 2200c883cefSAlexander Motin struct g_multipath_softc *sc; 2210c883cefSAlexander Motin uintptr_t *cnt; 2220c883cefSAlexander Motin 2230c883cefSAlexander Motin g_topology_assert(); 2240c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s in %s was disconnected\n", 225e770bc6bSMatt Jacob cp->provider->name, cp->geom->name); 2260c883cefSAlexander Motin sc = cp->geom->softc; 2270c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 2280c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 2290c883cefSAlexander Motin sc->sc_ndisks--; 2300c883cefSAlexander Motin g_multipath_fault(cp, MP_LOST); 2310c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_POSTED) == 0) { 2320c883cefSAlexander Motin cp->index |= MP_POSTED; 2330c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 234e770bc6bSMatt Jacob g_mpd(cp, 0); 2350c883cefSAlexander Motin } else 2360c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 237e770bc6bSMatt Jacob } 238e770bc6bSMatt Jacob 239e770bc6bSMatt Jacob static void 240e770bc6bSMatt Jacob g_multipath_start(struct bio *bp) 241e770bc6bSMatt Jacob { 242e770bc6bSMatt Jacob struct g_multipath_softc *sc; 243e770bc6bSMatt Jacob struct g_geom *gp; 244e770bc6bSMatt Jacob struct g_consumer *cp; 245e770bc6bSMatt Jacob struct bio *cbp; 2460c883cefSAlexander Motin uintptr_t *cnt; 247e770bc6bSMatt Jacob 248e770bc6bSMatt Jacob gp = bp->bio_to->geom; 249e770bc6bSMatt Jacob sc = gp->softc; 250e770bc6bSMatt Jacob KASSERT(sc != NULL, ("NULL sc")); 251e770bc6bSMatt Jacob cbp = g_clone_bio(bp); 252e770bc6bSMatt Jacob if (cbp == NULL) { 253e770bc6bSMatt Jacob g_io_deliver(bp, ENOMEM); 254e770bc6bSMatt Jacob return; 255e770bc6bSMatt Jacob } 2560c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 25763297dfdSAlexander Motin cp = g_multipath_choose(gp, bp); 2580c883cefSAlexander Motin if (cp == NULL) { 2590c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 2600c883cefSAlexander Motin g_destroy_bio(cbp); 2610c883cefSAlexander Motin g_io_deliver(bp, ENXIO); 2620c883cefSAlexander Motin return; 2630c883cefSAlexander Motin } 2640c883cefSAlexander Motin if ((uintptr_t)bp->bio_driver1 < sc->sc_ndisks) 2650c883cefSAlexander Motin bp->bio_driver1 = (void *)(uintptr_t)sc->sc_ndisks; 2660c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 2670c883cefSAlexander Motin (*cnt)++; 2680c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 269e770bc6bSMatt Jacob cbp->bio_done = g_multipath_done; 270e770bc6bSMatt Jacob g_io_request(cbp, cp); 271e770bc6bSMatt Jacob } 272e770bc6bSMatt Jacob 273e770bc6bSMatt Jacob static void 274e770bc6bSMatt Jacob g_multipath_done(struct bio *bp) 275e770bc6bSMatt Jacob { 2760c883cefSAlexander Motin struct g_multipath_softc *sc; 2770c883cefSAlexander Motin struct g_consumer *cp; 2780c883cefSAlexander Motin uintptr_t *cnt; 2790c883cefSAlexander Motin 280e770bc6bSMatt Jacob if (bp->bio_error == ENXIO || bp->bio_error == EIO) { 281e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 282e770bc6bSMatt Jacob bioq_insert_tail(&gmtbq, bp); 283e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 2840c883cefSAlexander Motin wakeup(&g_multipath_kt_state); 285e770bc6bSMatt Jacob } else { 2860c883cefSAlexander Motin cp = bp->bio_from; 2870c883cefSAlexander Motin sc = cp->geom->softc; 2880c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 2890c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 2900c883cefSAlexander Motin (*cnt)--; 2910c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_LOST)) { 2920c883cefSAlexander Motin cp->index |= MP_POSTED; 2930c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 2940c883cefSAlexander Motin g_post_event(g_mpd, cp, M_WAITOK, NULL); 2950c883cefSAlexander Motin } else 2960c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 297e770bc6bSMatt Jacob g_std_done(bp); 298e770bc6bSMatt Jacob } 299e770bc6bSMatt Jacob } 300e770bc6bSMatt Jacob 301e770bc6bSMatt Jacob static void 302e770bc6bSMatt Jacob g_multipath_done_error(struct bio *bp) 303e770bc6bSMatt Jacob { 304e770bc6bSMatt Jacob struct bio *pbp; 305e770bc6bSMatt Jacob struct g_geom *gp; 306e770bc6bSMatt Jacob struct g_multipath_softc *sc; 307e770bc6bSMatt Jacob struct g_consumer *cp; 308e770bc6bSMatt Jacob struct g_provider *pp; 3090c883cefSAlexander Motin uintptr_t *cnt; 310e770bc6bSMatt Jacob 311e770bc6bSMatt Jacob /* 312e770bc6bSMatt Jacob * If we had a failure, we have to check first to see 313e770bc6bSMatt Jacob * whether the consumer it failed on was the currently 314e770bc6bSMatt Jacob * active consumer (i.e., this is the first in perhaps 315e770bc6bSMatt Jacob * a number of failures). If so, we then switch consumers 316e770bc6bSMatt Jacob * to the next available consumer. 317e770bc6bSMatt Jacob */ 318e770bc6bSMatt Jacob 319e770bc6bSMatt Jacob pbp = bp->bio_parent; 320e770bc6bSMatt Jacob gp = pbp->bio_to->geom; 321e770bc6bSMatt Jacob sc = gp->softc; 322e770bc6bSMatt Jacob cp = bp->bio_from; 323e770bc6bSMatt Jacob pp = cp->provider; 3240c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 325e770bc6bSMatt Jacob 3260c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 32763297dfdSAlexander Motin if ((cp->index & MP_FAIL) == 0) { 3280c883cefSAlexander Motin printf("GEOM_MULTIPATH: Error %d, %s in %s marked FAIL\n", 3290c883cefSAlexander Motin bp->bio_error, pp->name, sc->sc_name); 3300c883cefSAlexander Motin g_multipath_fault(cp, MP_FAIL); 33163297dfdSAlexander Motin } 3320c883cefSAlexander Motin (*cnt)--; 3330c883cefSAlexander Motin if (*cnt == 0 && (cp->index & (MP_LOST | MP_POSTED)) == MP_LOST) { 334e770bc6bSMatt Jacob cp->index |= MP_POSTED; 3350c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 3360c883cefSAlexander Motin g_post_event(g_mpd, cp, M_WAITOK, NULL); 3370c883cefSAlexander Motin } else 3380c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 339e770bc6bSMatt Jacob 340e770bc6bSMatt Jacob /* 341e770bc6bSMatt Jacob * If we can fruitfully restart the I/O, do so. 342e770bc6bSMatt Jacob */ 3430c883cefSAlexander Motin if (pbp->bio_children < (uintptr_t)pbp->bio_driver1) { 3440c883cefSAlexander Motin pbp->bio_inbed++; 345e770bc6bSMatt Jacob g_destroy_bio(bp); 346e770bc6bSMatt Jacob g_multipath_start(pbp); 347e770bc6bSMatt Jacob } else { 348e770bc6bSMatt Jacob g_std_done(bp); 349e770bc6bSMatt Jacob } 350e770bc6bSMatt Jacob } 351e770bc6bSMatt Jacob 352e770bc6bSMatt Jacob static void 353e770bc6bSMatt Jacob g_multipath_kt(void *arg) 354e770bc6bSMatt Jacob { 35512f35a61SPawel Jakub Dawidek 356e770bc6bSMatt Jacob g_multipath_kt_state = GKT_RUN; 357e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 358e770bc6bSMatt Jacob while (g_multipath_kt_state == GKT_RUN) { 359e770bc6bSMatt Jacob for (;;) { 360e770bc6bSMatt Jacob struct bio *bp; 36112f35a61SPawel Jakub Dawidek 362e770bc6bSMatt Jacob bp = bioq_takefirst(&gmtbq); 36312f35a61SPawel Jakub Dawidek if (bp == NULL) 364e770bc6bSMatt Jacob break; 365e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 366e770bc6bSMatt Jacob g_multipath_done_error(bp); 367e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 368e770bc6bSMatt Jacob } 36963297dfdSAlexander Motin if (g_multipath_kt_state != GKT_RUN) 37063297dfdSAlexander Motin break; 371e770bc6bSMatt Jacob msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO, 37263297dfdSAlexander Motin "gkt:wait", 0); 373e770bc6bSMatt Jacob } 374e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 375e770bc6bSMatt Jacob wakeup(&g_multipath_kt_state); 3763745c395SJulian Elischer kproc_exit(0); 377e770bc6bSMatt Jacob } 378e770bc6bSMatt Jacob 379e770bc6bSMatt Jacob 380e770bc6bSMatt Jacob static int 381e770bc6bSMatt Jacob g_multipath_access(struct g_provider *pp, int dr, int dw, int de) 382e770bc6bSMatt Jacob { 383e770bc6bSMatt Jacob struct g_geom *gp; 384e770bc6bSMatt Jacob struct g_consumer *cp, *badcp = NULL; 3850c883cefSAlexander Motin struct g_multipath_softc *sc; 386e770bc6bSMatt Jacob int error; 387e770bc6bSMatt Jacob 388e770bc6bSMatt Jacob gp = pp->geom; 389e770bc6bSMatt Jacob 390e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 391e770bc6bSMatt Jacob error = g_access(cp, dr, dw, de); 392e770bc6bSMatt Jacob if (error) { 393e770bc6bSMatt Jacob badcp = cp; 394e770bc6bSMatt Jacob goto fail; 395e770bc6bSMatt Jacob } 396e770bc6bSMatt Jacob } 3970c883cefSAlexander Motin sc = gp->softc; 3980c883cefSAlexander Motin sc->sc_opened += dr + dw + de; 3990c883cefSAlexander Motin if (sc->sc_stopping && sc->sc_opened == 0) 4000c883cefSAlexander Motin g_multipath_destroy(gp); 401e770bc6bSMatt Jacob return (0); 402e770bc6bSMatt Jacob 403e770bc6bSMatt Jacob fail: 404e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 40512f35a61SPawel Jakub Dawidek if (cp == badcp) 406e770bc6bSMatt Jacob break; 407e770bc6bSMatt Jacob (void) g_access(cp, -dr, -dw, -de); 408e770bc6bSMatt Jacob } 409e770bc6bSMatt Jacob return (error); 410e770bc6bSMatt Jacob } 411e770bc6bSMatt Jacob 412e770bc6bSMatt Jacob static struct g_geom * 413e770bc6bSMatt Jacob g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md) 414e770bc6bSMatt Jacob { 415e770bc6bSMatt Jacob struct g_multipath_softc *sc; 416e770bc6bSMatt Jacob struct g_geom *gp; 417e770bc6bSMatt Jacob struct g_provider *pp; 418e770bc6bSMatt Jacob 419e770bc6bSMatt Jacob g_topology_assert(); 420e770bc6bSMatt Jacob 421e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 4220c883cefSAlexander Motin sc = gp->softc; 4230c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 4240c883cefSAlexander Motin continue; 425e770bc6bSMatt Jacob if (strcmp(gp->name, md->md_name) == 0) { 426e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: name %s already exists\n", 427e770bc6bSMatt Jacob md->md_name); 428e770bc6bSMatt Jacob return (NULL); 429e770bc6bSMatt Jacob } 430e770bc6bSMatt Jacob } 431e770bc6bSMatt Jacob 43202c62349SJaakko Heinonen gp = g_new_geomf(mp, "%s", md->md_name); 433e770bc6bSMatt Jacob sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); 4340c883cefSAlexander Motin mtx_init(&sc->sc_mtx, "multipath", NULL, MTX_DEF); 4350c883cefSAlexander Motin memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid)); 4360c883cefSAlexander Motin memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name)); 4370c883cefSAlexander Motin sc->sc_active_active = md->md_active_active; 438e770bc6bSMatt Jacob gp->softc = sc; 439e770bc6bSMatt Jacob gp->start = g_multipath_start; 440e770bc6bSMatt Jacob gp->orphan = g_multipath_orphan; 441e770bc6bSMatt Jacob gp->access = g_multipath_access; 4420c883cefSAlexander Motin gp->dumpconf = g_multipath_dumpconf; 443e770bc6bSMatt Jacob 444e770bc6bSMatt Jacob pp = g_new_providerf(gp, "multipath/%s", md->md_name); 445*40ea77a0SAlexander Motin pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; 4460c883cefSAlexander Motin if (md->md_size != 0) { 4470c883cefSAlexander Motin pp->mediasize = md->md_size - 4480c883cefSAlexander Motin ((md->md_uuid[0] != 0) ? md->md_sectorsize : 0); 449e770bc6bSMatt Jacob pp->sectorsize = md->md_sectorsize; 4500c883cefSAlexander Motin } 4510c883cefSAlexander Motin sc->sc_pp = pp; 452e770bc6bSMatt Jacob g_error_provider(pp, 0); 4530c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s created\n", gp->name); 454e770bc6bSMatt Jacob return (gp); 455e770bc6bSMatt Jacob } 456e770bc6bSMatt Jacob 457e770bc6bSMatt Jacob static int 458e770bc6bSMatt Jacob g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp) 459e770bc6bSMatt Jacob { 460e770bc6bSMatt Jacob struct g_multipath_softc *sc; 461e770bc6bSMatt Jacob struct g_consumer *cp, *nxtcp; 4620c883cefSAlexander Motin int error, acr, acw, ace; 463e770bc6bSMatt Jacob 464e770bc6bSMatt Jacob g_topology_assert(); 465e770bc6bSMatt Jacob 466e770bc6bSMatt Jacob sc = gp->softc; 467e770bc6bSMatt Jacob KASSERT(sc, ("no softc")); 468e770bc6bSMatt Jacob 469e770bc6bSMatt Jacob /* 470e770bc6bSMatt Jacob * Make sure that the passed provider isn't already attached 471e770bc6bSMatt Jacob */ 472e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 47312f35a61SPawel Jakub Dawidek if (cp->provider == pp) 474e770bc6bSMatt Jacob break; 475e770bc6bSMatt Jacob } 476e770bc6bSMatt Jacob if (cp) { 477e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: provider %s already attached to %s\n", 478e770bc6bSMatt Jacob pp->name, gp->name); 479e770bc6bSMatt Jacob return (EEXIST); 480e770bc6bSMatt Jacob } 481e770bc6bSMatt Jacob nxtcp = LIST_FIRST(&gp->consumer); 482e770bc6bSMatt Jacob cp = g_new_consumer(gp); 483*40ea77a0SAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 4840c883cefSAlexander Motin cp->private = NULL; 4850c883cefSAlexander Motin cp->index = MP_NEW; 486e770bc6bSMatt Jacob error = g_attach(cp, pp); 487e770bc6bSMatt Jacob if (error != 0) { 488e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot attach %s to %s", 489e770bc6bSMatt Jacob pp->name, sc->sc_name); 490e770bc6bSMatt Jacob g_destroy_consumer(cp); 491e770bc6bSMatt Jacob return (error); 492e770bc6bSMatt Jacob } 493e770bc6bSMatt Jacob 494e770bc6bSMatt Jacob /* 495e770bc6bSMatt Jacob * Set access permissions on new consumer to match other consumers 496e770bc6bSMatt Jacob */ 4970c883cefSAlexander Motin if (sc->sc_pp) { 4980c883cefSAlexander Motin acr = sc->sc_pp->acr; 4990c883cefSAlexander Motin acw = sc->sc_pp->acw; 5000c883cefSAlexander Motin ace = sc->sc_pp->ace; 5010c883cefSAlexander Motin } else 5020c883cefSAlexander Motin acr = acw = ace = 0; 5030c883cefSAlexander Motin if (g_multipath_exclusive) { 5040c883cefSAlexander Motin acr++; 5050c883cefSAlexander Motin acw++; 5060c883cefSAlexander Motin ace++; 5070c883cefSAlexander Motin } 5080c883cefSAlexander Motin error = g_access(cp, acr, acw, ace); 509e770bc6bSMatt Jacob if (error) { 510e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot set access in " 5110c883cefSAlexander Motin "attaching %s to %s (%d)\n", 5120c883cefSAlexander Motin pp->name, sc->sc_name, error); 513e770bc6bSMatt Jacob g_detach(cp); 514e770bc6bSMatt Jacob g_destroy_consumer(cp); 515e770bc6bSMatt Jacob return (error); 516e770bc6bSMatt Jacob } 5170c883cefSAlexander Motin if (sc->sc_pp != NULL && sc->sc_pp->mediasize == 0) { 5180c883cefSAlexander Motin sc->sc_pp->mediasize = pp->mediasize - 5190c883cefSAlexander Motin ((sc->sc_uuid[0] != 0) ? pp->sectorsize : 0); 5200c883cefSAlexander Motin sc->sc_pp->sectorsize = pp->sectorsize; 521e770bc6bSMatt Jacob } 5220c883cefSAlexander Motin if (sc->sc_pp != NULL && 5230c883cefSAlexander Motin sc->sc_pp->stripesize == 0 && sc->sc_pp->stripeoffset == 0) { 5240c883cefSAlexander Motin sc->sc_pp->stripesize = pp->stripesize; 5250c883cefSAlexander Motin sc->sc_pp->stripeoffset = pp->stripeoffset; 5260c883cefSAlexander Motin } 527f4673017SAlexander Motin if (sc->sc_pp != NULL) 528f4673017SAlexander Motin sc->sc_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED; 5290c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 5300c883cefSAlexander Motin cp->index = 0; 5310c883cefSAlexander Motin sc->sc_ndisks++; 5320c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 5330c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s added to %s\n", 5340c883cefSAlexander Motin pp->name, sc->sc_name); 5350c883cefSAlexander Motin if (sc->sc_active == NULL) { 5360c883cefSAlexander Motin sc->sc_active = cp; 53763297dfdSAlexander Motin if (sc->sc_active_active != 1) 5380c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 539e770bc6bSMatt Jacob pp->name, sc->sc_name); 540e770bc6bSMatt Jacob } 541e770bc6bSMatt Jacob return (0); 542e770bc6bSMatt Jacob } 543e770bc6bSMatt Jacob 544e770bc6bSMatt Jacob static int 545e770bc6bSMatt Jacob g_multipath_destroy(struct g_geom *gp) 546e770bc6bSMatt Jacob { 5470c883cefSAlexander Motin struct g_multipath_softc *sc; 5480c883cefSAlexander Motin struct g_consumer *cp, *cp1; 549e770bc6bSMatt Jacob 550e770bc6bSMatt Jacob g_topology_assert(); 55112f35a61SPawel Jakub Dawidek if (gp->softc == NULL) 552e770bc6bSMatt Jacob return (ENXIO); 5530c883cefSAlexander Motin sc = gp->softc; 5540c883cefSAlexander Motin if (!sc->sc_stopping) { 555e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: destroying %s\n", gp->name); 5560c883cefSAlexander Motin sc->sc_stopping = 1; 5570c883cefSAlexander Motin } 5580c883cefSAlexander Motin if (sc->sc_opened != 0) { 5590c883cefSAlexander Motin if (sc->sc_pp != NULL) { 5600c883cefSAlexander Motin g_wither_provider(sc->sc_pp, ENXIO); 5610c883cefSAlexander Motin sc->sc_pp = NULL; 5620c883cefSAlexander Motin } 5630c883cefSAlexander Motin return (EINPROGRESS); 5640c883cefSAlexander Motin } 5650c883cefSAlexander Motin LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 5660c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 5670c883cefSAlexander Motin if ((cp->index & MP_POSTED) == 0) { 5680c883cefSAlexander Motin cp->index |= MP_POSTED; 5690c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 5700c883cefSAlexander Motin g_mpd(cp, 0); 5710c883cefSAlexander Motin if (cp1 == NULL) 5720c883cefSAlexander Motin return(0); /* Recursion happened. */ 5730c883cefSAlexander Motin } else 5740c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 5750c883cefSAlexander Motin } 5760c883cefSAlexander Motin if (!LIST_EMPTY(&gp->consumer)) 5770c883cefSAlexander Motin return (EINPROGRESS); 5780c883cefSAlexander Motin mtx_destroy(&sc->sc_mtx); 579e770bc6bSMatt Jacob g_free(gp->softc); 580e770bc6bSMatt Jacob gp->softc = NULL; 5810c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s destroyed\n", gp->name); 582e770bc6bSMatt Jacob g_wither_geom(gp, ENXIO); 583e770bc6bSMatt Jacob return (0); 584e770bc6bSMatt Jacob } 585e770bc6bSMatt Jacob 586e770bc6bSMatt Jacob static int 587e770bc6bSMatt Jacob g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp, 588e770bc6bSMatt Jacob struct g_geom *gp) 589e770bc6bSMatt Jacob { 59012f35a61SPawel Jakub Dawidek 591e770bc6bSMatt Jacob return (g_multipath_destroy(gp)); 592e770bc6bSMatt Jacob } 593e770bc6bSMatt Jacob 594b5dce617SMatt Jacob static int 595b5dce617SMatt Jacob g_multipath_rotate(struct g_geom *gp) 596b5dce617SMatt Jacob { 5978fb378d6SThomas Quinot struct g_consumer *lcp, *first_good_cp = NULL; 598b5dce617SMatt Jacob struct g_multipath_softc *sc = gp->softc; 5998fb378d6SThomas Quinot int active_cp_seen = 0; 600b5dce617SMatt Jacob 601b5dce617SMatt Jacob g_topology_assert(); 602b5dce617SMatt Jacob if (sc == NULL) 603b5dce617SMatt Jacob return (ENXIO); 604b5dce617SMatt Jacob LIST_FOREACH(lcp, &gp->consumer, consumer) { 605b5dce617SMatt Jacob if ((lcp->index & MP_BAD) == 0) { 6068fb378d6SThomas Quinot if (first_good_cp == NULL) 6078fb378d6SThomas Quinot first_good_cp = lcp; 6088fb378d6SThomas Quinot if (active_cp_seen) 609b5dce617SMatt Jacob break; 610b5dce617SMatt Jacob } 6118fb378d6SThomas Quinot if (sc->sc_active == lcp) 6128fb378d6SThomas Quinot active_cp_seen = 1; 613b5dce617SMatt Jacob } 6148fb378d6SThomas Quinot if (lcp == NULL) 6158fb378d6SThomas Quinot lcp = first_good_cp; 6168fb378d6SThomas Quinot if (lcp && lcp != sc->sc_active) { 6170c883cefSAlexander Motin sc->sc_active = lcp; 61863297dfdSAlexander Motin if (sc->sc_active_active != 1) 6190c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 620b5dce617SMatt Jacob lcp->provider->name, sc->sc_name); 621b5dce617SMatt Jacob } 622b5dce617SMatt Jacob return (0); 623b5dce617SMatt Jacob } 624b5dce617SMatt Jacob 625e770bc6bSMatt Jacob static void 626e770bc6bSMatt Jacob g_multipath_init(struct g_class *mp) 627e770bc6bSMatt Jacob { 628e770bc6bSMatt Jacob bioq_init(&gmtbq); 629e770bc6bSMatt Jacob mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF); 63063297dfdSAlexander Motin kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt"); 631e770bc6bSMatt Jacob } 632e770bc6bSMatt Jacob 633e770bc6bSMatt Jacob static void 634e770bc6bSMatt Jacob g_multipath_fini(struct g_class *mp) 635e770bc6bSMatt Jacob { 636e770bc6bSMatt Jacob if (g_multipath_kt_state == GKT_RUN) { 637e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 638e770bc6bSMatt Jacob g_multipath_kt_state = GKT_DIE; 639e770bc6bSMatt Jacob wakeup(&g_multipath_kt_state); 640e770bc6bSMatt Jacob msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO, 641e770bc6bSMatt Jacob "gmp:fini", 0); 642e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 643e770bc6bSMatt Jacob } 644e770bc6bSMatt Jacob } 645e770bc6bSMatt Jacob 646e770bc6bSMatt Jacob static int 647e770bc6bSMatt Jacob g_multipath_read_metadata(struct g_consumer *cp, 648e770bc6bSMatt Jacob struct g_multipath_metadata *md) 649e770bc6bSMatt Jacob { 650e770bc6bSMatt Jacob struct g_provider *pp; 651e770bc6bSMatt Jacob u_char *buf; 652e770bc6bSMatt Jacob int error; 653e770bc6bSMatt Jacob 654e770bc6bSMatt Jacob g_topology_assert(); 655e770bc6bSMatt Jacob error = g_access(cp, 1, 0, 0); 65612f35a61SPawel Jakub Dawidek if (error != 0) 657e770bc6bSMatt Jacob return (error); 658e770bc6bSMatt Jacob pp = cp->provider; 659e770bc6bSMatt Jacob g_topology_unlock(); 660e770bc6bSMatt Jacob buf = g_read_data(cp, pp->mediasize - pp->sectorsize, 661e770bc6bSMatt Jacob pp->sectorsize, &error); 662e770bc6bSMatt Jacob g_topology_lock(); 663e770bc6bSMatt Jacob g_access(cp, -1, 0, 0); 66412f35a61SPawel Jakub Dawidek if (buf == NULL) 665e770bc6bSMatt Jacob return (error); 666e770bc6bSMatt Jacob multipath_metadata_decode(buf, md); 667e770bc6bSMatt Jacob g_free(buf); 668e770bc6bSMatt Jacob return (0); 669e770bc6bSMatt Jacob } 670e770bc6bSMatt Jacob 671e770bc6bSMatt Jacob static struct g_geom * 672e770bc6bSMatt Jacob g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 673e770bc6bSMatt Jacob { 674e770bc6bSMatt Jacob struct g_multipath_metadata md; 675e770bc6bSMatt Jacob struct g_multipath_softc *sc; 676e770bc6bSMatt Jacob struct g_consumer *cp; 677e770bc6bSMatt Jacob struct g_geom *gp, *gp1; 678e770bc6bSMatt Jacob int error, isnew; 679e770bc6bSMatt Jacob 680e770bc6bSMatt Jacob g_topology_assert(); 681e770bc6bSMatt Jacob 682e770bc6bSMatt Jacob gp = g_new_geomf(mp, "multipath:taste"); 683e770bc6bSMatt Jacob gp->start = g_multipath_start; 684e770bc6bSMatt Jacob gp->access = g_multipath_access; 685e770bc6bSMatt Jacob gp->orphan = g_multipath_orphan; 686e770bc6bSMatt Jacob cp = g_new_consumer(gp); 687e770bc6bSMatt Jacob g_attach(cp, pp); 688e770bc6bSMatt Jacob error = g_multipath_read_metadata(cp, &md); 689e770bc6bSMatt Jacob g_detach(cp); 690e770bc6bSMatt Jacob g_destroy_consumer(cp); 691e770bc6bSMatt Jacob g_destroy_geom(gp); 69212f35a61SPawel Jakub Dawidek if (error != 0) 693e770bc6bSMatt Jacob return (NULL); 694e770bc6bSMatt Jacob gp = NULL; 695e770bc6bSMatt Jacob 696e770bc6bSMatt Jacob if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) { 69712f35a61SPawel Jakub Dawidek if (g_multipath_debug) 698e770bc6bSMatt Jacob printf("%s is not MULTIPATH\n", pp->name); 699e770bc6bSMatt Jacob return (NULL); 700e770bc6bSMatt Jacob } 701e770bc6bSMatt Jacob if (md.md_version != G_MULTIPATH_VERSION) { 702e770bc6bSMatt Jacob printf("%s has version %d multipath id- this module is version " 703e770bc6bSMatt Jacob " %d: rejecting\n", pp->name, md.md_version, 704e770bc6bSMatt Jacob G_MULTIPATH_VERSION); 705e770bc6bSMatt Jacob return (NULL); 706e770bc6bSMatt Jacob } 7070c883cefSAlexander Motin if (md.md_size != 0 && md.md_size != pp->mediasize) 7080c883cefSAlexander Motin return (NULL); 7090c883cefSAlexander Motin if (md.md_sectorsize != 0 && md.md_sectorsize != pp->sectorsize) 7100c883cefSAlexander Motin return (NULL); 71112f35a61SPawel Jakub Dawidek if (g_multipath_debug) 712e770bc6bSMatt Jacob printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid); 713e770bc6bSMatt Jacob 714e770bc6bSMatt Jacob /* 715e770bc6bSMatt Jacob * Let's check if such a device already is present. We check against 716e770bc6bSMatt Jacob * uuid alone first because that's the true distinguishor. If that 717e770bc6bSMatt Jacob * passes, then we check for name conflicts. If there are conflicts, 718e770bc6bSMatt Jacob * modify the name. 719e770bc6bSMatt Jacob * 720e770bc6bSMatt Jacob * The whole purpose of this is to solve the problem that people don't 721e770bc6bSMatt Jacob * pick good unique names, but good unique names (like uuids) are a 722e770bc6bSMatt Jacob * pain to use. So, we allow people to build GEOMs with friendly names 723e770bc6bSMatt Jacob * and uuids, and modify the names in case there's a collision. 724e770bc6bSMatt Jacob */ 725e770bc6bSMatt Jacob sc = NULL; 726e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 727e770bc6bSMatt Jacob sc = gp->softc; 7280c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 729e770bc6bSMatt Jacob continue; 73012f35a61SPawel Jakub Dawidek if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0) 731e770bc6bSMatt Jacob break; 732e770bc6bSMatt Jacob } 733e770bc6bSMatt Jacob 734e770bc6bSMatt Jacob LIST_FOREACH(gp1, &mp->geom, geom) { 73512f35a61SPawel Jakub Dawidek if (gp1 == gp) 736e770bc6bSMatt Jacob continue; 737e770bc6bSMatt Jacob sc = gp1->softc; 7380c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 739e770bc6bSMatt Jacob continue; 74012f35a61SPawel Jakub Dawidek if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0) 741e770bc6bSMatt Jacob break; 742e770bc6bSMatt Jacob } 743e770bc6bSMatt Jacob 744e770bc6bSMatt Jacob /* 745e770bc6bSMatt Jacob * If gp is NULL, we had no extant MULTIPATH geom with this uuid. 746e770bc6bSMatt Jacob * 747e770bc6bSMatt Jacob * If gp1 is *not* NULL, that means we have a MULTIPATH geom extant 748e770bc6bSMatt Jacob * with the same name (but a different UUID). 749e770bc6bSMatt Jacob * 750e770bc6bSMatt Jacob * If gp is NULL, then modify the name with a random number and 751e770bc6bSMatt Jacob * complain, but allow the creation of the geom to continue. 752e770bc6bSMatt Jacob * 753e770bc6bSMatt Jacob * If gp is *not* NULL, just use the geom's name as we're attaching 754e770bc6bSMatt Jacob * this disk to the (previously generated) name. 755e770bc6bSMatt Jacob */ 756e770bc6bSMatt Jacob 757e770bc6bSMatt Jacob if (gp1) { 758e770bc6bSMatt Jacob sc = gp1->softc; 759e770bc6bSMatt Jacob if (gp == NULL) { 760e770bc6bSMatt Jacob char buf[16]; 761e770bc6bSMatt Jacob u_long rand = random(); 762e770bc6bSMatt Jacob 763e770bc6bSMatt Jacob snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand); 764e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: geom %s/%s exists already\n", 765e770bc6bSMatt Jacob sc->sc_name, sc->sc_uuid); 766e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n", 767e770bc6bSMatt Jacob md.md_uuid, buf); 768e770bc6bSMatt Jacob strlcpy(md.md_name, buf, sizeof(md.md_name)); 769e770bc6bSMatt Jacob } else { 770e770bc6bSMatt Jacob strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name)); 771e770bc6bSMatt Jacob } 772e770bc6bSMatt Jacob } 773e770bc6bSMatt Jacob 774e770bc6bSMatt Jacob if (gp == NULL) { 775e770bc6bSMatt Jacob gp = g_multipath_create(mp, &md); 776e770bc6bSMatt Jacob if (gp == NULL) { 777e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot create geom %s/%s\n", 778e770bc6bSMatt Jacob md.md_name, md.md_uuid); 779e770bc6bSMatt Jacob return (NULL); 780e770bc6bSMatt Jacob } 781e770bc6bSMatt Jacob isnew = 1; 782e770bc6bSMatt Jacob } else { 783e770bc6bSMatt Jacob isnew = 0; 784e770bc6bSMatt Jacob } 785e770bc6bSMatt Jacob 786e770bc6bSMatt Jacob sc = gp->softc; 787e770bc6bSMatt Jacob KASSERT(sc != NULL, ("sc is NULL")); 788e770bc6bSMatt Jacob error = g_multipath_add_disk(gp, pp); 789e770bc6bSMatt Jacob if (error != 0) { 79012f35a61SPawel Jakub Dawidek if (isnew) 791e770bc6bSMatt Jacob g_multipath_destroy(gp); 792e770bc6bSMatt Jacob return (NULL); 793e770bc6bSMatt Jacob } 794e770bc6bSMatt Jacob return (gp); 795e770bc6bSMatt Jacob } 796e770bc6bSMatt Jacob 797e770bc6bSMatt Jacob static void 7980c883cefSAlexander Motin g_multipath_ctl_add_name(struct gctl_req *req, struct g_class *mp, 7990c883cefSAlexander Motin const char *name) 800e770bc6bSMatt Jacob { 8010c883cefSAlexander Motin struct g_multipath_softc *sc; 802e770bc6bSMatt Jacob struct g_geom *gp; 8032b4969ffSMatt Jacob struct g_consumer *cp; 8040c883cefSAlexander Motin struct g_provider *pp; 8050c883cefSAlexander Motin const char *mpname; 806e770bc6bSMatt Jacob static const char devpf[6] = "/dev/"; 807e770bc6bSMatt Jacob 808e770bc6bSMatt Jacob g_topology_assert(); 809e770bc6bSMatt Jacob 810e770bc6bSMatt Jacob mpname = gctl_get_asciiparam(req, "arg0"); 811e770bc6bSMatt Jacob if (mpname == NULL) { 812e770bc6bSMatt Jacob gctl_error(req, "No 'arg0' argument"); 813e770bc6bSMatt Jacob return; 814e770bc6bSMatt Jacob } 8152b4969ffSMatt Jacob gp = g_multipath_find_geom(mp, mpname); 8162b4969ffSMatt Jacob if (gp == NULL) { 8172b4969ffSMatt Jacob gctl_error(req, "Device %s is invalid", mpname); 818e770bc6bSMatt Jacob return; 819e770bc6bSMatt Jacob } 8200c883cefSAlexander Motin sc = gp->softc; 821e770bc6bSMatt Jacob 82212f35a61SPawel Jakub Dawidek if (strncmp(name, devpf, 5) == 0) 823e770bc6bSMatt Jacob name += 5; 8242b4969ffSMatt Jacob pp = g_provider_by_name(name); 8252b4969ffSMatt Jacob if (pp == NULL) { 826e770bc6bSMatt Jacob gctl_error(req, "Provider %s is invalid", name); 827e770bc6bSMatt Jacob return; 828e770bc6bSMatt Jacob } 829e770bc6bSMatt Jacob 830e770bc6bSMatt Jacob /* 8310c883cefSAlexander Motin * Check to make sure parameters match. 832e770bc6bSMatt Jacob */ 8330c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 8340c883cefSAlexander Motin if (cp->provider == pp) { 8350c883cefSAlexander Motin gctl_error(req, "provider %s is already there", 8360c883cefSAlexander Motin pp->name); 837e770bc6bSMatt Jacob return; 838e770bc6bSMatt Jacob } 8390c883cefSAlexander Motin } 8400c883cefSAlexander Motin if (sc->sc_pp != NULL && sc->sc_pp->mediasize != 0 && 8410c883cefSAlexander Motin sc->sc_pp->mediasize + (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0) 8420c883cefSAlexander Motin != pp->mediasize) { 8430c883cefSAlexander Motin gctl_error(req, "Providers size mismatch %jd != %jd", 8440c883cefSAlexander Motin (intmax_t) sc->sc_pp->mediasize + 8450c883cefSAlexander Motin (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0), 8460c883cefSAlexander Motin (intmax_t) pp->mediasize); 847e770bc6bSMatt Jacob return; 848e770bc6bSMatt Jacob } 8490c883cefSAlexander Motin if (sc->sc_pp != NULL && sc->sc_pp->sectorsize != 0 && 8500c883cefSAlexander Motin sc->sc_pp->sectorsize != pp->sectorsize) { 8510c883cefSAlexander Motin gctl_error(req, "Providers sectorsize mismatch %u != %u", 8520c883cefSAlexander Motin sc->sc_pp->sectorsize, pp->sectorsize); 853e770bc6bSMatt Jacob return; 854e770bc6bSMatt Jacob } 855e770bc6bSMatt Jacob 856e770bc6bSMatt Jacob /* 8572b4969ffSMatt Jacob * Now add.... 858e770bc6bSMatt Jacob */ 8592b4969ffSMatt Jacob (void) g_multipath_add_disk(gp, pp); 860e770bc6bSMatt Jacob } 861e770bc6bSMatt Jacob 8620c883cefSAlexander Motin static void 86371ee4ef0SThomas Quinot g_multipath_ctl_prefer(struct gctl_req *req, struct g_class *mp) 86471ee4ef0SThomas Quinot { 86571ee4ef0SThomas Quinot struct g_geom *gp; 86671ee4ef0SThomas Quinot struct g_multipath_softc *sc; 86771ee4ef0SThomas Quinot struct g_consumer *cp; 86871ee4ef0SThomas Quinot const char *name, *mpname; 86971ee4ef0SThomas Quinot static const char devpf[6] = "/dev/"; 87071ee4ef0SThomas Quinot int *nargs; 87171ee4ef0SThomas Quinot 87271ee4ef0SThomas Quinot g_topology_assert(); 87371ee4ef0SThomas Quinot 87471ee4ef0SThomas Quinot mpname = gctl_get_asciiparam(req, "arg0"); 87571ee4ef0SThomas Quinot if (mpname == NULL) { 87671ee4ef0SThomas Quinot gctl_error(req, "No 'arg0' argument"); 87771ee4ef0SThomas Quinot return; 87871ee4ef0SThomas Quinot } 87971ee4ef0SThomas Quinot gp = g_multipath_find_geom(mp, mpname); 88071ee4ef0SThomas Quinot if (gp == NULL) { 88171ee4ef0SThomas Quinot gctl_error(req, "Device %s is invalid", mpname); 88271ee4ef0SThomas Quinot return; 88371ee4ef0SThomas Quinot } 88471ee4ef0SThomas Quinot sc = gp->softc; 88571ee4ef0SThomas Quinot 88671ee4ef0SThomas Quinot nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 88771ee4ef0SThomas Quinot if (nargs == NULL) { 88871ee4ef0SThomas Quinot gctl_error(req, "No 'nargs' argument"); 88971ee4ef0SThomas Quinot return; 89071ee4ef0SThomas Quinot } 89171ee4ef0SThomas Quinot if (*nargs != 2) { 89271ee4ef0SThomas Quinot gctl_error(req, "missing device"); 89371ee4ef0SThomas Quinot return; 89471ee4ef0SThomas Quinot } 89571ee4ef0SThomas Quinot 89671ee4ef0SThomas Quinot name = gctl_get_asciiparam(req, "arg1"); 89771ee4ef0SThomas Quinot if (name == NULL) { 89871ee4ef0SThomas Quinot gctl_error(req, "No 'arg1' argument"); 89971ee4ef0SThomas Quinot return; 90071ee4ef0SThomas Quinot } 90171ee4ef0SThomas Quinot if (strncmp(name, devpf, 5) == 0) { 90271ee4ef0SThomas Quinot name += 5; 90371ee4ef0SThomas Quinot } 90471ee4ef0SThomas Quinot 90571ee4ef0SThomas Quinot LIST_FOREACH(cp, &gp->consumer, consumer) { 90671ee4ef0SThomas Quinot if (cp->provider != NULL 90771ee4ef0SThomas Quinot && strcmp(cp->provider->name, name) == 0) 90871ee4ef0SThomas Quinot break; 90971ee4ef0SThomas Quinot } 91071ee4ef0SThomas Quinot 91171ee4ef0SThomas Quinot if (cp == NULL) { 91271ee4ef0SThomas Quinot gctl_error(req, "Provider %s not found", name); 91371ee4ef0SThomas Quinot return; 91471ee4ef0SThomas Quinot } 91571ee4ef0SThomas Quinot 91671ee4ef0SThomas Quinot mtx_lock(&sc->sc_mtx); 91771ee4ef0SThomas Quinot 91871ee4ef0SThomas Quinot if (cp->index & MP_BAD) { 91971ee4ef0SThomas Quinot gctl_error(req, "Consumer %s is invalid", name); 92071ee4ef0SThomas Quinot mtx_unlock(&sc->sc_mtx); 92171ee4ef0SThomas Quinot return; 92271ee4ef0SThomas Quinot } 92371ee4ef0SThomas Quinot 92471ee4ef0SThomas Quinot /* Here when the consumer is present and in good shape */ 92571ee4ef0SThomas Quinot 92671ee4ef0SThomas Quinot sc->sc_active = cp; 92771ee4ef0SThomas Quinot if (!sc->sc_active_active) 92871ee4ef0SThomas Quinot printf("GEOM_MULTIPATH: %s now active path in %s\n", 92971ee4ef0SThomas Quinot sc->sc_active->provider->name, sc->sc_name); 93071ee4ef0SThomas Quinot 93171ee4ef0SThomas Quinot mtx_unlock(&sc->sc_mtx); 93271ee4ef0SThomas Quinot } 93371ee4ef0SThomas Quinot 93471ee4ef0SThomas Quinot static void 9350c883cefSAlexander Motin g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp) 9360c883cefSAlexander Motin { 9370c883cefSAlexander Motin struct g_multipath_softc *sc; 9380c883cefSAlexander Motin struct g_geom *gp; 9390c883cefSAlexander Motin const char *mpname, *name; 9400c883cefSAlexander Motin 9410c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 9420c883cefSAlexander Motin if (mpname == NULL) { 9430c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 9440c883cefSAlexander Motin return; 9450c883cefSAlexander Motin } 9460c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 9470c883cefSAlexander Motin if (gp == NULL) { 9480c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 9490c883cefSAlexander Motin return; 9500c883cefSAlexander Motin } 9510c883cefSAlexander Motin sc = gp->softc; 9520c883cefSAlexander Motin 9530c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 9540c883cefSAlexander Motin if (name == NULL) { 9550c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 9560c883cefSAlexander Motin return; 9570c883cefSAlexander Motin } 9580c883cefSAlexander Motin g_multipath_ctl_add_name(req, mp, name); 9590c883cefSAlexander Motin } 9600c883cefSAlexander Motin 9610c883cefSAlexander Motin static void 9620c883cefSAlexander Motin g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp) 9630c883cefSAlexander Motin { 9640c883cefSAlexander Motin struct g_multipath_metadata md; 9650c883cefSAlexander Motin struct g_multipath_softc *sc; 9660c883cefSAlexander Motin struct g_geom *gp; 9670c883cefSAlexander Motin const char *mpname, *name; 9680c883cefSAlexander Motin char param[16]; 96963297dfdSAlexander Motin int *nargs, i, *val; 9700c883cefSAlexander Motin 9710c883cefSAlexander Motin g_topology_assert(); 9720c883cefSAlexander Motin 9730c883cefSAlexander Motin nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 9740c883cefSAlexander Motin if (*nargs < 2) { 9750c883cefSAlexander Motin gctl_error(req, "wrong number of arguments."); 9760c883cefSAlexander Motin return; 9770c883cefSAlexander Motin } 9780c883cefSAlexander Motin 9790c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 9800c883cefSAlexander Motin if (mpname == NULL) { 9810c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 9820c883cefSAlexander Motin return; 9830c883cefSAlexander Motin } 9840c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 9850c883cefSAlexander Motin if (gp != NULL) { 9860c883cefSAlexander Motin gctl_error(req, "Device %s already exist", mpname); 9870c883cefSAlexander Motin return; 9880c883cefSAlexander Motin } 9890c883cefSAlexander Motin sc = gp->softc; 9900c883cefSAlexander Motin 9910c883cefSAlexander Motin memset(&md, 0, sizeof(md)); 9920c883cefSAlexander Motin strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 9930c883cefSAlexander Motin md.md_version = G_MULTIPATH_VERSION; 9940c883cefSAlexander Motin strlcpy(md.md_name, mpname, sizeof(md.md_name)); 9950c883cefSAlexander Motin md.md_size = 0; 9960c883cefSAlexander Motin md.md_sectorsize = 0; 9970c883cefSAlexander Motin md.md_uuid[0] = 0; 99863297dfdSAlexander Motin md.md_active_active = 0; 99963297dfdSAlexander Motin val = gctl_get_paraml(req, "active_active", sizeof(*val)); 100063297dfdSAlexander Motin if (val != NULL && *val != 0) 100163297dfdSAlexander Motin md.md_active_active = 1; 100263297dfdSAlexander Motin val = gctl_get_paraml(req, "active_read", sizeof(*val)); 100363297dfdSAlexander Motin if (val != NULL && *val != 0) 100463297dfdSAlexander Motin md.md_active_active = 2; 10050c883cefSAlexander Motin gp = g_multipath_create(mp, &md); 10060c883cefSAlexander Motin if (gp == NULL) { 10070c883cefSAlexander Motin gctl_error(req, "GEOM_MULTIPATH: cannot create geom %s/%s\n", 10080c883cefSAlexander Motin md.md_name, md.md_uuid); 10090c883cefSAlexander Motin return; 10100c883cefSAlexander Motin } 10110c883cefSAlexander Motin sc = gp->softc; 10120c883cefSAlexander Motin 10130c883cefSAlexander Motin for (i = 1; i < *nargs; i++) { 10140c883cefSAlexander Motin snprintf(param, sizeof(param), "arg%d", i); 10150c883cefSAlexander Motin name = gctl_get_asciiparam(req, param); 10160c883cefSAlexander Motin g_multipath_ctl_add_name(req, mp, name); 10170c883cefSAlexander Motin } 10180c883cefSAlexander Motin 10190c883cefSAlexander Motin if (sc->sc_ndisks != (*nargs - 1)) 10200c883cefSAlexander Motin g_multipath_destroy(gp); 10210c883cefSAlexander Motin } 10220c883cefSAlexander Motin 10230c883cefSAlexander Motin static void 102463297dfdSAlexander Motin g_multipath_ctl_configure(struct gctl_req *req, struct g_class *mp) 102563297dfdSAlexander Motin { 102663297dfdSAlexander Motin struct g_multipath_softc *sc; 102763297dfdSAlexander Motin struct g_geom *gp; 102863297dfdSAlexander Motin struct g_consumer *cp; 102963297dfdSAlexander Motin struct g_provider *pp; 1030c0b1ef66SAlexander Motin struct g_multipath_metadata md; 103163297dfdSAlexander Motin const char *name; 103263297dfdSAlexander Motin int error, *val; 103363297dfdSAlexander Motin void *buf; 103463297dfdSAlexander Motin 103563297dfdSAlexander Motin g_topology_assert(); 103663297dfdSAlexander Motin 103763297dfdSAlexander Motin name = gctl_get_asciiparam(req, "arg0"); 103863297dfdSAlexander Motin if (name == NULL) { 103963297dfdSAlexander Motin gctl_error(req, "No 'arg0' argument"); 104063297dfdSAlexander Motin return; 104163297dfdSAlexander Motin } 104263297dfdSAlexander Motin gp = g_multipath_find_geom(mp, name); 104363297dfdSAlexander Motin if (gp == NULL) { 104463297dfdSAlexander Motin gctl_error(req, "Device %s is invalid", name); 104563297dfdSAlexander Motin return; 104663297dfdSAlexander Motin } 104763297dfdSAlexander Motin sc = gp->softc; 104863297dfdSAlexander Motin val = gctl_get_paraml(req, "active_active", sizeof(*val)); 104963297dfdSAlexander Motin if (val != NULL && *val != 0) 105063297dfdSAlexander Motin sc->sc_active_active = 1; 105163297dfdSAlexander Motin val = gctl_get_paraml(req, "active_read", sizeof(*val)); 105263297dfdSAlexander Motin if (val != NULL && *val != 0) 105363297dfdSAlexander Motin sc->sc_active_active = 2; 105463297dfdSAlexander Motin val = gctl_get_paraml(req, "active_passive", sizeof(*val)); 105563297dfdSAlexander Motin if (val != NULL && *val != 0) 105663297dfdSAlexander Motin sc->sc_active_active = 0; 105763297dfdSAlexander Motin if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) { 105863297dfdSAlexander Motin cp = sc->sc_active; 105963297dfdSAlexander Motin pp = cp->provider; 106063297dfdSAlexander Motin error = g_access(cp, 1, 1, 1); 106163297dfdSAlexander Motin if (error != 0) { 106263297dfdSAlexander Motin gctl_error(req, "Can't open %s (%d)", pp->name, error); 106363297dfdSAlexander Motin return; 106463297dfdSAlexander Motin } 106563297dfdSAlexander Motin g_topology_unlock(); 1066c0b1ef66SAlexander Motin buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 1067c0b1ef66SAlexander Motin strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 1068c0b1ef66SAlexander Motin memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid)); 1069c0b1ef66SAlexander Motin strlcpy(md.md_name, name, sizeof(md.md_name)); 1070c0b1ef66SAlexander Motin md.md_version = G_MULTIPATH_VERSION; 1071c0b1ef66SAlexander Motin md.md_size = pp->mediasize; 1072c0b1ef66SAlexander Motin md.md_sectorsize = pp->sectorsize; 1073c0b1ef66SAlexander Motin md.md_active_active = sc->sc_active_active; 1074c0b1ef66SAlexander Motin multipath_metadata_encode(&md, buf); 107563297dfdSAlexander Motin error = g_write_data(cp, pp->mediasize - pp->sectorsize, 107663297dfdSAlexander Motin buf, pp->sectorsize); 107763297dfdSAlexander Motin g_topology_lock(); 107863297dfdSAlexander Motin g_access(cp, -1, -1, -1); 107963297dfdSAlexander Motin if (error != 0) 108063297dfdSAlexander Motin gctl_error(req, "Can't update metadata on %s (%d)", 108163297dfdSAlexander Motin pp->name, error); 108263297dfdSAlexander Motin } 108363297dfdSAlexander Motin } 108463297dfdSAlexander Motin 108563297dfdSAlexander Motin static void 10860c883cefSAlexander Motin g_multipath_ctl_fail(struct gctl_req *req, struct g_class *mp, int fail) 10870c883cefSAlexander Motin { 10880c883cefSAlexander Motin struct g_multipath_softc *sc; 10890c883cefSAlexander Motin struct g_geom *gp; 10900c883cefSAlexander Motin struct g_consumer *cp; 10910c883cefSAlexander Motin const char *mpname, *name; 10920c883cefSAlexander Motin int found; 10930c883cefSAlexander Motin 10940c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 10950c883cefSAlexander Motin if (mpname == NULL) { 10960c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 10970c883cefSAlexander Motin return; 10980c883cefSAlexander Motin } 10990c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 11000c883cefSAlexander Motin if (gp == NULL) { 11010c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 11020c883cefSAlexander Motin return; 11030c883cefSAlexander Motin } 11040c883cefSAlexander Motin sc = gp->softc; 11050c883cefSAlexander Motin 11060c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 11070c883cefSAlexander Motin if (name == NULL) { 11080c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 11090c883cefSAlexander Motin return; 11100c883cefSAlexander Motin } 11110c883cefSAlexander Motin 11120c883cefSAlexander Motin found = 0; 11130c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 11140c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 11150c883cefSAlexander Motin if (cp->provider != NULL && 11160c883cefSAlexander Motin strcmp(cp->provider->name, name) == 0 && 11170c883cefSAlexander Motin (cp->index & MP_LOST) == 0) { 11180c883cefSAlexander Motin found = 1; 111963297dfdSAlexander Motin if (!fail == !(cp->index & MP_FAIL)) 112063297dfdSAlexander Motin continue; 11210c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s in %s is marked %s.\n", 11220c883cefSAlexander Motin name, sc->sc_name, fail ? "FAIL" : "OK"); 11230c883cefSAlexander Motin if (fail) { 11240c883cefSAlexander Motin g_multipath_fault(cp, MP_FAIL); 11250c883cefSAlexander Motin } else { 11260c883cefSAlexander Motin cp->index &= ~MP_FAIL; 11270c883cefSAlexander Motin } 11280c883cefSAlexander Motin } 11290c883cefSAlexander Motin } 11300c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 11310c883cefSAlexander Motin if (found == 0) 11320c883cefSAlexander Motin gctl_error(req, "Provider %s not found", name); 11330c883cefSAlexander Motin } 11340c883cefSAlexander Motin 11350c883cefSAlexander Motin static void 11360c883cefSAlexander Motin g_multipath_ctl_remove(struct gctl_req *req, struct g_class *mp) 11370c883cefSAlexander Motin { 11380c883cefSAlexander Motin struct g_multipath_softc *sc; 11390c883cefSAlexander Motin struct g_geom *gp; 11400c883cefSAlexander Motin struct g_consumer *cp, *cp1; 11410c883cefSAlexander Motin const char *mpname, *name; 11420c883cefSAlexander Motin uintptr_t *cnt; 11430c883cefSAlexander Motin int found; 11440c883cefSAlexander Motin 11450c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 11460c883cefSAlexander Motin if (mpname == NULL) { 11470c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 11480c883cefSAlexander Motin return; 11490c883cefSAlexander Motin } 11500c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 11510c883cefSAlexander Motin if (gp == NULL) { 11520c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 11530c883cefSAlexander Motin return; 11540c883cefSAlexander Motin } 11550c883cefSAlexander Motin sc = gp->softc; 11560c883cefSAlexander Motin 11570c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 11580c883cefSAlexander Motin if (name == NULL) { 11590c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 11600c883cefSAlexander Motin return; 11610c883cefSAlexander Motin } 11620c883cefSAlexander Motin 11630c883cefSAlexander Motin found = 0; 11640c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 11650c883cefSAlexander Motin LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 11660c883cefSAlexander Motin if (cp->provider != NULL && 11670c883cefSAlexander Motin strcmp(cp->provider->name, name) == 0 && 11680c883cefSAlexander Motin (cp->index & MP_LOST) == 0) { 11690c883cefSAlexander Motin found = 1; 11700c883cefSAlexander Motin printf("GEOM_MULTIPATH: removing %s from %s\n", 11710c883cefSAlexander Motin cp->provider->name, cp->geom->name); 11720c883cefSAlexander Motin sc->sc_ndisks--; 11730c883cefSAlexander Motin g_multipath_fault(cp, MP_LOST); 11740c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 11750c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_POSTED) == 0) { 11760c883cefSAlexander Motin cp->index |= MP_POSTED; 11770c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 11780c883cefSAlexander Motin g_mpd(cp, 0); 11790c883cefSAlexander Motin if (cp1 == NULL) 11800c883cefSAlexander Motin return; /* Recursion happened. */ 11810c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 11820c883cefSAlexander Motin } 11830c883cefSAlexander Motin } 11840c883cefSAlexander Motin } 11850c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 11860c883cefSAlexander Motin if (found == 0) 11870c883cefSAlexander Motin gctl_error(req, "Provider %s not found", name); 11880c883cefSAlexander Motin } 11890c883cefSAlexander Motin 1190e770bc6bSMatt Jacob static struct g_geom * 1191e770bc6bSMatt Jacob g_multipath_find_geom(struct g_class *mp, const char *name) 1192e770bc6bSMatt Jacob { 1193e770bc6bSMatt Jacob struct g_geom *gp; 11940c883cefSAlexander Motin struct g_multipath_softc *sc; 1195e770bc6bSMatt Jacob 1196e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 11970c883cefSAlexander Motin sc = gp->softc; 11980c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 11990c883cefSAlexander Motin continue; 12000c883cefSAlexander Motin if (strcmp(gp->name, name) == 0) 1201e770bc6bSMatt Jacob return (gp); 1202e770bc6bSMatt Jacob } 1203e770bc6bSMatt Jacob return (NULL); 1204e770bc6bSMatt Jacob } 1205e770bc6bSMatt Jacob 1206e770bc6bSMatt Jacob static void 12070c883cefSAlexander Motin g_multipath_ctl_stop(struct gctl_req *req, struct g_class *mp) 1208e770bc6bSMatt Jacob { 1209e770bc6bSMatt Jacob struct g_geom *gp; 1210e770bc6bSMatt Jacob const char *name; 1211e770bc6bSMatt Jacob int error; 1212e770bc6bSMatt Jacob 1213e770bc6bSMatt Jacob g_topology_assert(); 1214e770bc6bSMatt Jacob 1215e770bc6bSMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1216e770bc6bSMatt Jacob if (name == NULL) { 1217e770bc6bSMatt Jacob gctl_error(req, "No 'arg0' argument"); 1218e770bc6bSMatt Jacob return; 1219e770bc6bSMatt Jacob } 1220e770bc6bSMatt Jacob gp = g_multipath_find_geom(mp, name); 1221e770bc6bSMatt Jacob if (gp == NULL) { 1222e770bc6bSMatt Jacob gctl_error(req, "Device %s is invalid", name); 1223e770bc6bSMatt Jacob return; 1224e770bc6bSMatt Jacob } 1225e770bc6bSMatt Jacob error = g_multipath_destroy(gp); 12260c883cefSAlexander Motin if (error != 0 && error != EINPROGRESS) 12270c883cefSAlexander Motin gctl_error(req, "failed to stop %s (err=%d)", name, error); 1228e770bc6bSMatt Jacob } 12290c883cefSAlexander Motin 12300c883cefSAlexander Motin static void 12310c883cefSAlexander Motin g_multipath_ctl_destroy(struct gctl_req *req, struct g_class *mp) 12320c883cefSAlexander Motin { 12330c883cefSAlexander Motin struct g_geom *gp; 12340c883cefSAlexander Motin struct g_multipath_softc *sc; 12350c883cefSAlexander Motin struct g_consumer *cp; 12360c883cefSAlexander Motin struct g_provider *pp; 12370c883cefSAlexander Motin const char *name; 12380c883cefSAlexander Motin uint8_t *buf; 12390c883cefSAlexander Motin int error; 12400c883cefSAlexander Motin 12410c883cefSAlexander Motin g_topology_assert(); 12420c883cefSAlexander Motin 12430c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg0"); 12440c883cefSAlexander Motin if (name == NULL) { 12450c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 12460c883cefSAlexander Motin return; 12470c883cefSAlexander Motin } 12480c883cefSAlexander Motin gp = g_multipath_find_geom(mp, name); 12490c883cefSAlexander Motin if (gp == NULL) { 12500c883cefSAlexander Motin gctl_error(req, "Device %s is invalid", name); 12510c883cefSAlexander Motin return; 12520c883cefSAlexander Motin } 12530c883cefSAlexander Motin sc = gp->softc; 12540c883cefSAlexander Motin 12550c883cefSAlexander Motin if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) { 12560c883cefSAlexander Motin cp = sc->sc_active; 12570c883cefSAlexander Motin pp = cp->provider; 12580c883cefSAlexander Motin error = g_access(cp, 1, 1, 1); 12590c883cefSAlexander Motin if (error != 0) { 12600c883cefSAlexander Motin gctl_error(req, "Can't open %s (%d)", pp->name, error); 12610c883cefSAlexander Motin goto destroy; 12620c883cefSAlexander Motin } 12630c883cefSAlexander Motin g_topology_unlock(); 12640c883cefSAlexander Motin buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 12650c883cefSAlexander Motin error = g_write_data(cp, pp->mediasize - pp->sectorsize, 12660c883cefSAlexander Motin buf, pp->sectorsize); 12670c883cefSAlexander Motin g_topology_lock(); 12680c883cefSAlexander Motin g_access(cp, -1, -1, -1); 12690c883cefSAlexander Motin if (error != 0) 12700c883cefSAlexander Motin gctl_error(req, "Can't erase metadata on %s (%d)", 12710c883cefSAlexander Motin pp->name, error); 12720c883cefSAlexander Motin } 12730c883cefSAlexander Motin 12740c883cefSAlexander Motin destroy: 12750c883cefSAlexander Motin error = g_multipath_destroy(gp); 12760c883cefSAlexander Motin if (error != 0 && error != EINPROGRESS) 12770c883cefSAlexander Motin gctl_error(req, "failed to destroy %s (err=%d)", name, error); 1278e770bc6bSMatt Jacob } 1279e770bc6bSMatt Jacob 1280e770bc6bSMatt Jacob static void 1281b5dce617SMatt Jacob g_multipath_ctl_rotate(struct gctl_req *req, struct g_class *mp) 1282b5dce617SMatt Jacob { 1283b5dce617SMatt Jacob struct g_geom *gp; 1284b5dce617SMatt Jacob const char *name; 1285b5dce617SMatt Jacob int error; 1286b5dce617SMatt Jacob 1287b5dce617SMatt Jacob g_topology_assert(); 1288b5dce617SMatt Jacob 1289b5dce617SMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1290b5dce617SMatt Jacob if (name == NULL) { 1291b5dce617SMatt Jacob gctl_error(req, "No 'arg0' argument"); 1292b5dce617SMatt Jacob return; 1293b5dce617SMatt Jacob } 1294b5dce617SMatt Jacob gp = g_multipath_find_geom(mp, name); 1295b5dce617SMatt Jacob if (gp == NULL) { 1296b5dce617SMatt Jacob gctl_error(req, "Device %s is invalid", name); 1297b5dce617SMatt Jacob return; 1298b5dce617SMatt Jacob } 1299b5dce617SMatt Jacob error = g_multipath_rotate(gp); 1300b5dce617SMatt Jacob if (error != 0) { 1301b5dce617SMatt Jacob gctl_error(req, "failed to rotate %s (err=%d)", name, error); 1302b5dce617SMatt Jacob } 1303b5dce617SMatt Jacob } 1304b5dce617SMatt Jacob 1305b5dce617SMatt Jacob static void 1306b5dce617SMatt Jacob g_multipath_ctl_getactive(struct gctl_req *req, struct g_class *mp) 1307b5dce617SMatt Jacob { 1308b5dce617SMatt Jacob struct sbuf *sb; 1309b5dce617SMatt Jacob struct g_geom *gp; 1310b5dce617SMatt Jacob struct g_multipath_softc *sc; 13110c883cefSAlexander Motin struct g_consumer *cp; 1312b5dce617SMatt Jacob const char *name; 13130c883cefSAlexander Motin int empty; 1314b5dce617SMatt Jacob 1315b5dce617SMatt Jacob sb = sbuf_new_auto(); 1316b5dce617SMatt Jacob 1317b5dce617SMatt Jacob g_topology_assert(); 1318b5dce617SMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1319b5dce617SMatt Jacob if (name == NULL) { 1320b5dce617SMatt Jacob gctl_error(req, "No 'arg0' argument"); 1321b5dce617SMatt Jacob return; 1322b5dce617SMatt Jacob } 1323b5dce617SMatt Jacob gp = g_multipath_find_geom(mp, name); 1324b5dce617SMatt Jacob if (gp == NULL) { 1325b5dce617SMatt Jacob gctl_error(req, "Device %s is invalid", name); 1326b5dce617SMatt Jacob return; 1327b5dce617SMatt Jacob } 1328b5dce617SMatt Jacob sc = gp->softc; 132963297dfdSAlexander Motin if (sc->sc_active_active == 1) { 13300c883cefSAlexander Motin empty = 1; 13310c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 13320c883cefSAlexander Motin if (cp->index & MP_BAD) 13330c883cefSAlexander Motin continue; 13340c883cefSAlexander Motin if (!empty) 13350c883cefSAlexander Motin sbuf_cat(sb, " "); 13360c883cefSAlexander Motin sbuf_cat(sb, cp->provider->name); 13370c883cefSAlexander Motin empty = 0; 13380c883cefSAlexander Motin } 13390c883cefSAlexander Motin if (empty) 13400c883cefSAlexander Motin sbuf_cat(sb, "none"); 13410c883cefSAlexander Motin sbuf_cat(sb, "\n"); 13420c883cefSAlexander Motin } else if (sc->sc_active && sc->sc_active->provider) { 13430c883cefSAlexander Motin sbuf_printf(sb, "%s\n", sc->sc_active->provider->name); 1344b5dce617SMatt Jacob } else { 1345b5dce617SMatt Jacob sbuf_printf(sb, "none\n"); 1346b5dce617SMatt Jacob } 1347b5dce617SMatt Jacob sbuf_finish(sb); 1348b5dce617SMatt Jacob gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1349b5dce617SMatt Jacob sbuf_delete(sb); 1350b5dce617SMatt Jacob } 1351b5dce617SMatt Jacob 1352b5dce617SMatt Jacob static void 1353e770bc6bSMatt Jacob g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb) 1354e770bc6bSMatt Jacob { 1355e770bc6bSMatt Jacob uint32_t *version; 1356e770bc6bSMatt Jacob g_topology_assert(); 1357e770bc6bSMatt Jacob version = gctl_get_paraml(req, "version", sizeof(*version)); 1358e770bc6bSMatt Jacob if (version == NULL) { 1359e770bc6bSMatt Jacob gctl_error(req, "No 'version' argument"); 1360e770bc6bSMatt Jacob } else if (*version != G_MULTIPATH_VERSION) { 1361e770bc6bSMatt Jacob gctl_error(req, "Userland and kernel parts are out of sync"); 13622b4969ffSMatt Jacob } else if (strcmp(verb, "add") == 0) { 13632b4969ffSMatt Jacob g_multipath_ctl_add(req, mp); 136471ee4ef0SThomas Quinot } else if (strcmp(verb, "prefer") == 0) { 136571ee4ef0SThomas Quinot g_multipath_ctl_prefer(req, mp); 13660c883cefSAlexander Motin } else if (strcmp(verb, "create") == 0) { 13670c883cefSAlexander Motin g_multipath_ctl_create(req, mp); 136863297dfdSAlexander Motin } else if (strcmp(verb, "configure") == 0) { 136963297dfdSAlexander Motin g_multipath_ctl_configure(req, mp); 13700c883cefSAlexander Motin } else if (strcmp(verb, "stop") == 0) { 13710c883cefSAlexander Motin g_multipath_ctl_stop(req, mp); 1372e770bc6bSMatt Jacob } else if (strcmp(verb, "destroy") == 0) { 1373e770bc6bSMatt Jacob g_multipath_ctl_destroy(req, mp); 13740c883cefSAlexander Motin } else if (strcmp(verb, "fail") == 0) { 13750c883cefSAlexander Motin g_multipath_ctl_fail(req, mp, 1); 13760c883cefSAlexander Motin } else if (strcmp(verb, "restore") == 0) { 13770c883cefSAlexander Motin g_multipath_ctl_fail(req, mp, 0); 13780c883cefSAlexander Motin } else if (strcmp(verb, "remove") == 0) { 13790c883cefSAlexander Motin g_multipath_ctl_remove(req, mp); 1380b5dce617SMatt Jacob } else if (strcmp(verb, "rotate") == 0) { 1381b5dce617SMatt Jacob g_multipath_ctl_rotate(req, mp); 1382b5dce617SMatt Jacob } else if (strcmp(verb, "getactive") == 0) { 1383b5dce617SMatt Jacob g_multipath_ctl_getactive(req, mp); 1384e770bc6bSMatt Jacob } else { 1385e770bc6bSMatt Jacob gctl_error(req, "Unknown verb %s", verb); 1386e770bc6bSMatt Jacob } 1387e770bc6bSMatt Jacob } 13880c883cefSAlexander Motin 13890c883cefSAlexander Motin static void 13900c883cefSAlexander Motin g_multipath_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 13910c883cefSAlexander Motin struct g_consumer *cp, struct g_provider *pp) 13920c883cefSAlexander Motin { 13930c883cefSAlexander Motin struct g_multipath_softc *sc; 13940c883cefSAlexander Motin int good; 13950c883cefSAlexander Motin 13960c883cefSAlexander Motin g_topology_assert(); 13970c883cefSAlexander Motin 13980c883cefSAlexander Motin sc = gp->softc; 13990c883cefSAlexander Motin if (sc == NULL) 14000c883cefSAlexander Motin return; 14010c883cefSAlexander Motin if (cp != NULL) { 1402a839e332SAlexander Motin sbuf_printf(sb, "%s<State>%s</State>\n", indent, 14030c883cefSAlexander Motin (cp->index & MP_NEW) ? "NEW" : 14040c883cefSAlexander Motin (cp->index & MP_LOST) ? "LOST" : 14050c883cefSAlexander Motin (cp->index & MP_FAIL) ? "FAIL" : 140663297dfdSAlexander Motin (sc->sc_active_active == 1 || sc->sc_active == cp) ? 140763297dfdSAlexander Motin "ACTIVE" : 140863297dfdSAlexander Motin sc->sc_active_active == 2 ? "READ" : "PASSIVE"); 14090c883cefSAlexander Motin } else { 14100c883cefSAlexander Motin good = g_multipath_good(gp); 1411a839e332SAlexander Motin sbuf_printf(sb, "%s<State>%s</State>\n", indent, 14120c883cefSAlexander Motin good == 0 ? "BROKEN" : 14130c883cefSAlexander Motin (good != sc->sc_ndisks || sc->sc_ndisks == 1) ? 14140c883cefSAlexander Motin "DEGRADED" : "OPTIMAL"); 14150c883cefSAlexander Motin } 14160c883cefSAlexander Motin if (cp == NULL && pp == NULL) { 1417a839e332SAlexander Motin sbuf_printf(sb, "%s<UUID>%s</UUID>\n", indent, sc->sc_uuid); 1418a839e332SAlexander Motin sbuf_printf(sb, "%s<Mode>Active/%s</Mode>\n", indent, 141963297dfdSAlexander Motin sc->sc_active_active == 2 ? "Read" : 142063297dfdSAlexander Motin sc->sc_active_active == 1 ? "Active" : "Passive"); 1421a839e332SAlexander Motin sbuf_printf(sb, "%s<Type>%s</Type>\n", indent, 14220c883cefSAlexander Motin sc->sc_uuid[0] == 0 ? "MANUAL" : "AUTOMATIC"); 14230c883cefSAlexander Motin } 14240c883cefSAlexander Motin } 14250c883cefSAlexander Motin 1426e770bc6bSMatt Jacob DECLARE_GEOM_CLASS(g_multipath_class, g_multipath); 1427