dcavalca / rpms / mdadm

Forked from rpms/mdadm 3 years ago
Clone

Blame SOURCES/0013-imsm-fix-reshape-for-2TB-drives.patch

5d5466
From 9f4218274cd4a1e1f356a1617f9a1d09960cf255 Mon Sep 17 00:00:00 2001
5d5466
From: Pawel Baldysiak <pawel.baldysiak@intel.com>
5d5466
Date: Mon, 28 Jan 2019 17:10:41 +0100
5d5466
Subject: [RHEL7.7 PATCH 13/24] imsm: fix reshape for >2TB drives
5d5466
5d5466
If reshape is performed on drives larger then 2 TB,
5d5466
migration checkpoint area that is calculated exeeds 32-bit value.
5d5466
This checkpoint area is a reserved space threated as backup
5d5466
during reshape - at the end of the drive, right before metadata.
5d5466
As a result - wrong space is used and the data that may exists there
5d5466
is overwritten.
5d5466
5d5466
Adding additional field to migration record to track high order 32-bits
5d5466
of pba of this area. Three other fields that may exceed 32-bit value
5d5466
for large drives are added as well.
5d5466
5d5466
Signed-off-by: Pawel Baldysiak <pawel.baldysiak@intel.com>
5d5466
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
5d5466
---
5d5466
 super-intel.c | 149 +++++++++++++++++++++++++++++++++++++++++-----------------
5d5466
 1 file changed, 107 insertions(+), 42 deletions(-)
5d5466
5d5466
diff --git a/super-intel.c b/super-intel.c
5d5466
index 38a1b6c..1cc7d5f 100644
5d5466
--- a/super-intel.c
5d5466
+++ b/super-intel.c
5d5466
@@ -296,7 +296,7 @@ struct migr_record {
5d5466
 	__u32 rec_status;	    /* Status used to determine how to restart
5d5466
 				     * migration in case it aborts
5d5466
 				     * in some fashion */
5d5466
-	__u32 curr_migr_unit;	    /* 0..numMigrUnits-1 */
5d5466
+	__u32 curr_migr_unit_lo;    /* 0..numMigrUnits-1 */
5d5466
 	__u32 family_num;	    /* Family number of MPB
5d5466
 				     * containing the RaidDev
5d5466
 				     * that is migrating */
5d5466
@@ -306,16 +306,23 @@ struct migr_record {
5d5466
 	__u32 dest_depth_per_unit;  /* Num member blocks each destMap
5d5466
 				     * member disk
5d5466
 				     * advances per unit-of-operation */
5d5466
-	__u32 ckpt_area_pba;	    /* Pba of first block of ckpt copy area */
5d5466
-	__u32 dest_1st_member_lba;  /* First member lba on first
5d5466
-				     * stripe of destination */
5d5466
-	__u32 num_migr_units;	    /* Total num migration units-of-op */
5d5466
+	__u32 ckpt_area_pba_lo;	    /* Pba of first block of ckpt copy area */
5d5466
+	__u32 dest_1st_member_lba_lo;	/* First member lba on first
5d5466
+					 * stripe of destination */
5d5466
+	__u32 num_migr_units_lo;    /* Total num migration units-of-op */
5d5466
 	__u32 post_migr_vol_cap;    /* Size of volume after
5d5466
 				     * migration completes */
5d5466
 	__u32 post_migr_vol_cap_hi; /* Expansion space for LBA64 */
5d5466
 	__u32 ckpt_read_disk_num;   /* Which member disk in destSubMap[0] the
5d5466
 				     * migration ckpt record was read from
5d5466
 				     * (for recovered migrations) */
5d5466
+	__u32 curr_migr_unit_hi;    /* 0..numMigrUnits-1 high order 32 bits */
5d5466
+	__u32 ckpt_area_pba_hi;	    /* Pba of first block of ckpt copy area
5d5466
+				     * high order 32 bits */
5d5466
+	__u32 dest_1st_member_lba_hi; /* First member lba on first stripe of
5d5466
+				       * destination - high order 32 bits */
5d5466
+	__u32 num_migr_units_hi;      /* Total num migration units-of-op
5d5466
+				       * high order 32 bits */
5d5466
 } __attribute__ ((__packed__));
5d5466
 
5d5466
 struct md_list {
5d5466
@@ -1208,6 +1215,38 @@ static unsigned long long imsm_dev_size(struct imsm_dev *dev)
5d5466
 	return join_u32(dev->size_low, dev->size_high);
5d5466
 }
5d5466
 
5d5466
+static unsigned long long migr_chkp_area_pba(struct migr_record *migr_rec)
5d5466
+{
5d5466
+	if (migr_rec == NULL)
5d5466
+		return 0;
5d5466
+	return join_u32(migr_rec->ckpt_area_pba_lo,
5d5466
+			migr_rec->ckpt_area_pba_hi);
5d5466
+}
5d5466
+
5d5466
+static unsigned long long current_migr_unit(struct migr_record *migr_rec)
5d5466
+{
5d5466
+	if (migr_rec == NULL)
5d5466
+		return 0;
5d5466
+	return join_u32(migr_rec->curr_migr_unit_lo,
5d5466
+			migr_rec->curr_migr_unit_hi);
5d5466
+}
5d5466
+
5d5466
+static unsigned long long migr_dest_1st_member_lba(struct migr_record *migr_rec)
5d5466
+{
5d5466
+	if (migr_rec == NULL)
5d5466
+		return 0;
5d5466
+	return join_u32(migr_rec->dest_1st_member_lba_lo,
5d5466
+			migr_rec->dest_1st_member_lba_hi);
5d5466
+}
5d5466
+
5d5466
+static unsigned long long get_num_migr_units(struct migr_record *migr_rec)
5d5466
+{
5d5466
+	if (migr_rec == NULL)
5d5466
+		return 0;
5d5466
+	return join_u32(migr_rec->num_migr_units_lo,
5d5466
+			migr_rec->num_migr_units_hi);
5d5466
+}
5d5466
+
5d5466
 static void set_total_blocks(struct imsm_disk *disk, unsigned long long n)
5d5466
 {
5d5466
 	split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi);
5d5466
@@ -1233,6 +1272,33 @@ static void set_imsm_dev_size(struct imsm_dev *dev, unsigned long long n)
5d5466
 	split_ull(n, &dev->size_low, &dev->size_high);
5d5466
 }
