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 $
42 * $DragonFly: src/sys/dev/raid/vinum/vinumstate.c,v 1.7 2006/12/20 18:14:40 dillon Exp $
48 /* Update drive state */
49 /* Return 1 if the state changes, otherwise 0 */
51 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 */
83 queue_daemon_request(daemonrq_closedrive
, /* get the daemon to close it */
84 (union daemoninfo
) drive
);
85 if ((flags
& setstate_configuring
) == 0) /* configuring? */
86 save_config(); /* no: save the updated configuration now */
91 * Try to set the subdisk state. Return 1 if state changed to
92 * what we wanted, -1 if it changed to something else, and 0
95 * This routine is called both from the user (up, down states only)
98 * The setstate_force bit in the flags enables the state change even
99 * if it could be dangerous to data consistency. It shouldn't allow
103 set_sd_state(int sdno
, enum sdstate newstate
, enum setstateflags flags
)
105 struct sd
*sd
= &SD
[sdno
];
108 int oldstate
= sd
->state
;
109 int status
= 1; /* status to return */
111 if (newstate
== oldstate
) /* already there, */
113 else if (sd
->state
== sd_unallocated
) /* no subdisk to do anything with, */
114 return 0; /* can't do it */
116 if (sd
->driveoffset
< 0) { /* not allocated space */
118 if (newstate
!= sd_down
) {
120 sdstatemap(&PLEX
[sd
->plexno
]); /* count up subdisks */
123 } else { /* space allocated */
125 case sd_down
: /* take it down? */
127 * If we're attached to a plex, and we're
128 * not reborn, we won't go down without
131 if ((!flags
& setstate_force
)
133 && (sd
->state
!= sd_reborn
))
134 return 0; /* don't do it */
138 if ((sd
->state
== sd_initializing
) /* we were initializing */
139 ||(flags
& setstate_force
)) /* or we forced it */
141 return 0; /* can't do it otherwise */
144 if (DRIVE
[sd
->driveno
].state
!= drive_up
) /* can't bring the sd up if the drive isn't, */
145 return 0; /* not even by force */
146 if (flags
& setstate_force
) /* forcing it, */
147 break; /* just do it, and damn the consequences */
150 * Perform the necessary tests. To allow
151 * the state transition, just break out of
156 case sd_down
: /* been down, no data lost */
158 * If we're associated with a plex, and
159 * the plex isn't up, or we're the only
160 * subdisk in the plex, we can do it.
162 if ((sd
->plexno
>= 0)
163 && (((PLEX
[sd
->plexno
].state
< plex_firstup
)
164 || (PLEX
[sd
->plexno
].subdisks
> 1))))
166 if (oldstate
!= sd_reborn
) {
167 sd
->state
= sd_reborn
; /* here it is again */
169 "vinum: %s is %s, not %s\n",
177 case sd_init
: /* brand new */
178 if (flags
& setstate_configuring
) /* we're doing this while configuring */
180 /* otherwise it's like being empty */
186 * If we're not part of a plex, or the
187 * plex is not part of a volume with other
188 * plexes which are up, we can come up
189 * without being inconsistent.
191 * If we're part of a parity plex, we'll
192 * come up if the caller uses force. This
193 * is the way we bring them up after
197 || ((vpstate(&PLEX
[sd
->plexno
]) & volplex_otherup
) == 0)
198 || (isparity((&PLEX
[sd
->plexno
]))
199 && (flags
& setstate_force
)))
202 /* Otherwise it's just out of date */
205 case sd_stale
: /* out of date info, need reviving */
209 * 1. If the subdisk is not part of a
210 * plex, bring it up, don't revive.
212 * 2. If the subdisk is part of a
213 * one-plex volume or an unattached
214 * plex, and it's not RAID-4 or
215 * RAID-5, we *can't revive*. The
216 * subdisk doesn't change its state.
218 * 3. If the subdisk is part of a
219 * one-plex volume or an unattached
220 * plex, and it's RAID-4 or RAID-5,
221 * but more than one subdisk is down,
222 * we *still can't revive*. The
223 * subdisk doesn't change its state.
225 * 4. If the subdisk is part of a
226 * multi-plex volume, we'll change to
227 * reviving and let the revive
228 * routines find out whether it will
229 * work or not. If they don't, the
230 * revive stops with an error message,
231 * but the state doesn't change
234 if (sd
->plexno
< 0) /* no plex associated, */
235 break; /* bring it up */
236 plex
= &PLEX
[sd
->plexno
];
237 if (plex
->volno
>= 0) /* have a volume */
238 vol
= &VOL
[plex
->volno
];
244 * 1: we don't have a volume
245 * 2: we're the only plex in the volume
246 * 3: we're a RAID-4 or RAID-5 plex, and
247 * more than one subdisk is down.
250 || (vol
->plexes
== 1))
251 && ((!isparity(plex
))
252 || (plex
->sddowncount
> 1))) {
253 if (sd
->state
== sd_initializing
) /* it's finished initializing */
254 sd
->state
= sd_initialized
;
256 return 0; /* can't do it */
258 sd
->state
= sd_reviving
; /* put in reviving state */
259 sd
->revived
= 0; /* nothing done yet */
260 status
= EAGAIN
; /* need to repeat */
265 if (flags
& setstate_force
) /* insist, */
267 return EAGAIN
; /* no, try again */
269 default: /* can't do it */
271 * There's no way to bring subdisks up directly from
272 * other states. First they need to be initialized
279 default: /* other ones, only internal with force */
280 if ((flags
& setstate_force
) == 0) /* no force? What's this? */
281 return 0; /* don't do it */
284 if (status
== 1) { /* we can do it, */
285 sd
->state
= newstate
;
286 if (flags
& setstate_force
)
287 log(LOG_INFO
, "vinum: %s is %s by force\n", sd
->name
, sd_state(sd
->state
));
289 log(LOG_INFO
, "vinum: %s is %s\n", sd
->name
, sd_state(sd
->state
));
290 } else /* we don't get here with status 0 */
292 "vinum: %s is %s, not %s\n",
296 if (sd
->plexno
>= 0) /* we belong to a plex */
297 update_plex_state(sd
->plexno
); /* update plex state */
298 if ((flags
& setstate_configuring
) == 0) /* save config now */
304 * Set the state of a plex dependent on its subdisks.
305 * This time round, we'll let plex state just reflect
306 * aggregate subdisk state, so this becomes an order of
307 * magnitude less complicated. In particular, ignore
308 * the requested state.
311 set_plex_state(int plexno
, enum plexstate state
, enum setstateflags flags
)
313 struct plex
*plex
; /* point to our plex */
314 enum plexstate oldstate
;
315 enum volplexstate vps
; /* how do we compare with the other plexes? */
317 plex
= &PLEX
[plexno
]; /* point to our plex */
318 oldstate
= plex
->state
;
320 /* If the plex isn't allocated, we can't do it. */
321 if (plex
->state
== plex_unallocated
)
325 * If it's already in the the state we want,
326 * and it's not up, just return. If it's up,
327 * we still need to do some housekeeping.
329 if ((state
== oldstate
)
330 && (state
!= plex_up
))
332 vps
= vpstate(plex
); /* how do we compare with the other plexes? */
335 * We can't bring the plex up, even by force,
336 * unless it's ready. update_plex_state
339 case plex_up
: /* bring the plex up */
340 update_plex_state(plex
->plexno
); /* it'll come up if it can */
343 case plex_down
: /* want to take it down */
345 * If we're the only one, or the only one
346 * which is up, we need force to do it.
348 if (((vps
== volplex_onlyus
)
349 || (vps
== volplex_onlyusup
))
350 && (!(flags
& setstate_force
)))
351 return 0; /* can't do it */
352 plex
->state
= state
; /* do it */
353 invalidate_subdisks(plex
, sd_down
); /* and down all up subdisks */
357 * This is only requested internally.
361 plex
->state
= state
; /* do it */
362 invalidate_subdisks(plex
, sd_crashed
); /* and crash all up subdisks */
365 case plex_initializing
:
366 /* XXX consider what safeguards we need here */
367 if ((flags
& setstate_force
) == 0)
369 plex
->state
= state
; /* do it */
376 if (plex
->state
!= oldstate
) /* we've changed, */
377 log(LOG_INFO
, /* tell them about it */
380 plex_state(plex
->state
));
382 * Now see what we have left, and whether
383 * we're taking the volume down
385 if (plex
->volno
>= 0) /* we have a volume */
386 update_volume_state(plex
->volno
); /* update its state */
387 if ((flags
& setstate_configuring
) == 0) /* save config now */
388 save_config(); /* yes: save the updated configuration */
392 /* Update the state of a plex dependent on its plexes. */
394 set_volume_state(int volno
, enum volumestate state
, enum setstateflags flags
)
396 struct volume
*vol
= &VOL
[volno
]; /* point to our volume */
398 if (vol
->state
== volume_unallocated
) /* no volume to do anything with, */
400 if (vol
->state
== state
) /* we're there already */
403 if (state
== volume_up
) /* want to come up */
404 update_volume_state(volno
);
405 else if (state
== volume_down
) { /* want to go down */
406 if (((vol
->flags
& VF_OPEN
) == 0) /* not open */
407 ||((flags
& setstate_force
) != 0)) { /* or we're forcing */
408 vol
->state
= volume_down
;
410 "vinum: volume %s is %s\n",
412 volume_state(vol
->state
));
413 if ((flags
& setstate_configuring
) == 0) /* save config now */
414 save_config(); /* yes: save the updated configuration */
418 return 0; /* no change */
421 /* Set the state of a subdisk based on its environment */
423 update_sd_state(int sdno
)
427 enum sdstate oldstate
;
430 oldstate
= sd
->state
;
431 drive
= &DRIVE
[sd
->driveno
];
433 if (drive
->state
== drive_up
) {
437 sd
->state
= sd_reborn
; /* back up again with no loss */
443 } else { /* down or worse */
449 sd
->state
= sd_crashed
; /* lost our drive */
456 if (sd
->state
!= oldstate
) /* state has changed, */
457 log(LOG_INFO
, /* say so */
460 sd_state(sd
->state
));
461 if (sd
->plexno
>= 0) /* we're part of a plex, */
462 update_plex_state(sd
->plexno
); /* update its state */
466 * Force a plex and all its subdisks
467 * into an 'up' state. This is a helper
468 * for update_plex_state.
476 plex
= &PLEX
[plexno
]; /* point to the plex */
477 plex
->state
= plex_up
; /* and bring it up */
479 /* change the subdisks to up state */
480 for (sdno
= 0; sdno
< plex
->subdisks
; sdno
++) {
481 SD
[plex
->sdnos
[sdno
]].state
= sd_up
;
482 log(LOG_INFO
, /* tell them about it */
484 SD
[plex
->sdnos
[sdno
]].name
);
488 /* Set the state of a plex based on its environment */
490 update_plex_state(int plexno
)
492 struct plex
*plex
; /* point to our plex */
493 enum plexstate oldstate
;
494 enum sdstates statemap
; /* get a map of the subdisk states */
495 enum volplexstate vps
; /* how do we compare with the other plexes? */
497 plex
= &PLEX
[plexno
]; /* point to our plex */
498 oldstate
= plex
->state
;
499 statemap
= sdstatemap(plex
); /* get a map of the subdisk states */
500 vps
= vpstate(plex
); /* how do we compare with the other plexes? */
502 if (statemap
& sd_initstate
) /* something initializing? */
503 plex
->state
= plex_initializing
; /* yup, that makes the plex the same */
504 else if (statemap
== sd_upstate
)
506 * All the subdisks are up. This also means that
507 * they are consistent, so we can just bring
510 plex
->state
= plex_up
;
511 else if (isparity(plex
) /* RAID-4 or RAID-5 plex */
512 &&(plex
->sddowncount
== 1)) /* and exactly one subdisk down */
513 plex
->state
= plex_degraded
; /* limping a bit */
514 else if (((statemap
& ~sd_downstate
) == sd_emptystate
) /* all subdisks empty */
515 ||((statemap
& ~sd_downstate
)
516 == (statemap
& ~sd_downstate
& (sd_initializedstate
| sd_upstate
)))) {
517 if ((vps
& volplex_otherup
) == 0) { /* no other plex is up */
518 struct volume
*vol
= &VOL
[plex
->volno
]; /* possible volume to which it points */
521 * If we're a striped or concat plex
522 * associated with a volume, none of whose
523 * plexes are up, and we're new and untested,
524 * and the volume has the setupstate bit set,
525 * we can pretend to be in a consistent state.
527 * We need to do this in one swell foop: on
528 * the next call we will no longer be just
531 * This code assumes that all the other plexes
532 * are also capable of coming up (i.e. all the
533 * sds are up), but that's OK: we'll come back
534 * to this function for the remaining plexes
537 if ((plex
->state
== plex_init
)
538 && (plex
->volno
>= 0)
539 && (vol
->flags
& VF_CONFIG_SETUPSTATE
)) {
540 for (plexno
= 0; plexno
< vol
->plexes
; plexno
++)
541 forceup(VOL
[plex
->volno
].plex
[plexno
]);
542 } else if ((statemap
== sd_initializedstate
) /* if it's initialized (not empty) */
543 ||(plex
->organization
== plex_concat
) /* and we're not RAID-4 or RAID-5 */
544 ||(plex
->organization
== plex_striped
))
545 forceup(plexno
); /* we'll do it */
547 * This leaves a case where things don't get
548 * done: the plex is RAID-4 or RAID-5, and
549 * the subdisks are all empty. They need to
550 * be initialized first.
553 if (statemap
== sd_upstate
) /* all subdisks up */
554 plex
->state
= plex_up
; /* we can come up too */
556 plex
->state
= plex_faulty
;
558 } else if ((statemap
& (sd_upstate
| sd_rebornstate
)) == statemap
) /* all up or reborn */
559 plex
->state
= plex_flaky
;
560 else if (statemap
& (sd_upstate
| sd_rebornstate
)) /* some up or reborn */
561 plex
->state
= plex_corrupt
; /* corrupt */
562 else if (statemap
& (sd_initstate
| sd_emptystate
)) /* some subdisks empty or initializing */
563 plex
->state
= plex_initializing
;
564 else /* nothing at all up */
565 plex
->state
= plex_faulty
;
567 if (plex
->state
!= oldstate
) /* state has changed, */
568 log(LOG_INFO
, /* tell them about it */
571 plex_state(plex
->state
));
572 if (plex
->volno
>= 0) /* we're part of a volume, */
573 update_volume_state(plex
->volno
); /* update its state */
576 /* Set volume state based on its components */
578 update_volume_state(int volno
)
580 struct volume
*vol
; /* our volume */
582 enum volumestate oldstate
;
584 vol
= &VOL
[volno
]; /* point to our volume */
585 oldstate
= vol
->state
;
587 for (plexno
= 0; plexno
< vol
->plexes
; plexno
++) {
588 struct plex
*plex
= &PLEX
[vol
->plex
[plexno
]]; /* point to the plex */
589 if (plex
->state
>= plex_corrupt
) { /* something accessible, */
590 vol
->state
= volume_up
;
594 if (plexno
== vol
->plexes
) /* didn't find an up plex */
595 vol
->state
= volume_down
;
597 if (vol
->state
!= oldstate
) { /* state changed */
598 log(LOG_INFO
, "vinum: %s is %s\n", vol
->name
, volume_state(vol
->state
));
599 save_config(); /* save the updated configuration */
604 * Called from request routines when they find
605 * a subdisk which is not kosher. Decide whether
606 * it warrants changing the state. Return
607 * REQUEST_DOWN if we can't use the subdisk,
608 * REQUEST_OK if we can.
611 * A prior version of this function checked the plex
612 * state as well. At the moment, consider plex states
613 * information for the user only. We'll ignore them
614 * and use the subdisk state only. The last version of
615 * this file with the old logic was 2.7. XXX
618 checksdstate(struct sd
*sd
, struct request
*rq
, vinum_off_t diskaddr
, vinum_off_t diskend
)
620 struct plex
*plex
= &PLEX
[sd
->plexno
];
621 int writeop
= (rq
->bio
->bio_buf
->b_cmd
!= BUF_CMD_READ
); /* note if we're writing */
624 /* We shouldn't get called if the subdisk is up */
630 * Access to a reviving subdisk depends on the
631 * organization of the plex:
633 * - If it's concatenated, access the subdisk
634 * up to its current revive point. If we
635 * want to write to the subdisk overlapping
636 * the current revive block, set the
637 * conflict flag in the request, asking the
638 * caller to put the request on the wait
639 * list, which will be attended to by
640 * revive_block when it's done.
641 * - if it's striped, we can't do it (we could
642 * do some hairy calculations, but it's
644 * - if it's RAID-4 or RAID-5, we can do it as
645 * long as only one subdisk is down
647 if (plex
->organization
== plex_striped
) /* plex is striped, */
650 else if (isparity(plex
)) { /* RAID-4 or RAID-5 plex */
651 if (plex
->sddowncount
> 1) /* with more than one sd down, */
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
660 return REQUEST_OK
; /* OK, we'll find a way */
662 if (diskaddr
> (sd
->revived
664 + (sd
->revive_blocksize
>> DEV_BSHIFT
))) /* we're beyond the end */
666 else if (diskend
> (sd
->revived
+ sd
->plexoffset
)) { /* we finish beyond the end */
668 rq
->flags
|= XFR_REVIVECONFLICT
; /* note a potential conflict */
669 rq
->sdno
= sd
->sdno
; /* and which sd last caused it */
677 return REQUEST_OK
; /* always write to a reborn disk */
678 else /* don't allow a read */
680 * Handle the mapping. We don't want to reject
681 * a read request to a reborn subdisk if that's
687 if (writeop
) /* writing to a consistent down disk */
688 set_sd_state(sd
->sdno
, sd_obsolete
, setstate_force
); /* it's not consistent now */
692 if (writeop
) /* writing to a consistent down disk */
693 set_sd_state(sd
->sdno
, sd_stale
, setstate_force
); /* it's not consistent now */
701 /* return a state map for the subdisks of a plex */
703 sdstatemap(struct plex
*plex
)
706 enum sdstates statemap
= 0; /* note the states we find */
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 */
714 statemap
|= sd_emptystate
;
715 (plex
->sddowncount
)++; /* another unusable subdisk */
719 statemap
|= sd_initstate
;
720 (plex
->sddowncount
)++; /* another unusable subdisk */
724 statemap
|= sd_downstate
;
725 (plex
->sddowncount
)++; /* another unusable subdisk */
729 statemap
|= sd_crashedstate
;
730 (plex
->sddowncount
)++; /* another unusable subdisk */
734 statemap
|= sd_obsoletestate
;
735 (plex
->sddowncount
)++; /* another unusable subdisk */
739 statemap
|= sd_stalestate
;
740 (plex
->sddowncount
)++; /* another unusable subdisk */
744 statemap
|= sd_rebornstate
;
748 statemap
|= sd_upstate
;
751 case sd_initializing
:
752 statemap
|= sd_initstate
;
753 (plex
->sddowncount
)++; /* another unusable subdisk */
757 statemap
|= sd_initializedstate
;
758 (plex
->sddowncount
)++; /* another unusable subdisk */
765 statemap
|= sd_otherstate
;
766 (plex
->sddowncount
)++; /* another unusable subdisk */
772 /* determine the state of the volume relative to this plex */
774 vpstate(struct plex
*plex
)
777 enum volplexstate state
= volplex_onlyusdown
; /* state to return */
780 if (plex
->volno
< 0) { /* not associated with a volume */
781 if (plex
->state
> plex_degraded
)
782 return volplex_onlyus
; /* just us */
784 return volplex_onlyusdown
; /* assume the worst */
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 */
792 if (PLEX
[vol
->plex
[plexno
]].state
>= plex_degraded
) /* not us */
793 state
|= volplex_otherup
; /* and when they were up, they were up */
795 state
|= volplex_alldown
; /* and when they were down, they were down */
798 return state
; /* and when they were only halfway up */
799 } /* they were neither up nor down */
801 /* Check if all bits b are set in a */
802 int allset(int a
, int b
);
810 /* Invalidate the subdisks belonging to a plex */
812 invalidate_subdisks(struct plex
*plex
, enum sdstate state
)
816 for (sdno
= 0; sdno
< plex
->subdisks
; sdno
++) { /* for each subdisk */
817 struct sd
*sd
= &SD
[plex
->sdnos
[sdno
]];
823 case sd_initializing
:
836 set_sd_state(plex
->sdnos
[sdno
], state
, setstate_force
);
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
847 start_object(struct vinum_ioctl_msg
*data
)
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
;
854 if (data
->force
!= 0) /* are we going to use force? */
855 flags
= setstate_force
; /* yes */
857 flags
= setstate_none
; /* no */
859 switch (data
->type
) {
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
;
865 ioctl_reply
->error
= 0;
869 if (DRIVE
[SD
[objindex
].driveno
].state
!= drive_up
) {
870 ioctl_reply
->error
= EIO
;
871 strcpy(ioctl_reply
->msg
, "Drive is down");
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 */
882 } else if (SD
[objindex
].state
== sd_initializing
) { /* initializing, */
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 */
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
;
894 ioctl_reply
->error
= 0;
896 ioctl_reply
->error
= status
;
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
;
904 ioctl_reply
->error
= 0;
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
;
912 ioctl_reply
->error
= 0;
916 ioctl_reply
->error
= EINVAL
;
917 strcpy(ioctl_reply
->msg
, "Invalid object type");
921 * There's no point in saying anything here:
922 * the userland program does it better
924 ioctl_reply
->msg
[0] = '\0';
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.
933 stop_object(struct vinum_ioctl_msg
*data
)
936 int objindex
= data
->index
; /* save the number from change */
937 struct _ioctl_reply
*ioctl_reply
= (struct _ioctl_reply
*) data
; /* format for returning replies */
939 switch (data
->type
) {
941 status
= set_drive_state(objindex
, drive_down
, data
->force
);
945 status
= set_sd_state(objindex
, sd_down
, data
->force
);
949 status
= set_plex_state(objindex
, plex_down
, data
->force
);
953 status
= set_volume_state(objindex
, volume_down
, data
->force
);
957 ioctl_reply
->error
= EINVAL
;
958 strcpy(ioctl_reply
->msg
, "Invalid object type");
961 ioctl_reply
->msg
[0] = '\0';
962 if (status
== 0) /* couldn't do it */
963 ioctl_reply
->error
= EBUSY
;
965 ioctl_reply
->error
= 0;
969 * VINUM_SETSTATE ioctl: set an object state.
970 * msg is the message passed by the user.
973 setstate(struct vinum_ioctl_msg
*msg
)
978 struct _ioctl_reply
*ioctl_reply
= (struct _ioctl_reply
*) msg
; /* format for returning replies */
980 switch (msg
->state
) {
985 case object_initializing
:
988 sd
= &SD
[msg
->index
];
989 if ((msg
->index
>= vinum_conf
.subdisks_allocated
)
990 || (sd
->state
<= sd_referenced
)) {
991 ksprintf(ioctl_reply
->msg
, "Invalid subdisk %d", msg
->index
);
992 ioctl_reply
->error
= EFAULT
;
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
;
1000 ioctl_reply
->error
= 0;
1004 plex
= &PLEX
[msg
->index
];
1005 if ((msg
->index
>= vinum_conf
.plexes_allocated
)
1006 || (plex
->state
<= plex_unallocated
)) {
1007 ksprintf(ioctl_reply
->msg
, "Invalid plex %d", msg
->index
);
1008 ioctl_reply
->error
= EFAULT
;
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
;
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
;
1030 strcpy(ioctl_reply
->msg
, "Invalid object");
1031 ioctl_reply
->error
= EINVAL
;
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 ksprintf(ioctl_reply
->msg
, "Invalid subdisk %d", msg
->index
);
1041 ioctl_reply
->error
= EFAULT
;
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
;
1049 ioctl_reply
->error
= 0;
1051 strcpy(ioctl_reply
->msg
, "Invalid object");
1052 ioctl_reply
->error
= EINVAL
;
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.
1067 setstate_by_force(struct vinum_ioctl_msg
*msg
)
1069 struct _ioctl_reply
*ioctl_reply
= (struct _ioctl_reply
*) msg
; /* format for returning replies */
1071 switch (msg
->type
) {
1073 DRIVE
[msg
->index
].state
= msg
->state
;
1077 SD
[msg
->index
].state
= msg
->state
;
1081 PLEX
[msg
->index
].state
= msg
->state
;
1085 VOL
[msg
->index
].state
= msg
->state
;
1091 ioctl_reply
->error
= 0;
1093 /* Local Variables: */
1094 /* fill-column: 50 */