geom_vinum_state.c revision 135162
1/*- 2 * Copyright (c) 2004 Lukas Ertl 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/geom/vinum/geom_vinum_state.c 135162 2004-09-13 17:33:52Z le $"); 29 30#include <sys/param.h> 31#include <sys/kernel.h> 32#include <sys/libkern.h> 33#include <sys/malloc.h> 34 35#include <geom/geom.h> 36#include <geom/vinum/geom_vinum_var.h> 37#include <geom/vinum/geom_vinum.h> 38#include <geom/vinum/geom_vinum_share.h> 39 40/* Update drive state; return 1 if the state changes, otherwise 0. */ 41int 42gv_set_drive_state(struct gv_drive *d, int newstate, int flags) 43{ 44 struct gv_sd *s; 45 int oldstate; 46 47 KASSERT(d != NULL, ("gv_set_drive_state: NULL d")); 48 49 oldstate = d->state; 50 51 if (newstate == oldstate) 52 return (1); 53 54 /* We allow to take down an open drive only with force. */ 55 if ((newstate == GV_DRIVE_DOWN) && gv_is_open(d->geom) && 56 (!(flags & GV_SETSTATE_FORCE))) 57 return (0); 58 59 d->state = newstate; 60 61 if (d->state != oldstate) { 62 LIST_FOREACH(s, &d->subdisks, from_drive) 63 gv_update_sd_state(s); 64 } 65 66 /* Save the config back to disk. */ 67 if (flags & GV_SETSTATE_CONFIG) 68 gv_save_config_all(d->vinumconf); 69 70 return (1); 71} 72 73int 74gv_set_sd_state(struct gv_sd *s, int newstate, int flags) 75{ 76 struct gv_drive *d; 77 struct gv_plex *p; 78 int oldstate, status; 79 80 KASSERT(s != NULL, ("gv_set_sd_state: NULL s")); 81 82 oldstate = s->state; 83 84 /* We are optimistic and assume it will work. */ 85 status = 0; 86 87 if (newstate == oldstate) 88 return (0); 89 90 switch (newstate) { 91 case GV_SD_DOWN: 92 /* 93 * If we're attached to a plex, we won't go down without use of 94 * force. 95 */ 96 if ((s->plex_sc != NULL) && !(flags & GV_SETSTATE_FORCE)) 97 return (-1); 98 break; 99 100 case GV_SD_UP: 101 /* We can't bring the subdisk up if our drive is dead. */ 102 d = s->drive_sc; 103 if ((d == NULL) || (d->state != GV_DRIVE_UP)) 104 return (-1); 105 106 /* Check from where we want to be brought up. */ 107 switch (s->state) { 108 case GV_SD_REVIVING: 109 case GV_SD_INITIALIZING: 110 /* 111 * The subdisk was initializing. We allow it to be 112 * brought up. 113 */ 114 break; 115 116 case GV_SD_DOWN: 117 /* 118 * The subdisk is currently down. We allow it to be 119 * brought up if it is not attached to a plex. 120 */ 121 p = s->plex_sc; 122 if (p == NULL) 123 break; 124 125 /* 126 * If this subdisk is attached to a plex, we allow it 127 * to be brought up if the plex if it's not a RAID5 128 * plex, otherwise it's made 'stale'. 129 */ 130 131 if (p->org != GV_PLEX_RAID5) 132 break; 133 else 134 s->state = GV_SD_STALE; 135 136 status = -1; 137 break; 138 139 case GV_SD_STALE: 140 /* 141 * A stale subdisk can't be brought up directly, it 142 * needs to be revived or initialized first. 143 */ 144 /* FALLTHROUGH */ 145 default: 146 return (-1); 147 } 148 break; 149 150 /* Other state transitions are only possible with force. */ 151 default: 152 if (!(flags & GV_SETSTATE_FORCE)) 153 return (-1); 154 } 155 156 /* We can change the state and do it. */ 157 if (status == 0) 158 s->state = newstate; 159 160 /* Update our plex, if we're attached to one. */ 161 if (s->plex_sc != NULL) 162 gv_update_plex_state(s->plex_sc); 163 164 /* Save the config back to disk. */ 165 if (flags & GV_SETSTATE_CONFIG) 166 gv_save_config_all(s->vinumconf); 167 168 return (status); 169} 170 171 172/* Update the state of a subdisk based on its environment. */ 173void 174gv_update_sd_state(struct gv_sd *s) 175{ 176 struct gv_drive *d; 177 178 KASSERT(s != NULL, ("gv_update_sd_state: NULL s")); 179 d = s->drive_sc; 180 KASSERT(d != NULL, ("gv_update_sd_state: NULL d")); 181 182 /* If our drive isn't up we cannot be up either. */ 183 if (d->state != GV_DRIVE_UP) 184 s->state = GV_SD_DOWN; 185 /* If this subdisk was just created, we assume it is good.*/ 186 else if (s->flags & GV_SD_NEWBORN) { 187 s->state = GV_SD_UP; 188 s->flags &= ~GV_SD_NEWBORN; 189 } else if (s->state != GV_SD_UP) 190 s->state = GV_SD_STALE; 191 else 192 s->state = GV_SD_UP; 193 194 printf("GEOM_VINUM: subdisk %s is %s\n", s->name, gv_sdstate(s->state)); 195 /* Update the plex, if we have one. */ 196 if (s->plex_sc != NULL) 197 gv_update_plex_state(s->plex_sc); 198} 199 200/* Update the state of a plex based on its environment. */ 201void 202gv_update_plex_state(struct gv_plex *p) 203{ 204 int sdstates; 205 206 KASSERT(p != NULL, ("gv_update_plex_state: NULL p")); 207 208 /* First, check the state of our subdisks. */ 209 sdstates = gv_sdstatemap(p); 210 211 /* If all subdisks are up, our plex can be up, too. */ 212 if (sdstates == GV_SD_UPSTATE) 213 p->state = GV_PLEX_UP; 214 215 /* One or more of our subdisks are down. */ 216 else if (sdstates & GV_SD_DOWNSTATE) { 217 /* A RAID5 plex can handle one dead subdisk. */ 218 if ((p->org == GV_PLEX_RAID5) && (p->sddown == 1)) 219 p->state = GV_PLEX_DEGRADED; 220 else 221 p->state = GV_PLEX_DOWN; 222 223 /* Some of our subdisks are initializing. */ 224 } else if (sdstates & GV_SD_INITSTATE) { 225 if (p->flags & GV_PLEX_SYNCING) 226 p->state = GV_PLEX_DEGRADED; 227 else 228 p->state = GV_PLEX_DOWN; 229 } else 230 p->state = GV_PLEX_DOWN; 231 232 printf("GEOM_VINUM: plex %s is %s\n", p->name, gv_plexstate(p->state)); 233 /* Update our volume, if we have one. */ 234 if (p->vol_sc != NULL) 235 gv_update_vol_state(p->vol_sc); 236} 237 238/* Update the volume state based on its plexes. */ 239void 240gv_update_vol_state(struct gv_volume *v) 241{ 242 struct gv_plex *p; 243 244 KASSERT(v != NULL, ("gv_update_vol_state: NULL v")); 245 246 LIST_FOREACH(p, &v->plexes, in_volume) { 247 /* One of our plexes is accessible, and so are we. */ 248 if (p->state > GV_PLEX_DEGRADED) { 249 v->state = GV_VOL_UP; 250 return; 251 252 /* We can handle a RAID5 plex with one dead subdisk as well. */ 253 } else if ((p->org == GV_PLEX_RAID5) && 254 (p->state == GV_PLEX_DEGRADED)) { 255 v->state = GV_VOL_UP; 256 return; 257 } 258 } 259 260 /* Not one of our plexes is up, so we can't be either. */ 261 v->state = GV_VOL_DOWN; 262} 263 264/* Return a state map for the subdisks of a plex. */ 265int 266gv_sdstatemap(struct gv_plex *p) 267{ 268 struct gv_sd *s; 269 int statemap; 270 271 KASSERT(p != NULL, ("gv_sdstatemap: NULL p")); 272 273 statemap = 0; 274 p->sddown = 0; /* No subdisks down yet. */ 275 276 LIST_FOREACH(s, &p->subdisks, in_plex) { 277 switch (s->state) { 278 case GV_SD_DOWN: 279 case GV_SD_STALE: 280 statemap |= GV_SD_DOWNSTATE; 281 p->sddown++; /* Another unusable subdisk. */ 282 break; 283 284 case GV_SD_UP: 285 statemap |= GV_SD_UPSTATE; 286 break; 287 288 case GV_SD_INITIALIZING: 289 statemap |= GV_SD_INITSTATE; 290 break; 291 292 case GV_SD_REVIVING: 293 statemap |= GV_SD_INITSTATE; 294 p->sddown++; /* XXX: Another unusable subdisk? */ 295 break; 296 } 297 } 298 return (statemap); 299} 300