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

Cache object: 282a1fbd6eec903f3940b1783d654376


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