summaryrefslogtreecommitdiff
path: root/super-ddf.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2013-08-05 14:56:23 +1000
committerNeilBrown <neilb@suse.de>2013-08-05 15:10:05 +1000
commit92939eb29175a0dc7c9c46ff70f95b76b693b796 (patch)
treeb3da94274774a499d1699c8fd636bd7cd8bc6e52 /super-ddf.c
parent9540cc244dfc56d40f686d8f63aa5b6d73663bcf (diff)
DDF: fix removal of failed devices.
Commit c7079c84 arrange for DDF to forget about any device that is failed and not still marked as part of any array. However such devices could still be part of the container and this removal and updating of 'pdnum' can result in multiple devices having the same pdnum. This in turn easily leads to confusion and corruption. So only discard pd entries for devices which are failed, not listed in any virtual device, and for which we don't have a handle on the device. pd entries will not get removed until a new device is added after the device has been removed from the container, either by "mdadm --remove" or by assembling without the failed devices. Reported-by: Albert Pauw <albert.pauw@gmail.com> Analysed-by: Martin Wilck <mwilck@arcor.de> Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'super-ddf.c')
-rw-r--r--super-ddf.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/super-ddf.c b/super-ddf.c
index 20f4f257..b352a52a 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -4635,13 +4635,19 @@ static void ddf_process_update(struct supertype *st,
*/
pd2 = 0;
for (pdnum = 0; pdnum < be16_to_cpu(ddf->phys->used_pdes);
- pdnum++)
+ pdnum++) {
if (be16_and(ddf->phys->entries[pdnum].state,
cpu_to_be16(DDF_Failed))
&& be16_and(ddf->phys->entries[pdnum].state,
- cpu_to_be16(DDF_Transition)))
- /* skip this one */;
- else if (pdnum == pd2)
+ cpu_to_be16(DDF_Transition))) {
+ /* skip this one unless in dlist*/
+ for (dl = ddf->dlist; dl; dl = dl->next)
+ if (dl->pdnum == (int)pdnum)
+ break;
+ if (!dl)
+ continue;
+ }
+ if (pdnum == pd2)
pd2++;
else {
ddf->phys->entries[pd2] =
@@ -4651,6 +4657,7 @@ static void ddf_process_update(struct supertype *st,
dl->pdnum = pd2;
pd2++;
}
+ }
ddf->phys->used_pdes = cpu_to_be16(pd2);
while (pd2 < pdnum) {
memset(ddf->phys->entries[pd2].guid, 0xff,