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

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