5d5466
 
5d5466
+static void set_migr_chkp_area_pba(struct migr_record *migr_rec,
5d5466
+				   unsigned long long n)
5d5466
+{
5d5466
+	split_ull(n, &migr_rec->ckpt_area_pba_lo, &migr_rec->ckpt_area_pba_hi);
5d5466
+}
5d5466
+
5d5466
+static void set_current_migr_unit(struct migr_record *migr_rec,
5d5466
+				  unsigned long long n)
5d5466
+{
5d5466
+	split_ull(n, &migr_rec->curr_migr_unit_lo,
5d5466
+		  &migr_rec->curr_migr_unit_hi);
5d5466
+}
5d5466
+
5d5466
+static void set_migr_dest_1st_member_lba(struct migr_record *migr_rec,
5d5466
+					 unsigned long long n)
5d5466
+{
5d5466
+	split_ull(n, &migr_rec->dest_1st_member_lba_lo,
5d5466
+		  &migr_rec->dest_1st_member_lba_hi);
5d5466
+}
5d5466
+
5d5466
+static void set_num_migr_units(struct migr_record *migr_rec,
5d5466
+			       unsigned long long n)
5d5466
+{
5d5466
+	split_ull(n, &migr_rec->num_migr_units_lo,
5d5466
+		  &migr_rec->num_migr_units_hi);
5d5466
+}
5d5466
+
5d5466
 static unsigned long long per_dev_array_size(struct imsm_map *map)
