]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
DDF: fix removal of failed devices.
authorNeilBrown <neilb@suse.de>
Mon, 5 Aug 2013 04:56:23 +0000 (14:56 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 5 Aug 2013 05:10:05 +0000 (15:10 +1000)
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>
super-ddf.c

index 20f4f25723e56c4b987a0f2c9c9798574affb79f..b352a52a5fc035c6df408a41d6bf9f95e42d4d41 100644 (file)
@@ -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,