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: releng/8.3/sys/geom/vinum/geom_vinum_state.c 190507 2009-03-28 17:20:08Z lulf $");
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 }
Cache object: c8e717f068370ee34d7c8713d2617a1b
|