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