]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
imsm: fix: Fixes metadata after migration from Raid 0 to Raid 10
authorroot <root@gklab-128-192.igk.intel.com>
Sat, 22 Oct 2011 00:42:16 +0000 (11:42 +1100)
committerNeilBrown <neilb@suse.de>
Sat, 22 Oct 2011 00:42:16 +0000 (11:42 +1100)
After migration from Raid 0 to Raid 10, the metadata is incorrect,
leaving one mirror disk marked as spare and one missing disk as a member
of the array.
The reason is that the metadata update code for spare activation
procedure takes into account one spare disk only, not checking
the following ones.

Signed-off-by: Lukasz Orlowski <lukasz.orlowski@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
super-intel.c

index c8765a4673b8f783f36915a79fd744a44cb36c55..468aab2e9e1bec5c1b09349ac7c8b2fb08240719 100644 (file)
@@ -6996,90 +6996,102 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
        struct dl *dl;
        unsigned int found;
        int failed;
-       int victim = get_imsm_disk_idx(dev, u->slot, -1);
+       int victim;
        int i;
+       int second_map_created = 0;
 
-       for (dl = super->disks; dl; dl = dl->next)
-               if (dl == u->dl)
-                       break;
-
-       if (!dl) {
-               fprintf(stderr, "error: imsm_activate_spare passed "
-                       "an unknown disk (index: %d)\n",
-                       u->dl->index);
-               return 0;
-       }
+       for (; u; u = u->next) {
+               victim = get_imsm_disk_idx(dev, u->slot, -1);
 
-       /* count failures (excluding rebuilds and the victim)
-        * to determine map[0] state
-        */
-       failed = 0;
-       for (i = 0; i < map->num_members; i++) {
-               if (i == u->slot)
-                       continue;
-               disk = get_imsm_disk(super,
-                                    get_imsm_disk_idx(dev, i, -1));
-               if (!disk || is_failed(disk))
-                       failed++;
-       }
+               if (victim < 0)
+                       return 0;
 
-       /* adding a pristine spare, assign a new index */
-       if (dl->index < 0) {
-               dl->index = super->anchor->num_disks;
-               super->anchor->num_disks++;
-       }
-       disk = &dl->disk;
-       disk->status |= CONFIGURED_DISK;
-       disk->status &= ~SPARE_DISK;
+               for (dl = super->disks; dl; dl = dl->next)
+                       if (dl == u->dl)
+                               break;
 
-       /* mark rebuild */
-       to_state = imsm_check_degraded(super, dev, failed);
-       map->map_state = IMSM_T_STATE_DEGRADED;
-       migrate(dev, super, to_state, MIGR_REBUILD);
-       migr_map = get_imsm_map(dev, 1);
-       set_imsm_ord_tbl_ent(map, u->slot, dl->index);
-       set_imsm_ord_tbl_ent(migr_map, u->slot,
-                            dl->index | IMSM_ORD_REBUILD);
-
-       /* update the family_num to mark a new container
-        * generation, being careful to record the existing
-        * family_num in orig_family_num to clean up after
-        * earlier mdadm versions that neglected to set it.
-        */
-       if (mpb->orig_family_num == 0)
-               mpb->orig_family_num = mpb->family_num;
-       mpb->family_num += super->random;
+               if (!dl) {
+                       fprintf(stderr, "error: imsm_activate_spare passed "
+                               "an unknown disk (index: %d)\n",
+                               u->dl->index);
+                       return 0;
+               }
 
-       /* count arrays using the victim in the metadata */
-       found = 0;
-       for (a = active_array; a ; a = a->next) {
-               dev = get_imsm_dev(super, a->info.container_member);
-               map = get_imsm_map(dev, 0);
+               /* count failures (excluding rebuilds and the victim)
+                * to determine map[0] state
+                */
+               failed = 0;
+               for (i = 0; i < map->num_members; i++) {
+                       if (i == u->slot)
+                               continue;
+                       disk = get_imsm_disk(super,
+                                            get_imsm_disk_idx(dev, i, -1));
+                       if (!disk || is_failed(disk))
+                               failed++;
+               }
 
-               if (get_imsm_disk_slot(map, victim) >= 0)
-                       found++;
-       }
+               /* adding a pristine spare, assign a new index */
+               if (dl->index < 0) {
+                       dl->index = super->anchor->num_disks;
+                       super->anchor->num_disks++;
+               }
+               disk = &dl->disk;
+               disk->status |= CONFIGURED_DISK;
+               disk->status &= ~SPARE_DISK;
+
+               /* mark rebuild */
+               to_state = imsm_check_degraded(super, dev, failed);
+               if (!second_map_created) {
+                       second_map_created = 1;
+                       map->map_state = IMSM_T_STATE_DEGRADED;
+                       migrate(dev, super, to_state, MIGR_REBUILD);
+               } else
+                       map->map_state = to_state;
+               migr_map = get_imsm_map(dev, 1);
+               set_imsm_ord_tbl_ent(map, u->slot, dl->index);
+               set_imsm_ord_tbl_ent(migr_map, u->slot,
+                                    dl->index | IMSM_ORD_REBUILD);
+
+               /* update the family_num to mark a new container
+                * generation, being careful to record the existing
+                * family_num in orig_family_num to clean up after
+                * earlier mdadm versions that neglected to set it.
+                */
+               if (mpb->orig_family_num == 0)
+                       mpb->orig_family_num = mpb->family_num;
+               mpb->family_num += super->random;
+
+               /* count arrays using the victim in the metadata */
+               found = 0;
+               for (a = active_array; a ; a = a->next) {
+                       dev = get_imsm_dev(super, a->info.container_member);
+                       map = get_imsm_map(dev, 0);
 
-       /* delete the victim if it is no longer being
-        * utilized anywhere
-        */
-       if (!found) {
-               struct dl **dlp;
+                       if (get_imsm_disk_slot(map, victim) >= 0)
+                               found++;
+               }
 
-               /* We know that 'manager' isn't touching anything,
-                * so it is safe to delete
+               /* delete the victim if it is no longer being
+                * utilized anywhere
                 */
-               for (dlp = &super->disks; *dlp; dlp = &(*dlp)->next)
-                       if ((*dlp)->index == victim)
-                               break;
+               if (!found) {
+                       struct dl **dlp;
 
-               /* victim may be on the missing list */
-               if (!*dlp)
-                       for (dlp = &super->missing; *dlp;
-                            dlp = &(*dlp)->next)
+                       /* We know that 'manager' isn't touching anything,
+                        * so it is safe to delete
+                        */
+                       for (dlp = &super->disks; *dlp; dlp = &(*dlp)->next)
                                if ((*dlp)->index == victim)
                                        break;
-               imsm_delete(super, dlp, victim);
+
+                       /* victim may be on the missing list */
+                       if (!*dlp)
+                               for (dlp = &super->missing; *dlp;
+                                    dlp = &(*dlp)->next)
+                                       if ((*dlp)->index == victim)
+                                               break;
+                       imsm_delete(super, dlp, victim);
+               }
        }
 
        return 1;