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/vinum/geom_vinum_subr.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 Lukas Ertl
    3  * Copyright (c) 1997, 1998, 1999
    4  *      Nan Yang Computer Services Limited.  All rights reserved.
    5  *
    6  *  Parts written by Greg Lehey
    7  *
    8  *  This software is distributed under the so-called ``Berkeley
    9  *  License'':
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by Nan Yang Computer
   22  *      Services Limited.
   23  * 4. Neither the name of the Company nor the names of its contributors
   24  *    may be used to endorse or promote products derived from this software
   25  *    without specific prior written permission.
   26  *
   27  * This software is provided ``as is'', and any express or implied
   28  * warranties, including, but not limited to, the implied warranties of
   29  * merchantability and fitness for a particular purpose are disclaimed.
   30  * In no event shall the company or contributors be liable for any
   31  * direct, indirect, incidental, special, exemplary, or consequential
   32  * damages (including, but not limited to, procurement of substitute
   33  * goods or services; loss of use, data, or profits; or business
   34  * interruption) however caused and on any theory of liability, whether
   35  * in contract, strict liability, or tort (including negligence or
   36  * otherwise) arising in any way out of the use of this software, even if
   37  * advised of the possibility of such damage.
   38  *
   39  */
   40 
   41 #include <sys/cdefs.h>
   42 __FBSDID("$FreeBSD$");
   43 
   44 #include <sys/param.h>
   45 #include <sys/conf.h>
   46 #include <sys/kernel.h>
   47 #include <sys/libkern.h>
   48 #include <sys/malloc.h>
   49 #include <sys/systm.h>
   50 
   51 #include <geom/geom.h>
   52 #include <geom/geom_int.h>
   53 #include <geom/vinum/geom_vinum_var.h>
   54 #include <geom/vinum/geom_vinum.h>
   55 #include <geom/vinum/geom_vinum_share.h>
   56 
   57 static off_t gv_plex_smallest_sd(struct gv_plex *, off_t);
   58 
   59 /* Find the VINUM class and it's associated geom. */
   60 struct g_geom *
   61 find_vinum_geom(void)
   62 {
   63         struct g_class *mp;
   64         struct g_geom *gp;
   65 
   66         g_topology_assert();
   67 
   68         gp = NULL;
   69 
   70         LIST_FOREACH(mp, &g_classes, class) {
   71                 if (!strcmp(mp->name, "VINUM")) {
   72                         gp = LIST_FIRST(&mp->geom);
   73                         break;
   74                 }
   75         }
   76 
   77         return (gp);
   78 }
   79 
   80 /*
   81  * Parse the vinum config provided in *buf and store it in *gp's softc.
   82  * If parameter 'merge' is non-zero, then the given config is merged into
   83  * *gp.
   84  */
   85 void
   86 gv_parse_config(struct gv_softc *sc, u_char *buf, int merge)
   87 {
   88         char *aptr, *bptr, *cptr;
   89         struct gv_volume *v, *v2;
   90         struct gv_plex *p, *p2;
   91         struct gv_sd *s, *s2;
   92         int tokens;
   93         char *token[GV_MAXARGS];
   94 
   95         g_topology_assert();
   96 
   97         KASSERT(sc != NULL, ("gv_parse_config: NULL softc"));
   98 
   99         /* Until the end of the string *buf. */
  100         for (aptr = buf; *aptr != '\0'; aptr = bptr) {
  101                 bptr = aptr;
  102                 cptr = aptr;
  103 
  104                 /* Seperate input lines. */
  105                 while (*bptr != '\n')
  106                         bptr++;
  107                 *bptr = '\0';
  108                 bptr++;
  109 
  110                 tokens = gv_tokenize(cptr, token, GV_MAXARGS);
  111 
  112                 if (tokens > 0) {
  113                         if (!strcmp(token[0], "volume")) {
  114                                 v = gv_new_volume(tokens, token);
  115                                 if (v == NULL) {
  116                                         printf("geom_vinum: failed volume\n");
  117                                         break;
  118                                 }
  119 
  120                                 if (merge) {
  121                                         v2 = gv_find_vol(sc, v->name);
  122                                         if (v2 != NULL) {
  123                                                 g_free(v);
  124                                                 continue;
  125                                         }
  126                                 }
  127 
  128                                 v->vinumconf = sc;
  129                                 LIST_INIT(&v->plexes);
  130                                 LIST_INSERT_HEAD(&sc->volumes, v, volume);
  131 
  132                         } else if (!strcmp(token[0], "plex")) {
  133                                 p = gv_new_plex(tokens, token);
  134                                 if (p == NULL) {
  135                                         printf("geom_vinum: failed plex\n");
  136                                         break;
  137                                 }
  138 
  139                                 if (merge) {
  140                                         p2 = gv_find_plex(sc, p->name);
  141                                         if (p2 != NULL) {
  142                                                 g_free(p);
  143                                                 continue;
  144                                         }
  145                                 }
  146 
  147                                 p->vinumconf = sc;
  148                                 LIST_INIT(&p->subdisks);
  149                                 LIST_INSERT_HEAD(&sc->plexes, p, plex);
  150 
  151                         } else if (!strcmp(token[0], "sd")) {
  152                                 s = gv_new_sd(tokens, token);
  153 
  154                                 if (s == NULL) {
  155                                         printf("geom_vinum: failed subdisk\n");
  156                                         break;
  157                                 }
  158 
  159                                 if (merge) {
  160                                         s2 = gv_find_sd(sc, s->name);
  161                                         if (s2 != NULL) {
  162                                                 g_free(s);
  163                                                 continue;
  164                                         }
  165                                 }
  166 
  167                                 s->vinumconf = sc;
  168                                 LIST_INSERT_HEAD(&sc->subdisks, s, sd);
  169                         }
  170                 }
  171         }
  172 }
  173 
  174 /*
  175  * Format the vinum configuration properly.  If ondisk is non-zero then the
  176  * configuration is intended to be written to disk later.
  177  */
  178 void
  179 gv_format_config(struct gv_softc *sc, struct sbuf *sb, int ondisk, char *prefix)
  180 {
  181         struct gv_drive *d;
  182         struct gv_sd *s;
  183         struct gv_plex *p;
  184         struct gv_volume *v;
  185 
  186         g_topology_assert();
  187 
  188         /*
  189          * We don't need the drive configuration if we're not writing the
  190          * config to disk.
  191          */
  192         if (!ondisk) {
  193                 LIST_FOREACH(d, &sc->drives, drive) {
  194                         sbuf_printf(sb, "%sdrive %s device /dev/%s\n", prefix,
  195                             d->name, d->device);
  196                 }
  197         }
  198 
  199         LIST_FOREACH(v, &sc->volumes, volume) {
  200                 if (!ondisk)
  201                         sbuf_printf(sb, "%s", prefix);
  202                 sbuf_printf(sb, "volume %s", v->name);
  203                 if (ondisk)
  204                         sbuf_printf(sb, " state %s", gv_volstate(v->state));
  205                 sbuf_printf(sb, "\n");
  206         }
  207 
  208         LIST_FOREACH(p, &sc->plexes, plex) {
  209                 if (!ondisk)
  210                         sbuf_printf(sb, "%s", prefix);
  211                 sbuf_printf(sb, "plex name %s org %s ", p->name,
  212                     gv_plexorg(p->org));
  213                 if (gv_is_striped(p))
  214                         sbuf_printf(sb, "%ds ", p->stripesize / 512);
  215                 if (p->vol_sc != NULL)
  216                         sbuf_printf(sb, "vol %s", p->volume);
  217                 if (ondisk)
  218                         sbuf_printf(sb, " state %s", gv_plexstate(p->state));
  219                 sbuf_printf(sb, "\n");
  220         }
  221 
  222         LIST_FOREACH(s, &sc->subdisks, sd) {
  223                 if (!ondisk)
  224                         sbuf_printf(sb, "%s", prefix);
  225                 sbuf_printf(sb, "sd name %s drive %s len %jds driveoffset "
  226                     "%jds", s->name, s->drive, s->size / 512,
  227                     s->drive_offset / 512);
  228                 if (s->plex_sc != NULL) {
  229                         sbuf_printf(sb, " plex %s plexoffset %jds", s->plex,
  230                             s->plex_offset / 512);
  231                 }
  232                 if (ondisk)
  233                         sbuf_printf(sb, " state %s", gv_sdstate(s->state));
  234                 sbuf_printf(sb, "\n");
  235         }
  236 
  237         return;
  238 }
  239 
  240 static off_t
  241 gv_plex_smallest_sd(struct gv_plex *p, off_t smallest)
  242 {
  243         struct gv_sd *s;
  244 
  245         KASSERT(p != NULL, ("gv_plex_smallest_sd: NULL p"));
  246 
  247         LIST_FOREACH(s, &p->subdisks, in_plex) {
  248                 if (s->size < smallest)
  249                         smallest = s->size;
  250         }
  251         return (smallest);
  252 }
  253 
  254 int
  255 gv_sd_to_plex(struct gv_plex *p, struct gv_sd *s, int check)
  256 {
  257         struct gv_sd *s2;
  258 
  259         g_topology_assert();
  260 
  261         /* If this subdisk was already given to this plex, do nothing. */
  262         if (s->plex_sc == p)
  263                 return (0);
  264 
  265         /* Check correct size of this subdisk. */
  266         s2 = LIST_FIRST(&p->subdisks);
  267         if (s2 != NULL && gv_is_striped(p) && (s2->size != s->size)) {
  268                 printf("GEOM_VINUM: need equal sized subdisks for "
  269                     "this plex organisation - %s (%jd) <-> %s (%jd)\n",
  270                     s2->name, s2->size, s->name, s->size);
  271                 return (-1);
  272         }
  273 
  274         /* Find the correct plex offset for this subdisk, if needed. */
  275         if (s->plex_offset == -1) {
  276                 if (p->sdcount) {
  277                         LIST_FOREACH(s2, &p->subdisks, in_plex) {
  278                                 if (gv_is_striped(p))
  279                                         s->plex_offset = p->sdcount *
  280                                             p->stripesize;
  281                                 else
  282                                         s->plex_offset = s2->plex_offset +
  283                                             s2->size;
  284                         }
  285                 } else
  286                         s->plex_offset = 0;
  287         }
  288 
  289         p->sdcount++;
  290 
  291         /* Adjust the size of our plex. */
  292         switch (p->org) {
  293         case GV_PLEX_CONCAT:
  294         case GV_PLEX_STRIPED:
  295                 p->size += s->size;
  296                 break;
  297 
  298         case GV_PLEX_RAID5:
  299                 p->size = (p->sdcount - 1) * gv_plex_smallest_sd(p, s->size);
  300                 break;
  301 
  302         default:
  303                 break;
  304         }
  305 
  306         /* There are no subdisks for this plex yet, just insert it. */
  307         if (LIST_EMPTY(&p->subdisks)) {
  308                 LIST_INSERT_HEAD(&p->subdisks, s, in_plex);
  309 
  310         /* Insert in correct order, depending on plex_offset. */
  311         } else {
  312                 LIST_FOREACH(s2, &p->subdisks, in_plex) {
  313                         if (s->plex_offset < s2->plex_offset) {
  314                                 LIST_INSERT_BEFORE(s2, s, in_plex);
  315                                 break;
  316                         } else if (LIST_NEXT(s2, in_plex) == NULL) {
  317                                 LIST_INSERT_AFTER(s2, s, in_plex);
  318                                 break;
  319                         }
  320                 }
  321         }
  322 
  323         s->plex_sc = p;
  324 
  325         return (0);
  326 }
  327 
  328 void
  329 gv_update_vol_size(struct gv_volume *v, off_t size)
  330 {
  331         struct g_geom *gp;
  332         struct g_provider *pp;
  333 
  334         if (v == NULL)
  335                 return;
  336 
  337         gp = v->geom;
  338         if (gp == NULL)
  339                 return;
  340 
  341         LIST_FOREACH(pp, &gp->provider, provider) {
  342                 pp->mediasize = size;
  343         }
  344 
  345         v->size = size;
  346 }
  347 
  348 /* Calculates the plex size. */
  349 off_t
  350 gv_plex_size(struct gv_plex *p)
  351 {
  352         struct gv_sd *s;
  353         off_t size;
  354 
  355         KASSERT(p != NULL, ("gv_plex_size: NULL p"));
  356 
  357         if (p->sdcount == 0)
  358                 return (0);
  359 
  360         /* Adjust the size of our plex. */
  361         size = 0;
  362         switch (p->org) {
  363         case GV_PLEX_CONCAT:
  364                 LIST_FOREACH(s, &p->subdisks, in_plex)
  365                         size += s->size;
  366                 break;
  367         case GV_PLEX_STRIPED:
  368                 s = LIST_FIRST(&p->subdisks);
  369                 size = p->sdcount * s->size;
  370                 break;
  371         case GV_PLEX_RAID5:
  372                 s = LIST_FIRST(&p->subdisks);
  373                 size = (p->sdcount - 1) * s->size;
  374                 break;
  375         }
  376 
  377         return (size);
  378 }
  379 
  380 /* Returns the size of a volume. */
  381 off_t
  382 gv_vol_size(struct gv_volume *v)
  383 {
  384         struct gv_plex *p;
  385         off_t minplexsize;
  386 
  387         KASSERT(v != NULL, ("gv_vol_size: NULL v"));
  388 
  389         p = LIST_FIRST(&v->plexes);
  390         if (p == NULL)
  391                 return (0);
  392 
  393         minplexsize = p->size;
  394         LIST_FOREACH(p, &v->plexes, plex) {
  395                 if (p->size < minplexsize) {
  396                         minplexsize = p->size;
  397                 }
  398         }
  399         return (minplexsize);
  400 }
  401 
  402 void
  403 gv_update_plex_config(struct gv_plex *p)
  404 {
  405         struct gv_sd *s, *s2;
  406         off_t remainder;
  407         int required_sds, state;
  408 
  409         KASSERT(p != NULL, ("gv_update_plex_config: NULL p"));
  410 
  411         /* This is what we want the plex to be. */
  412         state = GV_PLEX_UP;
  413 
  414         /* The plex was added to an already running volume. */
  415         if (p->flags & GV_PLEX_ADDED)
  416                 state = GV_PLEX_DOWN;
  417 
  418         switch (p->org) {
  419         case GV_PLEX_STRIPED:
  420                 required_sds = 2;
  421                 break;
  422         case GV_PLEX_RAID5:
  423                 required_sds = 3;
  424                 break;
  425         case GV_PLEX_CONCAT:
  426         default:
  427                 required_sds = 0;
  428                 break;
  429         }
  430 
  431         if (required_sds) {
  432                 if (p->sdcount < required_sds) {
  433                         state = GV_PLEX_DOWN;
  434                 }
  435 
  436                 /*
  437                  * The subdisks in striped plexes must all have the same size.
  438                  */
  439                 s = LIST_FIRST(&p->subdisks);
  440                 LIST_FOREACH(s2, &p->subdisks, in_plex) {
  441                         if (s->size != s2->size) {
  442                                 printf("geom_vinum: subdisk size mismatch "
  443                                     "%s (%jd) <> %s (%jd)\n", s->name, s->size,
  444                                     s2->name, s2->size);
  445                                 state = GV_PLEX_DOWN;
  446                         }
  447                 }
  448 
  449                 /* Trim subdisk sizes so that they match the stripe size. */
  450                 LIST_FOREACH(s, &p->subdisks, in_plex) {
  451                         remainder = s->size % p->stripesize;
  452                         if (remainder) {
  453                                 printf("gvinum: size of sd %s is not a "
  454                                     "multiple of plex stripesize, taking off "
  455                                     "%jd bytes\n", s->name,
  456                                     (intmax_t)remainder);
  457                                 gv_adjust_freespace(s, remainder);
  458                         }
  459                 }
  460         }
  461 
  462         /* Adjust the size of our plex. */
  463         if (p->sdcount > 0) {
  464                 p->size = 0;
  465                 switch (p->org) {
  466                 case GV_PLEX_CONCAT:
  467                         LIST_FOREACH(s, &p->subdisks, in_plex)
  468                                 p->size += s->size;
  469                         break;
  470 
  471                 case GV_PLEX_STRIPED:
  472                         s = LIST_FIRST(&p->subdisks);
  473                         p->size = p->sdcount * s->size;
  474                         break;
  475                 
  476                 case GV_PLEX_RAID5:
  477                         s = LIST_FIRST(&p->subdisks);
  478                         p->size = (p->sdcount - 1) * s->size;
  479                         break;
  480                 
  481                 default:
  482                         break;
  483                 }
  484         }
  485 
  486         if (p->sdcount == 0)
  487                 state = GV_PLEX_DOWN;
  488         else if ((p->flags & GV_PLEX_ADDED) ||
  489             ((p->org == GV_PLEX_RAID5) && (p->flags & GV_PLEX_NEWBORN))) {
  490                 LIST_FOREACH(s, &p->subdisks, in_plex)
  491                         s->state = GV_SD_STALE;
  492                 p->flags &= ~GV_PLEX_ADDED;
  493                 p->flags &= ~GV_PLEX_NEWBORN;
  494                 p->state = GV_PLEX_DOWN;
  495         }
  496 }
  497 
  498 /*
  499  * Give a subdisk to a drive, check and adjust several parameters, adjust
  500  * freelist.
  501  */
  502 int
  503 gv_sd_to_drive(struct gv_softc *sc, struct gv_drive *d, struct gv_sd *s,
  504     char *errstr, int errlen)
  505 {
  506         struct gv_sd *s2;
  507         struct gv_freelist *fl, *fl2;
  508         off_t tmp;
  509         int i;
  510 
  511         g_topology_assert();
  512 
  513         fl2 = NULL;
  514 
  515         KASSERT(sc != NULL, ("gv_sd_to_drive: NULL softc"));
  516         KASSERT(d != NULL, ("gv_sd_to_drive: NULL drive"));
  517         KASSERT(s != NULL, ("gv_sd_to_drive: NULL subdisk"));
  518         KASSERT(errstr != NULL, ("gv_sd_to_drive: NULL errstr"));
  519         KASSERT(errlen >= ERRBUFSIZ, ("gv_sd_to_drive: short errlen (%d)",
  520             errlen));
  521 
  522         /* Check if this subdisk was already given to this drive. */
  523         if (s->drive_sc == d)
  524                 return (0);
  525 
  526         /* Preliminary checks. */
  527         if (s->size > d->avail || d->freelist_entries == 0) {
  528                 snprintf(errstr, errlen, "not enough space on '%s' for '%s'",
  529                     d->name, s->name);
  530                 return (-1);
  531         }
  532 
  533         /* No size given, autosize it. */
  534         if (s->size == -1) {
  535                 /* Find the largest available slot. */
  536                 LIST_FOREACH(fl, &d->freelist, freelist) {
  537                         if (fl->size >= s->size) {
  538                                 s->size = fl->size;
  539                                 s->drive_offset = fl->offset;
  540                                 fl2 = fl;
  541                         }
  542                 }
  543 
  544                 /* No good slot found? */
  545                 if (s->size == -1) {
  546                         snprintf(errstr, errlen, "couldn't autosize '%s' on "
  547                             "'%s'", s->name, d->name);
  548                         return (-1);
  549                 }
  550 
  551         /*
  552          * Check if we have a free slot that's large enough for the given size.
  553          */
  554         } else {
  555                 i = 0;
  556                 LIST_FOREACH(fl, &d->freelist, freelist) {
  557                         /* Yes, this subdisk fits. */
  558                         if (fl->size >= s->size) {
  559                                 i++;
  560                                 /* Assign drive offset, if not given. */
  561                                 if (s->drive_offset == -1)
  562                                         s->drive_offset = fl->offset;
  563                                 fl2 = fl;
  564                                 break;
  565                         }
  566                 }
  567 
  568                 /* Couldn't find a good free slot. */
  569                 if (i == 0) {
  570                         snprintf(errstr, errlen, "free slots to small for '%s' "
  571                             "on '%s'", s->name, d->name);
  572                         return (-1);
  573                 }
  574         }
  575 
  576         /* No drive offset given, try to calculate it. */
  577         if (s->drive_offset == -1) {
  578 
  579                 /* Add offsets and sizes from other subdisks on this drive. */
  580                 LIST_FOREACH(s2, &d->subdisks, from_drive) {
  581                         s->drive_offset = s2->drive_offset + s2->size;
  582                 }
  583 
  584                 /*
  585                  * If there are no other subdisks yet, then set the default
  586                  * offset to GV_DATA_START.
  587                  */
  588                 if (s->drive_offset == -1)
  589                         s->drive_offset = GV_DATA_START;
  590 
  591         /* Check if we have a free slot at the given drive offset. */
  592         } else {
  593                 i = 0;
  594                 LIST_FOREACH(fl, &d->freelist, freelist) {
  595                         /* Yes, this subdisk fits. */
  596                         if ((fl->offset <= s->drive_offset) &&
  597                             (fl->offset + fl->size >=
  598                             s->drive_offset + s->size)) {
  599                                 i++;
  600                                 fl2 = fl;
  601                                 break;
  602                         }
  603                 }
  604 
  605                 /* Couldn't find a good free slot. */
  606                 if (i == 0) {
  607                         snprintf(errstr, errlen, "given drive_offset for '%s' "
  608                             "won't fit on '%s'", s->name, d->name);
  609                         return (-1);
  610                 }
  611         }
  612 
  613         /*
  614          * Now that all parameters are checked and set up, we can give the
  615          * subdisk to the drive and adjust the freelist.
  616          */
  617 
  618         /* First, adjust the freelist. */
  619         LIST_FOREACH(fl, &d->freelist, freelist) {
  620 
  621                 /* This is the free slot that we have found before. */
  622                 if (fl == fl2) {
  623         
  624                         /*
  625                          * The subdisk starts at the beginning of the free
  626                          * slot.
  627                          */
  628                         if (fl->offset == s->drive_offset) {
  629                                 fl->offset += s->size;
  630                                 fl->size -= s->size;
  631 
  632                                 /*
  633                                  * The subdisk uses the whole slot, so remove
  634                                  * it.
  635                                  */
  636                                 if (fl->size == 0) {
  637                                         d->freelist_entries--;
  638                                         LIST_REMOVE(fl, freelist);
  639                                 }
  640                         /*
  641                          * The subdisk does not start at the beginning of the
  642                          * free slot.
  643                          */
  644                         } else {
  645                                 tmp = fl->offset + fl->size;
  646                                 fl->size = s->drive_offset - fl->offset;
  647 
  648                                 /*
  649                                  * The subdisk didn't use the complete rest of
  650                                  * the free slot, so we need to split it.
  651                                  */
  652                                 if (s->drive_offset + s->size != tmp) {
  653                                         fl2 = g_malloc(sizeof(*fl2),
  654                                             M_WAITOK | M_ZERO);
  655                                         fl2->offset = s->drive_offset + s->size;
  656                                         fl2->size = tmp - fl2->offset;
  657                                         LIST_INSERT_AFTER(fl, fl2, freelist);
  658                                         d->freelist_entries++;
  659                                 }
  660                         }
  661                         break;
  662                 }
  663         }
  664 
  665         /*
  666          * This is the first subdisk on this drive, just insert it into the
  667          * list.
  668          */
  669         if (LIST_EMPTY(&d->subdisks)) {
  670                 LIST_INSERT_HEAD(&d->subdisks, s, from_drive);
  671 
  672         /* There are other subdisks, so insert this one in correct order. */
  673         } else {
  674                 LIST_FOREACH(s2, &d->subdisks, from_drive) {
  675                         if (s->drive_offset < s2->drive_offset) {
  676                                 LIST_INSERT_BEFORE(s2, s, from_drive);
  677                                 break;
  678                         } else if (LIST_NEXT(s2, from_drive) == NULL) {
  679                                 LIST_INSERT_AFTER(s2, s, from_drive);
  680                                 break;
  681                         }
  682                 }
  683         }
  684 
  685         d->sdcount++;
  686         d->avail -= s->size;
  687 
  688         /* Link back from the subdisk to this drive. */
  689         s->drive_sc = d;
  690 
  691         return (0);
  692 }
  693 
  694 void
  695 gv_free_sd(struct gv_sd *s)
  696 {
  697         struct gv_drive *d;
  698         struct gv_freelist *fl, *fl2;
  699 
  700         KASSERT(s != NULL, ("gv_free_sd: NULL s"));
  701 
  702         d = s->drive_sc;
  703         if (d == NULL)
  704                 return;
  705 
  706         /*
  707          * First, find the free slot that's immediately before or after this
  708          * subdisk.
  709          */
  710         fl = NULL;
  711         LIST_FOREACH(fl, &d->freelist, freelist) {
  712                 if (fl->offset == s->drive_offset + s->size)
  713                         break;
  714                 if (fl->offset + fl->size == s->drive_offset)
  715                         break;
  716         }
  717 
  718         /* If there is no free slot behind this subdisk, so create one. */
  719         if (fl == NULL) {
  720 
  721                 fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO);
  722                 fl->size = s->size;
  723                 fl->offset = s->drive_offset;
  724 
  725                 if (d->freelist_entries == 0) {
  726                         LIST_INSERT_HEAD(&d->freelist, fl, freelist);
  727                 } else {
  728                         LIST_FOREACH(fl2, &d->freelist, freelist) {
  729                                 if (fl->offset < fl2->offset) {
  730                                         LIST_INSERT_BEFORE(fl2, fl, freelist);
  731                                         break;
  732                                 } else if (LIST_NEXT(fl2, freelist) == NULL) {
  733                                         LIST_INSERT_AFTER(fl2, fl, freelist);
  734                                         break;
  735                                 }
  736                         }
  737                 }
  738 
  739                 d->freelist_entries++;
  740 
  741         /* Expand the free slot we just found. */
  742         } else {
  743                 fl->size += s->size;
  744                 if (fl->offset > s->drive_offset)
  745                         fl->offset = s->drive_offset;
  746         }
  747 
  748         d->avail += s->size;
  749         d->sdcount--;
  750 }
  751 
  752 void
  753 gv_adjust_freespace(struct gv_sd *s, off_t remainder)
  754 {
  755         struct gv_drive *d;
  756         struct gv_freelist *fl, *fl2;
  757 
  758         KASSERT(s != NULL, ("gv_adjust_freespace: NULL s"));
  759         d = s->drive_sc;
  760         KASSERT(d != NULL, ("gv_adjust_freespace: NULL d"));
  761 
  762         /* First, find the free slot that's immediately after this subdisk. */
  763         fl = NULL;
  764         LIST_FOREACH(fl, &d->freelist, freelist) {
  765                 if (fl->offset == s->drive_offset + s->size)
  766                         break;
  767         }
  768 
  769         /* If there is no free slot behind this subdisk, so create one. */
  770         if (fl == NULL) {
  771 
  772                 fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO);
  773                 fl->size = remainder;
  774                 fl->offset = s->drive_offset + s->size - remainder;
  775 
  776                 if (d->freelist_entries == 0) {
  777                         LIST_INSERT_HEAD(&d->freelist, fl, freelist);
  778                 } else {
  779                         LIST_FOREACH(fl2, &d->freelist, freelist) {
  780                                 if (fl->offset < fl2->offset) {
  781                                         LIST_INSERT_BEFORE(fl2, fl, freelist);
  782                                         break;
  783                                 } else if (LIST_NEXT(fl2, freelist) == NULL) {
  784                                         LIST_INSERT_AFTER(fl2, fl, freelist);
  785                                         break;
  786                                 }
  787                         }
  788                 }
  789 
  790                 d->freelist_entries++;
  791 
  792         /* Expand the free slot we just found. */
  793         } else {
  794                 fl->offset -= remainder;
  795                 fl->size += remainder;
  796         }
  797 
  798         s->size -= remainder;
  799         d->avail += remainder;
  800 }
  801 
  802 /* Check if the given plex is a striped one. */
  803 int
  804 gv_is_striped(struct gv_plex *p)
  805 {
  806         KASSERT(p != NULL, ("gv_is_striped: NULL p"));
  807         switch(p->org) {
  808         case GV_PLEX_STRIPED:
  809         case GV_PLEX_RAID5:
  810                 return (1);
  811         default:
  812                 return (0);
  813         }
  814 }
  815 
  816 /* Find a volume by name. */
  817 struct gv_volume *
  818 gv_find_vol(struct gv_softc *sc, char *name)
  819 {
  820         struct gv_volume *v;
  821 
  822         LIST_FOREACH(v, &sc->volumes, volume) {
  823                 if (!strncmp(v->name, name, GV_MAXVOLNAME))
  824                         return (v);
  825         }
  826 
  827         return (NULL);
  828 }
  829 
  830 /* Find a plex by name. */
  831 struct gv_plex *
  832 gv_find_plex(struct gv_softc *sc, char *name)
  833 {
  834         struct gv_plex *p;
  835 
  836         LIST_FOREACH(p, &sc->plexes, plex) {
  837                 if (!strncmp(p->name, name, GV_MAXPLEXNAME))
  838                         return (p);
  839         }
  840 
  841         return (NULL);
  842 }
  843 
  844 /* Find a subdisk by name. */
  845 struct gv_sd *
  846 gv_find_sd(struct gv_softc *sc, char *name)
  847 {
  848         struct gv_sd *s;
  849 
  850         LIST_FOREACH(s, &sc->subdisks, sd) {
  851                 if (!strncmp(s->name, name, GV_MAXSDNAME))
  852                         return (s);
  853         }
  854 
  855         return (NULL);
  856 }
  857 
  858 /* Find a drive by name. */
  859 struct gv_drive *
  860 gv_find_drive(struct gv_softc *sc, char *name)
  861 {
  862         struct gv_drive *d;
  863 
  864         LIST_FOREACH(d, &sc->drives, drive) {
  865                 if (!strncmp(d->name, name, GV_MAXDRIVENAME))
  866                         return (d);
  867         }
  868 
  869         return (NULL);
  870 }
  871 
  872 /* Check if any consumer of the given geom is open. */
  873 int
  874 gv_is_open(struct g_geom *gp)
  875 {
  876         struct g_consumer *cp;
  877 
  878         if (gp == NULL)
  879                 return (0);
  880 
  881         LIST_FOREACH(cp, &gp->consumer, consumer) {
  882                 if (cp->acr || cp->acw || cp->ace)
  883                         return (1);
  884         }
  885 
  886         return (0);
  887 }
  888 
  889 /* Return the type of object identified by string 'name'. */
  890 int
  891 gv_object_type(struct gv_softc *sc, char *name)
  892 {
  893         struct gv_drive *d;
  894         struct gv_plex *p;
  895         struct gv_sd *s;
  896         struct gv_volume *v;
  897 
  898         LIST_FOREACH(v, &sc->volumes, volume) {
  899                 if (!strncmp(v->name, name, GV_MAXVOLNAME))
  900                         return (GV_TYPE_VOL);
  901         }
  902 
  903         LIST_FOREACH(p, &sc->plexes, plex) {
  904                 if (!strncmp(p->name, name, GV_MAXPLEXNAME))
  905                         return (GV_TYPE_PLEX);
  906         }
  907 
  908         LIST_FOREACH(s, &sc->subdisks, sd) {
  909                 if (!strncmp(s->name, name, GV_MAXSDNAME))
  910                         return (GV_TYPE_SD);
  911         }
  912 
  913         LIST_FOREACH(d, &sc->drives, drive) {
  914                 if (!strncmp(d->name, name, GV_MAXDRIVENAME))
  915                         return (GV_TYPE_DRIVE);
  916         }
  917 
  918         return (-1);
  919 }
  920 
  921 void
  922 gv_kill_drive_thread(struct gv_drive *d)
  923 {
  924         if (d->flags & GV_DRIVE_THREAD_ACTIVE) {
  925                 d->flags |= GV_DRIVE_THREAD_DIE;
  926                 wakeup(d);
  927                 while (!(d->flags & GV_DRIVE_THREAD_DEAD))
  928                         tsleep(d, PRIBIO, "gv_die", hz);
  929                 d->flags &= ~GV_DRIVE_THREAD_ACTIVE;
  930                 d->flags &= ~GV_DRIVE_THREAD_DIE;
  931                 d->flags &= ~GV_DRIVE_THREAD_DEAD;
  932                 g_free(d->bqueue);
  933                 d->bqueue = NULL;
  934                 mtx_destroy(&d->bqueue_mtx);
  935         }
  936 }
  937 
  938 void
  939 gv_kill_plex_thread(struct gv_plex *p)
  940 {
  941         if (p->flags & GV_PLEX_THREAD_ACTIVE) {
  942                 p->flags |= GV_PLEX_THREAD_DIE;
  943                 wakeup(p);
  944                 while (!(p->flags & GV_PLEX_THREAD_DEAD))
  945                         tsleep(p, PRIBIO, "gv_die", hz);
  946                 p->flags &= ~GV_PLEX_THREAD_ACTIVE;
  947                 p->flags &= ~GV_PLEX_THREAD_DIE;
  948                 p->flags &= ~GV_PLEX_THREAD_DEAD;
  949                 g_free(p->bqueue);
  950                 g_free(p->wqueue);
  951                 p->bqueue = NULL;
  952                 p->wqueue = NULL;
  953                 mtx_destroy(&p->bqueue_mtx);
  954         }
  955 }
  956 
  957 void
  958 gv_kill_vol_thread(struct gv_volume *v)
  959 {
  960         if (v->flags & GV_VOL_THREAD_ACTIVE) {
  961                 v->flags |= GV_VOL_THREAD_DIE;
  962                 wakeup(v);
  963                 while (!(v->flags & GV_VOL_THREAD_DEAD))
  964                         tsleep(v, PRIBIO, "gv_die", hz);
  965                 v->flags &= ~GV_VOL_THREAD_ACTIVE;
  966                 v->flags &= ~GV_VOL_THREAD_DIE;
  967                 v->flags &= ~GV_VOL_THREAD_DEAD;
  968                 g_free(v->bqueue);
  969                 v->bqueue = NULL;
  970                 mtx_destroy(&v->bqueue_mtx);
  971         }
  972 }

Cache object: 291bfb708a8daf821c5cd8dd56e088f7


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