Blame SOURCES/0007-imsm-do-not-use-blocks_per_member-in-array-size-calc.patch

59ea72
From 444909385fdaccf961308c4319d7029b82bf8bb1 Mon Sep 17 00:00:00 2001
59ea72
From: Mariusz Dabrowski <mariusz.dabrowski@intel.com>
59ea72
Date: Thu, 5 Apr 2018 13:38:38 +0200
59ea72
Subject: [RHEL7.5 PATCH 07/26] imsm: do not use blocks_per_member in array
59ea72
 size calculations
59ea72
59ea72
mdadm assumes that blocks_per_member value is equal to num_data_stripes *
59ea72
blocks_per_stripe but it is not true. For IMSM arrays created in OROM
59ea72
NUM_BLOCKS_DIRTY_STRIPE_REGION sectors are added up to this value. Because
59ea72
of this mdadm shows invalid size of arrays created in OROM and to fix this
59ea72
we need to use array size calculation based on num data stripes and blocks
59ea72
per stripe.
59ea72
59ea72
Signed-off-by: Mariusz Dabrowski <mariusz.dabrowski@intel.com>
59ea72
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
59ea72
---
59ea72
 super-intel.c | 105 ++++++++++++++++++++++++++++++++++++++++++----------------
59ea72
 1 file changed, 76 insertions(+), 29 deletions(-)
59ea72
59ea72
diff --git a/super-intel.c b/super-intel.c
59ea72
index 3fc3cf4..c55c85f 100644
59ea72
--- a/super-intel.c
59ea72
+++ b/super-intel.c
59ea72
@@ -1233,6 +1233,20 @@ static void set_imsm_dev_size(struct imsm_dev *dev, unsigned long long n)
59ea72
 	split_ull(n, &dev->size_low, &dev->size_high);
59ea72
 }
59ea72
 
59ea72
+static unsigned long long per_dev_array_size(struct imsm_map *map)
59ea72
+{
59ea72
+	unsigned long long array_size = 0;
59ea72
+
59ea72
+	if (map == NULL)
59ea72
+		return array_size;
59ea72
+
59ea72
+	array_size = num_data_stripes(map) * map->blocks_per_strip;
59ea72
+	if (get_imsm_raid_level(map) == 1 || get_imsm_raid_level(map) == 10)
59ea72
+		array_size *= 2;
59ea72
+
59ea72
+	return array_size;
59ea72
+}
59ea72
+
59ea72
 static struct extent *get_extents(struct intel_super *super, struct dl *dl)
59ea72
 {
59ea72
 	/* find a list of used extents on the given physical device */
59ea72
@@ -1259,7 +1273,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
59ea72
 
59ea72
 		if (get_imsm_disk_slot(map, dl->index) >= 0) {
59ea72
 			e->start = pba_of_lba0(map);
59ea72
-			e->size = blocks_per_member(map);
59ea72
+			e->size = per_dev_array_size(map);
59ea72
 			e++;
59ea72
 		}
59ea72
 	}
59ea72
@@ -2787,6 +2801,36 @@ static __u8 imsm_num_data_members(struct imsm_map *map)
59ea72
 	}
59ea72
 }
59ea72
 
59ea72
+static unsigned long long calc_component_size(struct imsm_map *map,
59ea72
+					      struct imsm_dev *dev)
59ea72
+{
59ea72
+	unsigned long long component_size;
59ea72
+	unsigned long long dev_size = imsm_dev_size(dev);
59ea72
+	unsigned long long calc_dev_size = 0;
59ea72
+	unsigned int member_disks = imsm_num_data_members(map);
59ea72
+
59ea72
+	if (member_disks == 0)
59ea72
+		return 0;
59ea72
+
59ea72
+	component_size = per_dev_array_size(map);
59ea72
+	calc_dev_size = component_size * member_disks;
59ea72
+
59ea72
+	/* Component size is rounded to 1MB so difference between size from
59ea72
+	 * metadata and size calculated from num_data_stripes equals up to
59ea72
+	 * 2048 blocks per each device. If the difference is higher it means
59ea72
+	 * that array size was expanded and num_data_stripes was not updated.
59ea72
+	 */
59ea72
+	if ((unsigned int)abs(calc_dev_size - dev_size) >
59ea72
+	    (1 << SECT_PER_MB_SHIFT) * member_disks) {
59ea72
+		component_size = dev_size / member_disks;
59ea72
+		dprintf("Invalid num_data_stripes in metadata; expected=%llu, found=%llu\n",
59ea72
+			component_size / map->blocks_per_strip,
59ea72
+			num_data_stripes(map));
59ea72
+	}
59ea72
+
59ea72
+	return component_size;
59ea72
+}
59ea72
+
59ea72
 static __u32 parity_segment_depth(struct imsm_dev *dev)
