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.1/sys/geom/stripe/g_stripe.c 201579 2010-01-05 13:46:39Z 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         gp->softc = NULL;       /* for a moment */
  822 
  823         sc = malloc(sizeof(*sc), M_STRIPE, M_WAITOK | M_ZERO);
  824         gp->start = g_stripe_start;
  825         gp->spoiled = g_stripe_orphan;
  826         gp->orphan = g_stripe_orphan;
  827         gp->access = g_stripe_access;
  828         gp->dumpconf = g_stripe_dumpconf;
  829 
  830         sc->sc_id = md->md_id;
  831         sc->sc_stripesize = md->md_stripesize;
  832         sc->sc_stripebits = bitcount32(sc->sc_stripesize - 1);
  833         sc->sc_ndisks = md->md_all;
  834         sc->sc_disks = malloc(sizeof(struct g_consumer *) * sc->sc_ndisks,
  835             M_STRIPE, M_WAITOK | M_ZERO);
  836         for (no = 0; no < sc->sc_ndisks; no++)
  837                 sc->sc_disks[no] = NULL;
  838         sc->sc_type = type;
  839 
  840         gp->softc = sc;
  841         sc->sc_geom = gp;
  842         sc->sc_provider = NULL;
  843 
  844         G_STRIPE_DEBUG(0, "Device %s created (id=%u).", sc->sc_name, sc->sc_id);
  845 
  846         return (gp);
  847 }
  848 
  849 static int
  850 g_stripe_destroy(struct g_stripe_softc *sc, boolean_t force)
  851 {
  852         struct g_provider *pp;
  853         struct g_geom *gp;
  854         u_int no;
  855 
  856         g_topology_assert();
  857 
  858         if (sc == NULL)
  859                 return (ENXIO);
  860 
  861         pp = sc->sc_provider;
  862         if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
  863                 if (force) {
  864                         G_STRIPE_DEBUG(0, "Device %s is still open, so it "
  865                             "can't be definitely removed.", pp->name);
  866                 } else {
  867                         G_STRIPE_DEBUG(1,
  868                             "Device %s is still open (r%dw%de%d).", pp->name,
  869                             pp->acr, pp->acw, pp->ace);
  870                         return (EBUSY);
  871                 }
  872         }
  873 
  874         for (no = 0; no < sc->sc_ndisks; no++) {
  875                 if (sc->sc_disks[no] != NULL)
  876                         g_stripe_remove_disk(sc->sc_disks[no]);
  877         }
  878 
  879         gp = sc->sc_geom;
  880         gp->softc = NULL;
  881         KASSERT(sc->sc_provider == NULL, ("Provider still exists? (device=%s)",
  882             gp->name));
  883         free(sc->sc_disks, M_STRIPE);
  884         free(sc, M_STRIPE);
  885 
  886         pp = LIST_FIRST(&gp->provider);
  887         if (pp == NULL || (pp->acr == 0 && pp->acw == 0 && pp->ace == 0))
  888                 G_STRIPE_DEBUG(0, "Device %s destroyed.", gp->name);
  889 
  890         g_wither_geom(gp, ENXIO);
  891 
  892         return (0);
  893 }
  894 
  895 static int
  896 g_stripe_destroy_geom(struct gctl_req *req __unused,
  897     struct g_class *mp __unused, struct g_geom *gp)
  898 {
  899         struct g_stripe_softc *sc;
  900 
  901         sc = gp->softc;
  902         return (g_stripe_destroy(sc, 0));
  903 }
  904 
  905 static struct g_geom *
  906 g_stripe_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
  907 {
  908         struct g_stripe_metadata md;
  909         struct g_stripe_softc *sc;
  910         struct g_consumer *cp;
  911         struct g_geom *gp;
  912         int error;
  913 
  914         g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
  915         g_topology_assert();
  916 
  917         /* Skip providers that are already open for writing. */
  918         if (pp->acw > 0)
  919                 return (NULL);
  920 
  921         G_STRIPE_DEBUG(3, "Tasting %s.", pp->name);
  922 
  923         gp = g_new_geomf(mp, "stripe:taste");
  924         gp->start = g_stripe_start;
  925         gp->access = g_stripe_access;
  926         gp->orphan = g_stripe_orphan;
  927         cp = g_new_consumer(gp);
  928         g_attach(cp, pp);
  929         error = g_stripe_read_metadata(cp, &md);
  930         g_detach(cp);
  931         g_destroy_consumer(cp);
  932         g_destroy_geom(gp);
  933         if (error != 0)
  934                 return (NULL);
  935         gp = NULL;
  936 
  937         if (strcmp(md.md_magic, G_STRIPE_MAGIC) != 0)
  938                 return (NULL);
  939         if (md.md_version > G_STRIPE_VERSION) {
  940                 printf("geom_stripe.ko module is too old to handle %s.\n",
  941                     pp->name);
  942                 return (NULL);
  943         }
  944         /*
  945          * Backward compatibility:
  946          */
  947         /* There was no md_provider field in earlier versions of metadata. */
  948         if (md.md_version < 2)
  949                 bzero(md.md_provider, sizeof(md.md_provider));
  950         /* There was no md_provsize field in earlier versions of metadata. */
  951         if (md.md_version < 3)
  952                 md.md_provsize = pp->mediasize;
  953 
  954         if (md.md_provider[0] != '\0' && strcmp(md.md_provider, pp->name) != 0)
  955                 return (NULL);
  956         if (md.md_provsize != pp->mediasize)
  957                 return (NULL);
  958 
  959         /*
  960          * Let's check if device already exists.
  961          */
  962         sc = NULL;
  963         LIST_FOREACH(gp, &mp->geom, geom) {
  964                 sc = gp->softc;
  965                 if (sc == NULL)
  966                         continue;
  967                 if (sc->sc_type != G_STRIPE_TYPE_AUTOMATIC)
  968                         continue;
  969                 if (strcmp(md.md_name, sc->sc_name) != 0)
  970                         continue;
  971                 if (md.md_id != sc->sc_id)
  972                         continue;
  973                 break;
  974         }
  975         if (gp != NULL) {
  976                 G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
  977                 error = g_stripe_add_disk(sc, pp, md.md_no);
  978                 if (error != 0) {
  979                         G_STRIPE_DEBUG(0,
  980                             "Cannot add disk %s to %s (error=%d).", pp->name,
  981                             gp->name, error);
  982                         return (NULL);
  983                 }
  984         } else {
  985                 gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_AUTOMATIC);
  986                 if (gp == NULL) {
  987                         G_STRIPE_DEBUG(0, "Cannot create device %s.",
  988                             md.md_name);
  989                         return (NULL);
  990                 }
  991                 sc = gp->softc;
  992                 G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
  993                 error = g_stripe_add_disk(sc, pp, md.md_no);
  994                 if (error != 0) {
  995                         G_STRIPE_DEBUG(0,
  996                             "Cannot add disk %s to %s (error=%d).", pp->name,
  997                             gp->name, error);
  998                         g_stripe_destroy(sc, 1);
  999                         return (NULL);
 1000                 }
 1001         }
 1002 
 1003         return (gp);
 1004 }
 1005 
 1006 static void
 1007 g_stripe_ctl_create(struct gctl_req *req, struct g_class *mp)
 1008 {
 1009         u_int attached, no;
 1010         struct g_stripe_metadata md;
 1011         struct g_provider *pp;
 1012         struct g_stripe_softc *sc;
 1013         struct g_geom *gp;
 1014         struct sbuf *sb;
 1015         intmax_t *stripesize;
 1016         const char *name;
 1017         char param[16];
 1018         int *nargs;
 1019 
 1020         g_topology_assert();
 1021         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
 1022         if (nargs == NULL) {
 1023                 gctl_error(req, "No '%s' argument.", "nargs");
 1024                 return;
 1025         }
 1026         if (*nargs <= 2) {
 1027                 gctl_error(req, "Too few arguments.");
 1028                 return;
 1029         }
 1030 
 1031         strlcpy(md.md_magic, G_STRIPE_MAGIC, sizeof(md.md_magic));
 1032         md.md_version = G_STRIPE_VERSION;
 1033         name = gctl_get_asciiparam(req, "arg0");
 1034         if (name == NULL) {
 1035                 gctl_error(req, "No 'arg%u' argument.", 0);
 1036                 return;
 1037         }
 1038         strlcpy(md.md_name, name, sizeof(md.md_name));
 1039         md.md_id = arc4random();
 1040         md.md_no = 0;
 1041         md.md_all = *nargs - 1;
 1042         stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize));
 1043         if (stripesize == NULL) {
 1044                 gctl_error(req, "No '%s' argument.", "stripesize");
 1045                 return;
 1046         }
 1047         md.md_stripesize = *stripesize;
 1048         bzero(md.md_provider, sizeof(md.md_provider));
 1049         /* This field is not important here. */
 1050         md.md_provsize = 0;
 1051 
 1052         /* Check all providers are valid */
 1053         for (no = 1; no < *nargs; no++) {
 1054                 snprintf(param, sizeof(param), "arg%u", no);
 1055                 name = gctl_get_asciiparam(req, param);
 1056                 if (name == NULL) {
 1057                         gctl_error(req, "No 'arg%u' argument.", no);
 1058                         return;
 1059                 }
 1060                 if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
 1061                         name += strlen("/dev/");
 1062                 pp = g_provider_by_name(name);
 1063                 if (pp == NULL) {
 1064                         G_STRIPE_DEBUG(1, "Disk %s is invalid.", name);
 1065                         gctl_error(req, "Disk %s is invalid.", name);
 1066                         return;
 1067                 }
 1068         }
 1069 
 1070         gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_MANUAL);
 1071         if (gp == NULL) {
 1072                 gctl_error(req, "Can't configure %s.", md.md_name);
 1073                 return;
 1074         }
 1075 
 1076         sc = gp->softc;
 1077         sb = sbuf_new_auto();
 1078         sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name);
 1079         for (attached = 0, no = 1; no < *nargs; no++) {
 1080                 snprintf(param, sizeof(param), "arg%u", no);
 1081                 name = gctl_get_asciiparam(req, param);
 1082                 if (name == NULL) {
 1083                         gctl_error(req, "No 'arg%u' argument.", no);
 1084                         continue;
 1085                 }
 1086                 if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
 1087                         name += strlen("/dev/");
 1088                 pp = g_provider_by_name(name);
 1089                 KASSERT(pp != NULL, ("Provider %s disappear?!", name));
 1090                 if (g_stripe_add_disk(sc, pp, no - 1) != 0) {
 1091                         G_STRIPE_DEBUG(1, "Disk %u (%s) not attached to %s.",
 1092                             no, pp->name, gp->name);
 1093                         sbuf_printf(sb, " %s", pp->name);
 1094                         continue;
 1095                 }
 1096                 attached++;
 1097         }
 1098         sbuf_finish(sb);
 1099         if (md.md_all != attached) {
 1100                 g_stripe_destroy(gp->softc, 1);
 1101                 gctl_error(req, "%s", sbuf_data(sb));
 1102         }
 1103         sbuf_delete(sb);
 1104 }
 1105 
 1106 static struct g_stripe_softc *
 1107 g_stripe_find_device(struct g_class *mp, const char *name)
 1108 {
 1109         struct g_stripe_softc *sc;
 1110         struct g_geom *gp;
 1111 
 1112         LIST_FOREACH(gp, &mp->geom, geom) {
 1113                 sc = gp->softc;
 1114                 if (sc == NULL)
 1115                         continue;
 1116                 if (strcmp(sc->sc_name, name) == 0)
 1117                         return (sc);
 1118         }
 1119         return (NULL);
 1120 }
 1121 
 1122 static void
 1123 g_stripe_ctl_destroy(struct gctl_req *req, struct g_class *mp)
 1124 {
 1125         struct g_stripe_softc *sc;
 1126         int *force, *nargs, error;
 1127         const char *name;
 1128         char param[16];
 1129         u_int i;
 1130 
 1131         g_topology_assert();
 1132 
 1133         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
 1134         if (nargs == NULL) {
 1135                 gctl_error(req, "No '%s' argument.", "nargs");
 1136                 return;
 1137         }
 1138         if (*nargs <= 0) {
 1139                 gctl_error(req, "Missing device(s).");
 1140                 return;
 1141         }
 1142         force = gctl_get_paraml(req, "force", sizeof(*force));
 1143         if (force == NULL) {
 1144                 gctl_error(req, "No '%s' argument.", "force");
 1145                 return;
 1146         }
 1147 
 1148         for (i = 0; i < (u_int)*nargs; i++) {
 1149                 snprintf(param, sizeof(param), "arg%u", i);
 1150                 name = gctl_get_asciiparam(req, param);
 1151                 if (name == NULL) {
 1152                         gctl_error(req, "No 'arg%u' argument.", i);
 1153                         return;
 1154                 }
 1155                 sc = g_stripe_find_device(mp, name);
 1156                 if (sc == NULL) {
 1157                         gctl_error(req, "No such device: %s.", name);
 1158                         return;
 1159                 }
 1160                 error = g_stripe_destroy(sc, *force);
 1161                 if (error != 0) {
 1162                         gctl_error(req, "Cannot destroy device %s (error=%d).",
 1163                             sc->sc_name, error);
 1164                         return;
 1165                 }
 1166         }
 1167 }
 1168 
 1169 static void
 1170 g_stripe_config(struct gctl_req *req, struct g_class *mp, const char *verb)
 1171 {
 1172         uint32_t *version;
 1173 
 1174         g_topology_assert();
 1175 
 1176         version = gctl_get_paraml(req, "version", sizeof(*version));
 1177         if (version == NULL) {
 1178                 gctl_error(req, "No '%s' argument.", "version");
 1179                 return;
 1180         }
 1181         if (*version != G_STRIPE_VERSION) {
 1182                 gctl_error(req, "Userland and kernel parts are out of sync.");
 1183                 return;
 1184         }
 1185 
 1186         if (strcmp(verb, "create") == 0) {
 1187                 g_stripe_ctl_create(req, mp);
 1188                 return;
 1189         } else if (strcmp(verb, "destroy") == 0 ||
 1190             strcmp(verb, "stop") == 0) {
 1191                 g_stripe_ctl_destroy(req, mp);
 1192                 return;
 1193         }
 1194 
 1195         gctl_error(req, "Unknown verb.");
 1196 }
 1197 
 1198 static void
 1199 g_stripe_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
 1200     struct g_consumer *cp, struct g_provider *pp)
 1201 {
 1202         struct g_stripe_softc *sc;
 1203 
 1204         sc = gp->softc;
 1205         if (sc == NULL)
 1206                 return;
 1207         if (pp != NULL) {
 1208                 /* Nothing here. */
 1209         } else if (cp != NULL) {
 1210                 sbuf_printf(sb, "%s<Number>%u</Number>\n", indent,
 1211                     (u_int)cp->index);
 1212         } else {
 1213                 sbuf_printf(sb, "%s<ID>%u</ID>\n", indent, (u_int)sc->sc_id);
 1214                 sbuf_printf(sb, "%s<Stripesize>%u</Stripesize>\n", indent,
 1215                     (u_int)sc->sc_stripesize);
 1216                 sbuf_printf(sb, "%s<Type>", indent);
 1217                 switch (sc->sc_type) {
 1218                 case G_STRIPE_TYPE_AUTOMATIC:
 1219                         sbuf_printf(sb, "AUTOMATIC");
 1220                         break;
 1221                 case G_STRIPE_TYPE_MANUAL:
 1222                         sbuf_printf(sb, "MANUAL");
 1223                         break;
 1224                 default:
 1225                         sbuf_printf(sb, "UNKNOWN");
 1226                         break;
 1227                 }
 1228                 sbuf_printf(sb, "</Type>\n");
 1229                 sbuf_printf(sb, "%s<Status>Total=%u, Online=%u</Status>\n",
 1230                     indent, sc->sc_ndisks, g_stripe_nvalid(sc));
 1231                 sbuf_printf(sb, "%s<State>", indent);
 1232                 if (sc->sc_provider != NULL && sc->sc_provider->error == 0)
 1233                         sbuf_printf(sb, "UP");
 1234                 else
 1235                         sbuf_printf(sb, "DOWN");
 1236                 sbuf_printf(sb, "</State>\n");
 1237         }
 1238 }
 1239 
 1240 DECLARE_GEOM_CLASS(g_stripe_class, g_stripe);

Cache object: e9bc4c09b923674cb60e84b301408649


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