5d5466
 {
5d5466
 	unsigned long long array_size = 0;
5d5466
@@ -1629,12 +1695,14 @@ void convert_to_4k_imsm_migr_rec(struct intel_super *super)
5d5466
 	struct migr_record *migr_rec = super->migr_rec;
5d5466
 
5d5466
 	migr_rec->blocks_per_unit /= IMSM_4K_DIV;
5d5466
-	migr_rec->ckpt_area_pba /= IMSM_4K_DIV;
5d5466
-	migr_rec->dest_1st_member_lba /= IMSM_4K_DIV;
5d5466
 	migr_rec->dest_depth_per_unit /= IMSM_4K_DIV;
5d5466
 	split_ull((join_u32(migr_rec->post_migr_vol_cap,
5d5466
 		 migr_rec->post_migr_vol_cap_hi) / IMSM_4K_DIV),
5d5466
 		 &migr_rec->post_migr_vol_cap, &migr_rec->post_migr_vol_cap_hi);
5d5466
+	set_migr_chkp_area_pba(migr_rec,
5d5466
+		 migr_chkp_area_pba(migr_rec) / IMSM_4K_DIV);
5d5466
+	set_migr_dest_1st_member_lba(migr_rec,
5d5466
+		 migr_dest_1st_member_lba(migr_rec) / IMSM_4K_DIV);
5d5466
 }
5d5466
 
5d5466
 void convert_to_4k_imsm_disk(struct imsm_disk *disk)
5d5466
@@ -1727,8 +1795,8 @@ void examine_migr_rec_imsm(struct intel_super *super)
5d5466
 			printf("Normal\n");
5d5466
 		else
5d5466
 			printf("Contains Data\n");
5d5466
-		printf("               Current Unit : %u\n",
5d5466
-		       __le32_to_cpu(migr_rec->curr_migr_unit));
5d5466
+		printf("               Current Unit : %llu\n",
5d5466
+		       current_migr_unit(migr_rec));
5d5466
 		printf("                     Family : %u\n",
5d5466
 		       __le32_to_cpu(migr_rec->family_num));
5d5466
 		printf("                  Ascending : %u\n",
5d5466
@@ -1737,16 +1805,15 @@ void examine_migr_rec_imsm(struct intel_super *super)
5d5466
 		       __le32_to_cpu(migr_rec->blocks_per_unit));
5d5466
 		printf("       Dest. Depth Per Unit : %u\n",
5d5466
 		       __le32_to_cpu(migr_rec->dest_depth_per_unit));
5d5466
-		printf("        Checkpoint Area pba : %u\n",
5d5466
-		       __le32_to_cpu(migr_rec->ckpt_area_pba));
5d5466
-		printf("           First member lba : %u\n",
5d5466
-		       __le32_to_cpu(migr_rec->dest_1st_member_lba));
5d5466
-		printf("      Total Number of Units : %u\n",
5d5466
-		       __le32_to_cpu(migr_rec->num_migr_units));
5d5466
-		printf("             Size of volume : %u\n",
5d5466
-		       __le32_to_cpu(migr_rec->post_migr_vol_cap));
5d5466
-		printf("  Expansion space for LBA64 : %u\n",
5d5466
-		       __le32_to_cpu(migr_rec->post_migr_vol_cap_hi));
5d5466
+		printf("        Checkpoint Area pba : %llu\n",
5d5466
+		       migr_chkp_area_pba(migr_rec));
5d5466
+		printf("           First member lba : %llu\n",
5d5466
+		       migr_dest_1st_member_lba(migr_rec));
5d5466
+		printf("      Total Number of Units : %llu\n",
5d5466
+		       get_num_migr_units(migr_rec));
5d5466
+		printf("             Size of volume : %llu\n",
5d5466
+		       join_u32(migr_rec->post_migr_vol_cap,
5d5466
+				migr_rec->post_migr_vol_cap_hi));
5d5466
 		printf("       Record was read from : %u\n",
5d5466
 		       __le32_to_cpu(migr_rec->ckpt_read_disk_num));
5d5466
 
5d5466
@@ -1759,13 +1826,15 @@ void convert_from_4k_imsm_migr_rec(struct intel_super *super)
5d5466
 	struct migr_record *migr_rec = super->migr_rec;
5d5466
 
5d5466
 	migr_rec->blocks_per_unit *= IMSM_4K_DIV;
