1e770bc6bSMatt Jacob /*- 2*0c883cefSAlexander 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"); 57*0c883cefSAlexander Motin static u_int g_multipath_exclusive = 1; 58*0c883cefSAlexander Motin SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, exclusive, CTLFLAG_RW, 59*0c883cefSAlexander 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; 86*0c883cefSAlexander 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 98*0c883cefSAlexander Motin #define MP_FAIL 0x00000001 99*0c883cefSAlexander Motin #define MP_LOST 0x00000002 100*0c883cefSAlexander Motin #define MP_NEW 0x00000004 101*0c883cefSAlexander Motin #define MP_POSTED 0x00000008 102*0c883cefSAlexander Motin #define MP_BAD (MP_FAIL | MP_LOST | MP_NEW) 103*0c883cefSAlexander Motin #define MP_IDLE 0x00000010 104*0c883cefSAlexander Motin #define MP_IDLE_MASK 0xfffffff0 105*0c883cefSAlexander Motin 106*0c883cefSAlexander Motin static int 107*0c883cefSAlexander Motin g_multipath_good(struct g_geom *gp) 108*0c883cefSAlexander Motin { 109*0c883cefSAlexander Motin struct g_consumer *cp; 110*0c883cefSAlexander Motin int n = 0; 111*0c883cefSAlexander Motin 112*0c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 113*0c883cefSAlexander Motin if ((cp->index & MP_BAD) == 0) 114*0c883cefSAlexander Motin n++; 115*0c883cefSAlexander Motin } 116*0c883cefSAlexander Motin return (n); 117*0c883cefSAlexander Motin } 118*0c883cefSAlexander Motin 119*0c883cefSAlexander Motin static void 120*0c883cefSAlexander Motin g_multipath_fault(struct g_consumer *cp, int cause) 121*0c883cefSAlexander Motin { 122*0c883cefSAlexander Motin struct g_multipath_softc *sc; 123*0c883cefSAlexander Motin struct g_consumer *lcp; 124*0c883cefSAlexander Motin struct g_geom *gp; 125*0c883cefSAlexander Motin 126*0c883cefSAlexander Motin gp = cp->geom; 127*0c883cefSAlexander Motin sc = gp->softc; 128*0c883cefSAlexander Motin cp->index |= cause; 129*0c883cefSAlexander Motin if (g_multipath_good(gp) == 0 && sc->sc_ndisks > 0) { 130*0c883cefSAlexander Motin LIST_FOREACH(lcp, &gp->consumer, consumer) { 131*0c883cefSAlexander Motin if (lcp->provider == NULL || 132*0c883cefSAlexander Motin (lcp->index & (MP_LOST | MP_NEW))) 133*0c883cefSAlexander Motin continue; 134*0c883cefSAlexander Motin if (sc->sc_ndisks > 1 && lcp == cp) 135*0c883cefSAlexander Motin continue; 136*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: " 137*0c883cefSAlexander Motin "all paths in %s were marked FAIL, restore %s\n", 138*0c883cefSAlexander Motin sc->sc_name, lcp->provider->name); 139*0c883cefSAlexander Motin lcp->index &= ~MP_FAIL; 140*0c883cefSAlexander Motin } 141*0c883cefSAlexander Motin } 142*0c883cefSAlexander Motin if (cp != sc->sc_active) 143*0c883cefSAlexander Motin return; 144*0c883cefSAlexander Motin sc->sc_active = NULL; 145*0c883cefSAlexander Motin LIST_FOREACH(lcp, &gp->consumer, consumer) { 146*0c883cefSAlexander Motin if ((lcp->index & MP_BAD) == 0) { 147*0c883cefSAlexander Motin sc->sc_active = lcp; 148*0c883cefSAlexander Motin break; 149*0c883cefSAlexander Motin } 150*0c883cefSAlexander Motin } 151*0c883cefSAlexander Motin if (sc->sc_active == NULL) { 152*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: out of providers for %s\n", 153*0c883cefSAlexander Motin sc->sc_name); 154*0c883cefSAlexander Motin } else if (!sc->sc_active_active) { 155*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 156*0c883cefSAlexander Motin sc->sc_active->provider->name, sc->sc_name); 157*0c883cefSAlexander Motin } 158*0c883cefSAlexander Motin } 159*0c883cefSAlexander Motin 160*0c883cefSAlexander Motin static struct g_consumer * 161*0c883cefSAlexander Motin g_multipath_choose(struct g_geom *gp) 162*0c883cefSAlexander Motin { 163*0c883cefSAlexander Motin struct g_multipath_softc *sc; 164*0c883cefSAlexander Motin struct g_consumer *best, *cp; 165*0c883cefSAlexander Motin 166*0c883cefSAlexander Motin sc = gp->softc; 167*0c883cefSAlexander Motin if (!sc->sc_active_active) 168*0c883cefSAlexander Motin return (sc->sc_active); 169*0c883cefSAlexander Motin best = NULL; 170*0c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 171*0c883cefSAlexander Motin if (cp->index & MP_BAD) 172*0c883cefSAlexander Motin continue; 173*0c883cefSAlexander Motin cp->index += MP_IDLE; 174*0c883cefSAlexander Motin if (best == NULL || cp->private < best->private || 175*0c883cefSAlexander Motin (cp->private == best->private && cp->index > best->index)) 176*0c883cefSAlexander Motin best = cp; 177*0c883cefSAlexander Motin } 178*0c883cefSAlexander Motin if (best != NULL) 179*0c883cefSAlexander Motin best->index &= ~MP_IDLE_MASK; 180*0c883cefSAlexander Motin return (best); 181*0c883cefSAlexander Motin } 182e770bc6bSMatt Jacob 183e770bc6bSMatt Jacob static void 184e770bc6bSMatt Jacob g_mpd(void *arg, int flags __unused) 185e770bc6bSMatt Jacob { 186*0c883cefSAlexander Motin struct g_geom *gp; 187*0c883cefSAlexander Motin struct g_multipath_softc *sc; 188e770bc6bSMatt Jacob struct g_consumer *cp; 189*0c883cefSAlexander Motin int w; 190e770bc6bSMatt Jacob 191e770bc6bSMatt Jacob g_topology_assert(); 192e770bc6bSMatt Jacob cp = arg; 193*0c883cefSAlexander Motin gp = cp->geom; 194*0c883cefSAlexander Motin if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) { 195*0c883cefSAlexander Motin w = cp->acw; 196e770bc6bSMatt Jacob g_access(cp, -cp->acr, -cp->acw, -cp->ace); 197*0c883cefSAlexander Motin if (w > 0 && cp->provider != NULL && 198*0c883cefSAlexander Motin (cp->provider->geom->flags & G_GEOM_WITHER) == 0) { 199*0c883cefSAlexander Motin g_post_event(g_mpd, cp, M_WAITOK, NULL); 200*0c883cefSAlexander Motin return; 201*0c883cefSAlexander Motin } 202*0c883cefSAlexander Motin } 203*0c883cefSAlexander Motin sc = gp->softc; 204*0c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 205e770bc6bSMatt Jacob if (cp->provider) { 206e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: %s removed from %s\n", 207*0c883cefSAlexander Motin cp->provider->name, gp->name); 208e770bc6bSMatt Jacob g_detach(cp); 209e770bc6bSMatt Jacob } 210e770bc6bSMatt Jacob g_destroy_consumer(cp); 211*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 212*0c883cefSAlexander Motin if (LIST_EMPTY(&gp->consumer)) 213*0c883cefSAlexander Motin g_multipath_destroy(gp); 214e770bc6bSMatt Jacob } 215e770bc6bSMatt Jacob 216e770bc6bSMatt Jacob static void 217e770bc6bSMatt Jacob g_multipath_orphan(struct g_consumer *cp) 218e770bc6bSMatt Jacob { 219*0c883cefSAlexander Motin struct g_multipath_softc *sc; 220*0c883cefSAlexander Motin uintptr_t *cnt; 221*0c883cefSAlexander Motin 222*0c883cefSAlexander Motin g_topology_assert(); 223*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s in %s was disconnected\n", 224e770bc6bSMatt Jacob cp->provider->name, cp->geom->name); 225*0c883cefSAlexander Motin sc = cp->geom->softc; 226*0c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 227*0c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 228*0c883cefSAlexander Motin sc->sc_ndisks--; 229*0c883cefSAlexander Motin g_multipath_fault(cp, MP_LOST); 230*0c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_POSTED) == 0) { 231*0c883cefSAlexander Motin cp->index |= MP_POSTED; 232*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 233e770bc6bSMatt Jacob g_mpd(cp, 0); 234*0c883cefSAlexander Motin } else 235*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 236e770bc6bSMatt Jacob } 237e770bc6bSMatt Jacob 238e770bc6bSMatt Jacob static void 239e770bc6bSMatt Jacob g_multipath_start(struct bio *bp) 240e770bc6bSMatt Jacob { 241e770bc6bSMatt Jacob struct g_multipath_softc *sc; 242e770bc6bSMatt Jacob struct g_geom *gp; 243e770bc6bSMatt Jacob struct g_consumer *cp; 244e770bc6bSMatt Jacob struct bio *cbp; 245*0c883cefSAlexander Motin uintptr_t *cnt; 246e770bc6bSMatt Jacob 247e770bc6bSMatt Jacob gp = bp->bio_to->geom; 248e770bc6bSMatt Jacob sc = gp->softc; 249e770bc6bSMatt Jacob KASSERT(sc != NULL, ("NULL sc")); 250e770bc6bSMatt Jacob cbp = g_clone_bio(bp); 251e770bc6bSMatt Jacob if (cbp == NULL) { 252e770bc6bSMatt Jacob g_io_deliver(bp, ENOMEM); 253e770bc6bSMatt Jacob return; 254e770bc6bSMatt Jacob } 255*0c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 256*0c883cefSAlexander Motin cp = g_multipath_choose(gp); 257*0c883cefSAlexander Motin if (cp == NULL) { 258*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 259*0c883cefSAlexander Motin g_destroy_bio(cbp); 260*0c883cefSAlexander Motin g_io_deliver(bp, ENXIO); 261*0c883cefSAlexander Motin return; 262*0c883cefSAlexander Motin } 263*0c883cefSAlexander Motin if ((uintptr_t)bp->bio_driver1 < sc->sc_ndisks) 264*0c883cefSAlexander Motin bp->bio_driver1 = (void *)(uintptr_t)sc->sc_ndisks; 265*0c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 266*0c883cefSAlexander Motin (*cnt)++; 267*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 268e770bc6bSMatt Jacob cbp->bio_done = g_multipath_done; 269e770bc6bSMatt Jacob g_io_request(cbp, cp); 270e770bc6bSMatt Jacob } 271e770bc6bSMatt Jacob 272e770bc6bSMatt Jacob static void 273e770bc6bSMatt Jacob g_multipath_done(struct bio *bp) 274e770bc6bSMatt Jacob { 275*0c883cefSAlexander Motin struct g_multipath_softc *sc; 276*0c883cefSAlexander Motin struct g_consumer *cp; 277*0c883cefSAlexander Motin uintptr_t *cnt; 278*0c883cefSAlexander Motin 279e770bc6bSMatt Jacob if (bp->bio_error == ENXIO || bp->bio_error == EIO) { 280e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 281e770bc6bSMatt Jacob bioq_insert_tail(&gmtbq, bp); 282e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 283*0c883cefSAlexander Motin wakeup(&g_multipath_kt_state); 284e770bc6bSMatt Jacob } else { 285*0c883cefSAlexander Motin cp = bp->bio_from; 286*0c883cefSAlexander Motin sc = cp->geom->softc; 287*0c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 288*0c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 289*0c883cefSAlexander Motin (*cnt)--; 290*0c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_LOST)) { 291*0c883cefSAlexander Motin cp->index |= MP_POSTED; 292*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 293*0c883cefSAlexander Motin g_post_event(g_mpd, cp, M_WAITOK, NULL); 294*0c883cefSAlexander Motin } else 295*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 296e770bc6bSMatt Jacob g_std_done(bp); 297e770bc6bSMatt Jacob } 298e770bc6bSMatt Jacob } 299e770bc6bSMatt Jacob 300e770bc6bSMatt Jacob static void 301e770bc6bSMatt Jacob g_multipath_done_error(struct bio *bp) 302e770bc6bSMatt Jacob { 303e770bc6bSMatt Jacob struct bio *pbp; 304e770bc6bSMatt Jacob struct g_geom *gp; 305e770bc6bSMatt Jacob struct g_multipath_softc *sc; 306e770bc6bSMatt Jacob struct g_consumer *cp; 307e770bc6bSMatt Jacob struct g_provider *pp; 308*0c883cefSAlexander Motin uintptr_t *cnt; 309e770bc6bSMatt Jacob 310e770bc6bSMatt Jacob /* 311e770bc6bSMatt Jacob * If we had a failure, we have to check first to see 312e770bc6bSMatt Jacob * whether the consumer it failed on was the currently 313e770bc6bSMatt Jacob * active consumer (i.e., this is the first in perhaps 314e770bc6bSMatt Jacob * a number of failures). If so, we then switch consumers 315e770bc6bSMatt Jacob * to the next available consumer. 316e770bc6bSMatt Jacob */ 317e770bc6bSMatt Jacob 318e770bc6bSMatt Jacob pbp = bp->bio_parent; 319e770bc6bSMatt Jacob gp = pbp->bio_to->geom; 320e770bc6bSMatt Jacob sc = gp->softc; 321e770bc6bSMatt Jacob cp = bp->bio_from; 322e770bc6bSMatt Jacob pp = cp->provider; 323*0c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 324e770bc6bSMatt Jacob 325*0c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 326*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: Error %d, %s in %s marked FAIL\n", 327*0c883cefSAlexander Motin bp->bio_error, pp->name, sc->sc_name); 328*0c883cefSAlexander Motin g_multipath_fault(cp, MP_FAIL); 329*0c883cefSAlexander Motin (*cnt)--; 330*0c883cefSAlexander Motin if (*cnt == 0 && (cp->index & (MP_LOST | MP_POSTED)) == MP_LOST) { 331e770bc6bSMatt Jacob cp->index |= MP_POSTED; 332*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 333*0c883cefSAlexander Motin g_post_event(g_mpd, cp, M_WAITOK, NULL); 334*0c883cefSAlexander Motin } else 335*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 336e770bc6bSMatt Jacob 337e770bc6bSMatt Jacob /* 338e770bc6bSMatt Jacob * If we can fruitfully restart the I/O, do so. 339e770bc6bSMatt Jacob */ 340*0c883cefSAlexander Motin if (pbp->bio_children < (uintptr_t)pbp->bio_driver1) { 341*0c883cefSAlexander Motin pbp->bio_inbed++; 342e770bc6bSMatt Jacob g_destroy_bio(bp); 343e770bc6bSMatt Jacob g_multipath_start(pbp); 344e770bc6bSMatt Jacob } else { 345e770bc6bSMatt Jacob g_std_done(bp); 346e770bc6bSMatt Jacob } 347e770bc6bSMatt Jacob } 348e770bc6bSMatt Jacob 349e770bc6bSMatt Jacob static void 350e770bc6bSMatt Jacob g_multipath_kt(void *arg) 351e770bc6bSMatt Jacob { 35212f35a61SPawel Jakub Dawidek 353e770bc6bSMatt Jacob g_multipath_kt_state = GKT_RUN; 354e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 355e770bc6bSMatt Jacob while (g_multipath_kt_state == GKT_RUN) { 356e770bc6bSMatt Jacob for (;;) { 357e770bc6bSMatt Jacob struct bio *bp; 35812f35a61SPawel Jakub Dawidek 359e770bc6bSMatt Jacob bp = bioq_takefirst(&gmtbq); 36012f35a61SPawel Jakub Dawidek if (bp == NULL) 361e770bc6bSMatt Jacob break; 362e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 363e770bc6bSMatt Jacob g_multipath_done_error(bp); 364e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 365e770bc6bSMatt Jacob } 366e770bc6bSMatt Jacob msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO, 367e770bc6bSMatt Jacob "gkt:wait", hz / 10); 368e770bc6bSMatt Jacob } 369e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 370e770bc6bSMatt Jacob wakeup(&g_multipath_kt_state); 3713745c395SJulian Elischer kproc_exit(0); 372e770bc6bSMatt Jacob } 373e770bc6bSMatt Jacob 374e770bc6bSMatt Jacob 375e770bc6bSMatt Jacob static int 376e770bc6bSMatt Jacob g_multipath_access(struct g_provider *pp, int dr, int dw, int de) 377e770bc6bSMatt Jacob { 378e770bc6bSMatt Jacob struct g_geom *gp; 379e770bc6bSMatt Jacob struct g_consumer *cp, *badcp = NULL; 380*0c883cefSAlexander Motin struct g_multipath_softc *sc; 381e770bc6bSMatt Jacob int error; 382e770bc6bSMatt Jacob 383e770bc6bSMatt Jacob gp = pp->geom; 384e770bc6bSMatt Jacob 385e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 386e770bc6bSMatt Jacob error = g_access(cp, dr, dw, de); 387e770bc6bSMatt Jacob if (error) { 388e770bc6bSMatt Jacob badcp = cp; 389e770bc6bSMatt Jacob goto fail; 390e770bc6bSMatt Jacob } 391e770bc6bSMatt Jacob } 392*0c883cefSAlexander Motin sc = gp->softc; 393*0c883cefSAlexander Motin sc->sc_opened += dr + dw + de; 394*0c883cefSAlexander Motin if (sc->sc_stopping && sc->sc_opened == 0) 395*0c883cefSAlexander Motin g_multipath_destroy(gp); 396e770bc6bSMatt Jacob return (0); 397e770bc6bSMatt Jacob 398e770bc6bSMatt Jacob fail: 399e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 40012f35a61SPawel Jakub Dawidek if (cp == badcp) 401e770bc6bSMatt Jacob break; 402e770bc6bSMatt Jacob (void) g_access(cp, -dr, -dw, -de); 403e770bc6bSMatt Jacob } 404e770bc6bSMatt Jacob return (error); 405e770bc6bSMatt Jacob } 406e770bc6bSMatt Jacob 407e770bc6bSMatt Jacob static struct g_geom * 408e770bc6bSMatt Jacob g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md) 409e770bc6bSMatt Jacob { 410e770bc6bSMatt Jacob struct g_multipath_softc *sc; 411e770bc6bSMatt Jacob struct g_geom *gp; 412e770bc6bSMatt Jacob struct g_provider *pp; 413e770bc6bSMatt Jacob 414e770bc6bSMatt Jacob g_topology_assert(); 415e770bc6bSMatt Jacob 416e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 417*0c883cefSAlexander Motin sc = gp->softc; 418*0c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 419*0c883cefSAlexander Motin continue; 420e770bc6bSMatt Jacob if (strcmp(gp->name, md->md_name) == 0) { 421e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: name %s already exists\n", 422e770bc6bSMatt Jacob md->md_name); 423e770bc6bSMatt Jacob return (NULL); 424e770bc6bSMatt Jacob } 425e770bc6bSMatt Jacob } 426e770bc6bSMatt Jacob 427e770bc6bSMatt Jacob gp = g_new_geomf(mp, md->md_name); 428e770bc6bSMatt Jacob sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); 429*0c883cefSAlexander Motin mtx_init(&sc->sc_mtx, "multipath", NULL, MTX_DEF); 430*0c883cefSAlexander Motin memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid)); 431*0c883cefSAlexander Motin memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name)); 432*0c883cefSAlexander Motin sc->sc_active_active = md->md_active_active; 433e770bc6bSMatt Jacob gp->softc = sc; 434e770bc6bSMatt Jacob gp->start = g_multipath_start; 435e770bc6bSMatt Jacob gp->orphan = g_multipath_orphan; 436e770bc6bSMatt Jacob gp->access = g_multipath_access; 437*0c883cefSAlexander Motin gp->dumpconf = g_multipath_dumpconf; 438e770bc6bSMatt Jacob 439e770bc6bSMatt Jacob pp = g_new_providerf(gp, "multipath/%s", md->md_name); 440*0c883cefSAlexander Motin if (md->md_size != 0) { 441*0c883cefSAlexander Motin pp->mediasize = md->md_size - 442*0c883cefSAlexander Motin ((md->md_uuid[0] != 0) ? md->md_sectorsize : 0); 443e770bc6bSMatt Jacob pp->sectorsize = md->md_sectorsize; 444*0c883cefSAlexander Motin } 445*0c883cefSAlexander Motin sc->sc_pp = pp; 446e770bc6bSMatt Jacob g_error_provider(pp, 0); 447*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s created\n", gp->name); 448e770bc6bSMatt Jacob return (gp); 449e770bc6bSMatt Jacob } 450e770bc6bSMatt Jacob 451e770bc6bSMatt Jacob static int 452e770bc6bSMatt Jacob g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp) 453e770bc6bSMatt Jacob { 454e770bc6bSMatt Jacob struct g_multipath_softc *sc; 455e770bc6bSMatt Jacob struct g_consumer *cp, *nxtcp; 456*0c883cefSAlexander Motin int error, acr, acw, ace; 457e770bc6bSMatt Jacob 458e770bc6bSMatt Jacob g_topology_assert(); 459e770bc6bSMatt Jacob 460e770bc6bSMatt Jacob sc = gp->softc; 461e770bc6bSMatt Jacob KASSERT(sc, ("no softc")); 462e770bc6bSMatt Jacob 463e770bc6bSMatt Jacob /* 464e770bc6bSMatt Jacob * Make sure that the passed provider isn't already attached 465e770bc6bSMatt Jacob */ 466e770bc6bSMatt Jacob LIST_FOREACH(cp, &gp->consumer, consumer) { 46712f35a61SPawel Jakub Dawidek if (cp->provider == pp) 468e770bc6bSMatt Jacob break; 469e770bc6bSMatt Jacob } 470e770bc6bSMatt Jacob if (cp) { 471e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: provider %s already attached to %s\n", 472e770bc6bSMatt Jacob pp->name, gp->name); 473e770bc6bSMatt Jacob return (EEXIST); 474e770bc6bSMatt Jacob } 475e770bc6bSMatt Jacob nxtcp = LIST_FIRST(&gp->consumer); 476e770bc6bSMatt Jacob cp = g_new_consumer(gp); 477*0c883cefSAlexander Motin cp->private = NULL; 478*0c883cefSAlexander Motin cp->index = MP_NEW; 479e770bc6bSMatt Jacob error = g_attach(cp, pp); 480e770bc6bSMatt Jacob if (error != 0) { 481e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot attach %s to %s", 482e770bc6bSMatt Jacob pp->name, sc->sc_name); 483e770bc6bSMatt Jacob g_destroy_consumer(cp); 484e770bc6bSMatt Jacob return (error); 485e770bc6bSMatt Jacob } 486e770bc6bSMatt Jacob 487e770bc6bSMatt Jacob /* 488e770bc6bSMatt Jacob * Set access permissions on new consumer to match other consumers 489e770bc6bSMatt Jacob */ 490*0c883cefSAlexander Motin if (sc->sc_pp) { 491*0c883cefSAlexander Motin acr = sc->sc_pp->acr; 492*0c883cefSAlexander Motin acw = sc->sc_pp->acw; 493*0c883cefSAlexander Motin ace = sc->sc_pp->ace; 494*0c883cefSAlexander Motin } else 495*0c883cefSAlexander Motin acr = acw = ace = 0; 496*0c883cefSAlexander Motin if (g_multipath_exclusive) { 497*0c883cefSAlexander Motin acr++; 498*0c883cefSAlexander Motin acw++; 499*0c883cefSAlexander Motin ace++; 500*0c883cefSAlexander Motin } 501*0c883cefSAlexander Motin error = g_access(cp, acr, acw, ace); 502e770bc6bSMatt Jacob if (error) { 503e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot set access in " 504*0c883cefSAlexander Motin "attaching %s to %s (%d)\n", 505*0c883cefSAlexander Motin pp->name, sc->sc_name, error); 506e770bc6bSMatt Jacob g_detach(cp); 507e770bc6bSMatt Jacob g_destroy_consumer(cp); 508e770bc6bSMatt Jacob return (error); 509e770bc6bSMatt Jacob } 510*0c883cefSAlexander Motin if (sc->sc_pp != NULL && sc->sc_pp->mediasize == 0) { 511*0c883cefSAlexander Motin sc->sc_pp->mediasize = pp->mediasize - 512*0c883cefSAlexander Motin ((sc->sc_uuid[0] != 0) ? pp->sectorsize : 0); 513*0c883cefSAlexander Motin sc->sc_pp->sectorsize = pp->sectorsize; 514e770bc6bSMatt Jacob } 515*0c883cefSAlexander Motin if (sc->sc_pp != NULL && 516*0c883cefSAlexander Motin sc->sc_pp->stripesize == 0 && sc->sc_pp->stripeoffset == 0) { 517*0c883cefSAlexander Motin sc->sc_pp->stripesize = pp->stripesize; 518*0c883cefSAlexander Motin sc->sc_pp->stripeoffset = pp->stripeoffset; 519*0c883cefSAlexander Motin } 520*0c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 521*0c883cefSAlexander Motin cp->index = 0; 522*0c883cefSAlexander Motin sc->sc_ndisks++; 523*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 524*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s added to %s\n", 525*0c883cefSAlexander Motin pp->name, sc->sc_name); 526*0c883cefSAlexander Motin if (sc->sc_active == NULL) { 527*0c883cefSAlexander Motin sc->sc_active = cp; 528*0c883cefSAlexander Motin if (!sc->sc_active_active) 529*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 530e770bc6bSMatt Jacob pp->name, sc->sc_name); 531e770bc6bSMatt Jacob } 532e770bc6bSMatt Jacob return (0); 533e770bc6bSMatt Jacob } 534e770bc6bSMatt Jacob 535e770bc6bSMatt Jacob static int 536e770bc6bSMatt Jacob g_multipath_destroy(struct g_geom *gp) 537e770bc6bSMatt Jacob { 538*0c883cefSAlexander Motin struct g_multipath_softc *sc; 539*0c883cefSAlexander Motin struct g_consumer *cp, *cp1; 540e770bc6bSMatt Jacob 541e770bc6bSMatt Jacob g_topology_assert(); 54212f35a61SPawel Jakub Dawidek if (gp->softc == NULL) 543e770bc6bSMatt Jacob return (ENXIO); 544*0c883cefSAlexander Motin sc = gp->softc; 545*0c883cefSAlexander Motin if (!sc->sc_stopping) { 546e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: destroying %s\n", gp->name); 547*0c883cefSAlexander Motin sc->sc_stopping = 1; 548*0c883cefSAlexander Motin } 549*0c883cefSAlexander Motin if (sc->sc_opened != 0) { 550*0c883cefSAlexander Motin if (sc->sc_pp != NULL) { 551*0c883cefSAlexander Motin g_wither_provider(sc->sc_pp, ENXIO); 552*0c883cefSAlexander Motin sc->sc_pp = NULL; 553*0c883cefSAlexander Motin } 554*0c883cefSAlexander Motin return (EINPROGRESS); 555*0c883cefSAlexander Motin } 556*0c883cefSAlexander Motin LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 557*0c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 558*0c883cefSAlexander Motin if ((cp->index & MP_POSTED) == 0) { 559*0c883cefSAlexander Motin cp->index |= MP_POSTED; 560*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 561*0c883cefSAlexander Motin g_mpd(cp, 0); 562*0c883cefSAlexander Motin if (cp1 == NULL) 563*0c883cefSAlexander Motin return(0); /* Recursion happened. */ 564*0c883cefSAlexander Motin } else 565*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 566*0c883cefSAlexander Motin } 567*0c883cefSAlexander Motin if (!LIST_EMPTY(&gp->consumer)) 568*0c883cefSAlexander Motin return (EINPROGRESS); 569*0c883cefSAlexander Motin mtx_destroy(&sc->sc_mtx); 570e770bc6bSMatt Jacob g_free(gp->softc); 571e770bc6bSMatt Jacob gp->softc = NULL; 572*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s destroyed\n", gp->name); 573e770bc6bSMatt Jacob g_wither_geom(gp, ENXIO); 574e770bc6bSMatt Jacob return (0); 575e770bc6bSMatt Jacob } 576e770bc6bSMatt Jacob 577e770bc6bSMatt Jacob static int 578e770bc6bSMatt Jacob g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp, 579e770bc6bSMatt Jacob struct g_geom *gp) 580e770bc6bSMatt Jacob { 58112f35a61SPawel Jakub Dawidek 582e770bc6bSMatt Jacob return (g_multipath_destroy(gp)); 583e770bc6bSMatt Jacob } 584e770bc6bSMatt Jacob 585b5dce617SMatt Jacob static int 586b5dce617SMatt Jacob g_multipath_rotate(struct g_geom *gp) 587b5dce617SMatt Jacob { 588b5dce617SMatt Jacob struct g_consumer *lcp; 589b5dce617SMatt Jacob struct g_multipath_softc *sc = gp->softc; 590b5dce617SMatt Jacob 591b5dce617SMatt Jacob g_topology_assert(); 592b5dce617SMatt Jacob if (sc == NULL) 593b5dce617SMatt Jacob return (ENXIO); 594b5dce617SMatt Jacob LIST_FOREACH(lcp, &gp->consumer, consumer) { 595b5dce617SMatt Jacob if ((lcp->index & MP_BAD) == 0) { 596*0c883cefSAlexander Motin if (sc->sc_active != lcp) 597b5dce617SMatt Jacob break; 598b5dce617SMatt Jacob } 599b5dce617SMatt Jacob } 600b5dce617SMatt Jacob if (lcp) { 601*0c883cefSAlexander Motin sc->sc_active = lcp; 602*0c883cefSAlexander Motin if (!sc->sc_active_active) 603*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s is now active path in %s\n", 604b5dce617SMatt Jacob lcp->provider->name, sc->sc_name); 605b5dce617SMatt Jacob } 606b5dce617SMatt Jacob return (0); 607b5dce617SMatt Jacob } 608b5dce617SMatt Jacob 609e770bc6bSMatt Jacob static void 610e770bc6bSMatt Jacob g_multipath_init(struct g_class *mp) 611e770bc6bSMatt Jacob { 612e770bc6bSMatt Jacob bioq_init(&gmtbq); 613e770bc6bSMatt Jacob mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF); 61412f35a61SPawel Jakub Dawidek if (kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt") == 0) 615e770bc6bSMatt Jacob g_multipath_kt_state = GKT_RUN; 616e770bc6bSMatt Jacob } 617e770bc6bSMatt Jacob 618e770bc6bSMatt Jacob static void 619e770bc6bSMatt Jacob g_multipath_fini(struct g_class *mp) 620e770bc6bSMatt Jacob { 621e770bc6bSMatt Jacob if (g_multipath_kt_state == GKT_RUN) { 622e770bc6bSMatt Jacob mtx_lock(&gmtbq_mtx); 623e770bc6bSMatt Jacob g_multipath_kt_state = GKT_DIE; 624e770bc6bSMatt Jacob wakeup(&g_multipath_kt_state); 625e770bc6bSMatt Jacob msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO, 626e770bc6bSMatt Jacob "gmp:fini", 0); 627e770bc6bSMatt Jacob mtx_unlock(&gmtbq_mtx); 628e770bc6bSMatt Jacob } 629e770bc6bSMatt Jacob } 630e770bc6bSMatt Jacob 631e770bc6bSMatt Jacob static int 632e770bc6bSMatt Jacob g_multipath_read_metadata(struct g_consumer *cp, 633e770bc6bSMatt Jacob struct g_multipath_metadata *md) 634e770bc6bSMatt Jacob { 635e770bc6bSMatt Jacob struct g_provider *pp; 636e770bc6bSMatt Jacob u_char *buf; 637e770bc6bSMatt Jacob int error; 638e770bc6bSMatt Jacob 639e770bc6bSMatt Jacob g_topology_assert(); 640e770bc6bSMatt Jacob error = g_access(cp, 1, 0, 0); 64112f35a61SPawel Jakub Dawidek if (error != 0) 642e770bc6bSMatt Jacob return (error); 643e770bc6bSMatt Jacob pp = cp->provider; 644e770bc6bSMatt Jacob g_topology_unlock(); 645e770bc6bSMatt Jacob buf = g_read_data(cp, pp->mediasize - pp->sectorsize, 646e770bc6bSMatt Jacob pp->sectorsize, &error); 647e770bc6bSMatt Jacob g_topology_lock(); 648e770bc6bSMatt Jacob g_access(cp, -1, 0, 0); 64912f35a61SPawel Jakub Dawidek if (buf == NULL) 650e770bc6bSMatt Jacob return (error); 651e770bc6bSMatt Jacob multipath_metadata_decode(buf, md); 652e770bc6bSMatt Jacob g_free(buf); 653e770bc6bSMatt Jacob return (0); 654e770bc6bSMatt Jacob } 655e770bc6bSMatt Jacob 656e770bc6bSMatt Jacob static struct g_geom * 657e770bc6bSMatt Jacob g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 658e770bc6bSMatt Jacob { 659e770bc6bSMatt Jacob struct g_multipath_metadata md; 660e770bc6bSMatt Jacob struct g_multipath_softc *sc; 661e770bc6bSMatt Jacob struct g_consumer *cp; 662e770bc6bSMatt Jacob struct g_geom *gp, *gp1; 663e770bc6bSMatt Jacob int error, isnew; 664e770bc6bSMatt Jacob 665e770bc6bSMatt Jacob g_topology_assert(); 666e770bc6bSMatt Jacob 667e770bc6bSMatt Jacob gp = g_new_geomf(mp, "multipath:taste"); 668e770bc6bSMatt Jacob gp->start = g_multipath_start; 669e770bc6bSMatt Jacob gp->access = g_multipath_access; 670e770bc6bSMatt Jacob gp->orphan = g_multipath_orphan; 671e770bc6bSMatt Jacob cp = g_new_consumer(gp); 672e770bc6bSMatt Jacob g_attach(cp, pp); 673e770bc6bSMatt Jacob error = g_multipath_read_metadata(cp, &md); 674e770bc6bSMatt Jacob g_detach(cp); 675e770bc6bSMatt Jacob g_destroy_consumer(cp); 676e770bc6bSMatt Jacob g_destroy_geom(gp); 67712f35a61SPawel Jakub Dawidek if (error != 0) 678e770bc6bSMatt Jacob return (NULL); 679e770bc6bSMatt Jacob gp = NULL; 680e770bc6bSMatt Jacob 681e770bc6bSMatt Jacob if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) { 68212f35a61SPawel Jakub Dawidek if (g_multipath_debug) 683e770bc6bSMatt Jacob printf("%s is not MULTIPATH\n", pp->name); 684e770bc6bSMatt Jacob return (NULL); 685e770bc6bSMatt Jacob } 686e770bc6bSMatt Jacob if (md.md_version != G_MULTIPATH_VERSION) { 687e770bc6bSMatt Jacob printf("%s has version %d multipath id- this module is version " 688e770bc6bSMatt Jacob " %d: rejecting\n", pp->name, md.md_version, 689e770bc6bSMatt Jacob G_MULTIPATH_VERSION); 690e770bc6bSMatt Jacob return (NULL); 691e770bc6bSMatt Jacob } 692*0c883cefSAlexander Motin if (md.md_size != 0 && md.md_size != pp->mediasize) 693*0c883cefSAlexander Motin return (NULL); 694*0c883cefSAlexander Motin if (md.md_sectorsize != 0 && md.md_sectorsize != pp->sectorsize) 695*0c883cefSAlexander Motin return (NULL); 69612f35a61SPawel Jakub Dawidek if (g_multipath_debug) 697e770bc6bSMatt Jacob printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid); 698e770bc6bSMatt Jacob 699e770bc6bSMatt Jacob /* 700e770bc6bSMatt Jacob * Let's check if such a device already is present. We check against 701e770bc6bSMatt Jacob * uuid alone first because that's the true distinguishor. If that 702e770bc6bSMatt Jacob * passes, then we check for name conflicts. If there are conflicts, 703e770bc6bSMatt Jacob * modify the name. 704e770bc6bSMatt Jacob * 705e770bc6bSMatt Jacob * The whole purpose of this is to solve the problem that people don't 706e770bc6bSMatt Jacob * pick good unique names, but good unique names (like uuids) are a 707e770bc6bSMatt Jacob * pain to use. So, we allow people to build GEOMs with friendly names 708e770bc6bSMatt Jacob * and uuids, and modify the names in case there's a collision. 709e770bc6bSMatt Jacob */ 710e770bc6bSMatt Jacob sc = NULL; 711e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 712e770bc6bSMatt Jacob sc = gp->softc; 713*0c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 714e770bc6bSMatt Jacob continue; 71512f35a61SPawel Jakub Dawidek if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0) 716e770bc6bSMatt Jacob break; 717e770bc6bSMatt Jacob } 718e770bc6bSMatt Jacob 719e770bc6bSMatt Jacob LIST_FOREACH(gp1, &mp->geom, geom) { 72012f35a61SPawel Jakub Dawidek if (gp1 == gp) 721e770bc6bSMatt Jacob continue; 722e770bc6bSMatt Jacob sc = gp1->softc; 723*0c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 724e770bc6bSMatt Jacob continue; 72512f35a61SPawel Jakub Dawidek if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0) 726e770bc6bSMatt Jacob break; 727e770bc6bSMatt Jacob } 728e770bc6bSMatt Jacob 729e770bc6bSMatt Jacob /* 730e770bc6bSMatt Jacob * If gp is NULL, we had no extant MULTIPATH geom with this uuid. 731e770bc6bSMatt Jacob * 732e770bc6bSMatt Jacob * If gp1 is *not* NULL, that means we have a MULTIPATH geom extant 733e770bc6bSMatt Jacob * with the same name (but a different UUID). 734e770bc6bSMatt Jacob * 735e770bc6bSMatt Jacob * If gp is NULL, then modify the name with a random number and 736e770bc6bSMatt Jacob * complain, but allow the creation of the geom to continue. 737e770bc6bSMatt Jacob * 738e770bc6bSMatt Jacob * If gp is *not* NULL, just use the geom's name as we're attaching 739e770bc6bSMatt Jacob * this disk to the (previously generated) name. 740e770bc6bSMatt Jacob */ 741e770bc6bSMatt Jacob 742e770bc6bSMatt Jacob if (gp1) { 743e770bc6bSMatt Jacob sc = gp1->softc; 744e770bc6bSMatt Jacob if (gp == NULL) { 745e770bc6bSMatt Jacob char buf[16]; 746e770bc6bSMatt Jacob u_long rand = random(); 747e770bc6bSMatt Jacob 748e770bc6bSMatt Jacob snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand); 749e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: geom %s/%s exists already\n", 750e770bc6bSMatt Jacob sc->sc_name, sc->sc_uuid); 751e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n", 752e770bc6bSMatt Jacob md.md_uuid, buf); 753e770bc6bSMatt Jacob strlcpy(md.md_name, buf, sizeof(md.md_name)); 754e770bc6bSMatt Jacob } else { 755e770bc6bSMatt Jacob strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name)); 756e770bc6bSMatt Jacob } 757e770bc6bSMatt Jacob } 758e770bc6bSMatt Jacob 759e770bc6bSMatt Jacob if (gp == NULL) { 760e770bc6bSMatt Jacob gp = g_multipath_create(mp, &md); 761e770bc6bSMatt Jacob if (gp == NULL) { 762e770bc6bSMatt Jacob printf("GEOM_MULTIPATH: cannot create geom %s/%s\n", 763e770bc6bSMatt Jacob md.md_name, md.md_uuid); 764e770bc6bSMatt Jacob return (NULL); 765e770bc6bSMatt Jacob } 766e770bc6bSMatt Jacob isnew = 1; 767e770bc6bSMatt Jacob } else { 768e770bc6bSMatt Jacob isnew = 0; 769e770bc6bSMatt Jacob } 770e770bc6bSMatt Jacob 771e770bc6bSMatt Jacob sc = gp->softc; 772e770bc6bSMatt Jacob KASSERT(sc != NULL, ("sc is NULL")); 773e770bc6bSMatt Jacob error = g_multipath_add_disk(gp, pp); 774e770bc6bSMatt Jacob if (error != 0) { 77512f35a61SPawel Jakub Dawidek if (isnew) 776e770bc6bSMatt Jacob g_multipath_destroy(gp); 777e770bc6bSMatt Jacob return (NULL); 778e770bc6bSMatt Jacob } 779e770bc6bSMatt Jacob return (gp); 780e770bc6bSMatt Jacob } 781e770bc6bSMatt Jacob 782e770bc6bSMatt Jacob static void 783*0c883cefSAlexander Motin g_multipath_ctl_add_name(struct gctl_req *req, struct g_class *mp, 784*0c883cefSAlexander Motin const char *name) 785e770bc6bSMatt Jacob { 786*0c883cefSAlexander Motin struct g_multipath_softc *sc; 787e770bc6bSMatt Jacob struct g_geom *gp; 7882b4969ffSMatt Jacob struct g_consumer *cp; 789*0c883cefSAlexander Motin struct g_provider *pp; 790*0c883cefSAlexander Motin const char *mpname; 791e770bc6bSMatt Jacob static const char devpf[6] = "/dev/"; 792e770bc6bSMatt Jacob 793e770bc6bSMatt Jacob g_topology_assert(); 794e770bc6bSMatt Jacob 795e770bc6bSMatt Jacob mpname = gctl_get_asciiparam(req, "arg0"); 796e770bc6bSMatt Jacob if (mpname == NULL) { 797e770bc6bSMatt Jacob gctl_error(req, "No 'arg0' argument"); 798e770bc6bSMatt Jacob return; 799e770bc6bSMatt Jacob } 8002b4969ffSMatt Jacob gp = g_multipath_find_geom(mp, mpname); 8012b4969ffSMatt Jacob if (gp == NULL) { 8022b4969ffSMatt Jacob gctl_error(req, "Device %s is invalid", mpname); 803e770bc6bSMatt Jacob return; 804e770bc6bSMatt Jacob } 805*0c883cefSAlexander Motin sc = gp->softc; 806e770bc6bSMatt Jacob 80712f35a61SPawel Jakub Dawidek if (strncmp(name, devpf, 5) == 0) 808e770bc6bSMatt Jacob name += 5; 8092b4969ffSMatt Jacob pp = g_provider_by_name(name); 8102b4969ffSMatt Jacob if (pp == NULL) { 811e770bc6bSMatt Jacob gctl_error(req, "Provider %s is invalid", name); 812e770bc6bSMatt Jacob return; 813e770bc6bSMatt Jacob } 814e770bc6bSMatt Jacob 815e770bc6bSMatt Jacob /* 816*0c883cefSAlexander Motin * Check to make sure parameters match. 817e770bc6bSMatt Jacob */ 818*0c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 819*0c883cefSAlexander Motin if (cp->provider == pp) { 820*0c883cefSAlexander Motin gctl_error(req, "provider %s is already there", 821*0c883cefSAlexander Motin pp->name); 822e770bc6bSMatt Jacob return; 823e770bc6bSMatt Jacob } 824*0c883cefSAlexander Motin } 825*0c883cefSAlexander Motin if (sc->sc_pp != NULL && sc->sc_pp->mediasize != 0 && 826*0c883cefSAlexander Motin sc->sc_pp->mediasize + (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0) 827*0c883cefSAlexander Motin != pp->mediasize) { 828*0c883cefSAlexander Motin gctl_error(req, "Providers size mismatch %jd != %jd", 829*0c883cefSAlexander Motin (intmax_t) sc->sc_pp->mediasize + 830*0c883cefSAlexander Motin (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0), 831*0c883cefSAlexander Motin (intmax_t) pp->mediasize); 832e770bc6bSMatt Jacob return; 833e770bc6bSMatt Jacob } 834*0c883cefSAlexander Motin if (sc->sc_pp != NULL && sc->sc_pp->sectorsize != 0 && 835*0c883cefSAlexander Motin sc->sc_pp->sectorsize != pp->sectorsize) { 836*0c883cefSAlexander Motin gctl_error(req, "Providers sectorsize mismatch %u != %u", 837*0c883cefSAlexander Motin sc->sc_pp->sectorsize, pp->sectorsize); 838e770bc6bSMatt Jacob return; 839e770bc6bSMatt Jacob } 840e770bc6bSMatt Jacob 841e770bc6bSMatt Jacob /* 8422b4969ffSMatt Jacob * Now add.... 843e770bc6bSMatt Jacob */ 8442b4969ffSMatt Jacob (void) g_multipath_add_disk(gp, pp); 845e770bc6bSMatt Jacob } 846e770bc6bSMatt Jacob 847*0c883cefSAlexander Motin static void 848*0c883cefSAlexander Motin g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp) 849*0c883cefSAlexander Motin { 850*0c883cefSAlexander Motin struct g_multipath_softc *sc; 851*0c883cefSAlexander Motin struct g_geom *gp; 852*0c883cefSAlexander Motin const char *mpname, *name; 853*0c883cefSAlexander Motin 854*0c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 855*0c883cefSAlexander Motin if (mpname == NULL) { 856*0c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 857*0c883cefSAlexander Motin return; 858*0c883cefSAlexander Motin } 859*0c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 860*0c883cefSAlexander Motin if (gp == NULL) { 861*0c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 862*0c883cefSAlexander Motin return; 863*0c883cefSAlexander Motin } 864*0c883cefSAlexander Motin sc = gp->softc; 865*0c883cefSAlexander Motin 866*0c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 867*0c883cefSAlexander Motin if (name == NULL) { 868*0c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 869*0c883cefSAlexander Motin return; 870*0c883cefSAlexander Motin } 871*0c883cefSAlexander Motin g_multipath_ctl_add_name(req, mp, name); 872*0c883cefSAlexander Motin } 873*0c883cefSAlexander Motin 874*0c883cefSAlexander Motin static void 875*0c883cefSAlexander Motin g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp) 876*0c883cefSAlexander Motin { 877*0c883cefSAlexander Motin struct g_multipath_metadata md; 878*0c883cefSAlexander Motin struct g_multipath_softc *sc; 879*0c883cefSAlexander Motin struct g_geom *gp; 880*0c883cefSAlexander Motin const char *mpname, *name; 881*0c883cefSAlexander Motin char param[16]; 882*0c883cefSAlexander Motin int *nargs, i, *active_active; 883*0c883cefSAlexander Motin 884*0c883cefSAlexander Motin g_topology_assert(); 885*0c883cefSAlexander Motin 886*0c883cefSAlexander Motin nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 887*0c883cefSAlexander Motin if (*nargs < 2) { 888*0c883cefSAlexander Motin gctl_error(req, "wrong number of arguments."); 889*0c883cefSAlexander Motin return; 890*0c883cefSAlexander Motin } 891*0c883cefSAlexander Motin 892*0c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 893*0c883cefSAlexander Motin if (mpname == NULL) { 894*0c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 895*0c883cefSAlexander Motin return; 896*0c883cefSAlexander Motin } 897*0c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 898*0c883cefSAlexander Motin if (gp != NULL) { 899*0c883cefSAlexander Motin gctl_error(req, "Device %s already exist", mpname); 900*0c883cefSAlexander Motin return; 901*0c883cefSAlexander Motin } 902*0c883cefSAlexander Motin sc = gp->softc; 903*0c883cefSAlexander Motin 904*0c883cefSAlexander Motin memset(&md, 0, sizeof(md)); 905*0c883cefSAlexander Motin strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); 906*0c883cefSAlexander Motin md.md_version = G_MULTIPATH_VERSION; 907*0c883cefSAlexander Motin strlcpy(md.md_name, mpname, sizeof(md.md_name)); 908*0c883cefSAlexander Motin md.md_size = 0; 909*0c883cefSAlexander Motin md.md_sectorsize = 0; 910*0c883cefSAlexander Motin md.md_uuid[0] = 0; 911*0c883cefSAlexander Motin active_active = gctl_get_paraml(req, "active_active", 912*0c883cefSAlexander Motin sizeof(*active_active)); 913*0c883cefSAlexander Motin md.md_active_active = 914*0c883cefSAlexander Motin (active_active == NULL || *active_active == 0) ? 0 : 1; 915*0c883cefSAlexander Motin gp = g_multipath_create(mp, &md); 916*0c883cefSAlexander Motin if (gp == NULL) { 917*0c883cefSAlexander Motin gctl_error(req, "GEOM_MULTIPATH: cannot create geom %s/%s\n", 918*0c883cefSAlexander Motin md.md_name, md.md_uuid); 919*0c883cefSAlexander Motin return; 920*0c883cefSAlexander Motin } 921*0c883cefSAlexander Motin sc = gp->softc; 922*0c883cefSAlexander Motin 923*0c883cefSAlexander Motin for (i = 1; i < *nargs; i++) { 924*0c883cefSAlexander Motin snprintf(param, sizeof(param), "arg%d", i); 925*0c883cefSAlexander Motin name = gctl_get_asciiparam(req, param); 926*0c883cefSAlexander Motin g_multipath_ctl_add_name(req, mp, name); 927*0c883cefSAlexander Motin } 928*0c883cefSAlexander Motin 929*0c883cefSAlexander Motin if (sc->sc_ndisks != (*nargs - 1)) 930*0c883cefSAlexander Motin g_multipath_destroy(gp); 931*0c883cefSAlexander Motin } 932*0c883cefSAlexander Motin 933*0c883cefSAlexander Motin static void 934*0c883cefSAlexander Motin g_multipath_ctl_fail(struct gctl_req *req, struct g_class *mp, int fail) 935*0c883cefSAlexander Motin { 936*0c883cefSAlexander Motin struct g_multipath_softc *sc; 937*0c883cefSAlexander Motin struct g_geom *gp; 938*0c883cefSAlexander Motin struct g_consumer *cp; 939*0c883cefSAlexander Motin const char *mpname, *name; 940*0c883cefSAlexander Motin int found; 941*0c883cefSAlexander Motin 942*0c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 943*0c883cefSAlexander Motin if (mpname == NULL) { 944*0c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 945*0c883cefSAlexander Motin return; 946*0c883cefSAlexander Motin } 947*0c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 948*0c883cefSAlexander Motin if (gp == NULL) { 949*0c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 950*0c883cefSAlexander Motin return; 951*0c883cefSAlexander Motin } 952*0c883cefSAlexander Motin sc = gp->softc; 953*0c883cefSAlexander Motin 954*0c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 955*0c883cefSAlexander Motin if (name == NULL) { 956*0c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 957*0c883cefSAlexander Motin return; 958*0c883cefSAlexander Motin } 959*0c883cefSAlexander Motin 960*0c883cefSAlexander Motin found = 0; 961*0c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 962*0c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 963*0c883cefSAlexander Motin if (cp->provider != NULL && 964*0c883cefSAlexander Motin strcmp(cp->provider->name, name) == 0 && 965*0c883cefSAlexander Motin (cp->index & MP_LOST) == 0) { 966*0c883cefSAlexander Motin found = 1; 967*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: %s in %s is marked %s.\n", 968*0c883cefSAlexander Motin name, sc->sc_name, fail ? "FAIL" : "OK"); 969*0c883cefSAlexander Motin if (fail) { 970*0c883cefSAlexander Motin g_multipath_fault(cp, MP_FAIL); 971*0c883cefSAlexander Motin } else { 972*0c883cefSAlexander Motin cp->index &= ~MP_FAIL; 973*0c883cefSAlexander Motin } 974*0c883cefSAlexander Motin } 975*0c883cefSAlexander Motin } 976*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 977*0c883cefSAlexander Motin if (found == 0) 978*0c883cefSAlexander Motin gctl_error(req, "Provider %s not found", name); 979*0c883cefSAlexander Motin } 980*0c883cefSAlexander Motin 981*0c883cefSAlexander Motin static void 982*0c883cefSAlexander Motin g_multipath_ctl_remove(struct gctl_req *req, struct g_class *mp) 983*0c883cefSAlexander Motin { 984*0c883cefSAlexander Motin struct g_multipath_softc *sc; 985*0c883cefSAlexander Motin struct g_geom *gp; 986*0c883cefSAlexander Motin struct g_consumer *cp, *cp1; 987*0c883cefSAlexander Motin const char *mpname, *name; 988*0c883cefSAlexander Motin uintptr_t *cnt; 989*0c883cefSAlexander Motin int found; 990*0c883cefSAlexander Motin 991*0c883cefSAlexander Motin mpname = gctl_get_asciiparam(req, "arg0"); 992*0c883cefSAlexander Motin if (mpname == NULL) { 993*0c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 994*0c883cefSAlexander Motin return; 995*0c883cefSAlexander Motin } 996*0c883cefSAlexander Motin gp = g_multipath_find_geom(mp, mpname); 997*0c883cefSAlexander Motin if (gp == NULL) { 998*0c883cefSAlexander Motin gctl_error(req, "Device %s not found", mpname); 999*0c883cefSAlexander Motin return; 1000*0c883cefSAlexander Motin } 1001*0c883cefSAlexander Motin sc = gp->softc; 1002*0c883cefSAlexander Motin 1003*0c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg1"); 1004*0c883cefSAlexander Motin if (name == NULL) { 1005*0c883cefSAlexander Motin gctl_error(req, "No 'arg1' argument"); 1006*0c883cefSAlexander Motin return; 1007*0c883cefSAlexander Motin } 1008*0c883cefSAlexander Motin 1009*0c883cefSAlexander Motin found = 0; 1010*0c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 1011*0c883cefSAlexander Motin LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 1012*0c883cefSAlexander Motin if (cp->provider != NULL && 1013*0c883cefSAlexander Motin strcmp(cp->provider->name, name) == 0 && 1014*0c883cefSAlexander Motin (cp->index & MP_LOST) == 0) { 1015*0c883cefSAlexander Motin found = 1; 1016*0c883cefSAlexander Motin printf("GEOM_MULTIPATH: removing %s from %s\n", 1017*0c883cefSAlexander Motin cp->provider->name, cp->geom->name); 1018*0c883cefSAlexander Motin sc->sc_ndisks--; 1019*0c883cefSAlexander Motin g_multipath_fault(cp, MP_LOST); 1020*0c883cefSAlexander Motin cnt = (uintptr_t *)&cp->private; 1021*0c883cefSAlexander Motin if (*cnt == 0 && (cp->index & MP_POSTED) == 0) { 1022*0c883cefSAlexander Motin cp->index |= MP_POSTED; 1023*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 1024*0c883cefSAlexander Motin g_mpd(cp, 0); 1025*0c883cefSAlexander Motin if (cp1 == NULL) 1026*0c883cefSAlexander Motin return; /* Recursion happened. */ 1027*0c883cefSAlexander Motin mtx_lock(&sc->sc_mtx); 1028*0c883cefSAlexander Motin } 1029*0c883cefSAlexander Motin } 1030*0c883cefSAlexander Motin } 1031*0c883cefSAlexander Motin mtx_unlock(&sc->sc_mtx); 1032*0c883cefSAlexander Motin if (found == 0) 1033*0c883cefSAlexander Motin gctl_error(req, "Provider %s not found", name); 1034*0c883cefSAlexander Motin } 1035*0c883cefSAlexander Motin 1036e770bc6bSMatt Jacob static struct g_geom * 1037e770bc6bSMatt Jacob g_multipath_find_geom(struct g_class *mp, const char *name) 1038e770bc6bSMatt Jacob { 1039e770bc6bSMatt Jacob struct g_geom *gp; 1040*0c883cefSAlexander Motin struct g_multipath_softc *sc; 1041e770bc6bSMatt Jacob 1042e770bc6bSMatt Jacob LIST_FOREACH(gp, &mp->geom, geom) { 1043*0c883cefSAlexander Motin sc = gp->softc; 1044*0c883cefSAlexander Motin if (sc == NULL || sc->sc_stopping) 1045*0c883cefSAlexander Motin continue; 1046*0c883cefSAlexander Motin if (strcmp(gp->name, name) == 0) 1047e770bc6bSMatt Jacob return (gp); 1048e770bc6bSMatt Jacob } 1049e770bc6bSMatt Jacob return (NULL); 1050e770bc6bSMatt Jacob } 1051e770bc6bSMatt Jacob 1052e770bc6bSMatt Jacob static void 1053*0c883cefSAlexander Motin g_multipath_ctl_stop(struct gctl_req *req, struct g_class *mp) 1054e770bc6bSMatt Jacob { 1055e770bc6bSMatt Jacob struct g_geom *gp; 1056e770bc6bSMatt Jacob const char *name; 1057e770bc6bSMatt Jacob int error; 1058e770bc6bSMatt Jacob 1059e770bc6bSMatt Jacob g_topology_assert(); 1060e770bc6bSMatt Jacob 1061e770bc6bSMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1062e770bc6bSMatt Jacob if (name == NULL) { 1063e770bc6bSMatt Jacob gctl_error(req, "No 'arg0' argument"); 1064e770bc6bSMatt Jacob return; 1065e770bc6bSMatt Jacob } 1066e770bc6bSMatt Jacob gp = g_multipath_find_geom(mp, name); 1067e770bc6bSMatt Jacob if (gp == NULL) { 1068e770bc6bSMatt Jacob gctl_error(req, "Device %s is invalid", name); 1069e770bc6bSMatt Jacob return; 1070e770bc6bSMatt Jacob } 1071e770bc6bSMatt Jacob error = g_multipath_destroy(gp); 1072*0c883cefSAlexander Motin if (error != 0 && error != EINPROGRESS) 1073*0c883cefSAlexander Motin gctl_error(req, "failed to stop %s (err=%d)", name, error); 1074e770bc6bSMatt Jacob } 1075*0c883cefSAlexander Motin 1076*0c883cefSAlexander Motin static void 1077*0c883cefSAlexander Motin g_multipath_ctl_destroy(struct gctl_req *req, struct g_class *mp) 1078*0c883cefSAlexander Motin { 1079*0c883cefSAlexander Motin struct g_geom *gp; 1080*0c883cefSAlexander Motin struct g_multipath_softc *sc; 1081*0c883cefSAlexander Motin struct g_consumer *cp; 1082*0c883cefSAlexander Motin struct g_provider *pp; 1083*0c883cefSAlexander Motin const char *name; 1084*0c883cefSAlexander Motin uint8_t *buf; 1085*0c883cefSAlexander Motin int error; 1086*0c883cefSAlexander Motin 1087*0c883cefSAlexander Motin g_topology_assert(); 1088*0c883cefSAlexander Motin 1089*0c883cefSAlexander Motin name = gctl_get_asciiparam(req, "arg0"); 1090*0c883cefSAlexander Motin if (name == NULL) { 1091*0c883cefSAlexander Motin gctl_error(req, "No 'arg0' argument"); 1092*0c883cefSAlexander Motin return; 1093*0c883cefSAlexander Motin } 1094*0c883cefSAlexander Motin gp = g_multipath_find_geom(mp, name); 1095*0c883cefSAlexander Motin if (gp == NULL) { 1096*0c883cefSAlexander Motin gctl_error(req, "Device %s is invalid", name); 1097*0c883cefSAlexander Motin return; 1098*0c883cefSAlexander Motin } 1099*0c883cefSAlexander Motin sc = gp->softc; 1100*0c883cefSAlexander Motin 1101*0c883cefSAlexander Motin if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) { 1102*0c883cefSAlexander Motin cp = sc->sc_active; 1103*0c883cefSAlexander Motin pp = cp->provider; 1104*0c883cefSAlexander Motin error = g_access(cp, 1, 1, 1); 1105*0c883cefSAlexander Motin if (error != 0) { 1106*0c883cefSAlexander Motin gctl_error(req, "Can't open %s (%d)", pp->name, error); 1107*0c883cefSAlexander Motin goto destroy; 1108*0c883cefSAlexander Motin } 1109*0c883cefSAlexander Motin g_topology_unlock(); 1110*0c883cefSAlexander Motin buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 1111*0c883cefSAlexander Motin error = g_write_data(cp, pp->mediasize - pp->sectorsize, 1112*0c883cefSAlexander Motin buf, pp->sectorsize); 1113*0c883cefSAlexander Motin g_topology_lock(); 1114*0c883cefSAlexander Motin g_access(cp, -1, -1, -1); 1115*0c883cefSAlexander Motin if (error != 0) 1116*0c883cefSAlexander Motin gctl_error(req, "Can't erase metadata on %s (%d)", 1117*0c883cefSAlexander Motin pp->name, error); 1118*0c883cefSAlexander Motin } 1119*0c883cefSAlexander Motin 1120*0c883cefSAlexander Motin destroy: 1121*0c883cefSAlexander Motin error = g_multipath_destroy(gp); 1122*0c883cefSAlexander Motin if (error != 0 && error != EINPROGRESS) 1123*0c883cefSAlexander Motin gctl_error(req, "failed to destroy %s (err=%d)", name, error); 1124e770bc6bSMatt Jacob } 1125e770bc6bSMatt Jacob 1126e770bc6bSMatt Jacob static void 1127b5dce617SMatt Jacob g_multipath_ctl_rotate(struct gctl_req *req, struct g_class *mp) 1128b5dce617SMatt Jacob { 1129b5dce617SMatt Jacob struct g_geom *gp; 1130b5dce617SMatt Jacob const char *name; 1131b5dce617SMatt Jacob int error; 1132b5dce617SMatt Jacob 1133b5dce617SMatt Jacob g_topology_assert(); 1134b5dce617SMatt Jacob 1135b5dce617SMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1136b5dce617SMatt Jacob if (name == NULL) { 1137b5dce617SMatt Jacob gctl_error(req, "No 'arg0' argument"); 1138b5dce617SMatt Jacob return; 1139b5dce617SMatt Jacob } 1140b5dce617SMatt Jacob gp = g_multipath_find_geom(mp, name); 1141b5dce617SMatt Jacob if (gp == NULL) { 1142b5dce617SMatt Jacob gctl_error(req, "Device %s is invalid", name); 1143b5dce617SMatt Jacob return; 1144b5dce617SMatt Jacob } 1145b5dce617SMatt Jacob error = g_multipath_rotate(gp); 1146b5dce617SMatt Jacob if (error != 0) { 1147b5dce617SMatt Jacob gctl_error(req, "failed to rotate %s (err=%d)", name, error); 1148b5dce617SMatt Jacob } 1149b5dce617SMatt Jacob } 1150b5dce617SMatt Jacob 1151b5dce617SMatt Jacob static void 1152b5dce617SMatt Jacob g_multipath_ctl_getactive(struct gctl_req *req, struct g_class *mp) 1153b5dce617SMatt Jacob { 1154b5dce617SMatt Jacob struct sbuf *sb; 1155b5dce617SMatt Jacob struct g_geom *gp; 1156b5dce617SMatt Jacob struct g_multipath_softc *sc; 1157*0c883cefSAlexander Motin struct g_consumer *cp; 1158b5dce617SMatt Jacob const char *name; 1159*0c883cefSAlexander Motin int empty; 1160b5dce617SMatt Jacob 1161b5dce617SMatt Jacob sb = sbuf_new_auto(); 1162b5dce617SMatt Jacob 1163b5dce617SMatt Jacob g_topology_assert(); 1164b5dce617SMatt Jacob name = gctl_get_asciiparam(req, "arg0"); 1165b5dce617SMatt Jacob if (name == NULL) { 1166b5dce617SMatt Jacob gctl_error(req, "No 'arg0' argument"); 1167b5dce617SMatt Jacob return; 1168b5dce617SMatt Jacob } 1169b5dce617SMatt Jacob gp = g_multipath_find_geom(mp, name); 1170b5dce617SMatt Jacob if (gp == NULL) { 1171b5dce617SMatt Jacob gctl_error(req, "Device %s is invalid", name); 1172b5dce617SMatt Jacob return; 1173b5dce617SMatt Jacob } 1174b5dce617SMatt Jacob sc = gp->softc; 1175*0c883cefSAlexander Motin if (sc->sc_active_active) { 1176*0c883cefSAlexander Motin empty = 1; 1177*0c883cefSAlexander Motin LIST_FOREACH(cp, &gp->consumer, consumer) { 1178*0c883cefSAlexander Motin if (cp->index & MP_BAD) 1179*0c883cefSAlexander Motin continue; 1180*0c883cefSAlexander Motin if (!empty) 1181*0c883cefSAlexander Motin sbuf_cat(sb, " "); 1182*0c883cefSAlexander Motin sbuf_cat(sb, cp->provider->name); 1183*0c883cefSAlexander Motin empty = 0; 1184*0c883cefSAlexander Motin } 1185*0c883cefSAlexander Motin if (empty) 1186*0c883cefSAlexander Motin sbuf_cat(sb, "none"); 1187*0c883cefSAlexander Motin sbuf_cat(sb, "\n"); 1188*0c883cefSAlexander Motin } else if (sc->sc_active && sc->sc_active->provider) { 1189*0c883cefSAlexander Motin sbuf_printf(sb, "%s\n", sc->sc_active->provider->name); 1190b5dce617SMatt Jacob } else { 1191b5dce617SMatt Jacob sbuf_printf(sb, "none\n"); 1192b5dce617SMatt Jacob } 1193b5dce617SMatt Jacob sbuf_finish(sb); 1194b5dce617SMatt Jacob gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1195b5dce617SMatt Jacob sbuf_delete(sb); 1196b5dce617SMatt Jacob } 1197b5dce617SMatt Jacob 1198b5dce617SMatt Jacob static void 1199e770bc6bSMatt Jacob g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb) 1200e770bc6bSMatt Jacob { 1201e770bc6bSMatt Jacob uint32_t *version; 1202e770bc6bSMatt Jacob g_topology_assert(); 1203e770bc6bSMatt Jacob version = gctl_get_paraml(req, "version", sizeof(*version)); 1204e770bc6bSMatt Jacob if (version == NULL) { 1205e770bc6bSMatt Jacob gctl_error(req, "No 'version' argument"); 1206e770bc6bSMatt Jacob } else if (*version != G_MULTIPATH_VERSION) { 1207e770bc6bSMatt Jacob gctl_error(req, "Userland and kernel parts are out of sync"); 12082b4969ffSMatt Jacob } else if (strcmp(verb, "add") == 0) { 12092b4969ffSMatt Jacob g_multipath_ctl_add(req, mp); 1210*0c883cefSAlexander Motin } else if (strcmp(verb, "create") == 0) { 1211*0c883cefSAlexander Motin g_multipath_ctl_create(req, mp); 1212*0c883cefSAlexander Motin } else if (strcmp(verb, "stop") == 0) { 1213*0c883cefSAlexander Motin g_multipath_ctl_stop(req, mp); 1214e770bc6bSMatt Jacob } else if (strcmp(verb, "destroy") == 0) { 1215e770bc6bSMatt Jacob g_multipath_ctl_destroy(req, mp); 1216*0c883cefSAlexander Motin } else if (strcmp(verb, "fail") == 0) { 1217*0c883cefSAlexander Motin g_multipath_ctl_fail(req, mp, 1); 1218*0c883cefSAlexander Motin } else if (strcmp(verb, "restore") == 0) { 1219*0c883cefSAlexander Motin g_multipath_ctl_fail(req, mp, 0); 1220*0c883cefSAlexander Motin } else if (strcmp(verb, "remove") == 0) { 1221*0c883cefSAlexander Motin g_multipath_ctl_remove(req, mp); 1222b5dce617SMatt Jacob } else if (strcmp(verb, "rotate") == 0) { 1223b5dce617SMatt Jacob g_multipath_ctl_rotate(req, mp); 1224b5dce617SMatt Jacob } else if (strcmp(verb, "getactive") == 0) { 1225b5dce617SMatt Jacob g_multipath_ctl_getactive(req, mp); 1226e770bc6bSMatt Jacob } else { 1227e770bc6bSMatt Jacob gctl_error(req, "Unknown verb %s", verb); 1228e770bc6bSMatt Jacob } 1229e770bc6bSMatt Jacob } 1230*0c883cefSAlexander Motin 1231*0c883cefSAlexander Motin static void 1232*0c883cefSAlexander Motin g_multipath_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1233*0c883cefSAlexander Motin struct g_consumer *cp, struct g_provider *pp) 1234*0c883cefSAlexander Motin { 1235*0c883cefSAlexander Motin struct g_multipath_softc *sc; 1236*0c883cefSAlexander Motin int good; 1237*0c883cefSAlexander Motin 1238*0c883cefSAlexander Motin g_topology_assert(); 1239*0c883cefSAlexander Motin 1240*0c883cefSAlexander Motin sc = gp->softc; 1241*0c883cefSAlexander Motin if (sc == NULL) 1242*0c883cefSAlexander Motin return; 1243*0c883cefSAlexander Motin if (cp != NULL) { 1244*0c883cefSAlexander Motin sbuf_printf(sb, "%s<State>%s</State>", indent, 1245*0c883cefSAlexander Motin (cp->index & MP_NEW) ? "NEW" : 1246*0c883cefSAlexander Motin (cp->index & MP_LOST) ? "LOST" : 1247*0c883cefSAlexander Motin (cp->index & MP_FAIL) ? "FAIL" : 1248*0c883cefSAlexander Motin (sc->sc_active_active || sc->sc_active == cp) ? 1249*0c883cefSAlexander Motin "ACTIVE" : "PASSIVE"); 1250*0c883cefSAlexander Motin } else { 1251*0c883cefSAlexander Motin good = g_multipath_good(gp); 1252*0c883cefSAlexander Motin sbuf_printf(sb, "%s<State>%s</State>", indent, 1253*0c883cefSAlexander Motin good == 0 ? "BROKEN" : 1254*0c883cefSAlexander Motin (good != sc->sc_ndisks || sc->sc_ndisks == 1) ? 1255*0c883cefSAlexander Motin "DEGRADED" : "OPTIMAL"); 1256*0c883cefSAlexander Motin } 1257*0c883cefSAlexander Motin if (cp == NULL && pp == NULL) { 1258*0c883cefSAlexander Motin sbuf_printf(sb, "%s<UUID>%s</UUID>", indent, sc->sc_uuid); 1259*0c883cefSAlexander Motin sbuf_printf(sb, "%s<Mode>Active/%s</Mode>", indent, 1260*0c883cefSAlexander Motin sc->sc_active_active ? "Active" : "Passive"); 1261*0c883cefSAlexander Motin sbuf_printf(sb, "%s<Type>%s</Type>", indent, 1262*0c883cefSAlexander Motin sc->sc_uuid[0] == 0 ? "MANUAL" : "AUTOMATIC"); 1263*0c883cefSAlexander Motin } 1264*0c883cefSAlexander Motin } 1265*0c883cefSAlexander Motin 1266e770bc6bSMatt Jacob DECLARE_GEOM_CLASS(g_multipath_class, g_multipath); 1267