2 * Copyright (c) 1997, 1998, 1999
3 * Nan Yang Computer Services Limited. All rights reserved.
5 * Parts copyright (c) 1997, 1998 Cybernet Corporation, NetMAX project.
7 * Written by Greg Lehey
9 * This software is distributed under the so-called ``Berkeley
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
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
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.
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.
40 * $Id: vinumstate.c,v 2.18 2000/05/10 07:30:50 grog Exp grog $
41 * $FreeBSD: src/sys/dev/vinum/vinumstate.c,v 1.28.2.2 2000/06/08 02:00:23 grog Exp $
47 /* Update drive state */
48 /* Return 1 if the state changes, otherwise 0 */
50 set_drive_state(int driveno
, enum drivestate newstate
, enum setstateflags flags
)
53 struct drive
*drive
= &DRIVE
[driveno
];
54 int oldstate
= drive
->state
;
57 if (drive
->state
== drive_unallocated
) /* no drive to do anything with, */
60 if (newstate
== oldstate
) /* don't change it if it's not different */
61 return 1; /* all OK */
62 if ((newstate
== drive_down
) /* the drive's going down */
63 &&(!(flags
& setstate_force
))
64 && (drive
->opencount
!= 0)) /* we can't do it */
65 return 0; /* don't do it */
66 drive
->state
= newstate
; /* set the state */
67 if (drive
->label
.name
[0] != '\0') /* we have a name, */
69 "vinum: drive %s is %s\n",
71 drive_state(drive
->state
));
72 if (drive
->state
!= oldstate
) { /* state has changed */
73 for (sdno
= 0; sdno
< vinum_conf
.subdisks_allocated
; sdno
++) { /* find this drive's subdisks */
74 if ((SD
[sdno
].state
>= sd_referenced
)
75 && (SD
[sdno
].driveno
== driveno
)) /* belongs to this drive */
76 update_sd_state(sdno
); /* update the state */
79 if (newstate
== drive_up
) { /* want to bring it up */
80 if ((drive
->flags
& VF_OPEN
) == 0) /* should be open, but we're not */
81 init_drive(drive
, 1); /* which changes the state again */
82 } else { /* taking it down or worse */
84 queue_daemon_request(daemonrq_closedrive
, di
); /* get the daemon to close it */
86 if ((flags
& setstate_configuring
) == 0) /* configuring? */
87 save_config(); /* no: save the updated configuration now */
92 * Try to set the subdisk state. Return 1 if state changed to
93 * what we wanted, -1 if it changed to something else, and 0
96 * This routine is called both from the user (up, down states only)
99 * The setstate_force bit in the flags enables the state change even
100 * if it could be dangerous to data consistency. It shouldn't allow
104 set_sd_state(int sdno
, enum sdstate newstate
, enum setstateflags flags
)
106 struct sd
*sd
= &SD
[sdno
];
109 int oldstate
= sd
->state
;
110 int status
= 1; /* status to return */
112 if (newstate
== oldstate
) /* already there, */
114 else if (sd
->state
== sd_unallocated
) /* no subdisk to do anything with, */
115 return 0; /* can't do it */
117 if (sd
->driveoffset
< 0) { /* not allocated space */
119 if (newstate
!= sd_down
) {
121 sdstatemap(&PLEX
[sd
->plexno
]); /* count up subdisks */
124 } else { /* space allocated */
126 case sd_down
: /* take it down? */
128 * If we're attached to a plex, and we're
129 * not reborn, we won't go down without
132 if (!(flags
& setstate_force
)
134 && (sd
->state
!= sd_reborn
))
135 return 0; /* don't do it */
139 if ((sd
->state
== sd_initializing
) /* we were initializing */
140 ||(flags
& setstate_force
)) /* or we forced it */
142 return 0; /* can't do it otherwise */
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 */
151 * Perform the necessary tests. To allow
152 * the state transition, just break out of
157 case sd_down
: /* been down, no data lost */
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.
163 if ((sd
->plexno
>= 0)
164 && (((PLEX
[sd
->plexno
].state
< plex_firstup
)
165 || (PLEX
[sd
->plexno
].subdisks
> 1))))
167 if (oldstate
!= sd_reborn
) {
168 sd
->state
= sd_reborn
; /* here it is again */
170 "vinum: %s is %s, not %s\n",
178 case sd_init
: /* brand new */
179 if (flags
& setstate_configuring
) /* we're doing this while configuring */
181 /* otherwise it's like being empty */
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.
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
198 || ((vpstate(&PLEX
[sd
->plexno
]) & volplex_otherup
) == 0)
199 || (isparity((&PLEX
[sd
->plexno
]))
200 && (flags
& setstate_force
)))
203 /* Otherwise it's just out of date */
206 case sd_stale
: /* out of date info, need reviving */
210 * 1. If the subdisk is not part of a
211 * plex, bring it up, don't revive.
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.
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.
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
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
];
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.
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
;
257 return 0; /* can't do it */
259 sd
->state
= sd_reviving
; /* put in reviving state */
260 sd
->revived
= 0; /* nothing done yet */
261 status
= EAGAIN
; /* need to repeat */
266 if (flags
& setstate_force
) /* insist, */
268 return EAGAIN
; /* no, try again */
270 default: /* can't do it */
272 * There's no way to bring subdisks up directly from
273 * other states. First they need to be initialized
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 */
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
));
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 */
293 "vinum: %s is %s, not %s\n",
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 */
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.
312 set_plex_state(int plexno
, enum plexstate state
, enum setstateflags flags
)
314 struct plex
*plex
; /* point to our plex */
315 enum plexstate oldstate
;
316 enum volplexstate vps
; /* how do we compare with the other plexes? */
318 plex
= &PLEX
[plexno
]; /* point to our plex */
319 oldstate
= plex
->state
;
321 /* If the plex isn't allocated, we can't do it. */
322 if (plex
->state
== plex_unallocated
)
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.
330 if ((state
== oldstate
)
331 && (state
!= plex_up
))
333 vps
= vpstate(plex
); /* how do we compare with the other plexes? */
336 * We can't bring the plex up, even by force,
337 * unless it's ready. update_plex_state
340 case plex_up
: /* bring the plex up */
341 update_plex_state(plex
->plexno
); /* it'll come up if it can */
344 case plex_down
: /* want to take it down */
346 * If we're the only one, or the only one
347 * which is up, we need force to do it.
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 */
358 * This is only requested internally.
362 plex
->state
= state
; /* do it */
363 invalidate_subdisks(plex
, sd_crashed
); /* and crash all up subdisks */
366 case plex_initializing
:
367 /* XXX consider what safeguards we need here */
368 if ((flags
& setstate_force
) == 0)
370 plex
->state
= state
; /* do it */
377 if (plex
->state
!= oldstate
) /* we've changed, */
378 log(LOG_INFO
, /* tell them about it */
381 plex_state(plex
->state
));
383 * Now see what we have left, and whether
384 * we're taking the volume down
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 */
393 /* Update the state of a plex dependent on its plexes. */
395 set_volume_state(int volno
, enum volumestate state
, enum setstateflags flags
)
397 struct volume
*vol
= &VOL
[volno
]; /* point to our volume */
399 if (vol
->state
== volume_unallocated
) /* no volume to do anything with, */
401 if (vol
->state
== state
) /* we're there already */
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
;
411 "vinum: volume %s is %s\n",
413 volume_state(vol
->state
));
414 if ((flags
& setstate_configuring
) == 0) /* save config now */
415 save_config(); /* yes: save the updated configuration */
419 return 0; /* no change */
422 /* Set the state of a subdisk based on its environment */
424 update_sd_state(int sdno
)
428 enum sdstate oldstate
;
431 oldstate
= sd
->state
;
432 drive
= &DRIVE
[sd
->driveno
];
434 if (drive
->state
== drive_up
) {
438 sd
->state
= sd_reborn
; /* back up again with no loss */
444 } else { /* down or worse */
450 sd
->state
= sd_crashed
; /* lost our drive */
457 if (sd
->state
!= oldstate
) /* state has changed, */
458 log(LOG_INFO
, /* say so */
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 */
467 * Force a plex and all its subdisks
468 * into an 'up' state. This is a helper
469 * for update_plex_state.
477 plex
= &PLEX
[plexno
]; /* point to the plex */
478 plex
->state
= plex_up
; /* and bring it up */
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 */
485 SD
[plex
->sdnos
[sdno
]].name
);
489 /* Set the state of a plex based on its environment */
491 update_plex_state(int plexno
)
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? */
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? */
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
)
507 * All the subdisks are up. This also means that
508 * they are consistent, so we can just bring
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 */
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.
528 * We need to do this in one swell foop: on
529 * the next call we will no longer be just
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
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 */
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.
554 if (statemap
== sd_upstate
) /* all subdisks up */
555 plex
->state
= plex_up
; /* we can come up too */
557 plex
->state
= plex_faulty
;
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
;
568 if (plex
->state
!= oldstate
) /* state has changed, */
569 log(LOG_INFO
, /* tell them about it */
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 */
577 /* Set volume state based on its components */
579 update_volume_state(int volno
)
581 struct volume
*vol
; /* our volume */
583 enum volumestate oldstate
;
585 vol
= &VOL
[volno
]; /* point to our volume */
586 oldstate
= vol
->state
;
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
;
595 if (plexno
== vol
->plexes
) /* didn't find an up plex */
596 vol
->state
= volume_down
;
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 */
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.
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
619 checksdstate(struct sd
*sd
, struct request
*rq
, vinum_off_t diskaddr
, vinum_off_t diskend
)
621 struct plex
*plex
= &PLEX
[sd
->plexno
];
622 int writeop
= (rq
->bio
->bio_buf
->b_cmd
!= BUF_CMD_READ
); /* note if we're writing */
625 /* We shouldn't get called if the subdisk is up */
631 * Access to a reviving subdisk depends on the
632 * organization of the plex:
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
645 * - if it's RAID-4 or RAID-5, we can do it as
646 * long as only one subdisk is down
648 if (plex
->organization
== plex_striped
) /* plex is striped, */
651 else if (isparity(plex
)) { /* RAID-4 or RAID-5 plex */
652 if (plex
->sddowncount
> 1) /* with more than one sd down, */
656 * XXX We shouldn't do this if we can find a
657 * better way. Check the other plexes
658 * first, and return a DOWN if another
659 * plex will do it better
661 return REQUEST_OK
; /* OK, we'll find a way */
663 if (diskaddr
> (sd
->revived
665 + (sd
->revive_blocksize
>> DEV_BSHIFT
))) /* we're beyond the end */
667 else if (diskend
> (sd
->revived
+ sd
->plexoffset
)) { /* we finish beyond the end */
669 rq
->flags
|= XFR_REVIVECONFLICT
; /* note a potential conflict */
670 rq
->sdno
= sd
->sdno
; /* and which sd last caused it */
678 return REQUEST_OK
; /* always write to a reborn disk */
679 else /* don't allow a read */
681 * Handle the mapping. We don't want to reject
682 * a read request to a reborn subdisk if that's
688 if (writeop
) /* writing to a consistent down disk */
689 set_sd_state(sd
->sdno
, sd_obsolete
, setstate_force
); /* it's not consistent now */
693 if (writeop
) /* writing to a consistent down disk */
694 set_sd_state(sd
->sdno
, sd_stale
, setstate_force
); /* it's not consistent now */
702 /* return a state map for the subdisks of a plex */
704 sdstatemap(struct plex
*plex
)
707 enum sdstates statemap
= 0; /* note the states we find */
709 plex
->sddowncount
= 0; /* no subdisks down yet */
710 for (sdno
= 0; sdno
< plex
->subdisks
; sdno
++) {
711 struct sd
*sd
= &SD
[plex
->sdnos
[sdno
]]; /* point to the subdisk */
715 statemap
|= sd_emptystate
;
716 (plex
->sddowncount
)++; /* another unusable subdisk */
720 statemap
|= sd_initstate
;
721 (plex
->sddowncount
)++; /* another unusable subdisk */
725 statemap
|= sd_downstate
;
726 (plex
->sddowncount
)++; /* another unusable subdisk */
730 statemap
|= sd_crashedstate
;
731 (plex
->sddowncount
)++; /* another unusable subdisk */
735 statemap
|= sd_obsoletestate
;
736 (plex
->sddowncount
)++; /* another unusable subdisk */
740 statemap
|= sd_stalestate
;
741 (plex
->sddowncount
)++; /* another unusable subdisk */
745 statemap
|= sd_rebornstate
;
749 statemap
|= sd_upstate
;
752 case sd_initializing
:
753 statemap
|= sd_initstate
;
754 (plex
->sddowncount
)++; /* another unusable subdisk */
758 statemap
|= sd_initializedstate
;
759 (plex
->sddowncount
)++; /* another unusable subdisk */
766 statemap
|= sd_otherstate
;
767 (plex
->sddowncount
)++; /* another unusable subdisk */
773 /* determine the state of the volume relative to this plex */
775 vpstate(struct plex
*plex
)
778 enum volplexstate state
= volplex_onlyusdown
; /* state to return */
781 if (plex
->volno
< 0) { /* not associated with a volume */
782 if (plex
->state
> plex_degraded
)
783 return volplex_onlyus
; /* just us */
785 return volplex_onlyusdown
; /* assume the worst */
787 vol
= &VOL
[plex
->volno
]; /* point to our volume */
788 for (plexno
= 0; plexno
< vol
->plexes
; plexno
++) {
789 if (&PLEX
[vol
->plex
[plexno
]] == plex
) { /* us */
790 if (PLEX
[vol
->plex
[plexno
]].state
>= plex_degraded
) /* are we up? */
791 state
|= volplex_onlyus
; /* yes */
793 if (PLEX
[vol
->plex
[plexno
]].state
>= plex_degraded
) /* not us */
794 state
|= volplex_otherup
; /* and when they were up, they were up */
796 state
|= volplex_alldown
; /* and when they were down, they were down */
799 return state
; /* and when they were only halfway up */
800 } /* they were neither up nor down */
802 /* Check if all bits b are set in a */
803 int allset(int a
, int b
);
811 /* Invalidate the subdisks belonging to a plex */
813 invalidate_subdisks(struct plex
*plex
, enum sdstate state
)
817 for (sdno
= 0; sdno
< plex
->subdisks
; sdno
++) { /* for each subdisk */
818 struct sd
*sd
= &SD
[plex
->sdnos
[sdno
]];
824 case sd_initializing
:
837 set_sd_state(plex
->sdnos
[sdno
], state
, setstate_force
);
843 * Start an object, in other words do what we can to get it up.
844 * This is called from vinumioctl (VINUMSTART).
845 * Return error indications via ioctl_reply
848 start_object(struct vinum_ioctl_msg
*data
)
851 int objindex
= data
->index
; /* data gets overwritten */
852 struct _ioctl_reply
*ioctl_reply
= (struct _ioctl_reply
*) data
; /* format for returning replies */
853 enum setstateflags flags
;
855 if (data
->force
!= 0) /* are we going to use force? */
856 flags
= setstate_force
; /* yes */
858 flags
= setstate_none
; /* no */
860 switch (data
->type
) {
862 status
= set_drive_state(objindex
, drive_up
, flags
);
863 if (DRIVE
[objindex
].state
!= drive_up
) /* set status on whether we really did it */
864 ioctl_reply
->error
= EBUSY
;
866 ioctl_reply
->error
= 0;
870 if (DRIVE
[SD
[objindex
].driveno
].state
!= drive_up
) {
871 ioctl_reply
->error
= EIO
;
872 strcpy(ioctl_reply
->msg
, "Drive is down");
876 SD
[objindex
].revive_blocksize
= data
->blocksize
;
877 if ((SD
[objindex
].state
== sd_reviving
) /* reviving, */
878 ||(SD
[objindex
].state
== sd_stale
)) { /* or stale, will revive */
879 SD
[objindex
].state
= sd_reviving
; /* make sure we're reviving */
880 ioctl_reply
->error
= revive_block(objindex
); /* revive another block */
881 ioctl_reply
->msg
[0] = '\0'; /* no comment */
883 } else if (SD
[objindex
].state
== sd_initializing
) { /* initializing, */
885 SD
[objindex
].init_blocksize
= data
->blocksize
;
886 ioctl_reply
->error
= initsd(objindex
, data
->verify
); /* initialize another block */
887 ioctl_reply
->msg
[0] = '\0'; /* no comment */
890 status
= set_sd_state(objindex
, sd_up
, flags
); /* set state */
891 if (status
!= EAGAIN
) { /* not first revive or initialize, */
892 if (SD
[objindex
].state
!= sd_up
) /* set status on whether we really did it */
893 ioctl_reply
->error
= EBUSY
;
895 ioctl_reply
->error
= 0;
897 ioctl_reply
->error
= status
;
901 status
= set_plex_state(objindex
, plex_up
, flags
);
902 if (PLEX
[objindex
].state
!= plex_up
) /* set status on whether we really did it */
903 ioctl_reply
->error
= EBUSY
;
905 ioctl_reply
->error
= 0;
909 status
= set_volume_state(objindex
, volume_up
, flags
);
910 if (VOL
[objindex
].state
!= volume_up
) /* set status on whether we really did it */
911 ioctl_reply
->error
= EBUSY
;
913 ioctl_reply
->error
= 0;
917 ioctl_reply
->error
= EINVAL
;
918 strcpy(ioctl_reply
->msg
, "Invalid object type");
922 * There's no point in saying anything here:
923 * the userland program does it better
925 ioctl_reply
->msg
[0] = '\0';
929 * Stop an object, in other words do what we can to get it down
930 * This is called from vinumioctl (VINUMSTOP).
931 * Return error indications via ioctl_reply.
934 stop_object(struct vinum_ioctl_msg
*data
)
937 int objindex
= data
->index
; /* save the number from change */
938 struct _ioctl_reply
*ioctl_reply
= (struct _ioctl_reply
*) data
; /* format for returning replies */
940 switch (data
->type
) {
942 status
= set_drive_state(objindex
, drive_down
, data
->force
);
946 status
= set_sd_state(objindex
, sd_down
, data
->force
);
950 status
= set_plex_state(objindex
, plex_down
, data
->force
);
954 status
= set_volume_state(objindex
, volume_down
, data
->force
);
958 ioctl_reply
->error
= EINVAL
;
959 strcpy(ioctl_reply
->msg
, "Invalid object type");
962 ioctl_reply
->msg
[0] = '\0';
963 if (status
== 0) /* couldn't do it */
964 ioctl_reply
->error
= EBUSY
;
966 ioctl_reply
->error
= 0;
970 * VINUM_SETSTATE ioctl: set an object state.
971 * msg is the message passed by the user.
974 setstate(struct vinum_ioctl_msg
*msg
)
979 struct _ioctl_reply
*ioctl_reply
= (struct _ioctl_reply
*) msg
; /* format for returning replies */
981 switch (msg
->state
) {
986 case object_initializing
:
989 sd
= &SD
[msg
->index
];
990 if ((msg
->index
>= vinum_conf
.subdisks_allocated
)
991 || (sd
->state
<= sd_referenced
)) {
992 ksprintf(ioctl_reply
->msg
, "Invalid subdisk %d", msg
->index
);
993 ioctl_reply
->error
= EFAULT
;
996 set_sd_state(msg
->index
, sd_initializing
, msg
->force
);
997 if (sd
->state
!= sd_initializing
) {
998 strcpy(ioctl_reply
->msg
, "Can't set state");
999 ioctl_reply
->error
= EBUSY
;
1001 ioctl_reply
->error
= 0;
1005 plex
= &PLEX
[msg
->index
];
1006 if ((msg
->index
>= vinum_conf
.plexes_allocated
)
1007 || (plex
->state
<= plex_unallocated
)) {
1008 ksprintf(ioctl_reply
->msg
, "Invalid plex %d", msg
->index
);
1009 ioctl_reply
->error
= EFAULT
;
1012 set_plex_state(msg
->index
, plex_initializing
, msg
->force
);
1013 if (plex
->state
!= plex_initializing
) {
1014 strcpy(ioctl_reply
->msg
, "Can't set state");
1015 ioctl_reply
->error
= EBUSY
;
1017 ioctl_reply
->error
= 0;
1018 for (sdno
= 0; sdno
< plex
->subdisks
; sdno
++) {
1019 sd
= &SD
[plex
->sdnos
[sdno
]];
1020 set_sd_state(plex
->sdnos
[sdno
], sd_initializing
, msg
->force
);
1021 if (sd
->state
!= sd_initializing
) {
1022 strcpy(ioctl_reply
->msg
, "Can't set state");
1023 ioctl_reply
->error
= EBUSY
;
1031 strcpy(ioctl_reply
->msg
, "Invalid object");
1032 ioctl_reply
->error
= EINVAL
;
1036 case object_initialized
:
1037 if (msg
->type
== sd_object
) {
1038 sd
= &SD
[msg
->index
];
1039 if ((msg
->index
>= vinum_conf
.subdisks_allocated
)
1040 || (sd
->state
<= sd_referenced
)) {
1041 ksprintf(ioctl_reply
->msg
, "Invalid subdisk %d", msg
->index
);
1042 ioctl_reply
->error
= EFAULT
;
1045 set_sd_state(msg
->index
, sd_initialized
, msg
->force
);
1046 if (sd
->state
!= sd_initializing
) {
1047 strcpy(ioctl_reply
->msg
, "Can't set state");
1048 ioctl_reply
->error
= EBUSY
;
1050 ioctl_reply
->error
= 0;
1052 strcpy(ioctl_reply
->msg
, "Invalid object");
1053 ioctl_reply
->error
= EINVAL
;
1063 * Brute force set state function. Don't look at
1064 * any dependencies, just do it. This is mainly
1065 * intended for testing and recovery.
1068 setstate_by_force(struct vinum_ioctl_msg
*msg
)
1070 struct _ioctl_reply
*ioctl_reply
= (struct _ioctl_reply
*) msg
; /* format for returning replies */
1072 switch (msg
->type
) {
1074 DRIVE
[msg
->index
].state
= msg
->state
;
1078 SD
[msg
->index
].state
= msg
->state
;
1082 PLEX
[msg
->index
].state
= msg
->state
;
1086 VOL
[msg
->index
].state
= msg
->state
;
1092 ioctl_reply
->error
= 0;