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_state.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, 2007 Lukas Ertl
    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 AUTHOR 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 AUTHOR 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/10.0/sys/geom/vinum/geom_vinum_state.c 190507 2009-03-28 17:20:08Z lulf $");
   29 
   30 #include <sys/libkern.h>
   31 #include <sys/malloc.h>
   32 
   33 #include <geom/geom.h>
   34 #include <geom/vinum/geom_vinum_var.h>
   35 #include <geom/vinum/geom_vinum.h>
   36 #include <geom/vinum/geom_vinum_share.h>
   37 
   38 void
   39 gv_setstate(struct g_geom *gp, struct gctl_req *req)
   40 {
   41         struct gv_softc *sc;
   42         struct gv_sd *s;
   43         struct gv_drive *d;
   44         struct gv_volume *v;
   45         struct gv_plex *p;
   46         char *obj, *state;
   47         int f, *flags, type;
   48 
   49         f = 0;
   50         obj = gctl_get_param(req, "object", NULL);
   51         if (obj == NULL) {
   52                 gctl_error(req, "no object given");
   53                 return;
   54         }
   55 
   56         state = gctl_get_param(req, "state", NULL);
   57         if (state == NULL) {
   58                 gctl_error(req, "no state given");
   59                 return;
   60         }
   61 
   62         flags = gctl_get_paraml(req, "flags", sizeof(*flags));
   63         if (flags == NULL) {
   64                 gctl_error(req, "no flags given");
   65                 return;
   66         }
   67 
   68         if (*flags & GV_FLAG_F)
   69                 f = GV_SETSTATE_FORCE;
   70 
   71         sc = gp->softc;
   72         type = gv_object_type(sc, obj);
   73         switch (type) {
   74         case GV_TYPE_VOL:
   75                 if (gv_volstatei(state) < 0) {
   76                         gctl_error(req, "invalid volume state '%s'", state);
   77                         break;
   78                 }
   79                 v = gv_find_vol(sc, obj);
   80                 gv_post_event(sc, GV_EVENT_SET_VOL_STATE, v, NULL,
   81                     gv_volstatei(state), f);
   82                 break;
   83 
   84         case GV_TYPE_PLEX:
   85                 if (gv_plexstatei(state) < 0) {
   86                         gctl_error(req, "invalid plex state '%s'", state);
   87                         break;
   88                 }
   89                 p = gv_find_plex(sc, obj);
   90                 gv_post_event(sc, GV_EVENT_SET_PLEX_STATE, p, NULL,
   91                     gv_plexstatei(state), f);
   92                 break;
   93 
   94         case GV_TYPE_SD:
   95                 if (gv_sdstatei(state) < 0) {
   96                         gctl_error(req, "invalid subdisk state '%s'", state);
   97                         break;
   98                 }
   99                 s = gv_find_sd(sc, obj);
  100                 gv_post_event(sc, GV_EVENT_SET_SD_STATE, s, NULL,
  101                     gv_sdstatei(state), f);
  102                 break;
  103 
  104         case GV_TYPE_DRIVE:
  105                 if (gv_drivestatei(state) < 0) {
  106                         gctl_error(req, "invalid drive state '%s'", state);
  107                         break;
  108                 }
  109                 d = gv_find_drive(sc, obj);
  110                 gv_post_event(sc, GV_EVENT_SET_DRIVE_STATE, d, NULL,
  111                     gv_drivestatei(state), f);
  112                 break;
  113 
  114         default:
  115                 gctl_error(req, "unknown object '%s'", obj);
  116                 break;
  117         }
  118 }
  119 
  120 /* Update drive state; return 0 if the state changes, otherwise error. */
  121 int
  122 gv_set_drive_state(struct gv_drive *d, int newstate, int flags)
  123 {
  124         struct gv_sd *s;
  125         int oldstate;
  126 
  127         KASSERT(d != NULL, ("gv_set_drive_state: NULL d"));
  128 
  129         oldstate = d->state;
  130         
  131         if (newstate == oldstate)
  132                 return (0);
  133 
  134         /* We allow to take down an open drive only with force. */
  135         if ((newstate == GV_DRIVE_DOWN) && gv_consumer_is_open(d->consumer) &&
  136             (!(flags & GV_SETSTATE_FORCE)))
  137                 return (GV_ERR_ISBUSY);
  138 
  139         d->state = newstate;
  140 
  141         if (d->state != oldstate) {
  142                 LIST_FOREACH(s, &d->subdisks, from_drive)
  143                         gv_update_sd_state(s);
  144         }
  145 
  146         /* Save the config back to disk. */
  147         if (flags & GV_SETSTATE_CONFIG)
  148                 gv_save_config(d->vinumconf);
  149 
  150         return (0);
  151 }
  152 
  153 int
  154 gv_set_sd_state(struct gv_sd *s, int newstate, int flags)
  155 {
  156         struct gv_drive *d;
  157         struct gv_plex *p;
  158         int oldstate, status;
  159 
  160         KASSERT(s != NULL, ("gv_set_sd_state: NULL s"));
  161 
  162         oldstate = s->state;
  163 
  164         /* We are optimistic and assume it will work. */
  165         status = 0;
  166         
  167         if (newstate == oldstate)
  168                 return (0);
  169 
  170         switch (newstate) {
  171         case GV_SD_DOWN:
  172                 /*
  173                  * If we're attached to a plex, we won't go down without use of
  174                  * force.
  175                  */
  176                 if ((s->plex_sc != NULL) && !(flags & GV_SETSTATE_FORCE))
  177                         return (GV_ERR_ISATTACHED);
  178                 break;
  179 
  180         case GV_SD_REVIVING:
  181         case GV_SD_INITIALIZING:
  182                 /*
  183                  * Only do this if we're forced, since it usually is done
  184                  * internally, and then we do use the force flag. 
  185                  */
  186                 if (!flags & GV_SETSTATE_FORCE)
  187                         return (GV_ERR_SETSTATE);
  188                 break;
  189 
  190         case GV_SD_UP:
  191                 /* We can't bring the subdisk up if our drive is dead. */
  192                 d = s->drive_sc;
  193                 if ((d == NULL) || (d->state != GV_DRIVE_UP))
  194                         return (GV_ERR_SETSTATE);
  195 
  196                 /* Check from where we want to be brought up. */
  197                 switch (s->state) {
  198                 case GV_SD_REVIVING:
  199                 case GV_SD_INITIALIZING:
  200                         /*
  201                          * The subdisk was initializing.  We allow it to be
  202                          * brought up.
  203                          */
  204                         break;
  205 
  206                 case GV_SD_DOWN:
  207                         /*
  208                          * The subdisk is currently down.  We allow it to be
  209                          * brought up if it is not attached to a plex.
  210                          */
  211                         p = s->plex_sc;
  212                         if (p == NULL)
  213                                 break;
  214 
  215                         /*
  216                          * If this subdisk is attached to a plex, we allow it
  217                          * to be brought up if the plex if it's not a RAID5
  218                          * plex, otherwise it's made 'stale'.
  219                          */
  220 
  221                         if (p->org != GV_PLEX_RAID5)
  222                                 break;
  223                         else if (s->flags & GV_SD_CANGOUP) {
  224                                 s->flags &= ~GV_SD_CANGOUP;
  225                                 break;
  226                         } else if (flags & GV_SETSTATE_FORCE)
  227                                 break;
  228                         else
  229                                 s->state = GV_SD_STALE;
  230 
  231                         status = GV_ERR_SETSTATE;
  232                         break;
  233 
  234                 case GV_SD_STALE:
  235                         /*
  236                          * A stale subdisk can be brought up only if it's part
  237                          * of a concat or striped plex that's the only one in a
  238                          * volume, or if the subdisk isn't attached to a plex.
  239                          * Otherwise it needs to be revived or initialized
  240                          * first.
  241                          */
  242                         p = s->plex_sc;
  243                         if (p == NULL || flags & GV_SETSTATE_FORCE)
  244                                 break;
  245 
  246                         if ((p->org != GV_PLEX_RAID5 &&
  247                             p->vol_sc->plexcount == 1) ||
  248                             (p->flags & GV_PLEX_SYNCING &&
  249                             p->synced > 0 &&
  250                             p->org == GV_PLEX_RAID5))
  251                                 break;
  252                         else
  253                                 return (GV_ERR_SETSTATE);
  254 
  255                 default:
  256                         return (GV_ERR_INVSTATE);
  257                 }
  258                 break;
  259 
  260         /* Other state transitions are only possible with force. */
  261         default:
  262                 if (!(flags & GV_SETSTATE_FORCE))
  263                         return (GV_ERR_SETSTATE);
  264         }
  265 
  266         /* We can change the state and do it. */
  267         if (status == 0)
  268                 s->state = newstate;
  269 
  270         /* Update our plex, if we're attached to one. */
  271         if (s->plex_sc != NULL)
  272                 gv_update_plex_state(s->plex_sc);
  273 
  274         /* Save the config back to disk. */
  275         if (flags & GV_SETSTATE_CONFIG)
  276                 gv_save_config(s->vinumconf);
  277 
  278         return (status);
  279 }
  280 
  281 int
  282 gv_set_plex_state(struct gv_plex *p, int newstate, int flags)
  283 {
  284         struct gv_volume *v;
  285         int oldstate, plexdown;
  286 
  287         KASSERT(p != NULL, ("gv_set_plex_state: NULL p"));
  288 
  289         oldstate = p->state;
  290         v = p->vol_sc;
  291         plexdown = 0;
  292 
  293         if (newstate == oldstate)
  294                 return (0);
  295 
  296         switch (newstate) {
  297         case GV_PLEX_UP:
  298                 /* Let update_plex handle if the plex can come up */
  299                 gv_update_plex_state(p);
  300                 if (p->state != GV_PLEX_UP && !(flags & GV_SETSTATE_FORCE))
  301                         return (GV_ERR_SETSTATE);
  302                 p->state = newstate;
  303                 break;
  304         case GV_PLEX_DOWN:
  305                 /*
  306                  * Set state to GV_PLEX_DOWN only if no-one is using the plex,
  307                  * or if the state is forced.
  308                  */
  309                 if (v != NULL) {
  310                         /* If the only one up, force is needed. */
  311                         plexdown = gv_plexdown(v);
  312                         if ((v->plexcount == 1 ||
  313                             (v->plexcount - plexdown == 1)) &&
  314                             ((flags & GV_SETSTATE_FORCE) == 0))
  315                                 return (GV_ERR_SETSTATE);
  316                 }
  317                 p->state = newstate;
  318                 break;
  319         case GV_PLEX_DEGRADED:
  320                 /* Only used internally, so we have to be forced. */
  321                 if (flags & GV_SETSTATE_FORCE)
  322                         p->state = newstate;
  323                 break;
  324         }
  325 
  326         /* Update our volume if we have one. */
  327         if (v != NULL)
  328                 gv_update_vol_state(v);
  329 
  330         /* Save config. */
  331         if (flags & GV_SETSTATE_CONFIG)
  332                 gv_save_config(p->vinumconf);
  333         return (0);
  334 }
  335 
  336 int
  337 gv_set_vol_state(struct gv_volume *v, int newstate, int flags)
  338 {
  339         int oldstate;
  340 
  341         KASSERT(v != NULL, ("gv_set_vol_state: NULL v"));
  342 
  343         oldstate = v->state;
  344 
  345         if (newstate == oldstate)
  346                 return (0);
  347 
  348         switch (newstate) {
  349         case GV_VOL_UP:
  350                 /* Let update handle if the volume can come up. */
  351                 gv_update_vol_state(v);
  352                 if (v->state != GV_VOL_UP && !(flags & GV_SETSTATE_FORCE))
  353                         return (GV_ERR_SETSTATE);
  354                 v->state = newstate;
  355                 break;
  356         case GV_VOL_DOWN:
  357                 /*
  358                  * Set state to GV_VOL_DOWN only if no-one is using the volume,
  359                  * or if the state should be forced.
  360                  */
  361                 if (!gv_provider_is_open(v->provider) &&
  362                     !(flags & GV_SETSTATE_FORCE))
  363                         return (GV_ERR_ISBUSY);
  364                 v->state = newstate;
  365                 break;
  366         }
  367         /* Save config */
  368         if (flags & GV_SETSTATE_CONFIG)
  369                 gv_save_config(v->vinumconf);
  370         return (0);
  371 }
  372 
  373 /* Update the state of a subdisk based on its environment. */
  374 void
  375 gv_update_sd_state(struct gv_sd *s)
  376 {
  377         struct gv_drive *d;
  378         int oldstate;
  379 
  380         KASSERT(s != NULL, ("gv_update_sd_state: NULL s"));
  381         d = s->drive_sc;
  382         KASSERT(d != NULL, ("gv_update_sd_state: NULL d"));
  383 
  384         oldstate = s->state;
  385         
  386         /* If our drive isn't up we cannot be up either. */
  387         if (d->state != GV_DRIVE_UP) {
  388                 s->state = GV_SD_DOWN;
  389         /* If this subdisk was just created, we assume it is good.*/
  390         } else if (s->flags & GV_SD_NEWBORN) {
  391                 s->state = GV_SD_UP;
  392                 s->flags &= ~GV_SD_NEWBORN;
  393         } else if (s->state != GV_SD_UP) {
  394                 if (s->flags & GV_SD_CANGOUP) {
  395                         s->state = GV_SD_UP;
  396                         s->flags &= ~GV_SD_CANGOUP;
  397                 } else
  398                         s->state = GV_SD_STALE;
  399         } else
  400                 s->state = GV_SD_UP;
  401         
  402         if (s->state != oldstate)
  403                 G_VINUM_DEBUG(1, "subdisk %s state change: %s -> %s", s->name,
  404                     gv_sdstate(oldstate), gv_sdstate(s->state));
  405 
  406         /* Update the plex, if we have one. */
  407         if (s->plex_sc != NULL)
  408                 gv_update_plex_state(s->plex_sc);
  409 }
  410 
  411 /* Update the state of a plex based on its environment. */
  412 void
  413 gv_update_plex_state(struct gv_plex *p)
  414 {
  415         struct gv_sd *s;
  416         int sdstates;
  417         int oldstate;
  418 
  419         KASSERT(p != NULL, ("gv_update_plex_state: NULL p"));
  420 
  421         oldstate = p->state;
  422 
  423         /* First, check the state of our subdisks. */
  424         sdstates = gv_sdstatemap(p);
  425         
  426         /* If all subdisks are up, our plex can be up, too. */
  427         if (sdstates == GV_SD_UPSTATE)
  428                 p->state = GV_PLEX_UP;
  429 
  430         /* One or more of our subdisks are down. */
  431         else if (sdstates & GV_SD_DOWNSTATE) {
  432                 /* A RAID5 plex can handle one dead subdisk. */
  433                 if ((p->org == GV_PLEX_RAID5) && (p->sddown == 1))
  434                         p->state = GV_PLEX_DEGRADED;
  435                 else
  436                         p->state = GV_PLEX_DOWN;
  437 
  438         /* Some of our subdisks are initializing. */
  439         } else if (sdstates & GV_SD_INITSTATE) {
  440 
  441                 if (p->flags & GV_PLEX_SYNCING ||
  442                     p->flags & GV_PLEX_REBUILDING)
  443                         p->state = GV_PLEX_DEGRADED;
  444                 else
  445                         p->state = GV_PLEX_DOWN;
  446         } else
  447                 p->state = GV_PLEX_DOWN;
  448 
  449         if (p->state == GV_PLEX_UP) {
  450                 LIST_FOREACH(s, &p->subdisks, in_plex) {
  451                         if (s->flags & GV_SD_GROW) {
  452                                 p->state = GV_PLEX_GROWABLE;
  453                                 break;
  454                         }
  455                 }
  456         }
  457 
  458         if (p->state != oldstate)
  459                 G_VINUM_DEBUG(1, "plex %s state change: %s -> %s", p->name,
  460                     gv_plexstate(oldstate), gv_plexstate(p->state));
  461 
  462         /* Update our volume, if we have one. */
  463         if (p->vol_sc != NULL)
  464                 gv_update_vol_state(p->vol_sc);
  465 }
  466 
  467 /* Update the volume state based on its plexes. */
  468 void
  469 gv_update_vol_state(struct gv_volume *v)
  470 {
  471         struct gv_plex *p;
  472 
  473         KASSERT(v != NULL, ("gv_update_vol_state: NULL v"));
  474 
  475         /* The volume can't be up without plexes. */
  476         if (v->plexcount == 0) {
  477                 v->state = GV_VOL_DOWN;
  478                 return;
  479         }
  480 
  481         LIST_FOREACH(p, &v->plexes, in_volume) {
  482                 /* One of our plexes is accessible, and so are we. */
  483                 if (p->state > GV_PLEX_DEGRADED) {
  484                         v->state = GV_VOL_UP;
  485                         return;
  486 
  487                 /* We can handle a RAID5 plex with one dead subdisk as well. */
  488                 } else if ((p->org == GV_PLEX_RAID5) &&
  489                     (p->state == GV_PLEX_DEGRADED)) {
  490                         v->state = GV_VOL_UP;
  491                         return;
  492                 }
  493         }
  494 
  495         /* Not one of our plexes is up, so we can't be either. */
  496         v->state = GV_VOL_DOWN;
  497 }
  498 
  499 /* Return a state map for the subdisks of a plex. */
  500 int
  501 gv_sdstatemap(struct gv_plex *p)
  502 {
  503         struct gv_sd *s;
  504         int statemap;
  505 
  506         KASSERT(p != NULL, ("gv_sdstatemap: NULL p"));
  507         
  508         statemap = 0;
  509         p->sddown = 0;  /* No subdisks down yet. */
  510 
  511         LIST_FOREACH(s, &p->subdisks, in_plex) {
  512                 switch (s->state) {
  513                 case GV_SD_DOWN:
  514                 case GV_SD_STALE:
  515                         statemap |= GV_SD_DOWNSTATE;
  516                         p->sddown++;    /* Another unusable subdisk. */
  517                         break;
  518 
  519                 case GV_SD_UP:
  520                         statemap |= GV_SD_UPSTATE;
  521                         break;
  522 
  523                 case GV_SD_INITIALIZING:
  524                         statemap |= GV_SD_INITSTATE;
  525                         break;
  526 
  527                 case GV_SD_REVIVING:
  528                         statemap |= GV_SD_INITSTATE;
  529                         p->sddown++;    /* XXX: Another unusable subdisk? */
  530                         break;
  531                 }
  532         }
  533         return (statemap);
  534 }

Cache object: 13d1fc8dafd66a6718df12d4f86c0c9a


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