5d5466
-	migr_rec->ckpt_area_pba *= IMSM_4K_DIV;
5d5466
-	migr_rec->dest_1st_member_lba *= IMSM_4K_DIV;
5d5466
 	migr_rec->dest_depth_per_unit *= IMSM_4K_DIV;
5d5466
 	split_ull((join_u32(migr_rec->post_migr_vol_cap,
5d5466
 		 migr_rec->post_migr_vol_cap_hi) * IMSM_4K_DIV),
5d5466
 		 &migr_rec->post_migr_vol_cap,
5d5466
 		 &migr_rec->post_migr_vol_cap_hi);
5d5466
+	set_migr_chkp_area_pba(migr_rec,
5d5466
+		 migr_chkp_area_pba(migr_rec) * IMSM_4K_DIV);
5d5466
+	set_migr_dest_1st_member_lba(migr_rec,
5d5466
+		 migr_dest_1st_member_lba(migr_rec) * IMSM_4K_DIV);
5d5466
 }
5d5466
 
5d5466
 void convert_from_4k(struct intel_super *super)
5d5466
@@ -3096,7 +3165,7 @@ static int imsm_create_metadata_checkpoint_update(
5d5466
 		return 0;
5d5466
 	}
5d5466
 	(*u)->type = update_general_migration_checkpoint;
5d5466
-	(*u)->curr_migr_unit = __le32_to_cpu(super->migr_rec->curr_migr_unit);
5d5466
+	(*u)->curr_migr_unit = current_migr_unit(super->migr_rec);
5d5466
 	dprintf("prepared for %u\n", (*u)->curr_migr_unit);
5d5466
 
5d5466
 	return update_memory_size;
5d5466
@@ -3397,13 +3466,13 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
5d5466
 		case MIGR_GEN_MIGR: {
5d5466
 			__u64 blocks_per_unit = blocks_per_migr_unit(super,
5d5466
 								     dev);
5d5466
-			__u64 units = __le32_to_cpu(migr_rec->curr_migr_unit);
5d5466
+			__u64 units = current_migr_unit(migr_rec);
5d5466
 			unsigned long long array_blocks;
5d5466
 			int used_disks;
5d5466
 
5d5466
 			if (__le32_to_cpu(migr_rec->ascending_migr) &&
5d5466
 			    (units <
5d5466
-				(__le32_to_cpu(migr_rec->num_migr_units)-1)) &&
5d5466
+				(get_num_migr_units(migr_rec)-1)) &&
5d5466
 			    (super->migr_rec->rec_status ==
5d5466
 					__cpu_to_le32(UNIT_SRC_IN_CP_AREA)))
5d5466
 				units++;
5d5466
@@ -10697,7 +10766,7 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
5d5466
 
5d5466
 	if (array_blocks % __le32_to_cpu(migr_rec->blocks_per_unit))
5d5466
 		num_migr_units++;
5d5466
-	migr_rec->num_migr_units = __cpu_to_le32(num_migr_units);
5d5466
+	set_num_migr_units(migr_rec, num_migr_units);
5d5466
 
5d5466
 	migr_rec->post_migr_vol_cap =  dev->size_low;
5d5466
 	migr_rec->post_migr_vol_cap_hi = dev->size_high;
5d5466
@@ -10714,7 +10783,7 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
5d5466
 			min_dev_sectors = dev_sectors;
5d5466
 		close(fd);
5d5466
 	}
