1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2004, 2007 Lukas Ertl 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 #include <sys/libkern.h> 31 #include <sys/malloc.h> 32 33 #include <geom/geom.h> 34 #include <geom/geom_dbg.h> 35 #include <geom/vinum/geom_vinum_var.h> 36 #include <geom/vinum/geom_vinum.h> 37 #include <geom/vinum/geom_vinum_share.h> 38 39 void 40 gv_setstate(struct g_geom *gp, struct gctl_req *req) 41 { 42 struct gv_softc *sc; 43 struct gv_sd *s; 44 struct gv_drive *d; 45 struct gv_volume *v; 46 struct gv_plex *p; 47 char *obj, *state; 48 int f, *flags, type; 49 50 f = 0; 51 obj = gctl_get_param(req, "object", NULL); 52 if (obj == NULL) { 53 gctl_error(req, "no object given"); 54 return; 55 } 56 57 state = gctl_get_param(req, "state", NULL); 58 if (state == NULL) { 59 gctl_error(req, "no state given"); 60 return; 61 } 62 63 flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 64 if (flags == NULL) { 65 gctl_error(req, "no flags given"); 66 return; 67 } 68 69 if (*flags & GV_FLAG_F) 70 f = GV_SETSTATE_FORCE; 71 72 sc = gp->softc; 73 type = gv_object_type(sc, obj); 74 switch (type) { 75 case GV_TYPE_VOL: 76 if (gv_volstatei(state) < 0) { 77 gctl_error(req, "invalid volume state '%s'", state); 78 break; 79 } 80 v = gv_find_vol(sc, obj); 81 gv_post_event(sc, GV_EVENT_SET_VOL_STATE, v, NULL, 82 gv_volstatei(state), f); 83 break; 84 85 case GV_TYPE_PLEX: 86 if (gv_plexstatei(state) < 0) { 87 gctl_error(req, "invalid plex state '%s'", state); 88 break; 89 } 90 p = gv_find_plex(sc, obj); 91 gv_post_event(sc, GV_EVENT_SET_PLEX_STATE, p, NULL, 92 gv_plexstatei(state), f); 93 break; 94 95 case GV_TYPE_SD: 96 if (gv_sdstatei(state) < 0) { 97 gctl_error(req, "invalid subdisk state '%s'", state); 98 break; 99 } 100 s = gv_find_sd(sc, obj); 101 gv_post_event(sc, GV_EVENT_SET_SD_STATE, s, NULL, 102 gv_sdstatei(state), f); 103 break; 104 105 case GV_TYPE_DRIVE: 106 if (gv_drivestatei(state) < 0) { 107 gctl_error(req, "invalid drive state '%s'", state); 108 break; 109 } 110 d = gv_find_drive(sc, obj); 111 gv_post_event(sc, GV_EVENT_SET_DRIVE_STATE, d, NULL, 112 gv_drivestatei(state), f); 113 break; 114 115 default: 116 gctl_error(req, "unknown object '%s'", obj); 117 break; 118 } 119 } 120 121 /* Update drive state; return 0 if the state changes, otherwise error. */ 122 int 123 gv_set_drive_state(struct gv_drive *d, int newstate, int flags) 124 { 125 struct gv_sd *s; 126 int oldstate; 127 128 KASSERT(d != NULL, ("gv_set_drive_state: NULL d")); 129 130 oldstate = d->state; 131 132 if (newstate == oldstate) 133 return (0); 134 135 /* We allow to take down an open drive only with force. */ 136 if ((newstate == GV_DRIVE_DOWN) && gv_consumer_is_open(d->consumer) && 137 (!(flags & GV_SETSTATE_FORCE))) 138 return (GV_ERR_ISBUSY); 139 140 d->state = newstate; 141 142 if (d->state != oldstate) { 143 LIST_FOREACH(s, &d->subdisks, from_drive) 144 gv_update_sd_state(s); 145 } 146 147 /* Save the config back to disk. */ 148 if (flags & GV_SETSTATE_CONFIG) 149 gv_save_config(d->vinumconf); 150 151 return (0); 152 } 153 154 int 155 gv_set_sd_state(struct gv_sd *s, int newstate, int flags) 156 { 157 struct gv_drive *d; 158 struct gv_plex *p; 159 int oldstate, status; 160 161 KASSERT(s != NULL, ("gv_set_sd_state: NULL s")); 162 163 oldstate = s->state; 164 165 /* We are optimistic and assume it will work. */ 166 status = 0; 167 168 if (newstate == oldstate) 169 return (0); 170 171 switch (newstate) { 172 case GV_SD_DOWN: 173 /* 174 * If we're attached to a plex, we won't go down without use of 175 * force. 176 */ 177 if ((s->plex_sc != NULL) && !(flags & GV_SETSTATE_FORCE)) 178 return (GV_ERR_ISATTACHED); 179 break; 180 181 case GV_SD_REVIVING: 182 case GV_SD_INITIALIZING: 183 /* 184 * Only do this if we're forced, since it usually is done 185 * internally, and then we do use the force flag. 186 */ 187 if (!(flags & GV_SETSTATE_FORCE)) 188 return (GV_ERR_SETSTATE); 189 break; 190 191 case GV_SD_UP: 192 /* We can't bring the subdisk up if our drive is dead. */ 193 d = s->drive_sc; 194 if ((d == NULL) || (d->state != GV_DRIVE_UP)) 195 return (GV_ERR_SETSTATE); 196 197 /* Check from where we want to be brought up. */ 198 switch (s->state) { 199 case GV_SD_REVIVING: 200 case GV_SD_INITIALIZING: 201 /* 202 * The subdisk was initializing. We allow it to be 203 * brought up. 204 */ 205 break; 206 207 case GV_SD_DOWN: 208 /* 209 * The subdisk is currently down. We allow it to be 210 * brought up if it is not attached to a plex. 211 */ 212 p = s->plex_sc; 213 if (p == NULL) 214 break; 215 216 /* 217 * If this subdisk is attached to a plex, we allow it 218 * to be brought up if the plex if it's not a RAID5 219 * plex, otherwise it's made 'stale'. 220 */ 221 222 if (p->org != GV_PLEX_RAID5) 223 break; 224 else if (s->flags & GV_SD_CANGOUP) { 225 s->flags &= ~GV_SD_CANGOUP; 226 break; 227 } else if (flags & GV_SETSTATE_FORCE) 228 break; 229 else 230 s->state = GV_SD_STALE; 231 232 status = GV_ERR_SETSTATE; 233 break; 234 235 case GV_SD_STALE: 236 /* 237 * A stale subdisk can be brought up only if it's part 238 * of a concat or striped plex that's the only one in a 239 * volume, or if the subdisk isn't attached to a plex. 240 * Otherwise it needs to be revived or initialized 241 * first. 242 */ 243 p = s->plex_sc; 244 if (p == NULL || flags & GV_SETSTATE_FORCE) 245 break; 246 247 if ((p->org != GV_PLEX_RAID5 && 248 p->vol_sc->plexcount == 1) || 249 (p->flags & GV_PLEX_SYNCING && 250 p->synced > 0 && 251 p->org == GV_PLEX_RAID5)) 252 break; 253 else 254 return (GV_ERR_SETSTATE); 255 256 default: 257 return (GV_ERR_INVSTATE); 258 } 259 break; 260 261 /* Other state transitions are only possible with force. */ 262 default: 263 if (!(flags & GV_SETSTATE_FORCE)) 264 return (GV_ERR_SETSTATE); 265 } 266 267 /* We can change the state and do it. */ 268 if (status == 0) 269 s->state = newstate; 270 271 /* Update our plex, if we're attached to one. */ 272 if (s->plex_sc != NULL) 273 gv_update_plex_state(s->plex_sc); 274 275 /* Save the config back to disk. */ 276 if (flags & GV_SETSTATE_CONFIG) 277 gv_save_config(s->vinumconf); 278 279 return (status); 280 } 281 282 int 283 gv_set_plex_state(struct gv_plex *p, int newstate, int flags) 284 { 285 struct gv_volume *v; 286 int oldstate, plexdown; 287 288 KASSERT(p != NULL, ("gv_set_plex_state: NULL p")); 289 290 oldstate = p->state; 291 v = p->vol_sc; 292 plexdown = 0; 293 294 if (newstate == oldstate) 295 return (0); 296 297 switch (newstate) { 298 case GV_PLEX_UP: 299 /* Let update_plex handle if the plex can come up */ 300 gv_update_plex_state(p); 301 if (p->state != GV_PLEX_UP && !(flags & GV_SETSTATE_FORCE)) 302 return (GV_ERR_SETSTATE); 303 p->state = newstate; 304 break; 305 case GV_PLEX_DOWN: 306 /* 307 * Set state to GV_PLEX_DOWN only if no-one is using the plex, 308 * or if the state is forced. 309 */ 310 if (v != NULL) { 311 /* If the only one up, force is needed. */ 312 plexdown = gv_plexdown(v); 313 if ((v->plexcount == 1 || 314 (v->plexcount - plexdown == 1)) && 315 ((flags & GV_SETSTATE_FORCE) == 0)) 316 return (GV_ERR_SETSTATE); 317 } 318 p->state = newstate; 319 break; 320 case GV_PLEX_DEGRADED: 321 /* Only used internally, so we have to be forced. */ 322 if (flags & GV_SETSTATE_FORCE) 323 p->state = newstate; 324 break; 325 } 326 327 /* Update our volume if we have one. */ 328 if (v != NULL) 329 gv_update_vol_state(v); 330 331 /* Save config. */ 332 if (flags & GV_SETSTATE_CONFIG) 333 gv_save_config(p->vinumconf); 334 return (0); 335 } 336 337 int 338 gv_set_vol_state(struct gv_volume *v, int newstate, int flags) 339 { 340 int oldstate; 341 342 KASSERT(v != NULL, ("gv_set_vol_state: NULL v")); 343 344 oldstate = v->state; 345 346 if (newstate == oldstate) 347 return (0); 348 349 switch (newstate) { 350 case GV_VOL_UP: 351 /* Let update handle if the volume can come up. */ 352 gv_update_vol_state(v); 353 if (v->state != GV_VOL_UP && !(flags & GV_SETSTATE_FORCE)) 354 return (GV_ERR_SETSTATE); 355 v->state = newstate; 356 break; 357 case GV_VOL_DOWN: 358 /* 359 * Set state to GV_VOL_DOWN only if no-one is using the volume, 360 * or if the state should be forced. 361 */ 362 if (!gv_provider_is_open(v->provider) && 363 !(flags & GV_SETSTATE_FORCE)) 364 return (GV_ERR_ISBUSY); 365 v->state = newstate; 366 break; 367 } 368 /* Save config */ 369 if (flags & GV_SETSTATE_CONFIG) 370 gv_save_config(v->vinumconf); 371 return (0); 372 } 373 374 /* Update the state of a subdisk based on its environment. */ 375 void 376 gv_update_sd_state(struct gv_sd *s) 377 { 378 struct gv_drive *d; 379 int oldstate; 380 381 KASSERT(s != NULL, ("gv_update_sd_state: NULL s")); 382 d = s->drive_sc; 383 KASSERT(d != NULL, ("gv_update_sd_state: NULL d")); 384 385 oldstate = s->state; 386 387 /* If our drive isn't up we cannot be up either. */ 388 if (d->state != GV_DRIVE_UP) { 389 s->state = GV_SD_DOWN; 390 /* If this subdisk was just created, we assume it is good.*/ 391 } else if (s->flags & GV_SD_NEWBORN) { 392 s->state = GV_SD_UP; 393 s->flags &= ~GV_SD_NEWBORN; 394 } else if (s->state != GV_SD_UP) { 395 if (s->flags & GV_SD_CANGOUP) { 396 s->state = GV_SD_UP; 397 s->flags &= ~GV_SD_CANGOUP; 398 } else 399 s->state = GV_SD_STALE; 400 } else 401 s->state = GV_SD_UP; 402 403 if (s->state != oldstate) 404 G_VINUM_DEBUG(1, "subdisk %s state change: %s -> %s", s->name, 405 gv_sdstate(oldstate), gv_sdstate(s->state)); 406 407 /* Update the plex, if we have one. */ 408 if (s->plex_sc != NULL) 409 gv_update_plex_state(s->plex_sc); 410 } 411 412 /* Update the state of a plex based on its environment. */ 413 void 414 gv_update_plex_state(struct gv_plex *p) 415 { 416 struct gv_sd *s; 417 int sdstates; 418 int oldstate; 419 420 KASSERT(p != NULL, ("gv_update_plex_state: NULL p")); 421 422 oldstate = p->state; 423 424 /* First, check the state of our subdisks. */ 425 sdstates = gv_sdstatemap(p); 426 427 /* If all subdisks are up, our plex can be up, too. */ 428 if (sdstates == GV_SD_UPSTATE) 429 p->state = GV_PLEX_UP; 430 431 /* One or more of our subdisks are down. */ 432 else if (sdstates & GV_SD_DOWNSTATE) { 433 /* A RAID5 plex can handle one dead subdisk. */ 434 if ((p->org == GV_PLEX_RAID5) && (p->sddown == 1)) 435 p->state = GV_PLEX_DEGRADED; 436 else 437 p->state = GV_PLEX_DOWN; 438 439 /* Some of our subdisks are initializing. */ 440 } else if (sdstates & GV_SD_INITSTATE) { 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