From 5961eeec2fe855a164c2e3719bd0835a5b7a8a04 Mon Sep 17 00:00:00 2001
From: root <root@gklab-128-192.igk.intel.com>
Date: Sat, 22 Oct 2011 11:42:16 +1100
Subject: [PATCH 115/115] 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 <lukasz.orlowski@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
---
 super-intel.c |  150 +++++++++++++++++++++++++++++++--------------------------
 1 files changed, 81 insertions(+), 69 deletions(-)

diff --git a/super-intel.c b/super-intel.c
index c8765a4..468aab2 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;
+	for (; u; u = u->next) {
+		victim = get_imsm_disk_idx(dev, u->slot, -1);
 
-	if (!dl) {
-		fprintf(stderr, "error: imsm_activate_spare passed "
-			"an unknown disk (index: %d)\n",
-			u->dl->index);
-		return 0;
-	}
+		if (victim < 0)
+			return 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++;
-	}
+		for (dl = super->disks; dl; dl = dl->next)
+			if (dl == u->dl)
+				break;
 
-	/* 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;
+		if (!dl) {
+			fprintf(stderr, "error: imsm_activate_spare passed "
+				"an unknown disk (index: %d)\n",
+				u->dl->index);
+			return 0;
+		}
 
-	/* 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);
+		/* 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++;
+		}
 
-	/* 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;
+		/* 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;
 
-	/* 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);
+		/* 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);
 
-		if (get_imsm_disk_slot(map, victim) >= 0)
-			found++;
-	}
+		/* 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;
 
-	/* delete the victim if it is no longer being
-	 * utilized anywhere
-	 */
-	if (!found) {
-		struct dl **dlp;
+		/* 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);
+
+			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;
-- 
1.7.7

