From 5961eeec2fe855a164c2e3719bd0835a5b7a8a04 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 22 Oct 2011 11:42:16 +1100 Subject: [PATCH 1/1] imsm: fix: Fixes metadata after migration from Raid 0 to Raid 10 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 Signed-off-by: NeilBrown --- super-intel.c | 154 +++++++++++++++++++++++++++----------------------- 1 file changed, 83 insertions(+), 71 deletions(-) diff --git a/super-intel.c b/super-intel.c index c8765a46..468aab2e 100644 --- a/super-intel.c +++ b/super-intel.c @@ -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; -- 2.39.5