5d5466
-	migr_rec->ckpt_area_pba = __cpu_to_le32(min_dev_sectors -
5d5466
+	set_migr_chkp_area_pba(migr_rec, min_dev_sectors -
5d5466
 					RAID_DISK_RESERVED_BLOCKS_IMSM_HI);
5d5466
 
5d5466
 	write_imsm_migr_rec(st);
5d5466
@@ -10765,8 +10834,7 @@ int save_backup_imsm(struct supertype *st,
5d5466
 
5d5466
 	start = info->reshape_progress * 512;
5d5466
 	for (i = 0; i < new_disks; i++) {
5d5466
-		target_offsets[i] = (unsigned long long)
5d5466
-		  __le32_to_cpu(super->migr_rec->ckpt_area_pba) * 512;
5d5466
+		target_offsets[i] = migr_chkp_area_pba(super->migr_rec) * 512;
5d5466
 		/* move back copy area adderss, it will be moved forward
5d5466
 		 * in restore_stripes() using start input variable
5d5466
 		 */
5d5466
@@ -10845,12 +10913,11 @@ int save_checkpoint_imsm(struct supertype *st, struct mdinfo *info, int state)
5d5466
 	if (info->reshape_progress % blocks_per_unit)
5d5466
 		curr_migr_unit++;
5d5466
 
5d5466
-	super->migr_rec->curr_migr_unit =
5d5466
-		__cpu_to_le32(curr_migr_unit);
5d5466
+	set_current_migr_unit(super->migr_rec, curr_migr_unit);
5d5466
 	super->migr_rec->rec_status = __cpu_to_le32(state);
5d5466
-	super->migr_rec->dest_1st_member_lba =
5d5466
-		__cpu_to_le32(curr_migr_unit *
5d5466
-			      __le32_to_cpu(super->migr_rec->dest_depth_per_unit));
5d5466
+	set_migr_dest_1st_member_lba(super->migr_rec,
5d5466
+			super->migr_rec->dest_depth_per_unit * curr_migr_unit);
5d5466
+
5d5466
 	if (write_imsm_migr_rec(st) < 0) {
5d5466
 		dprintf("imsm: Cannot write migration record outside backup area\n");
5d5466
 		return 1;
5d5466
@@ -10884,8 +10951,8 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
5d5466
 	char *buf = NULL;
5d5466
 	int retval = 1;
5d5466
 	unsigned int sector_size = super->sector_size;
5d5466
-	unsigned long curr_migr_unit = __le32_to_cpu(migr_rec->curr_migr_unit);
5d5466
-	unsigned long num_migr_units = __le32_to_cpu(migr_rec->num_migr_units);
5d5466
+	unsigned long curr_migr_unit = current_migr_unit(migr_rec);
5d5466
+	unsigned long num_migr_units = get_num_migr_units(migr_rec);
5d5466
 	char buffer[20];
5d5466
 	int skipped_disks = 0;
5d5466
 
5d5466
@@ -10912,11 +10979,9 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
5d5466
 	map_dest = get_imsm_map(id->dev, MAP_0);
5d5466
 	new_disks = map_dest->num_members;
5d5466
 
5d5466
-	read_offset = (unsigned long long)
5d5466
-			__le32_to_cpu(migr_rec->ckpt_area_pba) * 512;
5d5466
+	read_offset = migr_chkp_area_pba(migr_rec) * 512;
5d5466
 
5d5466
-	write_offset = ((unsigned long long)
5d5466
-			__le32_to_cpu(migr_rec->dest_1st_member_lba) +
5d5466
+	write_offset = (migr_dest_1st_member_lba(migr_rec) +
5d5466
 			pba_of_lba0(map_dest)) * 512;
5d5466
 
5d5466
 	unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512;
5d5466
@@ -12019,12 +12084,12 @@ static int imsm_manage_reshape(
5d5466
 	max_position = sra->component_size * ndata;
5d5466
 	source_layout = imsm_level_to_layout(map_src->raid_level);
5d5466
 
5d5466
-	while (__le32_to_cpu(migr_rec->curr_migr_unit) <
5d5466
-	       __le32_to_cpu(migr_rec->num_migr_units)) {
5d5466
+	while (current_migr_unit(migr_rec) <
5d5466
+	       get_num_migr_units(migr_rec)) {
5d5466
 		/* current reshape position [blocks] */
5d5466
 		unsigned long long current_position =
5d5466
 			__le32_to_cpu(migr_rec->blocks_per_unit)
5d5466
-			* __le32_to_cpu(migr_rec->curr_migr_unit);
5d5466
+			* current_migr_unit(migr_rec);
5d5466
 		unsigned long long border;
5d5466
 
5d5466
 		/* Check that array hasn't become failed.
5d5466
-- 
5d5466
2.7.5
5d5466