]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
imsm: FIX: Manage second map state on array degradation
authorAdam Kwolek <adam.kwolek@intel.com>
Tue, 6 Dec 2011 00:36:30 +0000 (11:36 +1100)
committerNeilBrown <neilb@suse.de>
Tue, 6 Dec 2011 00:36:30 +0000 (11:36 +1100)
When degradation during migration occurs second map state is not set
to degraded value (map are updated correctly).

Correct second map state according to it's degradation level.

Signed-off-by: Adam Kwolek <adam.kwolek@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
super-intel.c

index 9cea2672eaa548a69dccd85ce85fc2424a464310..38d02ea255f0cd90b1c3934298ca67bae942cf14 100644 (file)
@@ -106,6 +106,11 @@ struct imsm_disk {
        __u32 filler[IMSM_DISK_FILLERS]; /* 0xF4 - 0x107 MPB_DISK_FILLERS for future expansion */
 };
 
+/* map selector for map managment
+ */
+#define MAP_0          2
+#define MAP_1          4
+
 /* RAID map configuration infos. */
 struct imsm_map {
        __u32 pba_of_lba0;      /* start address of partition */
@@ -662,7 +667,9 @@ struct imsm_map *get_imsm_map(struct imsm_dev *dev, int second_map)
 {
        /* A device can have 2 maps if it is in the middle of a migration.
         * If second_map is:
+        *    MAP_0 or
         *    0   - we return the first map
+        *    MAP_1 or
         *    1   - we return the second map if it exists, else NULL
         *   -1   - we return the second map if it exists, else the first
         *   -2   - we return longer map /excluding uninitialized state/
@@ -674,8 +681,10 @@ struct imsm_map *get_imsm_map(struct imsm_dev *dev, int second_map)
                map2 = (void *)map + sizeof_imsm_map(map);
 
        switch (second_map) {
+       case MAP_0:
        case 0:
                break;
+       case MAP_1:
        case 1:
                map = map2;
                break;
@@ -2484,8 +2493,28 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
        }
 }
 
-static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev, int failed);
-static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev);
+static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
+                               int failed, int look_in_map);
+
+static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
+                            int look_in_map);
+
+static void manage_second_map(struct intel_super *super, struct imsm_dev *dev)
+{
+       if (is_gen_migration(dev)) {
+               int failed;
+               __u8 map_state;
+               struct imsm_map *map2 = get_imsm_map(dev, MAP_1);
+
+               failed = imsm_count_failed(super, dev, MAP_1);
+               map_state = imsm_check_degraded(super, dev, failed,
+                                               MAP_1);
+               if (map2->map_state != map_state) {
+                       map2->map_state = map_state;
+                       super->updates_pending++;
+               }
+       }
+}
 
 static struct imsm_disk *get_imsm_missing(struct intel_super *super, __u8 index)
 {
@@ -2546,8 +2575,8 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
                struct imsm_map *map;
                __u8 state;
 
-               failed = imsm_count_failed(super, dev);
-               state = imsm_check_degraded(super, dev, failed);
+               failed = imsm_count_failed(super, dev, MAP_0);
+               state = imsm_check_degraded(super, dev, failed, MAP_0);
                map = get_imsm_map(dev, 0);
 
                /* any newly missing disks?
@@ -5913,9 +5942,12 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
 }
 
 
-static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev, int failed)
+static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
+                               int failed, int look_in_map)
 {
-       struct imsm_map *map = get_imsm_map(dev, 0);
+       struct imsm_map *map;
+
+       map = get_imsm_map(dev, look_in_map);
 
        if (!failed)
                return map->map_state == IMSM_T_STATE_UNINITIALIZED ? 
@@ -5979,7 +6011,8 @@ static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
        return map->map_state;
 }
 
-static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev)
+static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
+                            int look_in_map)
 {
        int i;
        int failed = 0;
@@ -6003,9 +6036,9 @@ static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev)
 
        for (i = 0; i < map_for_loop->num_members; i++) {
                ord = 0;
-               if (i < prev->num_members)
+               if ((look_in_map & MAP_1) && (i < prev->num_members))
                        ord |= __le32_to_cpu(prev->disk_ord_tbl[i]);
-               if (i < map->num_members)
+               if ((look_in_map & MAP_0) && (i < map->num_members))
                        ord |= __le32_to_cpu(map->disk_ord_tbl[i]);
                idx = ord_to_idx(ord);
 
@@ -6215,8 +6248,8 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
        struct intel_super *super = a->container->sb;
        struct imsm_dev *dev = get_imsm_dev(super, inst);
        struct imsm_map *map = get_imsm_map(dev, 0);
-       int failed = imsm_count_failed(super, dev);
-       __u8 map_state = imsm_check_degraded(super, dev, failed);
+       int failed = imsm_count_failed(super, dev, MAP_0);
+       __u8 map_state = imsm_check_degraded(super, dev, failed, MAP_0);
        __u32 blocks_per_unit;
 
        if (dev->vol.migr_state &&
@@ -6390,8 +6423,8 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
                super->updates_pending++;
        }
 
-       failed = imsm_count_failed(super, dev);
-       map_state = imsm_check_degraded(super, dev, failed);
+       failed = imsm_count_failed(super, dev, MAP_0);
+       map_state = imsm_check_degraded(super, dev, failed, MAP_0);
 
        /* check if recovery complete, newly degraded, or failed */
        if (map_state == IMSM_T_STATE_NORMAL && is_rebuilding(dev)) {
@@ -6428,6 +6461,8 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
                        dprintf("degraded\n");
                        if (a->last_checkpoint >= a->info.component_size)
                                end_migration(dev, map_state);
+                       else
+                               manage_second_map(super, dev);
                        break;
                default:
                        dprintf("failed\n");
@@ -6624,7 +6659,8 @@ static int imsm_rebuild_allowed(struct supertype *cont, int dev_idx, int failed)
 
        dev2 = get_imsm_dev(cont->sb, dev_idx);
        if (dev2) {
-               state = imsm_check_degraded(cont->sb, dev2, failed);
+               state = imsm_check_degraded(cont->sb, dev2, failed,
+                                           MAP_0);
                if (state == IMSM_T_STATE_FAILED) {
                        map = get_imsm_map(dev2, 0);
                        if (!map)
@@ -6701,7 +6737,8 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
                 */
                return NULL;
 
-       if (imsm_check_degraded(super, dev, failed) != IMSM_T_STATE_DEGRADED)
+       if (imsm_check_degraded(super, dev, failed, MAP_0) !=
+                       IMSM_T_STATE_DEGRADED)
                return NULL;
 
        /*
@@ -7108,7 +7145,8 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
                disk->status &= ~SPARE_DISK;
 
                /* mark rebuild */
-               to_state = imsm_check_degraded(super, dev, failed);
+               to_state = imsm_check_degraded(super, dev, failed,
+                                              MAP_0);
                if (!second_map_created) {
                        second_map_created = 1;
                        map->map_state = IMSM_T_STATE_DEGRADED;
@@ -7293,7 +7331,8 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
 
        if (u->direction == R10_TO_R0) {
                /* Number of failed disks must be half of initial disk number */
-               if (imsm_count_failed(super, dev) != (map->num_members / 2))
+               if (imsm_count_failed(super, dev, MAP_0) !=
+                               (map->num_members / 2))
                        return 0;
 
                /* iterate through devices to mark removed disks as spare */