geom_vinum_state.c revision 135434
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 135434 2004-09-18 18:03:20Z 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 be brought up only if it's part 142 * of a concat or striped plex that's the only one in a 143 * volume, or if the subdisk isn't attached to a plex. 144 * Otherwise it needs to be revived or initialized 145 * first. 146 */ 147 p = s->plex_sc; 148 if (p == NULL) 149 break; 150 151 if ((p->org != GV_PLEX_RAID5) && 152 (p->vol_sc->plexcount == 1)) 153 break; 154 else 155 return (-1); 156 157 default: 158 return (-1); 159 } 160 break; 161 162 /* Other state transitions are only possible with force. */ 163 default: 164 if (!(flags & GV_SETSTATE_FORCE)) 165 return (-1); 166 } 167 168 /* We can change the state and do it. */ 169 if (status == 0) 170 s->state = newstate; 171 172 /* Update our plex, if we're attached to one. */ 173 if (s->plex_sc != NULL) 174 gv_update_plex_state(s->plex_sc); 175 176 /* Save the config back to disk. */ 177 if (flags & GV_SETSTATE_CONFIG) 178 gv_save_config_all(s->vinumconf); 179 180 return (status); 181} 182 183 184/* Update the state of a subdisk based on its environment. */ 185void 186gv_update_sd_state(struct gv_sd *s) 187{ 188 struct gv_drive *d; 189 190 KASSERT(s != NULL, ("gv_update_sd_state: NULL s")); 191 d = s->drive_sc; 192 KASSERT(d != NULL, ("gv_update_sd_state: NULL d")); 193 194 /* If our drive isn't up we cannot be up either. */ 195 if (d->state != GV_DRIVE_UP) 196 s->state = GV_SD_DOWN; 197 /* If this subdisk was just created, we assume it is good.*/ 198 else if (s->flags & GV_SD_NEWBORN) { 199 s->state = GV_SD_UP; 200 s->flags &= ~GV_SD_NEWBORN; 201 } else if (s->state != GV_SD_UP) 202 s->state = GV_SD_STALE; 203 else 204 s->state = GV_SD_UP; 205 206 printf("GEOM_VINUM: subdisk %s is %s\n", s->name, gv_sdstate(s->state)); 207 /* Update the plex, if we have one. */ 208 if (s->plex_sc != NULL) 209 gv_update_plex_state(s->plex_sc); 210} 211 212/* Update the state of a plex based on its environment. */ 213void 214gv_update_plex_state(struct gv_plex *p) 215{ 216 int sdstates; 217 218 KASSERT(p != NULL, ("gv_update_plex_state: NULL p")); 219 220 /* First, check the state of our subdisks. */ 221 sdstates = gv_sdstatemap(p); 222 223 /* If all subdisks are up, our plex can be up, too. */ 224 if (sdstates == GV_SD_UPSTATE) 225 p->state = GV_PLEX_UP; 226 227 /* One or more of our subdisks are down. */ 228 else if (sdstates & GV_SD_DOWNSTATE) { 229 /* A RAID5 plex can handle one dead subdisk. */ 230 if ((p->org == GV_PLEX_RAID5) && (p->sddown == 1)) 231 p->state = GV_PLEX_DEGRADED; 232 else 233 p->state = GV_PLEX_DOWN; 234 235 /* Some of our subdisks are initializing. */ 236 } else if (sdstates & GV_SD_INITSTATE) { 237 if (p->flags & GV_PLEX_SYNCING) 238 p->state = GV_PLEX_DEGRADED; 239 else 240 p->state = GV_PLEX_DOWN; 241 } else 242 p->state = GV_PLEX_DOWN; 243 244 printf("GEOM_VINUM: plex %s is %s\n", p->name, gv_plexstate(p->state)); 245 /* Update our volume, if we have one. */ 246 if (p->vol_sc != NULL) 247 gv_update_vol_state(p->vol_sc); 248} 249 250/* Update the volume state based on its plexes. */ 251void 252gv_update_vol_state(struct gv_volume *v) 253{ 254 struct gv_plex *p; 255 256 KASSERT(v != NULL, ("gv_update_vol_state: NULL v")); 257 258 LIST_FOREACH(p, &v->plexes, in_volume) { 259 /* One of our plexes is accessible, and so are we. */ 260 if (p->state > GV_PLEX_DEGRADED) { 261 v->state = GV_VOL_UP; 262 return; 263 264 /* We can handle a RAID5 plex with one dead subdisk as well. */ 265 } else if ((p->org == GV_PLEX_RAID5) && 266 (p->state == GV_PLEX_DEGRADED)) { 267 v->state = GV_VOL_UP; 268 return; 269 } 270 } 271 272 /* Not one of our plexes is up, so we can't be either. */ 273 v->state = GV_VOL_DOWN; 274} 275 276/* Return a state map for the subdisks of a plex. */ 277int 278gv_sdstatemap(struct gv_plex *p) 279{ 280 struct gv_sd *s; 281 int statemap; 282 283 KASSERT(p != NULL, ("gv_sdstatemap: NULL p")); 284 285 statemap = 0; 286 p->sddown = 0; /* No subdisks down yet. */ 287 288 LIST_FOREACH(s, &p->subdisks, in_plex) { 289 switch (s->state) { 290 case GV_SD_DOWN: 291 case GV_SD_STALE: 292 statemap |= GV_SD_DOWNSTATE; 293 p->sddown++; /* Another unusable subdisk. */ 294 break; 295 296 case GV_SD_UP: 297 statemap |= GV_SD_UPSTATE; 298 break; 299 300 case GV_SD_INITIALIZING: 301 statemap |= GV_SD_INITSTATE; 302 break; 303 304 case GV_SD_REVIVING: 305 statemap |= GV_SD_INITSTATE; 306 p->sddown++; /* XXX: Another unusable subdisk? */ 307 break; 308 } 309 } 310 return (statemap); 311} 312