dcavalca / rpms / mdadm

Forked from rpms/mdadm 3 years ago
Clone

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

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