59ea72
 {
59ea72
 	struct imsm_map *map = get_imsm_map(dev, MAP_0);
59ea72
@@ -3306,14 +3350,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
59ea72
 	}
59ea72
 
59ea72
 	info->data_offset	  = pba_of_lba0(map_to_analyse);
59ea72
-
59ea72
-	if (info->array.level == 5) {
59ea72
-		info->component_size = num_data_stripes(map_to_analyse) *
59ea72
-				       map_to_analyse->blocks_per_strip;
59ea72
-	} else {
59ea72
-		info->component_size = blocks_per_member(map_to_analyse);
59ea72
-	}
59ea72
-
59ea72
+	info->component_size = calc_component_size(map, dev);
59ea72
 	info->component_size = imsm_component_size_aligment_check(
59ea72
 							info->array.level,
59ea72
 							info->array.chunk_size,
59ea72
@@ -3381,7 +3418,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
59ea72
 
59ea72
 			used_disks = imsm_num_data_members(prev_map);
59ea72
 			if (used_disks > 0) {
59ea72
-				array_blocks = blocks_per_member(map) *
59ea72
+				array_blocks = per_dev_array_size(map) *
59ea72
 					used_disks;
59ea72
 				info->custom_array_size =
59ea72
 					round_size_to_mb(array_blocks,
59ea72
@@ -5383,9 +5420,6 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
59ea72
 	vol->curr_migr_unit = 0;
59ea72
 	map = get_imsm_map(dev, MAP_0);
59ea72
 	set_pba_of_lba0(map, super->create_offset);
59ea72
-	set_blocks_per_member(map, info_to_blocks_per_member(info,
59ea72
-							     size_per_member /
59ea72
-							     BLOCKS_PER_KB));
59ea72
 	map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
59ea72
 	map->failed_disk_num = ~0;
59ea72
 	if (info->level > 0)
59ea72
@@ -5417,6 +5451,11 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
59ea72
 	num_data_stripes /= map->num_domains;
59ea72
 	set_num_data_stripes(map, num_data_stripes);
59ea72
 
59ea72
+	size_per_member += NUM_BLOCKS_DIRTY_STRIPE_REGION;
59ea72
+	set_blocks_per_member(map, info_to_blocks_per_member(info,
59ea72
+							     size_per_member /
59ea72
+							     BLOCKS_PER_KB));
59ea72
+
59ea72
 	map->num_members = info->raid_disks;
59ea72
 	for (i = 0; i < map->num_members; i++) {
59ea72
 		/* initialized in add_to_super */
59ea72
@@ -7821,18 +7860,14 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
59ea72
 
59ea72
 			info_d->events = __le32_to_cpu(mpb->generation_num);
59ea72
 			info_d->data_offset = pba_of_lba0(map);
59ea72
+			info_d->component_size = calc_component_size(map, dev);
59ea72
 
59ea72
 			if (map->raid_level == 5) {
59ea72
-				info_d->component_size =
59ea72
-						num_data_stripes(map) *
59ea72
-						map->blocks_per_strip;
59ea72
 				info_d->ppl_sector = this->ppl_sector;
59ea72
 				info_d->ppl_size = this->ppl_size;
59ea72
 				if (this->consistency_policy == CONSISTENCY_POLICY_PPL &&
59ea72
 				    recovery_start == 0)
59ea72
 					this->resync_start = 0;
59ea72
-			} else {
59ea72
-				info_d->component_size = blocks_per_member(map);
59ea72
 			}
59ea72
 
59ea72
 			info_d->bb.supported = 1;
59ea72
@@ -8156,7 +8191,7 @@ static unsigned long long imsm_set_array_size(struct imsm_dev *dev,
59ea72
 	if (new_size <= 0)
59ea72
 		/* OLCE size change is caused by added disks
59ea72
 		 */
59ea72
-		array_blocks = blocks_per_member(map) * used_disks;
59ea72
+		array_blocks = per_dev_array_size(map) * used_disks;
59ea72
 	else
59ea72
 		/* Online Volume Size Change
59ea72
 		 * Using  available free space
59ea72
@@ -8273,7 +8308,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
59ea72
 				used_disks = imsm_num_data_members(map);
59ea72
 				if (used_disks > 0) {
59ea72
 					array_blocks =
59ea72
-						blocks_per_member(map) *
59ea72
+						per_dev_array_size(map) *
59ea72
 						used_disks;
59ea72
 					array_blocks =
59ea72
 						round_size_to_mb(array_blocks,
59ea72
@@ -8715,11 +8750,11 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot,
59ea72
 			pos = 0;
59ea72
 			array_start = pba_of_lba0(map);
59ea72
 			array_end = array_start +
59ea72
-				    blocks_per_member(map) - 1;
59ea72
+				    per_dev_array_size(map) - 1;
59ea72
 
59ea72
 			do {
59ea72
 				/* check that we can start at pba_of_lba0 with
59ea72
-				 * blocks_per_member of space
59ea72
+				 * num_data_stripes*blocks_per_stripe of space
59ea72
 				 */
59ea72
 				if (array_start >= pos && array_end < ex[j].start) {
59ea72
 					found = 1;
59ea72
@@ -9145,6 +9180,12 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
59ea72
 				set_num_data_stripes(map, num_data_stripes);
59ea72
 			}
59ea72
 
59ea72
+			/* ensure blocks_per_member has valid value
59ea72
+			 */
59ea72
+			set_blocks_per_member(map,
59ea72
+					      per_dev_array_size(map) +
59ea72
+					      NUM_BLOCKS_DIRTY_STRIPE_REGION);
59ea72
+
59ea72
 			/* add disk
59ea72
 			 */
59ea72
 			if (u->new_level != 5 || migr_map->raid_level != 0 ||
59ea72
@@ -9211,15 +9252,21 @@ static int apply_size_change_update(struct imsm_update_size_change *u,
59ea72
 			int used_disks = imsm_num_data_members(map);
59ea72
 			unsigned long long blocks_per_member;
59ea72
 			unsigned long long num_data_stripes;
59ea72
+			unsigned long long new_size_per_disk;
59ea72
+
59ea72
+			if (used_disks == 0)
59ea72
+				return 0;
59ea72
 
59ea72
 			/* calculate new size
59ea72
 			 */
59ea72
-			blocks_per_member = u->new_size / used_disks;
59ea72
-			num_data_stripes = blocks_per_member /
59ea72
+			new_size_per_disk = u->new_size / used_disks;
59ea72
+			blocks_per_member = new_size_per_disk +
59ea72
+					    NUM_BLOCKS_DIRTY_STRIPE_REGION;
59ea72
+			num_data_stripes = new_size_per_disk /
59ea72
 					   map->blocks_per_strip;
59ea72
 			num_data_stripes /= map->num_domains;
59ea72
 			dprintf("(size: %llu, blocks per member: %llu, num_data_stipes: %llu)\n",
59ea72
-				u->new_size, blocks_per_member,
59ea72
+				u->new_size, new_size_per_disk,
59ea72
 				num_data_stripes);
59ea72
 			set_blocks_per_member(map, blocks_per_member);
59ea72
 			set_num_data_stripes(map, num_data_stripes);
59ea72
@@ -9476,7 +9523,7 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
59ea72
 		unsigned long long num_data_stripes;
59ea72
 
59ea72
 		map->num_domains = 1;
59ea72
-		num_data_stripes = blocks_per_member(map);
59ea72
+		num_data_stripes = imsm_dev_size(dev) / 2;
59ea72
 		num_data_stripes /= map->blocks_per_strip;
59ea72
 		num_data_stripes /= map->num_domains;
59ea72
 		set_num_data_stripes(map, num_data_stripes);
59ea72
@@ -9692,7 +9739,7 @@ static void imsm_process_update(struct supertype *st,
59ea72
 
59ea72
 		new_map = get_imsm_map(&u->dev, MAP_0);
59ea72
 		new_start = pba_of_lba0(new_map);
59ea72
-		new_end = new_start + blocks_per_member(new_map);
59ea72
+		new_end = new_start + per_dev_array_size(new_map);
59ea72
 		inf = get_disk_info(u);
59ea72
 
59ea72
 		/* handle activate_spare versus create race:
59ea72
@@ -9703,7 +9750,7 @@ static void imsm_process_update(struct supertype *st,
59ea72
 			dev = get_imsm_dev(super, i);
59ea72
 			map = get_imsm_map(dev, MAP_0);
59ea72
 			start = pba_of_lba0(map);
59ea72
-			end = start + blocks_per_member(map);
59ea72
+			end = start + per_dev_array_size(map);
59ea72
 			if ((new_start >= start && new_start <= end) ||
59ea72
 			    (start >= new_start && start <= new_end))
59ea72
 				/* overlap */;
59ea72
@@ -10492,7 +10539,7 @@ static struct md_bb *imsm_get_badblocks(struct active_array *a, int slot)
59ea72
 		return NULL;
59ea72
 
59ea72
 	get_volume_badblocks(super->bbm_log, ord_to_idx(ord), pba_of_lba0(map),
59ea72
-			     blocks_per_member(map), &super->bb);
59ea72
+			     per_dev_array_size(map), &super->bb);
59ea72
 
59ea72
 	return &super->bb;
59ea72
 }
59ea72
-- 
59ea72
2.7.4
59ea72