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