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/stripe/g_stripe.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) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/8.3/sys/geom/stripe/g_stripe.c 222920 2011-06-10 09:12:09Z mav $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kernel.h>
   33 #include <sys/module.h>
   34 #include <sys/lock.h>
   35 #include <sys/mutex.h>
   36 #include <sys/bio.h>
   37 #include <sys/sysctl.h>
   38 #include <sys/malloc.h>
   39 #include <vm/uma.h>
   40 #include <geom/geom.h>
   41 #include <geom/stripe/g_stripe.h>
   42 
   43 
   44 static MALLOC_DEFINE(M_STRIPE, "stripe_data", "GEOM_STRIPE Data");
   45 
   46 static uma_zone_t g_stripe_zone;
   47 
   48 static int g_stripe_destroy(struct g_stripe_softc *sc, boolean_t force);
   49 static int g_stripe_destroy_geom(struct gctl_req *req, struct g_class *mp,
   50     struct g_geom *gp);
   51 
   52 static g_taste_t g_stripe_taste;
   53 static g_ctl_req_t g_stripe_config;
   54 static g_dumpconf_t g_stripe_dumpconf;
   55 static g_init_t g_stripe_init;
   56 static g_fini_t g_stripe_fini;
   57 
   58 struct g_class g_stripe_class = {
   59         .name = G_STRIPE_CLASS_NAME,
   60         .version = G_VERSION,
   61         .ctlreq = g_stripe_config,
   62         .taste = g_stripe_taste,
   63         .destroy_geom = g_stripe_destroy_geom,
   64         .init = g_stripe_init,
   65         .fini = g_stripe_fini
   66 };
   67 
   68 SYSCTL_DECL(_kern_geom);
   69 SYSCTL_NODE(_kern_geom, OID_AUTO, stripe, CTLFLAG_RW, 0, "GEOM_STRIPE stuff");
   70 static u_int g_stripe_debug = 0;
   71 TUNABLE_INT("kern.geom.stripe.debug", &g_stripe_debug);
   72 SYSCTL_UINT(_kern_geom_stripe, OID_AUTO, debug, CTLFLAG_RW, &g_stripe_debug, 0,
   73     "Debug level");
   74 static int g_stripe_fast = 0;
   75 TUNABLE_INT("kern.geom.stripe.fast", &g_stripe_fast);
   76 static int
   77 g_sysctl_stripe_fast(SYSCTL_HANDLER_ARGS)
   78 {
   79         int error, fast;
   80 
   81         fast = g_stripe_fast;
   82         error = sysctl_handle_int(oidp, &fast, 0, req);
   83         if (error == 0 && req->newptr != NULL)
   84                 g_stripe_fast = fast;
   85         return (error);
   86 }
   87 SYSCTL_PROC(_kern_geom_stripe, OID_AUTO, fast, CTLTYPE_INT | CTLFLAG_RW,
   88     NULL, 0, g_sysctl_stripe_fast, "I", "Fast, but memory-consuming, mode");
   89 static u_int g_stripe_maxmem = MAXPHYS * 100;
   90 TUNABLE_INT("kern.geom.stripe.maxmem", &g_stripe_maxmem);
   91 SYSCTL_UINT(_kern_geom_stripe, OID_AUTO, maxmem, CTLFLAG_RD, &g_stripe_maxmem,
   92     0, "Maximum memory that can be allocated in \"fast\" mode (in bytes)");
   93 static u_int g_stripe_fast_failed = 0;
   94 SYSCTL_UINT(_kern_geom_stripe, OID_AUTO, fast_failed, CTLFLAG_RD,
   95     &g_stripe_fast_failed, 0, "How many times \"fast\" mode failed");
   96 
   97 /*
   98  * Greatest Common Divisor.
   99  */
  100 static u_int
  101 gcd(u_int a, u_int b)
  102 {
  103         u_int c;
  104 
  105         while (b != 0) {
  106                 c = a;
  107                 a = b;
  108                 b = (c % b);
  109         }
  110         return (a);
  111 }
  112 
  113 /*
  114  * Least Common Multiple.
  115  */
  116 static u_int
  117 lcm(u_int a, u_int b)
  118 {
  119 
  120         return ((a * b) / gcd(a, b));
  121 }
  122 
  123 static void
  124 g_stripe_init(struct g_class *mp __unused)
  125 {
  126 
  127         g_stripe_zone = uma_zcreate("g_stripe_zone", MAXPHYS, NULL, NULL,
  128             NULL, NULL, 0, 0);
  129         g_stripe_maxmem -= g_stripe_maxmem % MAXPHYS;
  130         uma_zone_set_max(g_stripe_zone, g_stripe_maxmem / MAXPHYS);
  131 }
  132 
  133 static void
  134 g_stripe_fini(struct g_class *mp __unused)
  135 {
  136 
  137         uma_zdestroy(g_stripe_zone);
  138 }
  139 
  140 /*
  141  * Return the number of valid disks.
  142  */
  143 static u_int
  144 g_stripe_nvalid(struct g_stripe_softc *sc)
  145 {
  146         u_int i, no;
  147 
  148         no = 0;
  149         for (i = 0; i < sc->sc_ndisks; i++) {
  150                 if (sc->sc_disks[i] != NULL)
  151                         no++;
  152         }
  153 
  154         return (no);
  155 }
  156 
  157 static void
  158 g_stripe_remove_disk(struct g_consumer *cp)
  159 {
  160         struct g_stripe_softc *sc;
  161         u_int no;
  162 
  163         KASSERT(cp != NULL, ("Non-valid disk in %s.", __func__));
  164         sc = (struct g_stripe_softc *)cp->private;
  165         KASSERT(sc != NULL, ("NULL sc in %s.", __func__));
  166         no = cp->index;
  167 
  168         G_STRIPE_DEBUG(0, "Disk %s removed from %s.", cp->provider->name,
  169             sc->sc_name);
  170 
  171         sc->sc_disks[no] = NULL;
  172         if (sc->sc_provider != NULL) {
  173                 sc->sc_provider->flags |= G_PF_WITHER;
  174                 g_orphan_provider(sc->sc_provider, ENXIO);
  175                 sc->sc_provider = NULL;
  176                 G_STRIPE_DEBUG(0, "Device %s removed.", sc->sc_name);
  177         }
  178 
  179         if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
  180                 g_access(cp, -cp->acr, -cp->acw, -cp->ace);
  181         g_detach(cp);
  182         g_destroy_consumer(cp);
  183 }
  184 
  185 static void
  186 g_stripe_orphan(struct g_consumer *cp)
  187 {
  188         struct g_stripe_softc *sc;
  189         struct g_geom *gp;
  190 
  191         g_topology_assert();
  192         gp = cp->geom;
  193         sc = gp->softc;
  194         if (sc == NULL)
  195                 return;
  196 
  197         g_stripe_remove_disk(cp);
  198         /* If there are no valid disks anymore, remove device. */
  199         if (g_stripe_nvalid(sc) == 0)
  200                 g_stripe_destroy(sc, 1);
  201 }
  202 
  203 static int
  204 g_stripe_access(struct g_provider *pp, int dr, int dw, int de)
  205 {
  206         struct g_consumer *cp1, *cp2;
  207         struct g_stripe_softc *sc;
  208         struct g_geom *gp;
  209         int error;
  210 
  211         gp = pp->geom;
  212         sc = gp->softc;
  213 
  214         if (sc == NULL) {
  215                 /*
  216                  * It looks like geom is being withered.
  217                  * In that case we allow only negative requests.
  218                  */
  219                 KASSERT(dr <= 0 && dw <= 0 && de <= 0,
  220                     ("Positive access request (device=%s).", pp->name));
  221                 if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 &&
  222                     (pp->ace + de) == 0) {
  223                         G_STRIPE_DEBUG(0, "Device %s definitely destroyed.",
  224                             gp->name);
  225                 }
  226                 return (0);
  227         }
  228 
  229         /* On first open, grab an extra "exclusive" bit */
  230         if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0)
  231                 de++;
  232         /* ... and let go of it on last close */
  233         if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 && (pp->ace + de) == 0)
  234                 de--;
  235 
  236         error = ENXIO;
  237         LIST_FOREACH(cp1, &gp->consumer, consumer) {
  238                 error = g_access(cp1, dr, dw, de);
  239                 if (error == 0)
  240                         continue;
  241                 /*
  242                  * If we fail here, backout all previous changes.
  243                  */
  244                 LIST_FOREACH(cp2, &gp->consumer, consumer) {
  245                         if (cp1 == cp2)
  246                                 return (error);
  247                         g_access(cp2, -dr, -dw, -de);
  248                 }
  249                 /* NOTREACHED */
  250         }
  251 
  252         return (error);
  253 }
  254 
  255 static void
  256 g_stripe_copy(struct g_stripe_softc *sc, char *src, char *dst, off_t offset,
  257     off_t length, int mode)
  258 {
  259         u_int stripesize;
  260         size_t len;
  261 
  262         stripesize = sc->sc_stripesize;
  263         len = (size_t)(stripesize - (offset & (stripesize - 1)));
  264         do {
  265                 bcopy(src, dst, len);
  266                 if (mode) {
  267                         dst += len + stripesize * (sc->sc_ndisks - 1);
  268                         src += len;
  269                 } else {
  270                         dst += len;
  271                         src += len + stripesize * (sc->sc_ndisks - 1);
  272                 }
  273                 length -= len;
  274                 KASSERT(length >= 0,
  275                     ("Length < 0 (stripesize=%zu, offset=%jd, length=%jd).",
  276                     (size_t)stripesize, (intmax_t)offset, (intmax_t)length));
  277                 if (length > stripesize)
  278                         len = stripesize;
  279                 else
  280                         len = length;
  281         } while (length > 0);
  282 }
  283 
  284 static void
  285 g_stripe_done(struct bio *bp)
  286 {
  287         struct g_stripe_softc *sc;
  288         struct bio *pbp;
  289 
  290         pbp = bp->bio_parent;
  291         sc = pbp->bio_to->geom->softc;
  292         if (pbp->bio_error == 0)
  293                 pbp->bio_error = bp->bio_error;
  294         pbp->bio_completed += bp->bio_completed;
  295         if (bp->bio_cmd == BIO_READ && bp->bio_caller1 != NULL) {
  296                 g_stripe_copy(sc, bp->bio_data, bp->bio_caller1, bp->bio_offset,
  297                     bp->bio_length, 1);
  298                 bp->bio_data = bp->bio_caller1;
  299                 bp->bio_caller1 = NULL;
  300         }
  301         g_destroy_bio(bp);
  302         pbp->bio_inbed++;
  303         if (pbp->bio_children == pbp->bio_inbed) {
  304                 if (pbp->bio_driver1 != NULL)
  305                         uma_zfree(g_stripe_zone, pbp->bio_driver1);
  306                 g_io_deliver(pbp, pbp->bio_error);
  307         }
  308 }
  309 
  310 static int
  311 g_stripe_start_fast(struct bio *bp, u_int no, off_t offset, off_t length)
  312 {
  313         TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue);
  314         u_int nparts = 0, stripesize;
  315         struct g_stripe_softc *sc;
  316         char *addr, *data = NULL;
  317         struct bio *cbp;
  318         int error;
  319 
  320         sc = bp->bio_to->geom->softc;
  321 
  322         addr = bp->bio_data;
  323         stripesize = sc->sc_stripesize;
  324 
  325         cbp = g_clone_bio(bp);
  326         if (cbp == NULL) {
  327                 error = ENOMEM;
  328                 goto failure;
  329         }
  330         TAILQ_INSERT_TAIL(&queue, cbp, bio_queue);
  331         nparts++;
  332         /*
  333          * Fill in the component buf structure.
  334          */
  335         cbp->bio_done = g_stripe_done;
  336         cbp->bio_offset = offset;
  337         cbp->bio_data = addr;
  338         cbp->bio_caller1 = NULL;
  339         cbp->bio_length = length;
  340         cbp->bio_caller2 = sc->sc_disks[no];
  341 
  342         /* offset -= offset % stripesize; */
  343         offset -= offset & (stripesize - 1);
  344         addr += length;
  345         length = bp->bio_length - length;
  346         for (no++; length > 0; no++, length -= stripesize, addr += stripesize) {
  347                 if (no > sc->sc_ndisks - 1) {
  348                         no = 0;
  349                         offset += stripesize;
  350                 }
  351                 if (nparts >= sc->sc_ndisks) {
  352                         cbp = TAILQ_NEXT(cbp, bio_queue);
  353                         if (cbp == NULL)
  354                                 cbp = TAILQ_FIRST(&queue);
  355                         nparts++;
  356                         /*
  357                          * Update bio structure.
  358                          */
  359                         /*
  360                          * MIN() is in case when
  361                          * (bp->bio_length % sc->sc_stripesize) != 0.
  362                          */
  363                         cbp->bio_length += MIN(stripesize, length);
  364                         if (cbp->bio_caller1 == NULL) {
  365                                 cbp->bio_caller1 = cbp->bio_data;
  366                                 cbp->bio_data = NULL;
  367                                 if (data == NULL) {
  368                                         data = uma_zalloc(g_stripe_zone,
  369                                             M_NOWAIT);
  370                                         if (data == NULL) {
  371                                                 error = ENOMEM;
  372                                                 goto failure;
  373                                         }
  374                                 }
  375                         }
  376                 } else {
  377                         cbp = g_clone_bio(bp);
  378                         if (cbp == NULL) {
  379                                 error = ENOMEM;
  380                                 goto failure;
  381                         }
  382                         TAILQ_INSERT_TAIL(&queue, cbp, bio_queue);
  383                         nparts++;
  384                         /*
  385                          * Fill in the component buf structure.
  386                          */
  387                         cbp->bio_done = g_stripe_done;
  388                         cbp->bio_offset = offset;
  389                         cbp->bio_data = addr;
  390                         cbp->bio_caller1 = NULL;
  391                         /*
  392                          * MIN() is in case when
  393                          * (bp->bio_length % sc->sc_stripesize) != 0.
  394                          */
  395                         cbp->bio_length = MIN(stripesize, length);
  396                         cbp->bio_caller2 = sc->sc_disks[no];
  397                 }
  398         }
  399         if (data != NULL)
  400                 bp->bio_driver1 = data;
  401         /*
  402          * Fire off all allocated requests!
  403          */
  404         while ((cbp = TAILQ_FIRST(&queue)) != NULL) {
  405                 struct g_consumer *cp;
  406 
  407                 TAILQ_REMOVE(&queue, cbp, bio_queue);
  408                 cp = cbp->bio_caller2;
  409                 cbp->bio_caller2 = NULL;
  410                 cbp->bio_to = cp->provider;
  411                 if (cbp->bio_caller1 != NULL) {
  412                         cbp->bio_data = data;
  413                         if (bp->bio_cmd == BIO_WRITE) {
  414                                 g_stripe_copy(sc, cbp->bio_caller1, data,
  415                                     cbp->bio_offset, cbp->bio_length, 0);
  416                         }
  417                         data += cbp->bio_length;
  418                 }
  419                 G_STRIPE_LOGREQ(cbp, "Sending request.");
  420                 g_io_request(cbp, cp);
  421         }
  422         return (0);
  423 failure:
  424         if (data != NULL)
  425                 uma_zfree(g_stripe_zone, data);
  426         while ((cbp = TAILQ_FIRST(&queue)) != NULL) {
  427                 TAILQ_REMOVE(&queue, cbp, bio_queue);
  428                 if (cbp->bio_caller1 != NULL) {
  429                         cbp->bio_data = cbp->bio_caller1;
  430                         cbp->bio_caller1 = NULL;
  431                 }
  432                 bp->bio_children--;
  433                 g_destroy_bio(cbp);
  434         }
  435         return (error);
  436 }
  437 
  438 static int
  439 g_stripe_start_economic(struct bio *bp, u_int no, off_t offset, off_t length)
  440 {
  441         TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue);
  442         struct g_stripe_softc *sc;
  443         uint32_t stripesize;
  444         struct bio *cbp;
  445         char *addr;
  446         int error;
  447 
  448         sc = bp->bio_to->geom->softc;
  449 
  450         addr = bp->bio_data;
  451         stripesize = sc->sc_stripesize;
  452 
  453         cbp = g_clone_bio(bp);
  454         if (cbp == NULL) {
  455                 error = ENOMEM;
  456                 goto failure;
  457         }
  458         TAILQ_INSERT_TAIL(&queue, cbp, bio_queue);
  459         /*
  460          * Fill in the component buf structure.
  461          */
  462         cbp->bio_done = g_std_done;
  463         cbp->bio_offset = offset;
  464         cbp->bio_data = addr;
  465         cbp->bio_length = length;
  466         cbp->bio_caller2 = sc->sc_disks[no];
  467 
  468         /* offset -= offset % stripesize; */
  469         offset -= offset & (stripesize - 1);
  470         addr += length;
  471         length = bp->bio_length - length;
  472         for (no++; length > 0; no++, length -= stripesize, addr += stripesize) {
  473                 if (no > sc->sc_ndisks - 1) {
  474                         no = 0;
  475                         offset += stripesize;
  476                 }
  477                 cbp = g_clone_bio(bp);
  478                 if (cbp == NULL) {
  479                         error = ENOMEM;
  480                         goto failure;
  481                 }
  482                 TAILQ_INSERT_TAIL(&queue, cbp, bio_queue);
  483 
  484                 /*
  485                  * Fill in the component buf structure.
  486                  */
  487                 cbp->bio_done = g_std_done;
  488                 cbp->bio_offset = offset;
  489                 cbp->bio_data = addr;
  490                 /*
  491                  * MIN() is in case when
  492                  * (bp->bio_length % sc->sc_stripesize) != 0.
  493                  */
  494                 cbp->bio_length = MIN(stripesize, length);
  495 
  496                 cbp->bio_caller2 = sc->sc_disks[no];
  497         }
  498         /*
  499          * Fire off all allocated requests!
  500          */
  501         while ((cbp = TAILQ_FIRST(&queue)) != NULL) {
  502                 struct g_consumer *cp;
  503 
  504                 TAILQ_REMOVE(&queue, cbp, bio_queue);
  505                 cp = cbp->bio_caller2;
  506                 cbp->bio_caller2 = NULL;
  507                 cbp->bio_to = cp->provider;
  508                 G_STRIPE_LOGREQ(cbp, "Sending request.");
  509                 g_io_request(cbp, cp);
  510         }
  511         return (0);
  512 failure:
  513         while ((cbp = TAILQ_FIRST(&queue)) != NULL) {
  514                 TAILQ_REMOVE(&queue, cbp, bio_queue);
  515                 bp->bio_children--;
  516                 g_destroy_bio(cbp);
  517         }
  518         return (error);
  519 }
  520 
  521 static void
  522 g_stripe_flush(struct g_stripe_softc *sc, struct bio *bp)
  523 {
  524         struct bio_queue_head queue;
  525         struct g_consumer *cp;
  526         struct bio *cbp;
  527         u_int no;
  528 
  529         bioq_init(&queue);
  530         for (no = 0; no < sc->sc_ndisks; no++) {
  531                 cbp = g_clone_bio(bp);
  532                 if (cbp == NULL) {
  533                         for (cbp = bioq_first(&queue); cbp != NULL;
  534                             cbp = bioq_first(&queue)) {
  535                                 bioq_remove(&queue, cbp);
  536                                 g_destroy_bio(cbp);
  537                         }
  538                         if (bp->bio_error == 0)
  539                                 bp->bio_error = ENOMEM;
  540                         g_io_deliver(bp, bp->bio_error);
  541                         return;
  542                 }
  543                 bioq_insert_tail(&queue, cbp);
  544                 cbp->bio_done = g_std_done;
  545                 cbp->bio_caller1 = sc->sc_disks[no];
  546                 cbp->bio_to = sc->sc_disks[no]->provider;
  547         }
  548         for (cbp = bioq_first(&queue); cbp != NULL; cbp = bioq_first(&queue)) {
  549                 bioq_remove(&queue, cbp);
  550                 G_STRIPE_LOGREQ(cbp, "Sending request.");
  551                 cp = cbp->bio_caller1;
  552                 cbp->bio_caller1 = NULL;
  553                 g_io_request(cbp, cp);
  554         }
  555 }
  556 
  557 static void
  558 g_stripe_start(struct bio *bp)
  559 {
  560         off_t offset, start, length, nstripe;
  561         struct g_stripe_softc *sc;
  562         u_int no, stripesize;
  563         int error, fast = 0;
  564 
  565         sc = bp->bio_to->geom->softc;
  566         /*
  567          * If sc == NULL, provider's error should be set and g_stripe_start()
  568          * should not be called at all.
  569          */
  570         KASSERT(sc != NULL,
  571             ("Provider's error should be set (error=%d)(device=%s).",
  572             bp->bio_to->error, bp->bio_to->name));
  573 
  574         G_STRIPE_LOGREQ(bp, "Request received.");
  575 
  576         switch (bp->bio_cmd) {
  577         case BIO_READ:
  578         case BIO_WRITE:
  579         case BIO_DELETE:
  580                 break;
  581         case BIO_FLUSH:
  582                 g_stripe_flush(sc, bp);
  583                 return;
  584         case BIO_GETATTR:
  585                 /* To which provider it should be delivered? */
  586         default:
  587                 g_io_deliver(bp, EOPNOTSUPP);
  588                 return;
  589         }
  590 
  591         stripesize = sc->sc_stripesize;
  592 
  593         /*
  594          * Calculations are quite messy, but fast I hope.
  595          */
  596 
  597         /* Stripe number. */
  598         /* nstripe = bp->bio_offset / stripesize; */
  599         nstripe = bp->bio_offset >> (off_t)sc->sc_stripebits;
  600         /* Disk number. */
  601         no = nstripe % sc->sc_ndisks;
  602         /* Start position in stripe. */
  603         /* start = bp->bio_offset % stripesize; */
  604         start = bp->bio_offset & (stripesize - 1);
  605         /* Start position in disk. */
  606         /* offset = (nstripe / sc->sc_ndisks) * stripesize + start; */
  607         offset = ((nstripe / sc->sc_ndisks) << sc->sc_stripebits) + start;
  608         /* Length of data to operate. */
  609         length = MIN(bp->bio_length, stripesize - start);
  610 
  611         /*
  612          * Do use "fast" mode when:
  613          * 1. "Fast" mode is ON.
  614          * and
  615          * 2. Request size is less than or equal to MAXPHYS,
  616          *    which should always be true.
  617          * and
  618          * 3. Request size is bigger than stripesize * ndisks. If it isn't,
  619          *    there will be no need to send more than one I/O request to
  620          *    a provider, so there is nothing to optmize.
  621          */
  622         if (g_stripe_fast && bp->bio_length <= MAXPHYS &&
  623             bp->bio_length >= stripesize * sc->sc_ndisks) {
  624                 fast = 1;
  625         }
  626         error = 0;
  627         if (fast) {
  628                 error = g_stripe_start_fast(bp, no, offset, length);
  629                 if (error != 0)
  630                         g_stripe_fast_failed++;
  631         }
  632         /*
  633          * Do use "economic" when:
  634          * 1. "Economic" mode is ON.
  635          * or
  636          * 2. "Fast" mode failed. It can only failed if there is no memory.
  637          */
  638         if (!fast || error != 0)
  639                 error = g_stripe_start_economic(bp, no, offset, length);
  640         if (error != 0) {
  641                 if (bp->bio_error == 0)
  642                         bp->bio_error = error;
  643                 g_io_deliver(bp, bp->bio_error);
  644         }
  645 }
  646 
  647 static void
  648 g_stripe_check_and_run(struct g_stripe_softc *sc)
  649 {
  650         off_t mediasize, ms;
  651         u_int no, sectorsize = 0;
  652 
  653         if (g_stripe_nvalid(sc) != sc->sc_ndisks)
  654                 return;
  655 
  656         sc->sc_provider = g_new_providerf(sc->sc_geom, "stripe/%s",
  657             sc->sc_name);
  658         /*
  659          * Find the smallest disk.
  660          */
  661         mediasize = sc->sc_disks[0]->provider->mediasize;
  662         if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC)
  663                 mediasize -= sc->sc_disks[0]->provider->sectorsize;
  664         mediasize -= mediasize % sc->sc_stripesize;
  665         sectorsize = sc->sc_disks[0]->provider->sectorsize;
  666         for (no = 1; no < sc->sc_ndisks; no++) {
  667                 ms = sc->sc_disks[no]->provider->mediasize;
  668                 if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC)
  669                         ms -= sc->sc_disks[no]->provider->sectorsize;
  670                 ms -= ms % sc->sc_stripesize;
  671                 if (ms < mediasize)
  672                         mediasize = ms;
  673                 sectorsize = lcm(sectorsize,
  674                     sc->sc_disks[no]->provider->sectorsize);
  675         }
  676         sc->sc_provider->sectorsize = sectorsize;
  677         sc->sc_provider->mediasize = mediasize * sc->sc_ndisks;
  678         sc->sc_provider->stripesize = sc->sc_stripesize;
  679         sc->sc_provider->stripeoffset = 0;
  680         g_error_provider(sc->sc_provider, 0);
  681 
  682         G_STRIPE_DEBUG(0, "Device %s activated.", sc->sc_name);
  683 }
  684 
  685 static int
  686 g_stripe_read_metadata(struct g_consumer *cp, struct g_stripe_metadata *md)
  687 {
  688         struct g_provider *pp;
  689         u_char *buf;
  690         int error;
  691 
  692         g_topology_assert();
  693 
  694         error = g_access(cp, 1, 0, 0);
  695         if (error != 0)
  696                 return (error);
  697         pp = cp->provider;
  698         g_topology_unlock();
  699         buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
  700             &error);
  701         g_topology_lock();
  702         g_access(cp, -1, 0, 0);
  703         if (buf == NULL)
  704                 return (error);
  705 
  706         /* Decode metadata. */
  707         stripe_metadata_decode(buf, md);
  708         g_free(buf);
  709 
  710         return (0);
  711 }
  712 
  713 /*
  714  * Add disk to given device.
  715  */
  716 static int
  717 g_stripe_add_disk(struct g_stripe_softc *sc, struct g_provider *pp, u_int no)
  718 {
  719         struct g_consumer *cp, *fcp;
  720         struct g_geom *gp;
  721         int error;
  722 
  723         /* Metadata corrupted? */
  724         if (no >= sc->sc_ndisks)
  725                 return (EINVAL);
  726 
  727         /* Check if disk is not already attached. */
  728         if (sc->sc_disks[no] != NULL)
  729                 return (EEXIST);
  730 
  731         gp = sc->sc_geom;
  732         fcp = LIST_FIRST(&gp->consumer);
  733 
  734         cp = g_new_consumer(gp);
  735         error = g_attach(cp, pp);
  736         if (error != 0) {
  737                 g_destroy_consumer(cp);
  738                 return (error);
  739         }
  740 
  741         if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0)) {
  742                 error = g_access(cp, fcp->acr, fcp->acw, fcp->ace);
  743                 if (error != 0) {
  744                         g_detach(cp);
  745                         g_destroy_consumer(cp);
  746                         return (error);
  747                 }
  748         }
  749         if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC) {
  750                 struct g_stripe_metadata md;
  751 
  752                 /* Reread metadata. */
  753                 error = g_stripe_read_metadata(cp, &md);
  754                 if (error != 0)
  755                         goto fail;
  756 
  757                 if (strcmp(md.md_magic, G_STRIPE_MAGIC) != 0 ||
  758                     strcmp(md.md_name, sc->sc_name) != 0 ||
  759                     md.md_id != sc->sc_id) {
  760                         G_STRIPE_DEBUG(0, "Metadata on %s changed.", pp->name);
  761                         goto fail;
  762                 }
  763         }
  764 
  765         cp->private = sc;
  766         cp->index = no;
  767         sc->sc_disks[no] = cp;
  768 
  769         G_STRIPE_DEBUG(0, "Disk %s attached to %s.", pp->name, sc->sc_name);
  770 
  771         g_stripe_check_and_run(sc);
  772 
  773         return (0);
  774 fail:
  775         if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0))
  776                 g_access(cp, -fcp->acr, -fcp->acw, -fcp->ace);
  777         g_detach(cp);
  778         g_destroy_consumer(cp);
  779         return (error);
  780 }
  781 
  782 static struct g_geom *
  783 g_stripe_create(struct g_class *mp, const struct g_stripe_metadata *md,
  784     u_int type)
  785 {
  786         struct g_stripe_softc *sc;
  787         struct g_geom *gp;
  788         u_int no;
  789 
  790         G_STRIPE_DEBUG(1, "Creating device %s (id=%u).", md->md_name,
  791             md->md_id);
  792 
  793         /* Two disks is minimum. */
  794         if (md->md_all < 2) {
  795                 G_STRIPE_DEBUG(0, "Too few disks defined for %s.", md->md_name);
  796                 return (NULL);
  797         }
  798 #if 0
  799         /* Stripe size have to be grater than or equal to sector size. */
  800         if (md->md_stripesize < sectorsize) {
  801                 G_STRIPE_DEBUG(0, "Invalid stripe size for %s.", md->md_name);
  802                 return (NULL);
  803         }
  804 #endif
  805         /* Stripe size have to be power of 2. */
  806         if (!powerof2(md->md_stripesize)) {
  807                 G_STRIPE_DEBUG(0, "Invalid stripe size for %s.", md->md_name);
  808                 return (NULL);
  809         }
  810 
  811         /* Check for duplicate unit */
  812         LIST_FOREACH(gp, &mp->geom, geom) {
  813                 sc = gp->softc;
  814                 if (sc != NULL && strcmp(sc->sc_name, md->md_name) == 0) {
  815                         G_STRIPE_DEBUG(0, "Device %s already configured.",
  816                             sc->sc_name);
  817                         return (NULL);
  818                 }
  819         }
  820         gp = g_new_geomf(mp, "%s", md->md_name);
  821         sc = malloc(sizeof(*sc), M_STRIPE, M_WAITOK | M_ZERO);
  822         gp->start = g_stripe_start;
  823         gp->spoiled = g_stripe_orphan;
  824         gp->orphan = g_stripe_orphan;
  825         gp->access = g_stripe_access;
  826         gp->dumpconf = g_stripe_dumpconf;
  827 
  828         sc->sc_id = md->md_id;
  829         sc->sc_stripesize = md->md_stripesize;
  830         sc->sc_stripebits = bitcount32(sc->sc_stripesize - 1);
  831         sc->sc_ndisks = md->md_all;
  832         sc->sc_disks = malloc(sizeof(struct g_consumer *) * sc->sc_ndisks,
  833             M_STRIPE, M_WAITOK | M_ZERO);
  834         for (no = 0; no < sc->sc_ndisks; no++)
  835                 sc->sc_disks[no] = NULL;
  836         sc->sc_type = type;
  837 
  838         gp->softc = sc;
  839         sc->sc_geom = gp;
  840         sc->sc_provider = NULL;
  841 
  842         G_STRIPE_DEBUG(0, "Device %s created (id=%u).", sc->sc_name, sc->sc_id);
  843 
  844         return (gp);
  845 }
  846 
  847 static int
  848 g_stripe_destroy(struct g_stripe_softc *sc, boolean_t force)
  849 {
  850         struct g_provider *pp;
  851         struct g_geom *gp;
  852         u_int no;
  853 
  854         g_topology_assert();
  855 
  856         if (sc == NULL)
  857                 return (ENXIO);
  858 
  859         pp = sc->sc_provider;
  860         if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
  861                 if (force) {
  862                         G_STRIPE_DEBUG(0, "Device %s is still open, so it "
  863                             "can't be definitely removed.", pp->name);
  864                 } else {
  865                         G_STRIPE_DEBUG(1,
  866                             "Device %s is still open (r%dw%de%d).", pp->name,
  867                             pp->acr, pp->acw, pp->ace);
  868                         return (EBUSY);
  869                 }
  870         }
  871 
  872         for (no = 0; no < sc->sc_ndisks; no++) {
  873                 if (sc->sc_disks[no] != NULL)
  874                         g_stripe_remove_disk(sc->sc_disks[no]);
  875         }
  876 
  877         gp = sc->sc_geom;
  878         gp->softc = NULL;
  879         KASSERT(sc->sc_provider == NULL, ("Provider still exists? (device=%s)",
  880             gp->name));
  881         free(sc->sc_disks, M_STRIPE);
  882         free(sc, M_STRIPE);
  883 
  884         pp = LIST_FIRST(&gp->provider);
  885         if (pp == NULL || (pp->acr == 0 && pp->acw == 0 && pp->ace == 0))
  886                 G_STRIPE_DEBUG(0, "Device %s destroyed.", gp->name);
  887 
  888         g_wither_geom(gp, ENXIO);
  889 
  890         return (0);
  891 }
  892 
  893 static int
  894 g_stripe_destroy_geom(struct gctl_req *req __unused,
  895     struct g_class *mp __unused, struct g_geom *gp)
  896 {
  897         struct g_stripe_softc *sc;
  898 
  899         sc = gp->softc;
  900         return (g_stripe_destroy(sc, 0));
  901 }
  902 
  903 static struct g_geom *
  904 g_stripe_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
  905 {
  906         struct g_stripe_metadata md;
  907         struct g_stripe_softc *sc;
  908         struct g_consumer *cp;
  909         struct g_geom *gp;
  910         int error;
  911 
  912         g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
  913         g_topology_assert();
  914 
  915         /* Skip providers that are already open for writing. */
  916         if (pp->acw > 0)
  917                 return (NULL);
  918 
  919         G_STRIPE_DEBUG(3, "Tasting %s.", pp->name);
  920 
  921         gp = g_new_geomf(mp, "stripe:taste");
  922         gp->start = g_stripe_start;
  923         gp->access = g_stripe_access;
  924         gp->orphan = g_stripe_orphan;
  925         cp = g_new_consumer(gp);
  926         g_attach(cp, pp);
  927         error = g_stripe_read_metadata(cp, &md);
  928         g_detach(cp);
  929         g_destroy_consumer(cp);
  930         g_destroy_geom(gp);
  931         if (error != 0)
  932                 return (NULL);
  933         gp = NULL;
  934 
  935         if (strcmp(md.md_magic, G_STRIPE_MAGIC) != 0)
  936                 return (NULL);
  937         if (md.md_version > G_STRIPE_VERSION) {
  938                 printf("geom_stripe.ko module is too old to handle %s.\n",
  939                     pp->name);
  940                 return (NULL);
  941         }
  942         /*
  943          * Backward compatibility:
  944          */
  945         /* There was no md_provider field in earlier versions of metadata. */
  946         if (md.md_version < 2)
  947                 bzero(md.md_provider, sizeof(md.md_provider));
  948         /* There was no md_provsize field in earlier versions of metadata. */
  949         if (md.md_version < 3)
  950                 md.md_provsize = pp->mediasize;
  951 
  952         if (md.md_provider[0] != '\0' &&
  953             !g_compare_names(md.md_provider, pp->name))
  954                 return (NULL);
  955         if (md.md_provsize != pp->mediasize)
  956                 return (NULL);
  957 
  958         /*
  959          * Let's check if device already exists.
  960          */
  961         sc = NULL;
  962         LIST_FOREACH(gp, &mp->geom, geom) {
  963                 sc = gp->softc;
  964                 if (sc == NULL)
  965                         continue;
  966                 if (sc->sc_type != G_STRIPE_TYPE_AUTOMATIC)
  967                         continue;
  968                 if (strcmp(md.md_name, sc->sc_name) != 0)
  969                         continue;
  970                 if (md.md_id != sc->sc_id)
  971                         continue;
  972                 break;
  973         }
  974         if (gp != NULL) {
  975                 G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
  976                 error = g_stripe_add_disk(sc, pp, md.md_no);
  977                 if (error != 0) {
  978                         G_STRIPE_DEBUG(0,
  979                             "Cannot add disk %s to %s (error=%d).", pp->name,
  980                             gp->name, error);
  981                         return (NULL);
  982                 }
  983         } else {
  984                 gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_AUTOMATIC);
  985                 if (gp == NULL) {
  986                         G_STRIPE_DEBUG(0, "Cannot create device %s.",
  987                             md.md_name);
  988                         return (NULL);
  989                 }
  990                 sc = gp->softc;
  991                 G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
  992                 error = g_stripe_add_disk(sc, pp, md.md_no);
  993                 if (error != 0) {
  994                         G_STRIPE_DEBUG(0,
  995                             "Cannot add disk %s to %s (error=%d).", pp->name,
  996                             gp->name, error);
  997                         g_stripe_destroy(sc, 1);
  998                         return (NULL);
  999                 }
 1000         }
 1001 
 1002         return (gp);
 1003 }
 1004 
 1005 static void
 1006 g_stripe_ctl_create(struct gctl_req *req, struct g_class *mp)
 1007 {
 1008         u_int attached, no;
 1009         struct g_stripe_metadata md;
 1010         struct g_provider *pp;
 1011         struct g_stripe_softc *sc;
 1012         struct g_geom *gp;
 1013         struct sbuf *sb;
 1014         intmax_t *stripesize;
 1015         const char *name;
 1016         char param[16];
 1017         int *nargs;
 1018 
 1019         g_topology_assert();
 1020         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
 1021         if (nargs == NULL) {
 1022                 gctl_error(req, "No '%s' argument.", "nargs");
 1023                 return;
 1024         }
 1025         if (*nargs <= 2) {
 1026                 gctl_error(req, "Too few arguments.");
 1027                 return;
 1028         }
 1029 
 1030         strlcpy(md.md_magic, G_STRIPE_MAGIC, sizeof(md.md_magic));
 1031         md.md_version = G_STRIPE_VERSION;
 1032         name = gctl_get_asciiparam(req, "arg0");
 1033         if (name == NULL) {
 1034                 gctl_error(req, "No 'arg%u' argument.", 0);
 1035                 return;
 1036         }
 1037         strlcpy(md.md_name, name, sizeof(md.md_name));
 1038         md.md_id = arc4random();
 1039         md.md_no = 0;
 1040         md.md_all = *nargs - 1;
 1041         stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize));
 1042         if (stripesize == NULL) {
 1043                 gctl_error(req, "No '%s' argument.", "stripesize");
 1044                 return;
 1045         }
 1046         md.md_stripesize = *stripesize;
 1047         bzero(md.md_provider, sizeof(md.md_provider));
 1048         /* This field is not important here. */
 1049         md.md_provsize = 0;
 1050 
 1051         /* Check all providers are valid */
 1052         for (no = 1; no < *nargs; no++) {
 1053                 snprintf(param, sizeof(param), "arg%u", no);
 1054                 name = gctl_get_asciiparam(req, param);
 1055                 if (name == NULL) {
 1056                         gctl_error(req, "No 'arg%u' argument.", no);
 1057                         return;
 1058                 }
 1059                 if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
 1060                         name += strlen("/dev/");
 1061                 pp = g_provider_by_name(name);
 1062                 if (pp == NULL) {
 1063                         G_STRIPE_DEBUG(1, "Disk %s is invalid.", name);
 1064                         gctl_error(req, "Disk %s is invalid.", name);
 1065                         return;
 1066                 }
 1067         }
 1068 
 1069         gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_MANUAL);
 1070         if (gp == NULL) {
 1071                 gctl_error(req, "Can't configure %s.", md.md_name);
 1072                 return;
 1073         }
 1074 
 1075         sc = gp->softc;
 1076         sb = sbuf_new_auto();
 1077         sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name);
 1078         for (attached = 0, no = 1; no < *nargs; no++) {
 1079                 snprintf(param, sizeof(param), "arg%u", no);
 1080                 name = gctl_get_asciiparam(req, param);
 1081                 if (name == NULL) {
 1082                         gctl_error(req, "No 'arg%u' argument.", no);
 1083                         continue;
 1084                 }
 1085                 if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
 1086                         name += strlen("/dev/");
 1087                 pp = g_provider_by_name(name);
 1088                 KASSERT(pp != NULL, ("Provider %s disappear?!", name));
 1089                 if (g_stripe_add_disk(sc, pp, no - 1) != 0) {
 1090                         G_STRIPE_DEBUG(1, "Disk %u (%s) not attached to %s.",
 1091                             no, pp->name, gp->name);
 1092                         sbuf_printf(sb, " %s", pp->name);
 1093                         continue;
 1094                 }
 1095                 attached++;
 1096         }
 1097         sbuf_finish(sb);
 1098         if (md.md_all != attached) {
 1099                 g_stripe_destroy(gp->softc, 1);
 1100                 gctl_error(req, "%s", sbuf_data(sb));
 1101         }
 1102         sbuf_delete(sb);
 1103 }
 1104 
 1105 static struct g_stripe_softc *
 1106 g_stripe_find_device(struct g_class *mp, const char *name)
 1107 {
 1108         struct g_stripe_softc *sc;
 1109         struct g_geom *gp;
 1110 
 1111         LIST_FOREACH(gp, &mp->geom, geom) {
 1112                 sc = gp->softc;
 1113                 if (sc == NULL)
 1114                         continue;
 1115                 if (strcmp(sc->sc_name, name) == 0)
 1116                         return (sc);
 1117         }
 1118         return (NULL);
 1119 }
 1120 
 1121 static void
 1122 g_stripe_ctl_destroy(struct gctl_req *req, struct g_class *mp)
 1123 {
 1124         struct g_stripe_softc *sc;
 1125         int *force, *nargs, error;
 1126         const char *name;
 1127         char param[16];
 1128         u_int i;
 1129 
 1130         g_topology_assert();
 1131 
 1132         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
 1133         if (nargs == NULL) {
 1134                 gctl_error(req, "No '%s' argument.", "nargs");
 1135                 return;
 1136         }
 1137         if (*nargs <= 0) {
 1138                 gctl_error(req, "Missing device(s).");
 1139                 return;
 1140         }
 1141         force = gctl_get_paraml(req, "force", sizeof(*force));
 1142         if (force == NULL) {
 1143                 gctl_error(req, "No '%s' argument.", "force");
 1144                 return;
 1145         }
 1146 
 1147         for (i = 0; i < (u_int)*nargs; i++) {
 1148                 snprintf(param, sizeof(param), "arg%u", i);
 1149                 name = gctl_get_asciiparam(req, param);
 1150                 if (name == NULL) {
 1151                         gctl_error(req, "No 'arg%u' argument.", i);
 1152                         return;
 1153                 }
 1154                 sc = g_stripe_find_device(mp, name);
 1155                 if (sc == NULL) {
 1156                         gctl_error(req, "No such device: %s.", name);
 1157                         return;
 1158                 }
 1159                 error = g_stripe_destroy(sc, *force);
 1160                 if (error != 0) {
 1161                         gctl_error(req, "Cannot destroy device %s (error=%d).",
 1162                             sc->sc_name, error);
 1163                         return;
 1164                 }
 1165         }
 1166 }
 1167 
 1168 static void
 1169 g_stripe_config(struct gctl_req *req, struct g_class *mp, const char *verb)
 1170 {
 1171         uint32_t *version;
 1172 
 1173         g_topology_assert();
 1174 
 1175         version = gctl_get_paraml(req, "version", sizeof(*version));
 1176         if (version == NULL) {
 1177                 gctl_error(req, "No '%s' argument.", "version");
 1178                 return;
 1179         }
 1180         if (*version != G_STRIPE_VERSION) {
 1181                 gctl_error(req, "Userland and kernel parts are out of sync.");
 1182                 return;
 1183         }
 1184 
 1185         if (strcmp(verb, "create") == 0) {
 1186                 g_stripe_ctl_create(req, mp);
 1187                 return;
 1188         } else if (strcmp(verb, "destroy") == 0 ||
 1189             strcmp(verb, "stop") == 0) {
 1190                 g_stripe_ctl_destroy(req, mp);
 1191                 return;
 1192         }
 1193 
 1194         gctl_error(req, "Unknown verb.");
 1195 }
 1196 
 1197 static void
 1198 g_stripe_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
 1199     struct g_consumer *cp, struct g_provider *pp)
 1200 {
 1201         struct g_stripe_softc *sc;
 1202 
 1203         sc = gp->softc;
 1204         if (sc == NULL)
 1205                 return;
 1206         if (pp != NULL) {
 1207                 /* Nothing here. */
 1208         } else if (cp != NULL) {
 1209                 sbuf_printf(sb, "%s<Number>%u</Number>\n", indent,
 1210                     (u_int)cp->index);
 1211         } else {
 1212                 sbuf_printf(sb, "%s<ID>%u</ID>\n", indent, (u_int)sc->sc_id);
 1213                 sbuf_printf(sb, "%s<Stripesize>%u</Stripesize>\n", indent,
 1214                     (u_int)sc->sc_stripesize);
 1215                 sbuf_printf(sb, "%s<Type>", indent);
 1216                 switch (sc->sc_type) {
 1217                 case G_STRIPE_TYPE_AUTOMATIC:
 1218                         sbuf_printf(sb, "AUTOMATIC");
 1219                         break;
 1220                 case G_STRIPE_TYPE_MANUAL:
 1221                         sbuf_printf(sb, "MANUAL");
 1222                         break;
 1223                 default:
 1224                         sbuf_printf(sb, "UNKNOWN");
 1225                         break;
 1226                 }
 1227                 sbuf_printf(sb, "</Type>\n");
 1228                 sbuf_printf(sb, "%s<Status>Total=%u, Online=%u</Status>\n",
 1229                     indent, sc->sc_ndisks, g_stripe_nvalid(sc));
 1230                 sbuf_printf(sb, "%s<State>", indent);
 1231                 if (sc->sc_provider != NULL && sc->sc_provider->error == 0)
 1232                         sbuf_printf(sb, "UP");
 1233                 else
 1234                         sbuf_printf(sb, "DOWN");
 1235                 sbuf_printf(sb, "</State>\n");
 1236         }
 1237 }
 1238 
 1239 DECLARE_GEOM_CLASS(g_stripe_class, g_stripe);

Cache object: babbf81e02d3bdf54787e78b1ec65d5d


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