The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/geom/multipath/g_multipath.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 828d9fe07cd09785b6b92526760d0bd5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.