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

Cache object: 23e7c41ed4c28caab5b3397443c49270


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