1 /*- 2 * Copyright (c) 2004, 2007 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$"); 29 30 #include <sys/libkern.h> 31 #include <sys/malloc.h> 32 33 #include <geom/geom.h> 34 #include <geom/vinum/geom_vinum_var.h> 35 #include <geom/vinum/geom_vinum.h> 36 #include <geom/vinum/geom_vinum_share.h> 37 38 void 39 gv_setstate(struct g_geom *gp, struct gctl_req *req) 40 { 41 struct gv_softc *sc; 42 struct gv_sd *s; 43 struct gv_drive *d; 44 struct gv_volume *v; 45 struct gv_plex *p; 46 char *obj, *state; 47 int f, *flags, type; 48 49 f = 0; 50 obj = gctl_get_param(req, "object", NULL); 51 if (obj == NULL) { 52 gctl_error(req, "no object given"); 53 return; 54 } 55 56 state = gctl_get_param(req, "state", NULL); 57 if (state == NULL) { 58 gctl_error(req, "no state given"); 59 return; 60 } 61 62 flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 63 if (flags == NULL) { 64 gctl_error(req, "no flags given"); 65 return; 66 } 67 68 if (*flags & GV_FLAG_F) 69 f = GV_SETSTATE_FORCE; 70 71 sc = gp->softc; 72 type = gv_object_type(sc, obj); 73 switch (type) { 74 case GV_TYPE_VOL: 75 if (gv_volstatei(state) < 0) { 76 gctl_error(req, "invalid volume state '%s'", state); 77 break; 78 } 79 v = gv_find_vol(sc, obj); 80 gv_post_event(sc, GV_EVENT_SET_VOL_STATE, v, NULL, 81 gv_volstatei(state), f); 82 break; 83 84 case GV_TYPE_PLEX: 85 if (gv_plexstatei(state) < 0) { 86 gctl_error(req, "invalid plex state '%s'", state); 87 break; 88 } 89 p = gv_find_plex(sc, obj); 90 gv_post_event(sc, GV_EVENT_SET_PLEX_STATE, p, NULL, 91 gv_plexstatei(state), f); 92 break; 93 94 case GV_TYPE_SD: 95 if (gv_sdstatei(state) < 0) { 96 gctl_error(req, "invalid subdisk state '%s'", state); 97 break; 98 } 99 s = gv_find_sd(sc, obj); 100 gv_post_event(sc, GV_EVENT_SET_SD_STATE, s, NULL, 101 gv_sdstatei(state), f); 102 break; 103 104 case GV_TYPE_DRIVE: 105 if (gv_drivestatei(state) < 0) { 106 gctl_error(req, "invalid drive state '%s'", state); 107 break; 108 } 109 d = gv_find_drive(sc, obj); 110 gv_post_event(sc, GV_EVENT_SET_DRIVE_STATE, d, NULL, 111 gv_drivestatei(state), f); 112 break; 113 114 default: 115 gctl_error(req, "unknown object '%s'", obj); 116 break; 117 } 118 } 119 120 /* Update drive state; return 0 if the state changes, otherwise error. */ 121 int 122 gv_set_drive_state(struct gv_drive *d, int newstate, int flags) 123 { 124 struct gv_sd *s; 125 int oldstate; 126 127 KASSERT(d != NULL, ("gv_set_drive_state: NULL d")); 128 129 oldstate = d->state; 130 131 if (newstate == oldstate) 132 return (0); 133 134 /* We allow to take down an open drive only with force. */ 135 if ((newstate == GV_DRIVE_DOWN) && gv_consumer_is_open(d->consumer) && 136 (!(flags & GV_SETSTATE_FORCE))) 137 return (GV_ERR_ISBUSY); 138 139 d->state = newstate; 140 141 if (d->state != oldstate) { 142 LIST_FOREACH(s, &d->subdisks, from_drive) 143 gv_update_sd_state(s); 144 } 145 146 /* Save the config back to disk. */ 147 if (flags & GV_SETSTATE_CONFIG) 148 gv_save_config(d->vinumconf); 149 150 return (0); 151 } 152 153 int 154 gv_set_sd_state(struct gv_sd *s, int newstate, int flags) 155 { 156 struct gv_drive *d; 157 struct gv_plex *p; 158 int oldstate, status; 159 160 KASSERT(s != NULL, ("gv_set_sd_state: NULL s")); 161 162 oldstate = s->state; 163 164 /* We are optimistic and assume it will work. */ 165 status = 0; 166 167 if (newstate == oldstate) 168 return (0); 169 170 switch (newstate) { 171 case GV_SD_DOWN: 172 /* 173 * If we're attached to a plex, we won't go down without use of 174 * force. 175 */ 176 if ((s->plex_sc != NULL) && !(flags & GV_SETSTATE_FORCE)) 177 return (GV_ERR_ISATTACHED); 178 break; 179 180 case GV_SD_REVIVING: 181 case GV_SD_INITIALIZING: 182 /* 183 * Only do this if we're forced, since it usually is done 184 * internally, and then we do use the force flag. 185 */ 186 if (!flags & GV_SETSTATE_FORCE) 187 return (GV_ERR_SETSTATE); 188 break; 189 190 case GV_SD_UP: 191 /* We can't bring the subdisk up if our drive is dead. */ 192 d = s->drive_sc; 193 if ((d == NULL) || (d->state != GV_DRIVE_UP)) 194 return (GV_ERR_SETSTATE); 195 196 /* Check from where we want to be brought up. */ 197 switch (s->state) { 198 case GV_SD_REVIVING: 199 case GV_SD_INITIALIZING: 200 /* 201 * The subdisk was initializing. We allow it to be 202 * brought up. 203 */ 204 break; 205 206 case GV_SD_DOWN: 207 /* 208 * The subdisk is currently down. We allow it to be 209 * brought up if it is not attached to a plex. 210 */ 211 p = s->plex_sc; 212 if (p == NULL) 213 break; 214 215 /* 216 * If this subdisk is attached to a plex, we allow it 217 * to be brought up if the plex if it's not a RAID5 218 * plex, otherwise it's made 'stale'. 219 */ 220 221 if (p->org != GV_PLEX_RAID5) 222 break; 223 else if (s->flags & GV_SD_CANGOUP) { 224 s->flags &= ~GV_SD_CANGOUP; 225 break; 226 } else if (flags & GV_SETSTATE_FORCE) 227 break; 228 else 229 s->state = GV_SD_STALE; 230 231 status = GV_ERR_SETSTATE; 232 break; 233 234 case GV_SD_STALE: 235 /* 236 * A stale subdisk can be brought up only if it's part 237 * of a concat or striped plex that's the only one in a 238 * volume, or if the subdisk isn't attached to a plex. 239 * Otherwise it needs to be revived or initialized 240 * first. 241 */ 242 p = s->plex_sc; 243 if (p == NULL || flags & GV_SETSTATE_FORCE) 244 break; 245 246 if ((p->org != GV_PLEX_RAID5 && 247 p->vol_sc->plexcount == 1) || 248 (p->flags & GV_PLEX_SYNCING && 249 p->synced > 0 && 250 p->org == GV_PLEX_RAID5)) 251 break; 252 else 253 return (GV_ERR_SETSTATE); 254 255 default: 256 return (GV_ERR_INVSTATE); 257 } 258 break; 259 260 /* Other state transitions are only possible with force. */ 261 default: 262 if (!(flags & GV_SETSTATE_FORCE)) 263 return (GV_ERR_SETSTATE); 264 } 265 266 /* We can change the state and do it. */ 267 if (status == 0) 268 s->state = newstate; 269 270 /* Update our plex, if we're attached to one. */ 271 if (s->plex_sc != NULL) 272 gv_update_plex_state(s->plex_sc); 273 274 /* Save the config back to disk. */ 275 if (flags & GV_SETSTATE_CONFIG) 276 gv_save_config(s->vinumconf); 277 278 return (status); 279 } 280 281 int 282 gv_set_plex_state(struct gv_plex *p, int newstate, int flags) 283 { 284 struct gv_volume *v; 285 int oldstate, plexdown; 286 287 KASSERT(p != NULL, ("gv_set_plex_state: NULL p")); 288 289 oldstate = p->state; 290 v = p->vol_sc; 291 plexdown = 0; 292 293 if (newstate == oldstate) 294 return (0); 295 296 switch (newstate) { 297 case GV_PLEX_UP: 298 /* Let update_plex handle if the plex can come up */ 299 gv_update_plex_state(p); 300 if (p->state != GV_PLEX_UP && !(flags & GV_SETSTATE_FORCE)) 301 return (GV_ERR_SETSTATE); 302 p->state = newstate; 303 break; 304 case GV_PLEX_DOWN: 305 /* 306 * Set state to GV_PLEX_DOWN only if no-one is using the plex, 307 * or if the state is forced. 308 */ 309 if (v != NULL) { 310 /* If the only one up, force is needed. */ 311 plexdown = gv_plexdown(v); 312 if ((v->plexcount == 1 || 313 (v->plexcount - plexdown == 1)) && 314 ((flags & GV_SETSTATE_FORCE) == 0)) 315 return (GV_ERR_SETSTATE); 316 } 317 p->state = newstate; 318 break; 319 case GV_PLEX_DEGRADED: 320 /* Only used internally, so we have to be forced. */ 321 if (flags & GV_SETSTATE_FORCE) 322 p->state = newstate; 323 break; 324 } 325 326 /* Update our volume if we have one. */ 327 if (v != NULL) 328 gv_update_vol_state(v); 329 330 /* Save config. */ 331 if (flags & GV_SETSTATE_CONFIG) 332 gv_save_config(p->vinumconf); 333 return (0); 334 } 335 336 int 337 gv_set_vol_state(struct gv_volume *v, int newstate, int flags) 338 { 339 int oldstate; 340 341 KASSERT(v != NULL, ("gv_set_vol_state: NULL v")); 342 343 oldstate = v->state; 344 345 if (newstate == oldstate) 346 return (0); 347 348 switch (newstate) { 349 case GV_VOL_UP: 350 /* Let update handle if the volume can come up. */ 351 gv_update_vol_state(v); 352 if (v->state != GV_VOL_UP && !(flags & GV_SETSTATE_FORCE)) 353 return (GV_ERR_SETSTATE); 354 v->state = newstate; 355 break; 356 case GV_VOL_DOWN: 357 /* 358 * Set state to GV_VOL_DOWN only if no-one is using the volume, 359 * or if the state should be forced. 360 */ 361 if (!gv_provider_is_open(v->provider) && 362 !(flags & GV_SETSTATE_FORCE)) 363 return (GV_ERR_ISBUSY); 364 v->state = newstate; 365 break; 366 } 367 /* Save config */ 368 if (flags & GV_SETSTATE_CONFIG) 369 gv_save_config(v->vinumconf); 370 return (0); 371 } 372 373 /* Update the state of a subdisk based on its environment. */ 374 void 375 gv_update_sd_state(struct gv_sd *s) 376 { 377 struct gv_drive *d; 378 int oldstate; 379 380 KASSERT(s != NULL, ("gv_update_sd_state: NULL s")); 381 d = s->drive_sc; 382 KASSERT(d != NULL, ("gv_update_sd_state: NULL d")); 383 384 oldstate = s->state; 385 386 /* If our drive isn't up we cannot be up either. */ 387 if (d->state != GV_DRIVE_UP) { 388 s->state = GV_SD_DOWN; 389 /* If this subdisk was just created, we assume it is good.*/ 390 } else if (s->flags & GV_SD_NEWBORN) { 391 s->state = GV_SD_UP; 392 s->flags &= ~GV_SD_NEWBORN; 393 } else if (s->state != GV_SD_UP) { 394 if (s->flags & GV_SD_CANGOUP) { 395 s->state = GV_SD_UP; 396 s->flags &= ~GV_SD_CANGOUP; 397 } else 398 s->state = GV_SD_STALE; 399 } else 400 s->state = GV_SD_UP; 401 402 if (s->state != oldstate) 403 G_VINUM_DEBUG(1, "subdisk %s state change: %s -> %s", s->name, 404 gv_sdstate(oldstate), gv_sdstate(s->state)); 405 406 /* Update the plex, if we have one. */ 407 if (s->plex_sc != NULL) 408 gv_update_plex_state(s->plex_sc); 409 } 410 411 /* Update the state of a plex based on its environment. */ 412 void 413 gv_update_plex_state(struct gv_plex *p) 414 { 415 struct gv_sd *s; 416 int sdstates; 417 int oldstate; 418 419 KASSERT(p != NULL, ("gv_update_plex_state: NULL p")); 420 421 oldstate = p->state; 422 423 /* First, check the state of our subdisks. */ 424 sdstates = gv_sdstatemap(p); 425 426 /* If all subdisks are up, our plex can be up, too. */ 427 if (sdstates == GV_SD_UPSTATE) 428 p->state = GV_PLEX_UP; 429 430 /* One or more of our subdisks are down. */ 431 else if (sdstates & GV_SD_DOWNSTATE) { 432 /* A RAID5 plex can handle one dead subdisk. */ 433 if ((p->org == GV_PLEX_RAID5) && (p->sddown == 1)) 434 p->state = GV_PLEX_DEGRADED; 435 else 436 p->state = GV_PLEX_DOWN; 437 438 /* Some of our subdisks are initializing. */ 439 } else if (sdstates & GV_SD_INITSTATE) { 440 441 if (p->flags & GV_PLEX_SYNCING || 442 p->flags & GV_PLEX_REBUILDING) 443 p->state = GV_PLEX_DEGRADED; 444 else 445 p->state = GV_PLEX_DOWN; 446 } else 447 p->state = GV_PLEX_DOWN; 448 449 if (p->state == GV_PLEX_UP) { 450 LIST_FOREACH(s, &p->subdisks, in_plex) { 451 if (s->flags & GV_SD_GROW) { 452 p->state = GV_PLEX_GROWABLE; 453 break; 454 } 455 } 456 } 457 458 if (p->state != oldstate) 459 G_VINUM_DEBUG(1, "plex %s state change: %s -> %s", p->name, 460 gv_plexstate(oldstate), gv_plexstate(p->state)); 461 462 /* Update our volume, if we have one. */ 463 if (p->vol_sc != NULL) 464 gv_update_vol_state(p->vol_sc); 465 } 466 467 /* Update the volume state based on its plexes. */ 468 void 469 gv_update_vol_state(struct gv_volume *v) 470 { 471 struct gv_plex *p; 472 473 KASSERT(v != NULL, ("gv_update_vol_state: NULL v")); 474 475 /* The volume can't be up without plexes. */ 476 if (v->plexcount == 0) { 477 v->state = GV_VOL_DOWN; 478 return; 479 } 480 481 LIST_FOREACH(p, &v->plexes, in_volume) { 482 /* One of our plexes is accessible, and so are we. */ 483 if (p->state > GV_PLEX_DEGRADED) { 484 v->state = GV_VOL_UP; 485 return; 486 487 /* We can handle a RAID5 plex with one dead subdisk as well. */ 488 } else if ((p->org == GV_PLEX_RAID5) && 489 (p->state == GV_PLEX_DEGRADED)) { 490 v->state = GV_VOL_UP; 491 return; 492 } 493 } 494 495 /* Not one of our plexes is up, so we can't be either. */ 496 v->state = GV_VOL_DOWN; 497 } 498 499 /* Return a state map for the subdisks of a plex. */ 500 int 501 gv_sdstatemap(struct gv_plex *p) 502 { 503 struct gv_sd *s; 504 int statemap; 505 506 KASSERT(p != NULL, ("gv_sdstatemap: NULL p")); 507 508 statemap = 0; 509 p->sddown = 0; /* No subdisks down yet. */ 510 511 LIST_FOREACH(s, &p->subdisks, in_plex) { 512 switch (s->state) { 513 case GV_SD_DOWN: 514 case GV_SD_STALE: 515 statemap |= GV_SD_DOWNSTATE; 516 p->sddown++; /* Another unusable subdisk. */ 517 break; 518 519 case GV_SD_UP: 520 statemap |= GV_SD_UPSTATE; 521 break; 522 523 case GV_SD_INITIALIZING: 524 statemap |= GV_SD_INITSTATE; 525 break; 526 527 case GV_SD_REVIVING: 528 statemap |= GV_SD_INITSTATE; 529 p->sddown++; /* XXX: Another unusable subdisk? */ 530 break; 531 } 532 } 533 return (statemap); 534 } 535