1 /*-
2 * Copyright (c) 1997, 1998, 1999
3 * Nan Yang Computer Services Limited. All rights reserved.
4 *
5 * Parts copyright (c) 1997, 1998 Cybernet Corporation, NetMAX project.
6 *
7 * Written by Greg Lehey
8 *
9 * This software is distributed under the so-called ``Berkeley
10 * License'':
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by Nan Yang Computer
23 * Services Limited.
24 * 4. Neither the name of the Company nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * This software is provided ``as is'', and any express or implied
29 * warranties, including, but not limited to, the implied warranties of
30 * merchantability and fitness for a particular purpose are disclaimed.
31 * In no event shall the company or contributors be liable for any
32 * direct, indirect, incidental, special, exemplary, or consequential
33 * damages (including, but not limited to, procurement of substitute
34 * goods or services; loss of use, data, or profits; or business
35 * interruption) however caused and on any theory of liability, whether
36 * in contract, strict liability, or tort (including negligence or
37 * otherwise) arising in any way out of the use of this software, even if
38 * advised of the possibility of such damage.
39 *
40 * $Id: vinumstate.c,v 2.21 2003/04/28 02:54:43 grog Exp $
41 */
42
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 #include <dev/vinum/vinumhdr.h>
47 #include <dev/vinum/request.h>
48
49 /* Update drive state */
50 /* Return 1 if the state changes, otherwise 0 */
51 int
52 set_drive_state(int driveno, enum drivestate newstate, enum setstateflags flags)
53 {
54 struct drive *drive = &DRIVE[driveno];
55 int oldstate = drive->state;
56 int sdno;
57
58 if (drive->state == drive_unallocated) /* no drive to do anything with, */
59 return 0;
60
61 if (newstate == oldstate) /* don't change it if it's not different */
62 return 1; /* all OK */
63 if ((newstate == drive_down) /* the drive's going down */
64 &&(!(flags & setstate_force))
65 && (drive->opencount != 0)) /* we can't do it */
66 return 0; /* don't do it */
67 drive->state = newstate; /* set the state */
68 if (drive->label.name[0] != '\0') /* we have a name, */
69 log(LOG_INFO,
70 "vinum: drive %s is %s\n",
71 drive->label.name,
72 drive_state(drive->state));
73 if (drive->state != oldstate) { /* state has changed */
74 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) { /* find this drive's subdisks */
75 if ((SD[sdno].state >= sd_referenced)
76 && (SD[sdno].driveno == driveno)) /* belongs to this drive */
77 update_sd_state(sdno); /* update the state */
78 }
79 }
80 if (newstate == drive_up) { /* want to bring it up */
81 if ((drive->flags & VF_OPEN) == 0) /* should be open, but we're not */
82 init_drive(drive, 1); /* which changes the state again */
83 } else /* taking it down or worse */
84 queue_daemon_request(daemonrq_closedrive, /* get the daemon to close it */
85 (union daemoninfo) drive);
86 if ((flags & setstate_configuring) == 0) /* configuring? */
87 save_config(); /* no: save the updated configuration now */
88 return 1;
89 }
90
91 /*
92 * Try to set the subdisk state. Return 1 if
93 * state changed to what we wanted, -1 if it
94 * changed to something else, and 0 if no change.
95 *
96 * This routine is called both from the user (up,
97 * down states only) and internally.
98 *
99 * The setstate_force bit in the flags enables the
100 * state change even if it could be dangerous to
101 * data consistency. It shouldn't allow nonsense.
102 */
103 int
104 set_sd_state(int sdno, enum sdstate newstate, enum setstateflags flags)
105 {
106 struct sd *sd = &SD[sdno];
107 struct plex *plex;
108 struct volume *vol;
109 int oldstate = sd->state;
110 int status = 1; /* status to return */
111
112 if (newstate == oldstate) /* already there, */
113 return 1;
114 else if (sd->state == sd_unallocated) /* no subdisk to do anything with, */
115 return 0; /* can't do it */
116
117 if (sd->driveoffset < 0) { /* not allocated space */
118 sd->state = sd_down;
119 if (newstate != sd_down) {
120 if (sd->plexno >= 0)
121 sdstatemap(&PLEX[sd->plexno]); /* count up subdisks */
122 return -1;
123 }
124 } else { /* space allocated */
125 switch (newstate) {
126 case sd_down: /* take it down? */
127 /*
128 * If we're attached to a plex, and we're
129 * not reborn, we won't go down without
130 * use of force.
131 */
132 if ((!flags & setstate_force)
133 && (sd->plexno >= 0)
134 && (sd->state != sd_reborn))
135 return 0; /* don't do it */
136 break;
137
138 case sd_initialized:
139 if ((sd->state == sd_initializing) /* we were initializing */
140 ||(flags & setstate_force)) /* or we forced it */
141 break;
142 return 0; /* can't do it otherwise */
143
144 case sd_up:
145 if (DRIVE[sd->driveno].state != drive_up) /* can't bring the sd up if the drive isn't, */
146 return 0; /* not even by force */
147 if (flags & setstate_force) /* forcing it, */
148 break; /* just do it, and damn the consequences */
149 switch (sd->state) {
150 /*
151 * Perform the necessary tests. To allow
152 * the state transition, just break out of
153 * the switch.
154 */
155 case sd_crashed:
156 case sd_reborn:
157 case sd_down: /* been down, no data lost */
158 /*
159 * If we're associated with a plex, and
160 * the plex isn't up, or we're the only
161 * subdisk in the plex, we can do it.
162 */
163 if ((sd->plexno >= 0)
164 && (((PLEX[sd->plexno].state < plex_firstup)
165 || (PLEX[sd->plexno].subdisks > 1))))
166 break; /* do it */
167 if (oldstate != sd_reborn) {
168 sd->state = sd_reborn; /* here it is again */
169 log(LOG_INFO,
170 "vinum: %s is %s, not %s\n",
171 sd->name,
172 sd_state(sd->state),
173 sd_state(newstate));
174 }
175 status = -1;
176 break;
177
178 case sd_init: /* brand new */
179 if (flags & setstate_configuring) /* we're doing this while configuring */
180 break;
181 /* otherwise it's like being empty */
182 /* FALLTHROUGH */
183
184 case sd_empty:
185 case sd_initialized:
186 /*
187 * If we're not part of a plex, or the
188 * plex is not part of a volume with other
189 * plexes which are up, we can come up
190 * without being inconsistent.
191 *
192 * If we're part of a parity plex, we'll
193 * come up if the caller uses force. This
194 * is the way we bring them up after
195 * initialization.
196 */
197 if ((sd->plexno < 0)
198 || ((vpstate(&PLEX[sd->plexno]) & volplex_otherup) == 0)
199 || (isparity((&PLEX[sd->plexno]))
200 && (flags & setstate_force)))
201 break;
202
203 /* Otherwise it's just out of date */
204 /* FALLTHROUGH */
205
206 case sd_stale: /* out of date info, need reviving */
207 case sd_obsolete:
208 /*
209
210 * 1. If the subdisk is not part of a
211 * plex, bring it up, don't revive.
212 *
213 * 2. If the subdisk is part of a
214 * one-plex volume or an unattached
215 * plex, and it's not RAID-4 or
216 * RAID-5, we *can't revive*. The
217 * subdisk doesn't change its state.
218 *
219 * 3. If the subdisk is part of a
220 * one-plex volume or an unattached
221 * plex, and it's RAID-4 or RAID-5,
222 * but more than one subdisk is down,
223 * we *still can't revive*. The
224 * subdisk doesn't change its state.
225 *
226 * 4. If the subdisk is part of a
227 * multi-plex volume, we'll change to
228 * reviving and let the revive
229 * routines find out whether it will
230 * work or not. If they don't, the
231 * revive stops with an error message,
232 * but the state doesn't change
233 * (FWIW).
234 */
235 if (sd->plexno < 0) /* no plex associated, */
236 break; /* bring it up */
237 plex = &PLEX[sd->plexno];
238 if (plex->volno >= 0) /* have a volume */
239 vol = &VOL[plex->volno];
240 else
241 vol = NULL;
242 /*
243 * We can't do it if:
244 *
245 * 1: we don't have a volume
246 * 2: we're the only plex in the volume
247 * 3: we're a RAID-4 or RAID-5 plex, and
248 * more than one subdisk is down.
249 */
250 if (((vol == NULL)
251 || (vol->plexes == 1))
252 && ((!isparity(plex))
253 || (plex->sddowncount > 1))) {
254 if (sd->state == sd_initializing) /* it's finished initializing */
255 sd->state = sd_initialized;
256 else
257 return 0; /* can't do it */
258 } else {
259 sd->state = sd_reviving; /* put in reviving state */
260 sd->revived = 0; /* nothing done yet */
261 status = EAGAIN; /* need to repeat */
262 }
263 break;
264
265 case sd_reviving:
266 if (flags & setstate_force) /* insist, */
267 break;
268 return EAGAIN; /* no, try again */
269
270 default: /* can't do it */
271 /*
272 * There's no way to bring subdisks up directly from
273 * other states. First they need to be initialized
274 * or revived.
275 */
276 return 0;
277 }
278 break;
279
280 default: /* other ones, only internal with force */
281 if ((flags & setstate_force) == 0) /* no force? What's this? */
282 return 0; /* don't do it */
283 }
284 }
285 if (status == 1) { /* we can do it, */
286 sd->state = newstate;
287 if (flags & setstate_force)
288 log(LOG_INFO, "vinum: %s is %s by force\n", sd->name, sd_state(sd->state));
289 else
290 log(LOG_INFO, "vinum: %s is %s\n", sd->name, sd_state(sd->state));
291 } else /* we don't get here with status 0 */
292 log(LOG_INFO,
293 "vinum: %s is %s, not %s\n",
294 sd->name,
295 sd_state(sd->state),
296 sd_state(newstate));
297 if (sd->plexno >= 0) /* we belong to a plex */
298 update_plex_state(sd->plexno); /* update plex state */
299 if ((flags & setstate_configuring) == 0) /* save config now */
300 save_config();
301 return status;
302 }
303
304 /*
305 * Set the state of a plex dependent on its subdisks.
306 * This time round, we'll let plex state just reflect
307 * aggregate subdisk state, so this becomes an order of
308 * magnitude less complicated. In particular, ignore
309 * the requested state.
310 */
311 int
312 set_plex_state(int plexno, enum plexstate state, enum setstateflags flags)
313 {
314 struct plex *plex; /* point to our plex */
315 enum plexstate oldstate;
316 enum volplexstate vps; /* how do we compare with the other plexes? */
317
318 plex = &PLEX[plexno]; /* point to our plex */
319 oldstate = plex->state;
320
321 /* If the plex isn't allocated, we can't do it. */
322 if (plex->state == plex_unallocated)
323 return 0;
324
325 /*
326 * If it's already in the the state we want,
327 * and it's not up, just return. If it's up,
328 * we still need to do some housekeeping.
329 */
330 if ((state == oldstate)
331 && (state != plex_up))
332 return 1;
333 vps = vpstate(plex); /* how do we compare with the other plexes? */
334 switch (state) {
335 /*
336 * We can't bring the plex up, even by force,
337 * unless it's ready. update_plex_state
338 * checks that.
339 */
340 case plex_up: /* bring the plex up */
341 update_plex_state(plex->plexno); /* it'll come up if it can */
342 break;
343
344 case plex_down: /* want to take it down */
345 /*
346 * If we're the only one, or the only one
347 * which is up, we need force to do it.
348 */
349 if (((vps == volplex_onlyus)
350 || (vps == volplex_onlyusup))
351 && (!(flags & setstate_force)))
352 return 0; /* can't do it */
353 plex->state = state; /* do it */
354 invalidate_subdisks(plex, sd_down); /* and down all up subdisks */
355 break;
356
357 /*
358 * This is only requested internally.
359 * Trust ourselves
360 */
361 case plex_faulty:
362 plex->state = state; /* do it */
363 invalidate_subdisks(plex, sd_crashed); /* and crash all up subdisks */
364 break;
365
366 case plex_initializing:
367 /* XXX consider what safeguards we need here */
368 if ((flags & setstate_force) == 0)
369 return 0;
370 plex->state = state; /* do it */
371 break;
372
373 /* What's this? */
374 default:
375 return 0;
376 }
377 if (plex->state != oldstate) /* we've changed, */
378 log(LOG_INFO, /* tell them about it */
379 "vinum: %s is %s\n",
380 plex->name,
381 plex_state(plex->state));
382 /*
383 * Now see what we have left, and whether
384 * we're taking the volume down
385 */
386 if (plex->volno >= 0) /* we have a volume */
387 update_volume_state(plex->volno); /* update its state */
388 if ((flags & setstate_configuring) == 0) /* save config now */
389 save_config(); /* yes: save the updated configuration */
390 return 1;
391 }
392
393 /* Update the state of a plex dependent on its plexes. */
394 int
395 set_volume_state(int volno, enum volumestate state, enum setstateflags flags)
396 {
397 struct volume *vol = &VOL[volno]; /* point to our volume */
398
399 if (vol->state == volume_unallocated) /* no volume to do anything with, */
400 return 0;
401 if (vol->state == state) /* we're there already */
402 return 1;
403
404 if (state == volume_up) /* want to come up */
405 update_volume_state(volno);
406 else if (state == volume_down) { /* want to go down */
407 if (((vol->flags & VF_OPEN) == 0) /* not open */
408 ||((flags & setstate_force) != 0)) { /* or we're forcing */
409 vol->state = volume_down;
410 log(LOG_INFO,
411 "vinum: volume %s is %s\n",
412 vol->name,
413 volume_state(vol->state));
414 if ((flags & setstate_configuring) == 0) /* save config now */
415 save_config(); /* yes: save the updated configuration */
416 return 1;
417 }
418 }
419 return 0; /* no change */
420 }
421
422 /* Set the state of a subdisk based on its environment */
423 void
424 update_sd_state(int sdno)
425 {
426 struct sd *sd;
427 struct drive *drive;
428 enum sdstate oldstate;
429
430 sd = &SD[sdno];
431 oldstate = sd->state;
432 drive = &DRIVE[sd->driveno];
433
434 if (drive->state == drive_up) {
435 switch (sd->state) {
436 case sd_down:
437 case sd_crashed:
438 sd->state = sd_reborn; /* back up again with no loss */
439 break;
440
441 default:
442 break;
443 }
444 } else { /* down or worse */
445 switch (sd->state) {
446 case sd_up:
447 case sd_reborn:
448 case sd_reviving:
449 case sd_empty:
450 sd->state = sd_crashed; /* lost our drive */
451 break;
452
453 default:
454 break;
455 }
456 }
457 if (sd->state != oldstate) /* state has changed, */
458 log(LOG_INFO, /* say so */
459 "vinum: %s is %s\n",
460 sd->name,
461 sd_state(sd->state));
462 if (sd->plexno >= 0) /* we're part of a plex, */
463 update_plex_state(sd->plexno); /* update its state */
464 }
465
466 /*
467 * Force a plex and all its subdisks
468 * into an 'up' state. This is a helper
469 * for update_plex_state.
470 */
471 void
472 forceup(int plexno)
473 {
474 struct plex *plex;
475 int sdno;
476
477 plex = &PLEX[plexno]; /* point to the plex */
478 plex->state = plex_up; /* and bring it up */
479
480 /* change the subdisks to up state */
481 for (sdno = 0; sdno < plex->subdisks; sdno++) {
482 SD[plex->sdnos[sdno]].state = sd_up;
483 log(LOG_INFO, /* tell them about it */
484 "vinum: %s is up\n",
485 SD[plex->sdnos[sdno]].name);
486 }
487 }
488
489 /* Set the state of a plex based on its environment */
490 void
491 update_plex_state(int plexno)
492 {
493 struct plex *plex; /* point to our plex */
494 enum plexstate oldstate;
495 enum sdstates statemap; /* get a map of the subdisk states */
496 enum volplexstate vps; /* how do we compare with the other plexes? */
497
498 plex = &PLEX[plexno]; /* point to our plex */
499 oldstate = plex->state;
500 statemap = sdstatemap(plex); /* get a map of the subdisk states */
501 vps = vpstate(plex); /* how do we compare with the other plexes? */
502
503 if (statemap & sd_initstate) /* something initializing? */
504 plex->state = plex_initializing; /* yup, that makes the plex the same */
505 else if (statemap == sd_upstate)
506 /*
507 * All the subdisks are up. This also means that
508 * they are consistent, so we can just bring
509 * the plex up
510 */
511 plex->state = plex_up;
512 else if (isparity(plex) /* RAID-4 or RAID-5 plex */
513 &&(plex->sddowncount == 1)) /* and exactly one subdisk down */
514 plex->state = plex_degraded; /* limping a bit */
515 else if (((statemap & ~sd_downstate) == sd_emptystate) /* all subdisks empty */
516 ||((statemap & ~sd_downstate)
517 == (statemap & ~sd_downstate & (sd_initializedstate | sd_upstate)))) {
518 if ((vps & volplex_otherup) == 0) { /* no other plex is up */
519 struct volume *vol = &VOL[plex->volno]; /* possible volume to which it points */
520
521 /*
522 * If we're a striped or concat plex
523 * associated with a volume, none of whose
524 * plexes are up, and we're new and untested,
525 * and the volume has the setupstate bit set,
526 * we can pretend to be in a consistent state.
527 *
528 * We need to do this in one swell foop: on
529 * the next call we will no longer be just
530 * empty.
531 *
532 * This code assumes that all the other plexes
533 * are also capable of coming up (i.e. all the
534 * sds are up), but that's OK: we'll come back
535 * to this function for the remaining plexes
536 * in the volume.
537 */
538 if ((plex->state == plex_init)
539 && (plex->volno >= 0)
540 && (vol->flags & VF_CONFIG_SETUPSTATE)) {
541 for (plexno = 0; plexno < vol->plexes; plexno++)
542 forceup(VOL[plex->volno].plex[plexno]);
543 } else if ((statemap == sd_initializedstate) /* if it's initialized (not empty) */
544 ||(plex->organization == plex_concat) /* and we're not RAID-4 or RAID-5 */
545 ||(plex->organization == plex_striped))
546 forceup(plexno); /* we'll do it */
547 /*
548 * This leaves a case where things don't get
549 * done: the plex is RAID-4 or RAID-5, and
550 * the subdisks are all empty. They need to
551 * be initialized first.
552 */
553 } else {
554 if (statemap == sd_upstate) /* all subdisks up */
555 plex->state = plex_up; /* we can come up too */
556 else
557 plex->state = plex_faulty;
558 }
559 } else if ((statemap & (sd_upstate | sd_rebornstate)) == statemap) /* all up or reborn */
560 plex->state = plex_flaky;
561 else if (statemap & (sd_upstate | sd_rebornstate)) /* some up or reborn */
562 plex->state = plex_corrupt; /* corrupt */
563 else if (statemap & (sd_initstate | sd_emptystate)) /* some subdisks empty or initializing */
564 plex->state = plex_initializing;
565 else /* nothing at all up */
566 plex->state = plex_faulty;
567
568 if (plex->state != oldstate) /* state has changed, */
569 log(LOG_INFO, /* tell them about it */
570 "vinum: %s is %s\n",
571 plex->name,
572 plex_state(plex->state));
573 if (plex->volno >= 0) /* we're part of a volume, */
574 update_volume_state(plex->volno); /* update its state */
575 }
576
577 /* Set volume state based on its components */
578 void
579 update_volume_state(int volno)
580 {
581 struct volume *vol; /* our volume */
582 int plexno;
583 enum volumestate oldstate;
584
585 vol = &VOL[volno]; /* point to our volume */
586 oldstate = vol->state;
587
588 for (plexno = 0; plexno < vol->plexes; plexno++) {
589 struct plex *plex = &PLEX[vol->plex[plexno]]; /* point to the plex */
590 if (plex->state >= plex_corrupt) { /* something accessible, */
591 vol->state = volume_up;
592 break;
593 }
594 }
595 if (plexno == vol->plexes) /* didn't find an up plex */
596 vol->state = volume_down;
597
598 if (vol->state != oldstate) { /* state changed */
599 log(LOG_INFO, "vinum: %s is %s\n", vol->name, volume_state(vol->state));
600 save_config(); /* save the updated configuration */
601 }
602 }
603
604 /*
605 * Called from request routines when they find
606 * a subdisk which is not kosher. Decide whether
607 * it warrants changing the state. Return
608 * REQUEST_DOWN if we can't use the subdisk,
609 * REQUEST_OK if we can.
610 */
611 /*
612 * A prior version of this function checked the plex
613 * state as well. At the moment, consider plex states
614 * information for the user only. We'll ignore them
615 * and use the subdisk state only. The last version of
616 * this file with the old logic was 2.7. XXX
617 */
618 enum requeststatus
619 checksdstate(struct sd *sd, struct request *rq, daddr_t diskaddr, daddr_t diskend)
620 {
621 struct plex *plex = &PLEX[sd->plexno];
622 int writeop = (rq->bp->b_iocmd == BIO_WRITE); /* note if we're writing */
623
624 switch (sd->state) {
625 /* We shouldn't get called if the subdisk is up */
626 case sd_up:
627 return REQUEST_OK;
628
629 case sd_reviving:
630 /*
631 * Access to a reviving subdisk depends on the
632 * organization of the plex:
633 *
634 * - If it's concatenated, access the subdisk
635 * up to its current revive point. If we
636 * want to write to the subdisk overlapping
637 * the current revive block, set the
638 * conflict flag in the request, asking the
639 * caller to put the request on the wait
640 * list, which will be attended to by
641 * revive_block when it's done.
642 * - if it's striped, we can't do it (we could
643 * do some hairy calculations, but it's
644 * unlikely to work).
645 * - if it's RAID-4 or RAID-5, we can do it as
646 * long as only one subdisk is down
647 */
648 if (plex->organization == plex_striped) /* plex is striped, */
649 return REQUEST_DOWN;
650 else if (isparity(plex)) { /* RAID-4 or RAID-5 plex */
651 if (plex->sddowncount > 1) /* with more than one sd down, */
652 return REQUEST_DOWN;
653 else
654 /*
655 * XXX We shouldn't do this if we can find a
656 * better way. Check the other plexes
657 * first, and return a DOWN if another
658 * plex will do it better
659 */
660 return REQUEST_OK; /* OK, we'll find a way */
661 }
662 if (diskaddr > (sd->revived
663 + sd->plexoffset
664 + (sd->revive_blocksize >> DEV_BSHIFT))) /* we're beyond the end */
665 return REQUEST_DOWN;
666 else if (diskend > (sd->revived + sd->plexoffset)) { /* we finish beyond the end */
667 if (writeop) {
668 rq->flags |= XFR_REVIVECONFLICT; /* note a potential conflict */
669 rq->sdno = sd->sdno; /* and which sd last caused it */
670 } else
671 return REQUEST_DOWN;
672 }
673 return REQUEST_OK;
674
675 case sd_reborn:
676 if (writeop)
677 return REQUEST_OK; /* always write to a reborn disk */
678 else /* don't allow a read */
679 /*
680 * Handle the mapping. We don't want to reject
681 * a read request to a reborn subdisk if that's
682 * all we have. XXX
683 */
684 return REQUEST_DOWN;
685
686 case sd_down:
687 if (writeop) /* writing to a consistent down disk */
688 set_sd_state(sd->sdno, sd_obsolete, setstate_force); /* it's not consistent now */
689 return REQUEST_DOWN;
690
691 case sd_crashed:
692 if (writeop) /* writing to a consistent down disk */
693 set_sd_state(sd->sdno, sd_stale, setstate_force); /* it's not consistent now */
694 return REQUEST_DOWN;
695
696 default:
697 return REQUEST_DOWN;
698 }
699 }
700
701 /* return a state map for the subdisks of a plex */
702 enum sdstates
703 sdstatemap(struct plex *plex)
704 {
705 int sdno;
706 enum sdstates statemap = 0; /* note the states we find */
707
708 plex->sddowncount = 0; /* no subdisks down yet */
709 for (sdno = 0; sdno < plex->subdisks; sdno++) {
710 struct sd *sd = &SD[plex->sdnos[sdno]]; /* point to the subdisk */
711
712 switch (sd->state) {
713 case sd_empty:
714 statemap |= sd_emptystate;
715 (plex->sddowncount)++; /* another unusable subdisk */
716 break;
717
718 case sd_init:
719 statemap |= sd_initstate;
720 (plex->sddowncount)++; /* another unusable subdisk */
721 break;
722
723 case sd_down:
724 statemap |= sd_downstate;
725 (plex->sddowncount)++; /* another unusable subdisk */
726 break;
727
728 case sd_crashed:
729 statemap |= sd_crashedstate;
730 (plex->sddowncount)++; /* another unusable subdisk */
731 break;
732
733 case sd_obsolete:
734 statemap |= sd_obsoletestate;
735 (plex->sddowncount)++; /* another unusable subdisk */
736 break;
737
738 case sd_stale:
739 statemap |= sd_stalestate;
740 (plex->sddowncount)++; /* another unusable subdisk */
741 break;
742
743 case sd_reborn:
744 statemap |= sd_rebornstate;
745 break;
746
747 case sd_up:
748 statemap |= sd_upstate;
749 break;
750
751 case sd_initializing:
752 statemap |= sd_initstate;
753 (plex->sddowncount)++; /* another unusable subdisk */
754 break;
755
756 case sd_initialized:
757 statemap |= sd_initializedstate;
758 (plex->sddowncount)++; /* another unusable subdisk */
759 break;
760
761 case sd_unallocated:
762 case sd_uninit:
763 case sd_reviving:
764 case sd_referenced:
765 statemap |= sd_otherstate;
766 (plex->sddowncount)++; /* another unusable subdisk */
767 }
768 }
769 return statemap;
770 }
771
772 /* determine the state of the volume relative to this plex */
773 enum volplexstate
774 vpstate(struct plex *plex)
775 {
776 struct volume *vol;
777 enum volplexstate state = volplex_onlyusdown; /* state to return */
778 int plexno;
779
780 if (plex->volno < 0) { /* not associated with a volume */
781 if (plex->state > plex_degraded)
782 return volplex_onlyus; /* just us */
783 else
784 return volplex_onlyusdown; /* assume the worst */
785 }
786 vol = &VOL[plex->volno]; /* point to our volume */
787 for (plexno = 0; plexno < vol->plexes; plexno++) {
788 if (&PLEX[vol->plex[plexno]] == plex) { /* us */
789 if (PLEX[vol->plex[plexno]].state >= plex_degraded) /* are we up? */
790 state |= volplex_onlyus; /* yes */
791 } else {
792 if (PLEX[vol->plex[plexno]].state >= plex_degraded) /* not us */
793 state |= volplex_otherup; /* and when they were up, they were up */
794 else
795 state |= volplex_alldown; /* and when they were down, they were down */
796 }
797 }
798 return state; /* and when they were only halfway up */
799 } /* they were neither up nor down */
800
801 /* Check if all bits b are set in a */
802 int allset(int a, int b);
803
804 int
805 allset(int a, int b)
806 {
807 return (a & b) == b;
808 }
809
810 /* Invalidate the subdisks belonging to a plex */
811 void
812 invalidate_subdisks(struct plex *plex, enum sdstate state)
813 {
814 int sdno;
815
816 for (sdno = 0; sdno < plex->subdisks; sdno++) { /* for each subdisk */
817 struct sd *sd = &SD[plex->sdnos[sdno]];
818
819 switch (sd->state) {
820 case sd_unallocated:
821 case sd_uninit:
822 case sd_init:
823 case sd_initializing:
824 case sd_initialized:
825 case sd_empty:
826 case sd_obsolete:
827 case sd_stale:
828 case sd_crashed:
829 case sd_down:
830 case sd_referenced:
831 break;
832
833 case sd_reviving:
834 case sd_reborn:
835 case sd_up:
836 set_sd_state(plex->sdnos[sdno], state, setstate_force);
837 }
838 }
839 }
840
841 /*
842 * Start an object, in other words do what we can to get it up.
843 * This is called from vinumioctl (VINUMSTART).
844 * Return error indications via ioctl_reply
845 */
846 void
847 start_object(struct vinum_ioctl_msg *data)
848 {
849 int status;
850 int objindex = data->index; /* data gets overwritten */
851 struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) data; /* format for returning replies */
852 enum setstateflags flags;
853
854 if (data->force != 0) /* are we going to use force? */
855 flags = setstate_force; /* yes */
856 else
857 flags = setstate_none; /* no */
858
859 switch (data->type) {
860 case drive_object:
861 status = set_drive_state(objindex, drive_up, flags);
862 if (DRIVE[objindex].state != drive_up) /* set status on whether we really did it */
863 ioctl_reply->error = EBUSY;
864 else
865 ioctl_reply->error = 0;
866 break;
867
868 case sd_object:
869 if (DRIVE[SD[objindex].driveno].state != drive_up) {
870 ioctl_reply->error = EIO;
871 strcpy(ioctl_reply->msg, "Drive is down");
872 return;
873 }
874 if (data->blocksize)
875 SD[objindex].revive_blocksize = data->blocksize;
876 if ((SD[objindex].state == sd_reviving) /* reviving, */
877 ||(SD[objindex].state == sd_stale)) { /* or stale, will revive */
878 SD[objindex].state = sd_reviving; /* make sure we're reviving */
879 ioctl_reply->error = revive_block(objindex); /* revive another block */
880 ioctl_reply->msg[0] = '\0'; /* no comment */
881 return;
882 } else if (SD[objindex].state == sd_initializing) { /* initializing, */
883 if (data->blocksize)
884 SD[objindex].init_blocksize = data->blocksize;
885 ioctl_reply->error = initsd(objindex, data->verify); /* initialize another block */
886 ioctl_reply->msg[0] = '\0'; /* no comment */
887 return;
888 }
889 status = set_sd_state(objindex, sd_up, flags); /* set state */
890 if (status != EAGAIN) { /* not first revive or initialize, */
891 if (SD[objindex].state != sd_up) /* set status on whether we really did it */
892 ioctl_reply->error = EBUSY;
893 else
894 ioctl_reply->error = 0;
895 } else
896 ioctl_reply->error = status;
897 break;
898
899 case plex_object:
900 status = set_plex_state(objindex, plex_up, flags);
901 if (PLEX[objindex].state != plex_up) /* set status on whether we really did it */
902 ioctl_reply->error = EBUSY;
903 else
904 ioctl_reply->error = 0;
905 break;
906
907 case volume_object:
908 status = set_volume_state(objindex, volume_up, flags);
909 if (VOL[objindex].state != volume_up) /* set status on whether we really did it */
910 ioctl_reply->error = EBUSY;
911 else
912 ioctl_reply->error = 0;
913 break;
914
915 default:
916 ioctl_reply->error = EINVAL;
917 strcpy(ioctl_reply->msg, "Invalid object type");
918 return;
919 }
920 /*
921 * There's no point in saying anything here:
922 * the userland program does it better
923 */
924 ioctl_reply->msg[0] = '\0';
925 }
926
927 /*
928 * Stop an object, in other words do what we can to get it down
929 * This is called from vinumioctl (VINUMSTOP).
930 * Return error indications via ioctl_reply.
931 */
932 void
933 stop_object(struct vinum_ioctl_msg *data)
934 {
935 int status = 1;
936 int objindex = data->index; /* save the number from change */
937 struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) data; /* format for returning replies */
938
939 switch (data->type) {
940 case drive_object:
941 status = set_drive_state(objindex, drive_down, data->force);
942 break;
943
944 case sd_object:
945 status = set_sd_state(objindex, sd_down, data->force);
946 break;
947
948 case plex_object:
949 status = set_plex_state(objindex, plex_down, data->force);
950 break;
951
952 case volume_object:
953 status = set_volume_state(objindex, volume_down, data->force);
954 break;
955
956 default:
957 ioctl_reply->error = EINVAL;
958 strcpy(ioctl_reply->msg, "Invalid object type");
959 return;
960 }
961 ioctl_reply->msg[0] = '\0';
962 if (status == 0) /* couldn't do it */
963 ioctl_reply->error = EBUSY;
964 else
965 ioctl_reply->error = 0;
966 }
967
968 /*
969 * VINUM_SETSTATE ioctl: set an object state.
970 * msg is the message passed by the user.
971 */
972 void
973 setstate(struct vinum_ioctl_msg *msg)
974 {
975 int sdno;
976 struct sd *sd;
977 struct plex *plex;
978 struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) msg; /* format for returning replies */
979
980 switch (msg->state) {
981 case object_down:
982 stop_object(msg);
983 break;
984
985 case object_initializing:
986 switch (msg->type) {
987 case sd_object:
988 sd = &SD[msg->index];
989 if ((msg->index >= vinum_conf.subdisks_allocated)
990 || (sd->state <= sd_referenced)) {
991 sprintf(ioctl_reply->msg, "Invalid subdisk %d", msg->index);
992 ioctl_reply->error = EFAULT;
993 return;
994 }
995 set_sd_state(msg->index, sd_initializing, msg->force);
996 if (sd->state != sd_initializing) {
997 strcpy(ioctl_reply->msg, "Can't set state");
998 ioctl_reply->error = EBUSY;
999 } else
1000 ioctl_reply->error = 0;
1001 break;
1002
1003 case plex_object:
1004 plex = &PLEX[msg->index];
1005 if ((msg->index >= vinum_conf.plexes_allocated)
1006 || (plex->state <= plex_unallocated)) {
1007 sprintf(ioctl_reply->msg, "Invalid plex %d", msg->index);
1008 ioctl_reply->error = EFAULT;
1009 return;
1010 }
1011 set_plex_state(msg->index, plex_initializing, msg->force);
1012 if (plex->state != plex_initializing) {
1013 strcpy(ioctl_reply->msg, "Can't set state");
1014 ioctl_reply->error = EBUSY;
1015 } else {
1016 ioctl_reply->error = 0;
1017 for (sdno = 0; sdno < plex->subdisks; sdno++) {
1018 sd = &SD[plex->sdnos[sdno]];
1019 set_sd_state(plex->sdnos[sdno], sd_initializing, msg->force);
1020 if (sd->state != sd_initializing) {
1021 strcpy(ioctl_reply->msg, "Can't set state");
1022 ioctl_reply->error = EBUSY;
1023 break;
1024 }
1025 }
1026 }
1027 break;
1028
1029 default:
1030 strcpy(ioctl_reply->msg, "Invalid object");
1031 ioctl_reply->error = EINVAL;
1032 }
1033 break;
1034
1035 case object_initialized:
1036 if (msg->type == sd_object) {
1037 sd = &SD[msg->index];
1038 if ((msg->index >= vinum_conf.subdisks_allocated)
1039 || (sd->state <= sd_referenced)) {
1040 sprintf(ioctl_reply->msg, "Invalid subdisk %d", msg->index);
1041 ioctl_reply->error = EFAULT;
1042 return;
1043 }
1044 set_sd_state(msg->index, sd_initialized, msg->force);
1045 if (sd->state != sd_initializing) {
1046 strcpy(ioctl_reply->msg, "Can't set state");
1047 ioctl_reply->error = EBUSY;
1048 } else
1049 ioctl_reply->error = 0;
1050 } else {
1051 strcpy(ioctl_reply->msg, "Invalid object");
1052 ioctl_reply->error = EINVAL;
1053 }
1054 break;
1055
1056 case object_up:
1057 start_object(msg);
1058 }
1059 }
1060
1061 /*
1062 * Brute force set state function. Don't look at
1063 * any dependencies, just do it. This is mainly
1064 * intended for testing and recovery.
1065 */
1066 void
1067 setstate_by_force(struct vinum_ioctl_msg *msg)
1068 {
1069 struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) msg; /* format for returning replies */
1070
1071 switch (msg->type) {
1072 case drive_object:
1073 DRIVE[msg->index].state = msg->state;
1074 break;
1075
1076 case sd_object:
1077 SD[msg->index].state = msg->state;
1078 break;
1079
1080 case plex_object:
1081 PLEX[msg->index].state = msg->state;
1082 break;
1083
1084 case volume_object:
1085 VOL[msg->index].state = msg->state;
1086 break;
1087
1088 default:
1089 break;
1090 }
1091 ioctl_reply->error = 0;
1092 }
1093 /* Local Variables: */
1094 /* fill-column: 50 */
1095 /* End: */
Cache object: 23e7c41ed4c28caab5b3397443c49270
|