Blame SOURCES/0099-imsm-update-num_data_stripes-according-to-dev_size.patch

3c4af5
From 895ffd992954069e4ea67efb8a85bb0fd72c3707 Mon Sep 17 00:00:00 2001
3c4af5
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
3c4af5
Date: Tue, 24 Nov 2020 14:15:15 +0100
3c4af5
Subject: [PATCH 099/108] imsm: update num_data_stripes according to dev_size
3c4af5
MIME-Version: 1.0
3c4af5
Content-Type: text/plain; charset=UTF-8
3c4af5
Content-Transfer-Encoding: 8bit
3c4af5
3c4af5
If array was created in UEFI there is possibility that
3c4af5
member size is not rounded to 1MB. After any size reconfiguration
3c4af5
it will be rounded down to 1MB per each member but the old
3c4af5
component size will remain in metadata.
3c4af5
During reshape old array size is calculated from component size because
3c4af5
dev_size is not a part of map and is bumped to new value quickly.
3c4af5
It may result in size mismatch if array is assembled during reshape.
3c4af5
3c4af5
If difference in calculated size and dev_size is observed try to fix it.
3c4af5
num_data_stripes value can be safety updated to smaller value if array
3c4af5
doesn't occuppy whole reserved component space.
3c4af5
3c4af5
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
3c4af5
---
3c4af5
 super-intel.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
3c4af5
 1 file changed, 78 insertions(+), 6 deletions(-)
3c4af5
3c4af5
diff --git a/super-intel.c b/super-intel.c
3c4af5
index 3a73d2b..9562064 100644
3c4af5
--- a/super-intel.c
3c4af5
+++ b/super-intel.c
3c4af5
@@ -3453,7 +3453,6 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
3c4af5
 			__u64 blocks_per_unit = blocks_per_migr_unit(super,
3c4af5
 								     dev);
3c4af5
 			__u64 units = current_migr_unit(migr_rec);
3c4af5
-			unsigned long long array_blocks;
3c4af5
 			int used_disks;
3c4af5
 
3c4af5
 			if (__le32_to_cpu(migr_rec->ascending_migr) &&
3c4af5
@@ -3472,12 +3471,8 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
3c4af5
 
3c4af5
 			used_disks = imsm_num_data_members(prev_map);
3c4af5
 			if (used_disks > 0) {
3c4af5
-				array_blocks = per_dev_array_size(map) *
3c4af5
+				info->custom_array_size = per_dev_array_size(map) *
3c4af5
 					used_disks;
3c4af5
-				info->custom_array_size =
3c4af5
-					round_size_to_mb(array_blocks,
3c4af5
-							 used_disks);
3c4af5
-
3c4af5
 			}
3c4af5
 		}
3c4af5
 		case MIGR_VERIFY:
3c4af5
@@ -11682,6 +11677,68 @@ int imsm_takeover(struct supertype *st, struct geo_params *geo)
3c4af5
 	return 0;
3c4af5
 }
3c4af5
 
