diff options
author | le <le@FreeBSD.org> | 2004-06-12 21:16:10 +0000 |
---|---|---|
committer | le <le@FreeBSD.org> | 2004-06-12 21:16:10 +0000 |
commit | cf31d52b42bd2309bb855b34e8260283eabfc570 (patch) | |
tree | b37e9b83eff28125aba7f626ab2e3bea5b487658 /sys/geom/vinum/geom_vinum_state.c | |
parent | f66d897510d4772f7c5efd834cd66203558e9cb5 (diff) | |
download | FreeBSD-src-cf31d52b42bd2309bb855b34e8260283eabfc570.zip FreeBSD-src-cf31d52b42bd2309bb855b34e8260283eabfc570.tar.gz |
Add a first version of a GEOMified vinum.
Diffstat (limited to 'sys/geom/vinum/geom_vinum_state.c')
-rw-r--r-- | sys/geom/vinum/geom_vinum_state.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/sys/geom/vinum/geom_vinum_state.c b/sys/geom/vinum/geom_vinum_state.c new file mode 100644 index 0000000..fe8a88e --- /dev/null +++ b/sys/geom/vinum/geom_vinum_state.c @@ -0,0 +1,289 @@ +/*- + * Copyright (c) 2004 Lukas Ertl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/libkern.h> +#include <sys/malloc.h> + +#include <geom/geom.h> +#include <geom/vinum/geom_vinum_var.h> +#include <geom/vinum/geom_vinum.h> +#include <geom/vinum/geom_vinum_share.h> + +/* Update drive state; return 1 if the state changes, otherwise 0. */ +int +gv_set_drive_state(struct gv_drive *d, int newstate, int flags) +{ + struct gv_sd *s; + int oldstate; + + KASSERT(d != NULL, ("gv_set_drive_state: NULL d")); + + oldstate = d->state; + + if (newstate == oldstate) + return (1); + + /* We allow to take down an open drive only with force. */ + if ((newstate == GV_DRIVE_DOWN) && gv_is_open(d->geom) && + (!(flags & GV_SETSTATE_FORCE))) + return (0); + + d->state = newstate; + + if (d->state != oldstate) { + LIST_FOREACH(s, &d->subdisks, from_drive) + gv_update_sd_state(s); + } + + return (1); +} + +int +gv_set_sd_state(struct gv_sd *s, int newstate, int flags) +{ + struct gv_drive *d; + struct gv_plex *p; + int oldstate, status; + + KASSERT(s != NULL, ("gv_set_sd_state: NULL s")); + + oldstate = s->state; + + /* We are optimistic and assume it will work. */ + status = 0; + + if (newstate == oldstate) + return (0); + + switch (newstate) { + case GV_SD_DOWN: + /* + * If we're attached to a plex, we won't go down without use of + * force. + */ + if ((s->plex_sc != NULL) && !(flags & GV_SETSTATE_FORCE)) + return (-1); + break; + + case GV_SD_UP: + /* We can't bring the subdisk up if our drive is dead. */ + d = s->drive_sc; + if ((d == NULL) || (d->state != GV_DRIVE_UP)) + return (-1); + + /* Check from where we want to be brought up. */ + switch (s->state) { + case GV_SD_REVIVING: + case GV_SD_INITIALIZING: + /* + * The subdisk was initializing. We allow it to be + * brought up. + */ + break; + + case GV_SD_DOWN: + /* + * The subdisk is currently down. We allow it to be + * brought up if it is not attached to a plex. + */ + p = s->plex_sc; + if (p == NULL) + break; + + /* + * If this subdisk is attached to a plex, we allow it + * to be brought up if the plex if it's not a RAID5 + * plex, otherwise it's made 'stale'. + */ + + if (p->org != GV_PLEX_RAID5) + break; + else + s->state = GV_SD_STALE; + + status = -1; + break; + + case GV_SD_STALE: + /* + * A stale subdisk can't be brought up directly, it + * needs to be revived or initialized first. + */ + /* FALLTHROUGH */ + default: + return (-1); + } + break; + + /* Other state transitions are only possible with force. */ + default: + if (!(flags & GV_SETSTATE_FORCE)) + return (-1); + } + + /* We can change the state and do it. */ + if (status == 0) + s->state = newstate; + + /* Update our plex, if we're attached to one. */ + if (s->plex_sc != NULL) + gv_update_plex_state(s->plex_sc); + + /* Save the config back to disk. */ + if (flags & GV_SETSTATE_CONFIG) + gv_save_config_all(s->vinumconf); + + return (status); +} + + +/* Update the state of a subdisk based on its environment. */ +void +gv_update_sd_state(struct gv_sd *s) +{ + struct gv_drive *d; + + KASSERT(s != NULL, ("gv_update_sd_state: NULL s")); + d = s->drive_sc; + KASSERT(d != NULL, ("gv_update_sd_state: NULL d")); + + /* If our drive isn't up we cannot be up either. */ + if (d->state != GV_DRIVE_UP) + s->state = GV_SD_DOWN; + /* If this subdisk was just created, we assume it is good.*/ + else if (s->flags & GV_SD_NEWBORN) { + s->state = GV_SD_UP; + s->flags &= ~GV_SD_NEWBORN; + } else if (s->state != GV_SD_UP) + s->state = GV_SD_STALE; + else + s->state = GV_SD_UP; + + printf("FOO: sd %s is %s\n", s->name, gv_sdstate(s->state)); + /* Update the plex, if we have one. */ + if (s->plex_sc != NULL) + gv_update_plex_state(s->plex_sc); +} + +/* Update the state of a plex based on its environment. */ +void +gv_update_plex_state(struct gv_plex *p) +{ + int sdstates; + + KASSERT(p != NULL, ("gv_update_plex_state: NULL p")); + + /* First, check the state of our subdisks. */ + sdstates = gv_sdstatemap(p); + + /* If all subdisks are up, our plex can be up, too. */ + if (sdstates == GV_SD_UPSTATE) + p->state = GV_PLEX_UP; + + /* One or more of our subdisks are down. */ + else if (sdstates & GV_SD_DOWNSTATE) { + /* A RAID5 plex can handle one dead subdisk. */ + if ((p->org == GV_PLEX_RAID5) && (p->sddown == 1)) + p->state = GV_PLEX_DEGRADED; + else + p->state = GV_PLEX_DOWN; + + /* Some of our subdisks are initializing. */ + } else if (sdstates & GV_SD_INITSTATE) { + if (p->flags & GV_PLEX_SYNCING) + p->state = GV_PLEX_DEGRADED; + else + p->state = GV_PLEX_DOWN; + } else + p->state = GV_PLEX_DOWN; + + printf("FOO: plex %s is %s\n", p->name, gv_plexstate(p->state)); + /* Update our volume, if we have one. */ + if (p->vol_sc != NULL) + gv_update_vol_state(p->vol_sc); +} + +/* Update the volume state based on its plexes. */ +void +gv_update_vol_state(struct gv_volume *v) +{ + struct gv_plex *p; + + KASSERT(v != NULL, ("gv_update_vol_state: NULL v")); + + LIST_FOREACH(p, &v->plexes, in_volume) { + /* One of our plexes is accessible, and so are we. */ + if (p->state > GV_PLEX_DEGRADED) { + v->state = GV_VOL_UP; + return; + } + } + + /* Not one of our plexes is up, so we can't be either. */ + v->state = GV_VOL_DOWN; +} + +/* Return a state map for the subdisks of a plex. */ +int +gv_sdstatemap(struct gv_plex *p) +{ + struct gv_sd *s; + int statemap; + + KASSERT(p != NULL, ("gv_sdstatemap: NULL p")); + + statemap = 0; + p->sddown = 0; /* No subdisks down yet. */ + + LIST_FOREACH(s, &p->subdisks, in_plex) { + switch (s->state) { + case GV_SD_DOWN: + case GV_SD_STALE: + statemap |= GV_SD_DOWNSTATE; + p->sddown++; /* Another unusable subdisk. */ + break; + + case GV_SD_UP: + statemap |= GV_SD_UPSTATE; + break; + + case GV_SD_INITIALIZING: + statemap |= GV_SD_INITSTATE; + break; + + case GV_SD_REVIVING: + statemap |= GV_SD_INITSTATE; + p->sddown++; /* XXX: Another unusable subdisk? */ + break; + } + } + return (statemap); +} |