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

Cache object: 39c28b7ba29801b4518ac49bab7e08c6


[ 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.