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 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$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/kernel.h>
   32 #include <sys/libkern.h>
   33 #include <sys/malloc.h>
   34 
   35 #include <geom/geom.h>
   36 #include <geom/vinum/geom_vinum_var.h>
   37 #include <geom/vinum/geom_vinum.h>
   38 #include <geom/vinum/geom_vinum_share.h>
   39 
   40 void
   41 gv_setstate(struct g_geom *gp, struct gctl_req *req)
   42 {
   43         struct gv_softc *sc;
   44         struct gv_sd *s;
   45         struct gv_drive *d;
   46         char *obj, *state;
   47         int err, f, *flags, newstate, 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         case GV_TYPE_PLEX:
   76                 gctl_error(req, "volume or plex state cannot be set currently");
   77                 break;
   78 
   79         case GV_TYPE_SD:
   80                 newstate = gv_sdstatei(state);
   81                 if (newstate < 0) {
   82                         gctl_error(req, "invalid subdisk state '%s'", state);
   83                         break;
   84                 }
   85                 s = gv_find_sd(sc, obj);
   86                 err = gv_set_sd_state(s, newstate, f);
   87                 if (err)
   88                         gctl_error(req, "cannot set subdisk state");
   89                 break;
   90 
   91         case GV_TYPE_DRIVE:
   92                 newstate = gv_drivestatei(state);
   93                 if (newstate < 0) {
   94                         gctl_error(req, "invalid drive state '%s'", state);
   95                         break;
   96                 }
   97                 d = gv_find_drive(sc, obj);
   98                 err = gv_set_drive_state(d, newstate, f);
   99                 if (err)
  100                         gctl_error(req, "cannot set drive state");
  101                 break;
  102 
  103         default:
  104                 gctl_error(req, "unknown object '%s'", obj);
  105                 break;
  106         }
  107 
  108         return;
  109 }
  110 
  111 /* Update drive state; return 0 if the state changes, otherwise -1. */
  112 int
  113 gv_set_drive_state(struct gv_drive *d, int newstate, int flags)
  114 {
  115         struct gv_sd *s;
  116         int oldstate;
  117 
  118         KASSERT(d != NULL, ("gv_set_drive_state: NULL d"));
  119 
  120         oldstate = d->state;
  121         
  122         if (newstate == oldstate)
  123                 return (0);
  124 
  125         /* We allow to take down an open drive only with force. */
  126         if ((newstate == GV_DRIVE_DOWN) && gv_is_open(d->geom) &&
  127             (!(flags & GV_SETSTATE_FORCE)))
  128                 return (-1);
  129 
  130         d->state = newstate;
  131 
  132         if (d->state != oldstate) {
  133                 LIST_FOREACH(s, &d->subdisks, from_drive)
  134                         gv_update_sd_state(s);
  135         }
  136 
  137         /* Save the config back to disk. */
  138         if (flags & GV_SETSTATE_CONFIG)
  139                 gv_save_config_all(d->vinumconf);
  140 
  141         return (0);
  142 }
  143 
  144 int
  145 gv_set_sd_state(struct gv_sd *s, int newstate, int flags)
  146 {
  147         struct gv_drive *d;
  148         struct gv_plex *p;
  149         int oldstate, status;
  150 
  151         KASSERT(s != NULL, ("gv_set_sd_state: NULL s"));
  152 
  153         oldstate = s->state;
  154 
  155         /* We are optimistic and assume it will work. */
  156         status = 0;
  157         
  158         if (newstate == oldstate)
  159                 return (0);
  160 
  161         switch (newstate) {
  162         case GV_SD_DOWN:
  163                 /*
  164                  * If we're attached to a plex, we won't go down without use of
  165                  * force.
  166                  */
  167                 if ((s->plex_sc != NULL) && !(flags & GV_SETSTATE_FORCE))
  168                         return (-1);
  169                 break;
  170 
  171         case GV_SD_UP:
  172                 /* We can't bring the subdisk up if our drive is dead. */
  173                 d = s->drive_sc;
  174                 if ((d == NULL) || (d->state != GV_DRIVE_UP))
  175                         return (-1);
  176 
  177                 /* Check from where we want to be brought up. */
  178                 switch (s->state) {
  179                 case GV_SD_REVIVING:
  180                 case GV_SD_INITIALIZING:
  181                         /*
  182                          * The subdisk was initializing.  We allow it to be
  183                          * brought up.
  184                          */
  185                         break;
  186 
  187                 case GV_SD_DOWN:
  188                         /*
  189                          * The subdisk is currently down.  We allow it to be
  190                          * brought up if it is not attached to a plex.
  191                          */
  192                         p = s->plex_sc;
  193                         if (p == NULL)
  194                                 break;
  195 
  196                         /*
  197                          * If this subdisk is attached to a plex, we allow it
  198                          * to be brought up if the plex if it's not a RAID5
  199                          * plex, otherwise it's made 'stale'.
  200                          */
  201 
  202                         if (p->org != GV_PLEX_RAID5)
  203                                 break;
  204                         else if (flags & GV_SETSTATE_FORCE)
  205                                 break;
  206                         else
  207                                 s->state = GV_SD_STALE;
  208 
  209                         status = -1;
  210                         break;
  211 
  212                 case GV_SD_STALE:
  213                         /*
  214                          * A stale subdisk can be brought up only if it's part
  215                          * of a concat or striped plex that's the only one in a
  216                          * volume, or if the subdisk isn't attached to a plex.
  217                          * Otherwise it needs to be revived or initialized
  218                          * first.
  219                          */
  220                         p = s->plex_sc;
  221                         if (p == NULL || flags & GV_SETSTATE_FORCE)
  222                                 break;
  223 
  224                         if ((p->org != GV_PLEX_RAID5) &&
  225                             (p->vol_sc->plexcount == 1))
  226                                 break;
  227                         else
  228                                 return (-1);
  229 
  230                 default:
  231                         return (-1);
  232                 }
  233                 break;
  234 
  235         /* Other state transitions are only possible with force. */
  236         default:
  237                 if (!(flags & GV_SETSTATE_FORCE))
  238                         return (-1);
  239         }
  240 
  241         /* We can change the state and do it. */
  242         if (status == 0)
  243                 s->state = newstate;
  244 
  245         /* Update our plex, if we're attached to one. */
  246         if (s->plex_sc != NULL)
  247                 gv_update_plex_state(s->plex_sc);
  248 
  249         /* Save the config back to disk. */
  250         if (flags & GV_SETSTATE_CONFIG)
  251                 gv_save_config_all(s->vinumconf);
  252 
  253         return (status);
  254 }
  255 
  256 
  257 /* Update the state of a subdisk based on its environment. */
  258 void
  259 gv_update_sd_state(struct gv_sd *s)
  260 {
  261         struct gv_drive *d;
  262         int oldstate;
  263 
  264         KASSERT(s != NULL, ("gv_update_sd_state: NULL s"));
  265         d = s->drive_sc;
  266         KASSERT(d != NULL, ("gv_update_sd_state: NULL d"));
  267 
  268         oldstate = s->state;
  269         
  270         /* If our drive isn't up we cannot be up either. */
  271         if (d->state != GV_DRIVE_UP)
  272                 s->state = GV_SD_DOWN;
  273         /* If this subdisk was just created, we assume it is good.*/
  274         else if (s->flags & GV_SD_NEWBORN) {
  275                 s->state = GV_SD_UP;
  276                 s->flags &= ~GV_SD_NEWBORN;
  277         } else if (s->state != GV_SD_UP)
  278                 s->state = GV_SD_STALE;
  279         else
  280                 s->state = GV_SD_UP;
  281         
  282         if (s->state != oldstate)
  283                 printf("GEOM_VINUM: subdisk %s state change: %s -> %s\n",
  284                     s->name, gv_sdstate(oldstate), gv_sdstate(s->state));
  285 
  286         /* Update the plex, if we have one. */
  287         if (s->plex_sc != NULL)
  288                 gv_update_plex_state(s->plex_sc);
  289 }
  290 
  291 /* Update the state of a plex based on its environment. */
  292 void
  293 gv_update_plex_state(struct gv_plex *p)
  294 {
  295         int sdstates;
  296         int oldstate;
  297 
  298         KASSERT(p != NULL, ("gv_update_plex_state: NULL p"));
  299 
  300         oldstate = p->state;
  301 
  302         /* First, check the state of our subdisks. */
  303         sdstates = gv_sdstatemap(p);
  304         
  305         /* If all subdisks are up, our plex can be up, too. */
  306         if (sdstates == GV_SD_UPSTATE)
  307                 p->state = GV_PLEX_UP;
  308 
  309         /* One or more of our subdisks are down. */
  310         else if (sdstates & GV_SD_DOWNSTATE) {
  311                 /* A RAID5 plex can handle one dead subdisk. */
  312                 if ((p->org == GV_PLEX_RAID5) && (p->sddown == 1))
  313                         p->state = GV_PLEX_DEGRADED;
  314                 else
  315                         p->state = GV_PLEX_DOWN;
  316 
  317         /* Some of our subdisks are initializing. */
  318         } else if (sdstates & GV_SD_INITSTATE) {
  319                 if (p->flags & GV_PLEX_SYNCING)
  320                         p->state = GV_PLEX_DEGRADED;
  321                 else
  322                         p->state = GV_PLEX_DOWN;
  323         } else
  324                 p->state = GV_PLEX_DOWN;
  325 
  326         if (p->state != oldstate)
  327                 printf("GEOM_VINUM: plex %s state change: %s -> %s\n", p->name,
  328                     gv_plexstate(oldstate), gv_plexstate(p->state));
  329 
  330         /* Update our volume, if we have one. */
  331         if (p->vol_sc != NULL)
  332                 gv_update_vol_state(p->vol_sc);
  333 }
  334 
  335 /* Update the volume state based on its plexes. */
  336 void
  337 gv_update_vol_state(struct gv_volume *v)
  338 {
  339         struct gv_plex *p;
  340 
  341         KASSERT(v != NULL, ("gv_update_vol_state: NULL v"));
  342 
  343         /* The volume can't be up without plexes. */
  344         if (v->plexcount == 0) {
  345                 v->state = GV_VOL_DOWN;
  346                 return;
  347         }
  348 
  349         LIST_FOREACH(p, &v->plexes, in_volume) {
  350                 /* One of our plexes is accessible, and so are we. */
  351                 if (p->state > GV_PLEX_DEGRADED) {
  352                         v->state = GV_VOL_UP;
  353                         return;
  354 
  355                 /* We can handle a RAID5 plex with one dead subdisk as well. */
  356                 } else if ((p->org == GV_PLEX_RAID5) &&
  357                     (p->state == GV_PLEX_DEGRADED)) {
  358                         v->state = GV_VOL_UP;
  359                         return;
  360                 }
  361         }
  362 
  363         /* Not one of our plexes is up, so we can't be either. */
  364         v->state = GV_VOL_DOWN;
  365 }
  366 
  367 /* Return a state map for the subdisks of a plex. */
  368 int
  369 gv_sdstatemap(struct gv_plex *p)
  370 {
  371         struct gv_sd *s;
  372         int statemap;
  373 
  374         KASSERT(p != NULL, ("gv_sdstatemap: NULL p"));
  375         
  376         statemap = 0;
  377         p->sddown = 0;  /* No subdisks down yet. */
  378 
  379         LIST_FOREACH(s, &p->subdisks, in_plex) {
  380                 switch (s->state) {
  381                 case GV_SD_DOWN:
  382                 case GV_SD_STALE:
  383                         statemap |= GV_SD_DOWNSTATE;
  384                         p->sddown++;    /* Another unusable subdisk. */
  385                         break;
  386 
  387                 case GV_SD_UP:
  388                         statemap |= GV_SD_UPSTATE;
  389                         break;
  390 
  391                 case GV_SD_INITIALIZING:
  392                         statemap |= GV_SD_INITSTATE;
  393                         break;
  394 
  395                 case GV_SD_REVIVING:
  396                         statemap |= GV_SD_INITSTATE;
  397                         p->sddown++;    /* XXX: Another unusable subdisk? */
  398                         break;
  399                 }
  400         }
  401         return (statemap);
  402 }

Cache object: 666ba42f8e2150883769b9426c2d5270


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