2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2004, 2007 Lukas Ertl
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/libkern.h>
33 #include <sys/malloc.h>
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>
42 gv_setstate(struct g_geom *gp, struct gctl_req *req)
53 obj = gctl_get_param(req, "object", NULL);
55 gctl_error(req, "no object given");
59 state = gctl_get_param(req, "state", NULL);
61 gctl_error(req, "no state given");
65 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
67 gctl_error(req, "no flags given");
71 if (*flags & GV_FLAG_F)
72 f = GV_SETSTATE_FORCE;
75 type = gv_object_type(sc, obj);
78 if (gv_volstatei(state) < 0) {
79 gctl_error(req, "invalid volume state '%s'", state);
82 v = gv_find_vol(sc, obj);
83 gv_post_event(sc, GV_EVENT_SET_VOL_STATE, v, NULL,
84 gv_volstatei(state), f);
88 if (gv_plexstatei(state) < 0) {
89 gctl_error(req, "invalid plex state '%s'", state);
92 p = gv_find_plex(sc, obj);
93 gv_post_event(sc, GV_EVENT_SET_PLEX_STATE, p, NULL,
94 gv_plexstatei(state), f);
98 if (gv_sdstatei(state) < 0) {
99 gctl_error(req, "invalid subdisk state '%s'", state);
102 s = gv_find_sd(sc, obj);
103 gv_post_event(sc, GV_EVENT_SET_SD_STATE, s, NULL,
104 gv_sdstatei(state), f);
108 if (gv_drivestatei(state) < 0) {
109 gctl_error(req, "invalid drive state '%s'", state);
112 d = gv_find_drive(sc, obj);
113 gv_post_event(sc, GV_EVENT_SET_DRIVE_STATE, d, NULL,
114 gv_drivestatei(state), f);
118 gctl_error(req, "unknown object '%s'", obj);
123 /* Update drive state; return 0 if the state changes, otherwise error. */
125 gv_set_drive_state(struct gv_drive *d, int newstate, int flags)
130 KASSERT(d != NULL, ("gv_set_drive_state: NULL d"));
134 if (newstate == oldstate)
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);
144 if (d->state != oldstate) {
145 LIST_FOREACH(s, &d->subdisks, from_drive)
146 gv_update_sd_state(s);
149 /* Save the config back to disk. */
150 if (flags & GV_SETSTATE_CONFIG)
151 gv_save_config(d->vinumconf);
157 gv_set_sd_state(struct gv_sd *s, int newstate, int flags)
161 int oldstate, status;
163 KASSERT(s != NULL, ("gv_set_sd_state: NULL s"));
167 /* We are optimistic and assume it will work. */
170 if (newstate == oldstate)
176 * If we're attached to a plex, we won't go down without use of
179 if ((s->plex_sc != NULL) && !(flags & GV_SETSTATE_FORCE))
180 return (GV_ERR_ISATTACHED);
184 case GV_SD_INITIALIZING:
186 * Only do this if we're forced, since it usually is done
187 * internally, and then we do use the force flag.
189 if (!(flags & GV_SETSTATE_FORCE))
190 return (GV_ERR_SETSTATE);
194 /* We can't bring the subdisk up if our drive is dead. */
196 if ((d == NULL) || (d->state != GV_DRIVE_UP))
197 return (GV_ERR_SETSTATE);
199 /* Check from where we want to be brought up. */
202 case GV_SD_INITIALIZING:
204 * The subdisk was initializing. We allow it to be
211 * The subdisk is currently down. We allow it to be
212 * brought up if it is not attached to a plex.
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'.
224 if (p->org != GV_PLEX_RAID5)
226 else if (s->flags & GV_SD_CANGOUP) {
227 s->flags &= ~GV_SD_CANGOUP;
229 } else if (flags & GV_SETSTATE_FORCE)
232 s->state = GV_SD_STALE;
234 status = GV_ERR_SETSTATE;
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
246 if (p == NULL || flags & GV_SETSTATE_FORCE)
249 if ((p->org != GV_PLEX_RAID5 &&
250 p->vol_sc->plexcount == 1) ||
251 (p->flags & GV_PLEX_SYNCING &&
253 p->org == GV_PLEX_RAID5))
256 return (GV_ERR_SETSTATE);
259 return (GV_ERR_INVSTATE);
263 /* Other state transitions are only possible with force. */
265 if (!(flags & GV_SETSTATE_FORCE))
266 return (GV_ERR_SETSTATE);
269 /* We can change the state and do it. */
273 /* Update our plex, if we're attached to one. */
274 if (s->plex_sc != NULL)
275 gv_update_plex_state(s->plex_sc);
277 /* Save the config back to disk. */
278 if (flags & GV_SETSTATE_CONFIG)
279 gv_save_config(s->vinumconf);
285 gv_set_plex_state(struct gv_plex *p, int newstate, int flags)
288 int oldstate, plexdown;
290 KASSERT(p != NULL, ("gv_set_plex_state: NULL p"));
296 if (newstate == oldstate)
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);
309 * Set state to GV_PLEX_DOWN only if no-one is using the plex,
310 * or if the state is forced.
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);
322 case GV_PLEX_DEGRADED:
323 /* Only used internally, so we have to be forced. */
324 if (flags & GV_SETSTATE_FORCE)
329 /* Update our volume if we have one. */
331 gv_update_vol_state(v);
334 if (flags & GV_SETSTATE_CONFIG)
335 gv_save_config(p->vinumconf);
340 gv_set_vol_state(struct gv_volume *v, int newstate, int flags)
344 KASSERT(v != NULL, ("gv_set_vol_state: NULL v"));
348 if (newstate == oldstate)
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);
361 * Set state to GV_VOL_DOWN only if no-one is using the volume,
362 * or if the state should be forced.
364 if (!gv_provider_is_open(v->provider) &&
365 !(flags & GV_SETSTATE_FORCE))
366 return (GV_ERR_ISBUSY);
371 if (flags & GV_SETSTATE_CONFIG)
372 gv_save_config(v->vinumconf);
376 /* Update the state of a subdisk based on its environment. */
378 gv_update_sd_state(struct gv_sd *s)
383 KASSERT(s != NULL, ("gv_update_sd_state: NULL s"));
385 KASSERT(d != NULL, ("gv_update_sd_state: NULL d"));
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) {
395 s->flags &= ~GV_SD_NEWBORN;
396 } else if (s->state != GV_SD_UP) {
397 if (s->flags & GV_SD_CANGOUP) {
399 s->flags &= ~GV_SD_CANGOUP;
401 s->state = GV_SD_STALE;
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));
409 /* Update the plex, if we have one. */
410 if (s->plex_sc != NULL)
411 gv_update_plex_state(s->plex_sc);
414 /* Update the state of a plex based on its environment. */
416 gv_update_plex_state(struct gv_plex *p)
422 KASSERT(p != NULL, ("gv_update_plex_state: NULL p"));
426 /* First, check the state of our subdisks. */
427 sdstates = gv_sdstatemap(p);
429 /* If all subdisks are up, our plex can be up, too. */
430 if (sdstates == GV_SD_UPSTATE)
431 p->state = GV_PLEX_UP;
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;
439 p->state = GV_PLEX_DOWN;
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;
447 p->state = GV_PLEX_DOWN;
449 p->state = GV_PLEX_DOWN;
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;
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));
464 /* Update our volume, if we have one. */
465 if (p->vol_sc != NULL)
466 gv_update_vol_state(p->vol_sc);
469 /* Update the volume state based on its plexes. */
471 gv_update_vol_state(struct gv_volume *v)
475 KASSERT(v != NULL, ("gv_update_vol_state: NULL v"));
477 /* The volume can't be up without plexes. */
478 if (v->plexcount == 0) {
479 v->state = GV_VOL_DOWN;
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;
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;
497 /* Not one of our plexes is up, so we can't be either. */
498 v->state = GV_VOL_DOWN;
501 /* Return a state map for the subdisks of a plex. */
503 gv_sdstatemap(struct gv_plex *p)
508 KASSERT(p != NULL, ("gv_sdstatemap: NULL p"));
511 p->sddown = 0; /* No subdisks down yet. */
513 LIST_FOREACH(s, &p->subdisks, in_plex) {
517 statemap |= GV_SD_DOWNSTATE;
518 p->sddown++; /* Another unusable subdisk. */
522 statemap |= GV_SD_UPSTATE;
525 case GV_SD_INITIALIZING:
526 statemap |= GV_SD_INITSTATE;
530 statemap |= GV_SD_INITSTATE;
531 p->sddown++; /* XXX: Another unusable subdisk? */