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

Cache object: 69cfcf4b527a6f39fdbdd4c0fc33eb03


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