2 * Copyright (c) 2004 Lukas Ertl
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/libkern.h>
33 #include <sys/malloc.h>
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>
41 gv_setstate(struct g_geom *gp, struct gctl_req *req)
47 int err, f, *flags, newstate, type;
50 obj = gctl_get_param(req, "object", NULL);
52 gctl_error(req, "no object given");
56 state = gctl_get_param(req, "state", NULL);
58 gctl_error(req, "no state given");
62 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
64 gctl_error(req, "no flags given");
68 if (*flags & GV_FLAG_F)
69 f = GV_SETSTATE_FORCE;
72 type = gv_object_type(sc, obj);
76 gctl_error(req, "volume or plex state cannot be set currently");
80 newstate = gv_sdstatei(state);
82 gctl_error(req, "invalid subdisk state '%s'", state);
85 s = gv_find_sd(sc, obj);
86 err = gv_set_sd_state(s, newstate, f);
88 gctl_error(req, "cannot set subdisk state");
92 newstate = gv_drivestatei(state);
94 gctl_error(req, "invalid drive state '%s'", state);
97 d = gv_find_drive(sc, obj);
98 err = gv_set_drive_state(d, newstate, f);
100 gctl_error(req, "cannot set drive state");
104 gctl_error(req, "unknown object '%s'", obj);
111 /* Update drive state; return 0 if the state changes, otherwise -1. */
113 gv_set_drive_state(struct gv_drive *d, int newstate, int flags)
118 KASSERT(d != NULL, ("gv_set_drive_state: NULL d"));
122 if (newstate == oldstate)
125 /* We allow to take down an open drive only with force. */
126 if ((newstate == GV_DRIVE_DOWN) && gv_is_open(d->geom) &&
127 (!(flags & GV_SETSTATE_FORCE)))
132 if (d->state != oldstate) {
133 LIST_FOREACH(s, &d->subdisks, from_drive)
134 gv_update_sd_state(s);
137 /* Save the config back to disk. */
138 if (flags & GV_SETSTATE_CONFIG)
139 gv_save_config_all(d->vinumconf);
145 gv_set_sd_state(struct gv_sd *s, int newstate, int flags)
149 int oldstate, status;
151 KASSERT(s != NULL, ("gv_set_sd_state: NULL s"));
155 /* We are optimistic and assume it will work. */
158 if (newstate == oldstate)
164 * If we're attached to a plex, we won't go down without use of
167 if ((s->plex_sc != NULL) && !(flags & GV_SETSTATE_FORCE))
172 /* We can't bring the subdisk up if our drive is dead. */
174 if ((d == NULL) || (d->state != GV_DRIVE_UP))
177 /* Check from where we want to be brought up. */
180 case GV_SD_INITIALIZING:
182 * The subdisk was initializing. We allow it to be
189 * The subdisk is currently down. We allow it to be
190 * brought up if it is not attached to a plex.
197 * If this subdisk is attached to a plex, we allow it
198 * to be brought up if the plex if it's not a RAID5
199 * plex, otherwise it's made 'stale'.
202 if (p->org != GV_PLEX_RAID5)
204 else if (flags & GV_SETSTATE_FORCE)
207 s->state = GV_SD_STALE;
214 * A stale subdisk can be brought up only if it's part
215 * of a concat or striped plex that's the only one in a
216 * volume, or if the subdisk isn't attached to a plex.
217 * Otherwise it needs to be revived or initialized
221 if (p == NULL || flags & GV_SETSTATE_FORCE)
224 if ((p->org != GV_PLEX_RAID5) &&
225 (p->vol_sc->plexcount == 1))
235 /* Other state transitions are only possible with force. */
237 if (!(flags & GV_SETSTATE_FORCE))
241 /* We can change the state and do it. */
245 /* Update our plex, if we're attached to one. */
246 if (s->plex_sc != NULL)
247 gv_update_plex_state(s->plex_sc);
249 /* Save the config back to disk. */
250 if (flags & GV_SETSTATE_CONFIG)
251 gv_save_config_all(s->vinumconf);
257 /* Update the state of a subdisk based on its environment. */
259 gv_update_sd_state(struct gv_sd *s)
264 KASSERT(s != NULL, ("gv_update_sd_state: NULL s"));
266 KASSERT(d != NULL, ("gv_update_sd_state: NULL d"));
270 /* If our drive isn't up we cannot be up either. */
271 if (d->state != GV_DRIVE_UP)
272 s->state = GV_SD_DOWN;
273 /* If this subdisk was just created, we assume it is good.*/
274 else if (s->flags & GV_SD_NEWBORN) {
276 s->flags &= ~GV_SD_NEWBORN;
277 } else if (s->state != GV_SD_UP)
278 s->state = GV_SD_STALE;
282 if (s->state != oldstate)
283 printf("GEOM_VINUM: subdisk %s state change: %s -> %s\n",
284 s->name, gv_sdstate(oldstate), gv_sdstate(s->state));
286 /* Update the plex, if we have one. */
287 if (s->plex_sc != NULL)
288 gv_update_plex_state(s->plex_sc);
291 /* Update the state of a plex based on its environment. */
293 gv_update_plex_state(struct gv_plex *p)
298 KASSERT(p != NULL, ("gv_update_plex_state: NULL p"));
302 /* First, check the state of our subdisks. */
303 sdstates = gv_sdstatemap(p);
305 /* If all subdisks are up, our plex can be up, too. */
306 if (sdstates == GV_SD_UPSTATE)
307 p->state = GV_PLEX_UP;
309 /* One or more of our subdisks are down. */
310 else if (sdstates & GV_SD_DOWNSTATE) {
311 /* A RAID5 plex can handle one dead subdisk. */
312 if ((p->org == GV_PLEX_RAID5) && (p->sddown == 1))
313 p->state = GV_PLEX_DEGRADED;
315 p->state = GV_PLEX_DOWN;
317 /* Some of our subdisks are initializing. */
318 } else if (sdstates & GV_SD_INITSTATE) {
319 if (p->flags & GV_PLEX_SYNCING)
320 p->state = GV_PLEX_DEGRADED;
322 p->state = GV_PLEX_DOWN;
324 p->state = GV_PLEX_DOWN;
326 if (p->state != oldstate)
327 printf("GEOM_VINUM: plex %s state change: %s -> %s\n", p->name,
328 gv_plexstate(oldstate), gv_plexstate(p->state));
330 /* Update our volume, if we have one. */
331 if (p->vol_sc != NULL)
332 gv_update_vol_state(p->vol_sc);
335 /* Update the volume state based on its plexes. */
337 gv_update_vol_state(struct gv_volume *v)
341 KASSERT(v != NULL, ("gv_update_vol_state: NULL v"));
343 /* The volume can't be up without plexes. */
344 if (v->plexcount == 0) {
345 v->state = GV_VOL_DOWN;
349 LIST_FOREACH(p, &v->plexes, in_volume) {
350 /* One of our plexes is accessible, and so are we. */
351 if (p->state > GV_PLEX_DEGRADED) {
352 v->state = GV_VOL_UP;
355 /* We can handle a RAID5 plex with one dead subdisk as well. */
356 } else if ((p->org == GV_PLEX_RAID5) &&
357 (p->state == GV_PLEX_DEGRADED)) {
358 v->state = GV_VOL_UP;
363 /* Not one of our plexes is up, so we can't be either. */
364 v->state = GV_VOL_DOWN;
367 /* Return a state map for the subdisks of a plex. */
369 gv_sdstatemap(struct gv_plex *p)
374 KASSERT(p != NULL, ("gv_sdstatemap: NULL p"));
377 p->sddown = 0; /* No subdisks down yet. */
379 LIST_FOREACH(s, &p->subdisks, in_plex) {
383 statemap |= GV_SD_DOWNSTATE;
384 p->sddown++; /* Another unusable subdisk. */
388 statemap |= GV_SD_UPSTATE;
391 case GV_SD_INITIALIZING:
392 statemap |= GV_SD_INITSTATE;
396 statemap |= GV_SD_INITSTATE;
397 p->sddown++; /* XXX: Another unusable subdisk? */