3c4af5
+/* Flush size update if size calculated by num_data_stripes is higher than
3c4af5
+ * imsm_dev_size to eliminate differences during reshape.
3c4af5
+ * Mdmon will recalculate them correctly.
3c4af5
+ * If subarray index is not set then check whole container.
3c4af5
+ * Returns:
3c4af5
+ *	0 - no error occurred
3c4af5
+ *	1 - error detected
3c4af5
+ */
3c4af5
+static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
3c4af5
+{
3c4af5
+	struct intel_super *super = st->sb;
3c4af5
+	int tmp = super->current_vol;
3c4af5
+	int ret_val = 1;
3c4af5
+	int i;
3c4af5
+
3c4af5
+	for (i = 0; i < super->anchor->num_raid_devs; i++) {
3c4af5
+		if (subarray_index >= 0 && i != subarray_index)
3c4af5
+			continue;
3c4af5
+		super->current_vol = i;
3c4af5
+		struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
3c4af5
+		struct imsm_map *map = get_imsm_map(dev, MAP_0);
3c4af5
+		unsigned int disc_count = imsm_num_data_members(map);
3c4af5
+		struct geo_params geo;
3c4af5
+		struct imsm_update_size_change *update;
3c4af5
+		unsigned long long calc_size = per_dev_array_size(map) * disc_count;
3c4af5
+		unsigned long long d_size = imsm_dev_size(dev);
3c4af5
+		int u_size;
3c4af5
+
3c4af5
+		if (calc_size == d_size || dev->vol.migr_type == MIGR_GEN_MIGR)
3c4af5
+			continue;
3c4af5
+
3c4af5
+		/* There is a difference, verify that imsm_dev_size is
3c4af5
+		 * rounded correctly and push update.
3c4af5
+		 */
3c4af5
+		if (d_size != round_size_to_mb(d_size, disc_count)) {
3c4af5
+			dprintf("imsm: Size of volume %d is not rounded correctly\n",
3c4af5
+				 i);
3c4af5
+			goto exit;
3c4af5
+		}
3c4af5
+		memset(&geo, 0, sizeof(struct geo_params));
3c4af5
+		geo.size = d_size;
3c4af5
+		u_size = imsm_create_metadata_update_for_size_change(st, &geo,
3c4af5
+								     &update);
3c4af5
+		if (u_size < 1) {
3c4af5
+			dprintf("imsm: Cannot prepare size change update\n");
3c4af5
+			goto exit;
3c4af5
+		}
3c4af5
+		imsm_update_metadata_locally(st, update, u_size);
3c4af5
+		if (st->update_tail) {
3c4af5
+			append_metadata_update(st, update, u_size);
3c4af5
+			flush_metadata_updates(st);
3c4af5
+			st->update_tail = &st->updates;
3c4af5
+		} else {
3c4af5
+			imsm_sync_metadata(st);
3c4af5
+		}
3c4af5
+	}
3c4af5
+	ret_val = 0;
3c4af5
+exit:
3c4af5
+	super->current_vol = tmp;
3c4af5
+	return ret_val;
3c4af5
+}
3c4af5
+
3c4af5
 static int imsm_reshape_super(struct supertype *st, unsigned long long size,
3c4af5
 			      int level,
3c4af5
 			      int layout, int chunksize, int raid_disks,
3c4af5
@@ -11718,6 +11775,11 @@ static int imsm_reshape_super(struct supertype *st, unsigned long long size,
3c4af5
 			struct imsm_update_reshape *u = NULL;
3c4af5
 			int len;
3c4af5
 
3c4af5
+			if (imsm_fix_size_mismatch(st, -1)) {
3c4af5
+				dprintf("imsm: Cannot fix size mismatch\n");
3c4af5
+				goto exit_imsm_reshape_super;
3c4af5
+			}
3c4af5
+
3c4af5
 			len = imsm_create_metadata_update_for_reshape(
3c4af5
 				st, &geo, old_raid_disks, &u);
3c4af5
 
3c4af5
@@ -12020,6 +12082,7 @@ static int imsm_manage_reshape(
3c4af5
 	unsigned long long start_buf_shift; /* [bytes] */
3c4af5
 	int degraded = 0;
3c4af5
 	int source_layout = 0;
3c4af5
+	int subarray_index = -1;
3c4af5
 
3c4af5
 	if (!sra)
3c4af5
 		return ret_val;
3c4af5
@@ -12033,6 +12096,7 @@ static int imsm_manage_reshape(
3c4af5
 		    dv->dev->vol.migr_state == 1) {
3c4af5
 			dev = dv->dev;
3c4af5
 			migr_vol_qan++;
3c4af5
+			subarray_index = dv->index;
3c4af5
 		}
3c4af5
 	}
3c4af5
 	/* Only one volume can migrate at the same time */
3c4af5
@@ -12217,6 +12281,14 @@ static int imsm_manage_reshape(
3c4af5
 
3c4af5
 	/* return '1' if done */
3c4af5
 	ret_val = 1;
3c4af5
+
3c4af5
+	/* After the reshape eliminate size mismatch in metadata.
3c4af5
+	 * Don't update md/component_size here, volume hasn't
3c4af5
+	 * to take whole space. It is allowed by kernel.
3c4af5
+	 * md/component_size will be set propoperly after next assembly.
3c4af5
+	 */
3c4af5
+	imsm_fix_size_mismatch(st, subarray_index);
3c4af5
+
3c4af5
 abort:
3c4af5
 	free(buf);
3c4af5
 	/* See Grow.c: abort_reshape() for further explanation */
3c4af5
-- 
3c4af5
2.7.5
3c4af5