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/dev/vinum/vinumstate.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) 1997, 1998, 1999
    3  *      Nan Yang Computer Services Limited.  All rights reserved.
    4  *
    5  *  Parts copyright (c) 1997, 1998 Cybernet Corporation, NetMAX project.
    6  *
    7  *  Written by Greg Lehey
    8  *
    9  *  This software is distributed under the so-called ``Berkeley
   10  *  License'':
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *      This product includes software developed by Nan Yang Computer
   23  *      Services Limited.
   24  * 4. Neither the name of the Company nor the names of its contributors
   25  *    may be used to endorse or promote products derived from this software
   26  *    without specific prior written permission.
   27  *
   28  * This software is provided ``as is'', and any express or implied
   29  * warranties, including, but not limited to, the implied warranties of
   30  * merchantability and fitness for a particular purpose are disclaimed.
   31  * In no event shall the company or contributors be liable for any
   32  * direct, indirect, incidental, special, exemplary, or consequential
   33  * damages (including, but not limited to, procurement of substitute
   34  * goods or services; loss of use, data, or profits; or business
   35  * interruption) however caused and on any theory of liability, whether
   36  * in contract, strict liability, or tort (including negligence or
   37  * otherwise) arising in any way out of the use of this software, even if
   38  * advised of the possibility of such damage.
   39  *
   40  * $Id: vinumstate.c,v 1.1.1.1 2003/10/10 03:09:32 grog Exp $
   41  * $FreeBSD$
   42  */
   43 
   44 #include <dev/vinum/vinumhdr.h>
   45 #include <dev/vinum/request.h>
   46 
   47 /* Update drive state */
   48 /* Return 1 if the state changes, otherwise 0 */
   49 int
   50 set_drive_state(int driveno, enum drivestate newstate, enum setstateflags flags)
   51 {
   52     struct drive *drive = &DRIVE[driveno];
   53     int oldstate = drive->state;
   54     int sdno;
   55 
   56     if (drive->state == drive_unallocated)                  /* no drive to do anything with, */
   57         return 0;
   58 
   59     if (newstate == oldstate)                               /* don't change it if it's not different */
   60         return 1;                                           /* all OK */
   61     if ((newstate == drive_down)                            /* the drive's going down */
   62     &&(!(flags & setstate_force))
   63         && (drive->opencount != 0))                         /* we can't do it */
   64         return 0;                                           /* don't do it */
   65     drive->state = newstate;                                /* set the state */
   66     if (drive->label.name[0] != '\0')                       /* we have a name, */
   67         log(LOG_INFO,
   68             "vinum: drive %s is %s\n",
   69             drive->label.name,
   70             drive_state(drive->state));
   71     if (drive->state != oldstate) {                         /* state has changed */
   72         for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) { /* find this drive's subdisks */
   73             if ((SD[sdno].state >= sd_referenced)
   74                 && (SD[sdno].driveno == driveno))           /* belongs to this drive */
   75                 update_sd_state(sdno);                      /* update the state */
   76         }
   77     }
   78     if (newstate == drive_up) {                             /* want to bring it up */
   79         if ((drive->flags & VF_OPEN) == 0)                  /* should be open, but we're not */
   80             init_drive(drive, 1);                           /* which changes the state again */
   81     } else                                                  /* taking it down or worse */
   82         queue_daemon_request(daemonrq_closedrive,           /* get the daemon to close it */
   83             (union daemoninfo) drive);
   84     if ((flags & setstate_configuring) == 0)                /* configuring? */
   85         save_config();                                      /* no: save the updated configuration now */
   86     return 1;
   87 }
   88 
   89 /*
   90  * Try to set the subdisk state.  Return 1 if
   91  * state changed to what we wanted, -1 if it
   92  * changed to something else, and 0 if no change.
   93  *
   94  * This routine is called both from the user (up,
   95  * down states only) and internally.
   96  *
   97  * The setstate_force bit in the flags enables the
   98  * state change even if it could be dangerous to
   99  * data consistency.  It shouldn't allow nonsense.
  100  */
  101 int
  102 set_sd_state(int sdno, enum sdstate newstate, enum setstateflags flags)
  103 {
  104     struct sd *sd = &SD[sdno];
  105     struct plex *plex;
  106     struct volume *vol;
  107     int oldstate = sd->state;
  108     int status = 1;                                         /* status to return */
  109 
  110     if (newstate == oldstate)                               /* already there, */
  111         return 1;
  112     else if (sd->state == sd_unallocated)                   /* no subdisk to do anything with, */
  113         return 0;                                           /* can't do it */
  114 
  115     if (sd->driveoffset < 0) {                              /* not allocated space */
  116         sd->state = sd_down;
  117         if (newstate != sd_down) {
  118             if (sd->plexno >= 0)
  119                 sdstatemap(&PLEX[sd->plexno]);              /* count up subdisks */
  120             return -1;
  121         }
  122     } else {                                                /* space allocated */
  123         switch (newstate) {
  124         case sd_down:                                       /* take it down? */
  125             /*
  126              * If we're attached to a plex, and we're
  127              * not reborn, we won't go down without
  128              * use of force.
  129              */
  130             if ((!flags & setstate_force)
  131                 && (sd->plexno >= 0)
  132                 && (sd->state != sd_reborn))
  133                 return 0;                                   /* don't do it */
  134             break;
  135 
  136         case sd_initialized:
  137             if ((sd->state == sd_initializing)              /* we were initializing */
  138             ||(flags & setstate_force))                     /* or we forced it */
  139                 break;
  140             return 0;                                       /* can't do it otherwise */
  141 
  142         case sd_up:
  143             if (DRIVE[sd->driveno].state != drive_up)       /* can't bring the sd up if the drive isn't, */
  144                 return 0;                                   /* not even by force */
  145             if (flags & setstate_force)                     /* forcing it, */
  146                 break;                                      /* just do it, and damn the consequences */
  147             switch (sd->state) {
  148                 /*
  149                  * Perform the necessary tests.  To allow
  150                  * the state transition, just break out of
  151                  * the switch.
  152                  */
  153             case sd_crashed:
  154             case sd_reborn:
  155             case sd_down:                                   /* been down, no data lost */
  156                 /*
  157                  * If we're associated with a plex, and
  158                  * the plex isn't up, or we're the only
  159                  * subdisk in the plex, we can do it.
  160                  */
  161                 if ((sd->plexno >= 0)
  162                     && (((PLEX[sd->plexno].state < plex_firstup)
  163                             || (PLEX[sd->plexno].subdisks > 1))))
  164                     break;                                  /* do it */
  165                 if (oldstate != sd_reborn) {
  166                     sd->state = sd_reborn;                  /* here it is again */
  167                     log(LOG_INFO,
  168                         "vinum: %s is %s, not %s\n",
  169                         sd->name,
  170                         sd_state(sd->state),
  171                         sd_state(newstate));
  172                 }
  173                 status = -1;
  174                 break;
  175 
  176             case sd_init:                                   /* brand new */
  177                 if (flags & setstate_configuring)           /* we're doing this while configuring */
  178                     break;
  179                 /* otherwise it's like being empty */
  180                 /* FALLTHROUGH */
  181 
  182             case sd_empty:
  183             case sd_initialized:
  184                 /*
  185                  * If we're not part of a plex, or the
  186                  * plex is not part of a volume with other
  187                  * plexes which are up, we can come up
  188                  * without being inconsistent.
  189                  *
  190                  * If we're part of a parity plex, we'll
  191                  * come up if the caller uses force.  This
  192                  * is the way we bring them up after
  193                  * initialization.
  194                  */
  195                 if ((sd->plexno < 0)
  196                     || ((vpstate(&PLEX[sd->plexno]) & volplex_otherup) == 0)
  197                     || (isparity((&PLEX[sd->plexno]))
  198                         && (flags & setstate_force)))
  199                     break;
  200 
  201                 /* Otherwise it's just out of date */
  202                 /* FALLTHROUGH */
  203 
  204             case sd_stale:                                  /* out of date info, need reviving */
  205             case sd_obsolete:
  206                 /*
  207 
  208                  * 1.  If the subdisk is not part of a
  209                  *     plex, bring it up, don't revive.
  210                  *
  211                  * 2.  If the subdisk is part of a
  212                  *     one-plex volume or an unattached
  213                  *     plex, and it's not RAID-4 or
  214                  *     RAID-5, we *can't revive*.  The
  215                  *     subdisk doesn't change its state.
  216                  *
  217                  * 3.  If the subdisk is part of a
  218                  *     one-plex volume or an unattached
  219                  *     plex, and it's RAID-4 or RAID-5,
  220                  *     but more than one subdisk is down,
  221                  *     we *still can't revive*.  The
  222                  *     subdisk doesn't change its state.
  223                  *
  224                  * 4.  If the subdisk is part of a
  225                  *     multi-plex volume, we'll change to
  226                  *     reviving and let the revive
  227                  *     routines find out whether it will
  228                  *     work or not.  If they don't, the
  229                  *     revive stops with an error message,
  230                  *     but the state doesn't change
  231                  *     (FWIW).
  232                  */
  233                 if (sd->plexno < 0)                         /* no plex associated, */
  234                     break;                                  /* bring it up */
  235                 plex = &PLEX[sd->plexno];
  236                 if (plex->volno >= 0)                       /* have a volume */
  237                     vol = &VOL[plex->volno];
  238                 else
  239                     vol = NULL;
  240                 /*
  241                  * We can't do it if:
  242                  *
  243                  * 1: we don't have a volume
  244                  * 2: we're the only plex in the volume
  245                  * 3: we're a RAID-4 or RAID-5 plex, and
  246                  *    more than one subdisk is down.
  247                  */
  248                 if (((vol == NULL)
  249                         || (vol->plexes == 1))
  250                     && ((!isparity(plex))
  251                         || (plex->sddowncount > 1))) {
  252                     if (sd->state == sd_initializing)       /* it's finished initializing  */
  253                         sd->state = sd_initialized;
  254                     else
  255                         return 0;                           /* can't do it */
  256                 } else {
  257                     sd->state = sd_reviving;                /* put in reviving state */
  258                     sd->revived = 0;                        /* nothing done yet */
  259                     status = EAGAIN;                        /* need to repeat */
  260                 }
  261                 break;
  262 
  263             case sd_reviving:
  264                 if (flags & setstate_force)                 /* insist, */
  265                     break;
  266                 return EAGAIN;                              /* no, try again */
  267 
  268             default:                                        /* can't do it */
  269                 /*
  270                  * There's no way to bring subdisks up directly from
  271                  * other states.  First they need to be initialized
  272                  * or revived.
  273                  */
  274                 return 0;
  275             }
  276             break;
  277 
  278         default:                                            /* other ones, only internal with force */
  279             if ((flags & setstate_force) == 0)              /* no force?  What's this? */
  280                 return 0;                                   /* don't do it */
  281         }
  282     }
  283     if (status == 1) {                                      /* we can do it, */
  284         sd->state = newstate;
  285         if (flags & setstate_force)
  286             log(LOG_INFO, "vinum: %s is %s by force\n", sd->name, sd_state(sd->state));
  287         else
  288             log(LOG_INFO, "vinum: %s is %s\n", sd->name, sd_state(sd->state));
  289     } else                                                  /* we don't get here with status 0 */
  290         log(LOG_INFO,
  291             "vinum: %s is %s, not %s\n",
  292             sd->name,
  293             sd_state(sd->state),
  294             sd_state(newstate));
  295     if (sd->plexno >= 0)                                    /* we belong to a plex */
  296         update_plex_state(sd->plexno);                      /* update plex state */
  297     if ((flags & setstate_configuring) == 0)                /* save config now */
  298         save_config();
  299     return status;
  300 }
  301 
  302 /*
  303  * Set the state of a plex dependent on its subdisks.
  304  * This time round, we'll let plex state just reflect
  305  * aggregate subdisk state, so this becomes an order of
  306  * magnitude less complicated.  In particular, ignore
  307  * the requested state.
  308  */
  309 int
  310 set_plex_state(int plexno, enum plexstate state, enum setstateflags flags)
  311 {
  312     struct plex *plex;                                      /* point to our plex */
  313     enum plexstate oldstate;
  314     enum volplexstate vps;                                  /* how do we compare with the other plexes? */
  315 
  316     plex = &PLEX[plexno];                                   /* point to our plex */
  317     oldstate = plex->state;
  318 
  319     /* If the plex isn't allocated, we can't do it. */
  320     if (plex->state == plex_unallocated)
  321         return 0;
  322 
  323     /*
  324      * If it's already in the the state we want,
  325      * and it's not up, just return.  If it's up,
  326      * we still need to do some housekeeping.
  327      */
  328     if ((state == oldstate)
  329         && (state != plex_up))
  330         return 1;
  331     vps = vpstate(plex);                                    /* how do we compare with the other plexes? */
  332     switch (state) {
  333         /*
  334          * We can't bring the plex up, even by force,
  335          * unless it's ready.  update_plex_state
  336          * checks that.
  337          */
  338     case plex_up:                                           /* bring the plex up */
  339         update_plex_state(plex->plexno);                    /* it'll come up if it can */
  340         break;
  341 
  342     case plex_down:                                         /* want to take it down */
  343         /*
  344          * If we're the only one, or the only one
  345          * which is up, we need force to do it.
  346          */
  347         if (((vps == volplex_onlyus)
  348                 || (vps == volplex_onlyusup))
  349             && (!(flags & setstate_force)))
  350             return 0;                                       /* can't do it */
  351         plex->state = state;                                /* do it */
  352         invalidate_subdisks(plex, sd_down);                 /* and down all up subdisks */
  353         break;
  354 
  355         /*
  356          * This is only requested internally.
  357          * Trust ourselves
  358          */
  359     case plex_faulty:
  360         plex->state = state;                                /* do it */
  361         invalidate_subdisks(plex, sd_crashed);              /* and crash all up subdisks */
  362         break;
  363 
  364     case plex_initializing:
  365         /* XXX consider what safeguards we need here */
  366         if ((flags & setstate_force) == 0)
  367             return 0;
  368         plex->state = state;                                /* do it */
  369         break;
  370 
  371         /* What's this? */
  372     default:
  373         return 0;
  374     }
  375     if (plex->state != oldstate)                            /* we've changed, */
  376         log(LOG_INFO,                                       /* tell them about it */
  377             "vinum: %s is %s\n",
  378             plex->name,
  379             plex_state(plex->state));
  380     /*
  381      * Now see what we have left, and whether
  382      * we're taking the volume down
  383      */
  384     if (plex->volno >= 0)                                   /* we have a volume */
  385         update_volume_state(plex->volno);                   /* update its state */
  386     if ((flags & setstate_configuring) == 0)                /* save config now */
  387         save_config();                                      /* yes: save the updated configuration */
  388     return 1;
  389 }
  390 
  391 /* Update the state of a plex dependent on its plexes. */
  392 int
  393 set_volume_state(int volno, enum volumestate state, enum setstateflags flags)
  394 {
  395     struct volume *vol = &VOL[volno];                       /* point to our volume */
  396 
  397     if (vol->state == volume_unallocated)                   /* no volume to do anything with, */
  398         return 0;
  399     if (vol->state == state)                                /* we're there already */
  400         return 1;
  401 
  402     if (state == volume_up)                                 /* want to come up */
  403         update_volume_state(volno);
  404     else if (state == volume_down) {                        /* want to go down */
  405         if (((vol->flags & VF_OPEN) == 0)                   /* not open */
  406         ||((flags & setstate_force) != 0)) {                /* or we're forcing */
  407             vol->state = volume_down;
  408             log(LOG_INFO,
  409                 "vinum: volume %s is %s\n",
  410                 vol->name,
  411                 volume_state(vol->state));
  412             if ((flags & setstate_configuring) == 0)        /* save config now */
  413                 save_config();                              /* yes: save the updated configuration */
  414             return 1;
  415         }
  416     }
  417     return 0;                                               /* no change */
  418 }
  419 
  420 /* Set the state of a subdisk based on its environment */
  421 void
  422 update_sd_state(int sdno)
  423 {
  424     struct sd *sd;
  425     struct drive *drive;
  426     enum sdstate oldstate;
  427 
  428     sd = &SD[sdno];
  429     oldstate = sd->state;
  430     drive = &DRIVE[sd->driveno];
  431 
  432     if (drive->state == drive_up) {
  433         switch (sd->state) {
  434         case sd_down:
  435         case sd_crashed:
  436             sd->state = sd_reborn;                          /* back up again with no loss */
  437             break;
  438 
  439         default:
  440             break;
  441         }
  442     } else {                                                /* down or worse */
  443         switch (sd->state) {
  444         case sd_up:
  445         case sd_reborn:
  446         case sd_reviving:
  447         case sd_empty:
  448             sd->state = sd_crashed;                         /* lost our drive */
  449             break;
  450 
  451         default:
  452             break;
  453         }
  454     }
  455     if (sd->state != oldstate)                              /* state has changed, */
  456         log(LOG_INFO,                                       /* say so */
  457             "vinum: %s is %s\n",
  458             sd->name,
  459             sd_state(sd->state));
  460     if (sd->plexno >= 0)                                    /* we're part of a plex, */
  461         update_plex_state(sd->plexno);                      /* update its state */
  462 }
  463 
  464 /*
  465  * Force a plex and all its subdisks
  466  * into an 'up' state.  This is a helper
  467  * for update_plex_state.
  468  */
  469 void
  470 forceup(int plexno)
  471 {
  472     struct plex *plex;
  473     int sdno;
  474 
  475     plex = &PLEX[plexno];                                   /* point to the plex */
  476     plex->state = plex_up;                                  /* and bring it up */
  477 
  478     /* change the subdisks to up state */
  479     for (sdno = 0; sdno < plex->subdisks; sdno++) {
  480         SD[plex->sdnos[sdno]].state = sd_up;
  481         log(LOG_INFO,                                       /* tell them about it */
  482             "vinum: %s is up\n",
  483             SD[plex->sdnos[sdno]].name);
  484     }
  485 }
  486 
  487 /* Set the state of a plex based on its environment */
  488 void
  489 update_plex_state(int plexno)
  490 {
  491     struct plex *plex;                                      /* point to our plex */
  492     enum plexstate oldstate;
  493     enum sdstates statemap;                                 /* get a map of the subdisk states */
  494     enum volplexstate vps;                                  /* how do we compare with the other plexes? */
  495 
  496     plex = &PLEX[plexno];                                   /* point to our plex */
  497     oldstate = plex->state;
  498     statemap = sdstatemap(plex);                            /* get a map of the subdisk states */
  499     vps = vpstate(plex);                                    /* how do we compare with the other plexes? */
  500 
  501     if (statemap & sd_initstate)                            /* something initializing? */
  502         plex->state = plex_initializing;                    /* yup, that makes the plex the same */
  503     else if (statemap == sd_upstate)
  504         /*
  505          * All the subdisks are up.  This also means that
  506          * they are consistent, so we can just bring
  507          * the plex up
  508          */
  509         plex->state = plex_up;
  510     else if (isparity(plex)                                 /* RAID-4 or RAID-5 plex */
  511     &&(plex->sddowncount == 1))                             /* and exactly one subdisk down */
  512         plex->state = plex_degraded;                        /* limping a bit */
  513     else if (((statemap & ~sd_downstate) == sd_emptystate)  /* all subdisks empty */
  514     ||((statemap & ~sd_downstate)
  515             == (statemap & ~sd_downstate & (sd_initializedstate | sd_upstate)))) {
  516         if ((vps & volplex_otherup) == 0) {                 /* no other plex is up */
  517             struct volume *vol = &VOL[plex->volno];         /* possible volume to which it points */
  518 
  519             /*
  520              * If we're a striped or concat plex
  521              * associated with a volume, none of whose
  522              * plexes are up, and we're new and untested,
  523              * and the volume has the setupstate bit set,
  524              * we can pretend to be in a consistent state.
  525              *
  526              * We need to do this in one swell foop: on
  527              * the next call we will no longer be just
  528              * empty.
  529              *
  530              * This code assumes that all the other plexes
  531              * are also capable of coming up (i.e. all the
  532              * sds are up), but that's OK: we'll come back
  533              * to this function for the remaining plexes
  534              * in the volume.
  535              */
  536             if ((plex->state == plex_init)
  537                 && (plex->volno >= 0)
  538                 && (vol->flags & VF_CONFIG_SETUPSTATE)) {
  539                 for (plexno = 0; plexno < vol->plexes; plexno++)
  540                     forceup(VOL[plex->volno].plex[plexno]);
  541             } else if ((statemap == sd_initializedstate)    /* if it's initialized (not empty) */
  542             ||(plex->organization == plex_concat)           /* and we're not RAID-4 or RAID-5 */
  543             ||(plex->organization == plex_striped))
  544                 forceup(plexno);                            /* we'll do it */
  545             /*
  546              * This leaves a case where things don't get
  547              * done: the plex is RAID-4 or RAID-5, and
  548              * the subdisks are all empty.  They need to
  549              * be initialized first.
  550              */
  551         } else {
  552             if (statemap == sd_upstate)                     /* all subdisks up */
  553                 plex->state = plex_up;                      /* we can come up too */
  554             else
  555                 plex->state = plex_faulty;
  556         }
  557     } else if ((statemap & (sd_upstate | sd_rebornstate)) == statemap) /* all up or reborn */
  558         plex->state = plex_flaky;
  559     else if (statemap & (sd_upstate | sd_rebornstate))      /* some up or reborn */
  560         plex->state = plex_corrupt;                         /* corrupt */
  561     else if (statemap & (sd_initstate | sd_emptystate))     /* some subdisks empty or initializing */
  562         plex->state = plex_initializing;
  563     else                                                    /* nothing at all up */
  564         plex->state = plex_faulty;
  565 
  566     if (plex->state != oldstate)                            /* state has changed, */
  567         log(LOG_INFO,                                       /* tell them about it */
  568             "vinum: %s is %s\n",
  569             plex->name,
  570             plex_state(plex->state));
  571     if (plex->volno >= 0)                                   /* we're part of a volume, */
  572         update_volume_state(plex->volno);                   /* update its state */
  573 }
  574 
  575 /* Set volume state based on its components */
  576 void
  577 update_volume_state(int volno)
  578 {
  579     struct volume *vol;                                     /* our volume */
  580     int plexno;
  581     enum volumestate oldstate;
  582 
  583     vol = &VOL[volno];                                      /* point to our volume */
  584     oldstate = vol->state;
  585 
  586     for (plexno = 0; plexno < vol->plexes; plexno++) {
  587         struct plex *plex = &PLEX[vol->plex[plexno]];       /* point to the plex */
  588         if (plex->state >= plex_corrupt) {                  /* something accessible, */
  589             vol->state = volume_up;
  590             break;
  591         }
  592     }
  593     if (plexno == vol->plexes)                              /* didn't find an up plex */
  594         vol->state = volume_down;
  595 
  596     if (vol->state != oldstate) {                           /* state changed */
  597         log(LOG_INFO, "vinum: %s is %s\n", vol->name, volume_state(vol->state));
  598         save_config();                                      /* save the updated configuration */
  599     }
  600 }
  601 
  602 /*
  603  * Called from request routines when they find
  604  * a subdisk which is not kosher.  Decide whether
  605  * it warrants changing the state.  Return
  606  * REQUEST_DOWN if we can't use the subdisk,
  607  * REQUEST_OK if we can.
  608  */
  609 /*
  610  * A prior version of this function checked the plex
  611  * state as well.  At the moment, consider plex states
  612  * information for the user only.  We'll ignore them
  613  * and use the subdisk state only.  The last version of
  614  * this file with the old logic was 2.7. XXX
  615  */
  616 enum requeststatus
  617 checksdstate(struct sd *sd, struct request *rq, daddr_t diskaddr, daddr_t diskend)
  618 {
  619     struct plex *plex = &PLEX[sd->plexno];
  620     int writeop = (rq->bp->b_flags & B_READ) == 0;          /* note if we're writing */
  621 
  622     switch (sd->state) {
  623         /* We shouldn't get called if the subdisk is up */
  624     case sd_up:
  625         return REQUEST_OK;
  626 
  627     case sd_reviving:
  628         /*
  629          * Access to a reviving subdisk depends on the
  630          * organization of the plex:
  631          *
  632          * - If it's concatenated, access the subdisk
  633          *   up to its current revive point.  If we
  634          *   want to write to the subdisk overlapping
  635          *   the current revive block, set the
  636          *   conflict flag in the request, asking the
  637          *   caller to put the request on the wait
  638          *   list, which will be attended to by
  639          *   revive_block when it's done.
  640          * - if it's striped, we can't do it (we could
  641          *   do some hairy calculations, but it's
  642          *   unlikely to work).
  643          * - if it's RAID-4 or RAID-5, we can do it as
  644          *   long as only one subdisk is down
  645          */
  646         if (plex->organization == plex_striped)             /* plex is striped, */
  647             return REQUEST_DOWN;
  648         else if (isparity(plex)) {                          /* RAID-4 or RAID-5 plex */
  649             if (plex->sddowncount > 1)                      /* with more than one sd down, */
  650                 return REQUEST_DOWN;
  651             else
  652                 /*
  653                  * XXX We shouldn't do this if we can find a
  654                  * better way.  Check the other plexes
  655                  * first, and return a DOWN if another
  656                  * plex will do it better
  657                  */
  658                 return REQUEST_OK;                          /* OK, we'll find a way */
  659         }
  660         if (diskaddr > (sd->revived
  661                 + sd->plexoffset
  662                 + (sd->revive_blocksize >> DEV_BSHIFT)))    /* we're beyond the end */
  663             return REQUEST_DOWN;
  664         else if (diskend > (sd->revived + sd->plexoffset)) { /* we finish beyond the end */
  665             if (writeop) {
  666                 rq->flags |= XFR_REVIVECONFLICT;            /* note a potential conflict */
  667                 rq->sdno = sd->sdno;                        /* and which sd last caused it */
  668             } else
  669                 return REQUEST_DOWN;
  670         }
  671         return REQUEST_OK;
  672 
  673     case sd_reborn:
  674         if (writeop)
  675             return REQUEST_OK;                              /* always write to a reborn disk */
  676         else                                                /* don't allow a read */
  677             /*
  678                * Handle the mapping.  We don't want to reject
  679                * a read request to a reborn subdisk if that's
  680                * all we have. XXX
  681              */
  682             return REQUEST_DOWN;
  683 
  684     case sd_down:
  685         if (writeop)                                        /* writing to a consistent down disk */
  686             set_sd_state(sd->sdno, sd_obsolete, setstate_force); /* it's not consistent now */
  687         return REQUEST_DOWN;
  688 
  689     case sd_crashed:
  690         if (writeop)                                        /* writing to a consistent down disk */
  691             set_sd_state(sd->sdno, sd_stale, setstate_force); /* it's not consistent now */
  692         return REQUEST_DOWN;
  693 
  694     default:
  695         return REQUEST_DOWN;
  696     }
  697 }
  698 
  699 /* return a state map for the subdisks of a plex */
  700 enum sdstates
  701 sdstatemap(struct plex *plex)
  702 {
  703     int sdno;
  704     enum sdstates statemap = 0;                             /* note the states we find */
  705 
  706     plex->sddowncount = 0;                                  /* no subdisks down yet */
  707     for (sdno = 0; sdno < plex->subdisks; sdno++) {
  708         struct sd *sd = &SD[plex->sdnos[sdno]];             /* point to the subdisk */
  709 
  710         switch (sd->state) {
  711         case sd_empty:
  712             statemap |= sd_emptystate;
  713             (plex->sddowncount)++;                          /* another unusable subdisk */
  714             break;
  715 
  716         case sd_init:
  717             statemap |= sd_initstate;
  718             (plex->sddowncount)++;                          /* another unusable subdisk */
  719             break;
  720 
  721         case sd_down:
  722             statemap |= sd_downstate;
  723             (plex->sddowncount)++;                          /* another unusable subdisk */
  724             break;
  725 
  726         case sd_crashed:
  727             statemap |= sd_crashedstate;
  728             (plex->sddowncount)++;                          /* another unusable subdisk */
  729             break;
  730 
  731         case sd_obsolete:
  732             statemap |= sd_obsoletestate;
  733             (plex->sddowncount)++;                          /* another unusable subdisk */
  734             break;
  735 
  736         case sd_stale:
  737             statemap |= sd_stalestate;
  738             (plex->sddowncount)++;                          /* another unusable subdisk */
  739             break;
  740 
  741         case sd_reborn:
  742             statemap |= sd_rebornstate;
  743             break;
  744 
  745         case sd_up:
  746             statemap |= sd_upstate;
  747             break;
  748 
  749         case sd_initializing:
  750             statemap |= sd_initstate;
  751             (plex->sddowncount)++;                          /* another unusable subdisk */
  752             break;
  753 
  754         case sd_initialized:
  755             statemap |= sd_initializedstate;
  756             (plex->sddowncount)++;                          /* another unusable subdisk */
  757             break;
  758 
  759         case sd_unallocated:
  760         case sd_uninit:
  761         case sd_reviving:
  762         case sd_referenced:
  763             statemap |= sd_otherstate;
  764             (plex->sddowncount)++;                          /* another unusable subdisk */
  765         }
  766     }
  767     return statemap;
  768 }
  769 
  770 /* determine the state of the volume relative to this plex */
  771 enum volplexstate
  772 vpstate(struct plex *plex)
  773 {
  774     struct volume *vol;
  775     enum volplexstate state = volplex_onlyusdown;           /* state to return */
  776     int plexno;
  777 
  778     if (plex->volno < 0) {                                  /* not associated with a volume */
  779         if (plex->state > plex_degraded)
  780             return volplex_onlyus;                          /* just us */
  781         else
  782             return volplex_onlyusdown;                      /* assume the worst */
  783     }
  784     vol = &VOL[plex->volno];                                /* point to our volume */
  785     for (plexno = 0; plexno < vol->plexes; plexno++) {
  786         if (&PLEX[vol->plex[plexno]] == plex) {             /* us */
  787             if (PLEX[vol->plex[plexno]].state >= plex_degraded) /* are we up? */
  788                 state |= volplex_onlyus;                    /* yes */
  789         } else {
  790             if (PLEX[vol->plex[plexno]].state >= plex_degraded) /* not us */
  791                 state |= volplex_otherup;                   /* and when they were up, they were up */
  792             else
  793                 state |= volplex_alldown;                   /* and when they were down, they were down */
  794         }
  795     }
  796     return state;                                           /* and when they were only halfway up */
  797 }                                                           /* they were neither up nor down */
  798 
  799 /* Check if all bits b are set in a */
  800 int allset(int a, int b);
  801 
  802 int
  803 allset(int a, int b)
  804 {
  805     return (a & b) == b;
  806 }
  807 
  808 /* Invalidate the subdisks belonging to a plex */
  809 void
  810 invalidate_subdisks(struct plex *plex, enum sdstate state)
  811 {
  812     int sdno;
  813 
  814     for (sdno = 0; sdno < plex->subdisks; sdno++) {         /* for each subdisk */
  815         struct sd *sd = &SD[plex->sdnos[sdno]];
  816 
  817         switch (sd->state) {
  818         case sd_unallocated:
  819         case sd_uninit:
  820         case sd_init:
  821         case sd_initializing:
  822         case sd_initialized:
  823         case sd_empty:
  824         case sd_obsolete:
  825         case sd_stale:
  826         case sd_crashed:
  827         case sd_down:
  828         case sd_referenced:
  829             break;
  830 
  831         case sd_reviving:
  832         case sd_reborn:
  833         case sd_up:
  834             set_sd_state(plex->sdnos[sdno], state, setstate_force);
  835         }
  836     }
  837 }
  838 
  839 /*
  840  * Start an object, in other words do what we can to get it up.
  841  * This is called from vinumioctl (VINUMSTART).
  842  * Return error indications via ioctl_reply
  843  */
  844 void
  845 start_object(struct vinum_ioctl_msg *data)
  846 {
  847     int status;
  848     int objindex = data->index;                             /* data gets overwritten */
  849     struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) data; /* format for returning replies */
  850     enum setstateflags flags;
  851 
  852     if (data->force != 0)                                   /* are we going to use force? */
  853         flags = setstate_force;                             /* yes */
  854     else
  855         flags = setstate_none;                              /* no */
  856 
  857     switch (data->type) {
  858     case drive_object:
  859         status = set_drive_state(objindex, drive_up, flags);
  860         if (DRIVE[objindex].state != drive_up)              /* set status on whether we really did it */
  861             ioctl_reply->error = EBUSY;
  862         else
  863             ioctl_reply->error = 0;
  864         break;
  865 
  866     case sd_object:
  867         if (DRIVE[SD[objindex].driveno].state != drive_up) {
  868             ioctl_reply->error = EIO;
  869             strcpy(ioctl_reply->msg, "Drive is down");
  870             return;
  871         }
  872         if (data->blocksize)
  873             SD[objindex].revive_blocksize = data->blocksize;
  874         if ((SD[objindex].state == sd_reviving)             /* reviving, */
  875         ||(SD[objindex].state == sd_stale)) {               /* or stale, will revive */
  876             SD[objindex].state = sd_reviving;               /* make sure we're reviving */
  877             ioctl_reply->error = revive_block(objindex);    /* revive another block */
  878             ioctl_reply->msg[0] = '\0';                     /* no comment */
  879             return;
  880         } else if (SD[objindex].state == sd_initializing) { /* initializing, */
  881             if (data->blocksize)
  882                 SD[objindex].init_blocksize = data->blocksize;
  883             ioctl_reply->error = initsd(objindex, data->verify); /* initialize another block */
  884             ioctl_reply->msg[0] = '\0';                     /* no comment */
  885             return;
  886         }
  887         status = set_sd_state(objindex, sd_up, flags);      /* set state */
  888         if (status != EAGAIN) {                             /* not first revive or initialize, */
  889             if (SD[objindex].state != sd_up)                /* set status on whether we really did it */
  890                 ioctl_reply->error = EBUSY;
  891             else
  892                 ioctl_reply->error = 0;
  893         } else
  894             ioctl_reply->error = status;
  895         break;
  896 
  897     case plex_object:
  898         status = set_plex_state(objindex, plex_up, flags);
  899         if (PLEX[objindex].state != plex_up)                /* set status on whether we really did it */
  900             ioctl_reply->error = EBUSY;
  901         else
  902             ioctl_reply->error = 0;
  903         break;
  904 
  905     case volume_object:
  906         status = set_volume_state(objindex, volume_up, flags);
  907         if (VOL[objindex].state != volume_up)               /* set status on whether we really did it */
  908             ioctl_reply->error = EBUSY;
  909         else
  910             ioctl_reply->error = 0;
  911         break;
  912 
  913     default:
  914         ioctl_reply->error = EINVAL;
  915         strcpy(ioctl_reply->msg, "Invalid object type");
  916         return;
  917     }
  918     /*
  919      * There's no point in saying anything here:
  920      * the userland program does it better
  921      */
  922     ioctl_reply->msg[0] = '\0';
  923 }
  924 
  925 /*
  926  * Stop an object, in other words do what we can to get it down
  927  * This is called from vinumioctl (VINUMSTOP).
  928  * Return error indications via ioctl_reply.
  929  */
  930 void
  931 stop_object(struct vinum_ioctl_msg *data)
  932 {
  933     int status = 1;
  934     int objindex = data->index;                             /* save the number from change */
  935     struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) data; /* format for returning replies */
  936 
  937     switch (data->type) {
  938     case drive_object:
  939         status = set_drive_state(objindex, drive_down, data->force);
  940         break;
  941 
  942     case sd_object:
  943         status = set_sd_state(objindex, sd_down, data->force);
  944         break;
  945 
  946     case plex_object:
  947         status = set_plex_state(objindex, plex_down, data->force);
  948         break;
  949 
  950     case volume_object:
  951         status = set_volume_state(objindex, volume_down, data->force);
  952         break;
  953 
  954     default:
  955         ioctl_reply->error = EINVAL;
  956         strcpy(ioctl_reply->msg, "Invalid object type");
  957         return;
  958     }
  959     ioctl_reply->msg[0] = '\0';
  960     if (status == 0)                                        /* couldn't do it */
  961         ioctl_reply->error = EBUSY;
  962     else
  963         ioctl_reply->error = 0;
  964 }
  965 
  966 /*
  967  * VINUM_SETSTATE ioctl: set an object state.
  968  * msg is the message passed by the user.
  969  */
  970 void
  971 setstate(struct vinum_ioctl_msg *msg)
  972 {
  973     int sdno;
  974     struct sd *sd;
  975     struct plex *plex;
  976     struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) msg; /* format for returning replies */
  977 
  978     switch (msg->state) {
  979     case object_down:
  980         stop_object(msg);
  981         break;
  982 
  983     case object_initializing:
  984         switch (msg->type) {
  985         case sd_object:
  986             sd = &SD[msg->index];
  987             if ((msg->index >= vinum_conf.subdisks_allocated)
  988                 || (sd->state <= sd_referenced)) {
  989                 sprintf(ioctl_reply->msg, "Invalid subdisk %d", msg->index);
  990                 ioctl_reply->error = EFAULT;
  991                 return;
  992             }
  993             set_sd_state(msg->index, sd_initializing, msg->force);
  994             if (sd->state != sd_initializing) {
  995                 strcpy(ioctl_reply->msg, "Can't set state");
  996                 ioctl_reply->error = EBUSY;
  997             } else
  998                 ioctl_reply->error = 0;
  999             break;
 1000 
 1001         case plex_object:
 1002             plex = &PLEX[msg->index];
 1003             if ((msg->index >= vinum_conf.plexes_allocated)
 1004                 || (plex->state <= plex_unallocated)) {
 1005                 sprintf(ioctl_reply->msg, "Invalid plex %d", msg->index);
 1006                 ioctl_reply->error = EFAULT;
 1007                 return;
 1008             }
 1009             set_plex_state(msg->index, plex_initializing, msg->force);
 1010             if (plex->state != plex_initializing) {
 1011                 strcpy(ioctl_reply->msg, "Can't set state");
 1012                 ioctl_reply->error = EBUSY;
 1013             } else {
 1014                 ioctl_reply->error = 0;
 1015                 for (sdno = 0; sdno < plex->subdisks; sdno++) {
 1016                     sd = &SD[plex->sdnos[sdno]];
 1017                     set_sd_state(plex->sdnos[sdno], sd_initializing, msg->force);
 1018                     if (sd->state != sd_initializing) {
 1019                         strcpy(ioctl_reply->msg, "Can't set state");
 1020                         ioctl_reply->error = EBUSY;
 1021                         break;
 1022                     }
 1023                 }
 1024             }
 1025             break;
 1026 
 1027         default:
 1028             strcpy(ioctl_reply->msg, "Invalid object");
 1029             ioctl_reply->error = EINVAL;
 1030         }
 1031         break;
 1032 
 1033     case object_initialized:
 1034         if (msg->type == sd_object) {
 1035             sd = &SD[msg->index];
 1036             if ((msg->index >= vinum_conf.subdisks_allocated)
 1037                 || (sd->state <= sd_referenced)) {
 1038                 sprintf(ioctl_reply->msg, "Invalid subdisk %d", msg->index);
 1039                 ioctl_reply->error = EFAULT;
 1040                 return;
 1041             }
 1042             set_sd_state(msg->index, sd_initialized, msg->force);
 1043             if (sd->state != sd_initializing) {
 1044                 strcpy(ioctl_reply->msg, "Can't set state");
 1045                 ioctl_reply->error = EBUSY;
 1046             } else
 1047                 ioctl_reply->error = 0;
 1048         } else {
 1049             strcpy(ioctl_reply->msg, "Invalid object");
 1050             ioctl_reply->error = EINVAL;
 1051         }
 1052         break;
 1053 
 1054     case object_up:
 1055         start_object(msg);
 1056     }
 1057 }
 1058 
 1059 /*
 1060  * Brute force set state function.  Don't look at
 1061  * any dependencies, just do it.  This is mainly
 1062  * intended for testing and recovery.
 1063  */
 1064 void
 1065 setstate_by_force(struct vinum_ioctl_msg *msg)
 1066 {
 1067     struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) msg; /* format for returning replies */
 1068 
 1069     switch (msg->type) {
 1070     case drive_object:
 1071         DRIVE[msg->index].state = msg->state;
 1072         break;
 1073 
 1074     case sd_object:
 1075         SD[msg->index].state = msg->state;
 1076         break;
 1077 
 1078     case plex_object:
 1079         PLEX[msg->index].state = msg->state;
 1080         break;
 1081 
 1082     case volume_object:
 1083         VOL[msg->index].state = msg->state;
 1084         break;
 1085 
 1086     default:
 1087         break;
 1088     }
 1089     ioctl_reply->error = 0;
 1090 }
 1091 /* Local Variables: */
 1092 /* fill-column: 50 */
 1093 /* End: */

Cache object: bb04884fbd70b54f3a5b12025b53117d


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