Skip to contentSkip to conversation

dm raid: fix redundancy check and avoid frozen raid recovery

PATCH New Heinz Mauelshagen 1 participant 6 messages Dec 13, 2017

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover dm raid: fix redundancy check and avoid frozen raid recovery

Patch 1 fixes validate_raid_redundancy() to check the current raid set level as stored in the superblock rather than the constructor requested one. In case of a raid0 to raid10 conversion, the related flaw caused a raid10 check on the given raid0 raid set leading to a divide error.

Patch 2 hardens raid resync/recover/reshape by retrieving any current related offsets from the active, uspended mapping thus avoiding frozen raid recovery across reloads altogether.

Patch 3 ensures 'a' chars during reshaping.

Patch 4 + 5 add simplification and cleanup without functional change.

This series presumes
https://www.redhat.com/archives/dm-devel/2017-December/msg00012.html
or
linux-dm.git, revision-range fbc7c07ec23c..b84cf26924cf respectively.

Heinz Mauelshagen (5):
dm raid: validate current raid sets redundancy dm raid: avoid keeping raid set frozen altogether dm raid: ensure 'a' chars during reshape dm raid: simplify rs_get_progress()
dm raid: use rs_is_raid*() / comment

 Documentation/device-mapper/dm-raid.txt |   1 +
 drivers/md/dm-raid.c                    | 168 ++++++++++++++++++--------------
 2 files changed, 98 insertions(+), 71 deletions(-)
Signature · 1 line
2.13.6
#1 lore raw

PATCH 1/5 dm raid: validate current raid sets redundancy

Verifying the current raid sets redundancy based on retrieved superblock content has to use the raid level as of superblock content (e.g. raid0), not the constructor requested one (e.g. raid10).

Using the requested raid level of raid10 lead to a "divide error" on raid0 which defines data copies divided by to be zero.

Also check for bogus data copies.

---
 drivers/md/dm-raid.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/md/dm-raid.c +6 -1
index dfbc2bd787c1..c9287666ee5a 100644
@@ -1007,7 +1007,7 @@ static int validate_raid_redundancy(struct raid_set *rs)
 		    !rs->dev[i].rdev.sb_page)
 			rebuild_cnt++;
 
-	switch (rs->raid_type->level) {
+	switch (rs->md.level) {
 	case 0:
 		break;
 	case 1:
@@ -1022,6 +1022,11 @@ static int validate_raid_redundancy(struct raid_set *rs)
 		break;
 	case 10:
 		copies = raid10_md_layout_to_copies(rs->md.new_layout);
+		if (copies < 2) {
+			DMERR("Bogus raid10 data copies < 2!");
+			return -EINVAL;
+		}
+
 		if (rebuild_cnt < copies)
 			break;
 
Signature · 1 line
2.13.6
#2 lore raw

PATCH 2/5 dm raid: avoid keeping raid set frozen altogether

In reply to Heinz Mauelshagen

In order to avoid redoing synchronization/recovery/reshape partially, the raid set got frozen until after all passed in table line flags had been cleared. The related table reload sequence had to be precisely followed, or reshaping may lead to data corruption caused by the active mapping carrying on with a reshape when the inactive mapping already had retrieved a stale reshape position.

Harden by retrieving the actual resync/recovery/reshape position during resume whilst the active table is suspended thus avoiding to keep the raid set frozen altogether. This prevents superfluous redoing of an already resynchronized or recovered segment and, most importantly, potential redoing of an already reshaped segment causing data corruption.

This is an enhancement to upstream commit
d39f0010e40964d959c5157be02839da8a178015.

Bump target version to reflect these changes.

Also update Documentation respectively.

---
 Documentation/device-mapper/dm-raid.txt |   1 +
 drivers/md/dm-raid.c                    | 109 ++++++++++++++++++++------------
 2 files changed, 71 insertions(+), 39 deletions(-)
Documentation/device-mapper/dm-raid.txt +1 -0
index 4d260fedcd8b..9ee76904fbff 100644
@@ -346,3 +346,4 @@ Version History
 1.12.1  Fix for MD deadlock between mddev_suspend() and md_write_start() available
 1.13.0  Fix dev_health status at end of "recover" (was 'a', now 'A')
 1.13.1  Fix deadlock caused by early md_stop_writes()
+1.13.2  Fix raid redundancy validation and avoid keeping raid set frozen
drivers/md/dm-raid.c +70 -39

199 lines not on this page · raw message

Signature · 1 line
2.13.6
#3 lore raw

PATCH 3/5 dm raid: ensure 'a' chars during reshape

In reply to Heinz Mauelshagen

During reshape, 'A' chars were reported in status rather than 'a'.

---
 drivers/md/dm-raid.c | 9 +++++++++
 1 file changed, 9 insertions(+)
drivers/md/dm-raid.c +9 -0
index 0e1a296cd08d..f5db4ce69d6b 100644
@@ -3451,6 +3451,15 @@ static sector_t rs_get_progress(struct raid_set *rs, unsigned long recovery,
 			 */
 			set_bit(RT_FLAG_RS_RESYNCING, &rs->runtime_flags);
 
+		} else if (test_bit(MD_RECOVERY_RESHAPE, &recovery) &&
+			   !test_bit(MD_RECOVERY_REQUESTED, &recovery)) {
+			/*
+			 * If "reshape" is occurring, the raid set
+			 * is or may be out of sync hence the health
+			 * characters shall be 'a'.
+			 */
+			set_bit(RT_FLAG_RS_RESYNCING, &rs->runtime_flags);
+
 		} else if (test_bit(MD_RECOVERY_REQUESTED, &recovery)) {
 			/*
 			 * If "check" or "repair" is occurring, the raid set has
Signature · 1 line
2.13.6
#4 lore raw

PATCH 4/5 dm raid: simplify rs_get_progress()

In reply to Heinz Mauelshagen

No need to calculate the reshaping progress because mddev->curr_resync_completed holds it.

---
 drivers/md/dm-raid.c | 23 +++--------------------
 1 file changed, 3 insertions(+), 20 deletions(-)
drivers/md/dm-raid.c +3 -20
index f5db4ce69d6b..41a411526b27 100644
@@ -3399,26 +3399,9 @@ static sector_t rs_get_progress(struct raid_set *rs, unsigned long recovery,
 		set_bit(RT_FLAG_RS_IN_SYNC, &rs->runtime_flags);
 
 	} else {
-		/* Reshape is relative to the array size */
-		if (test_bit(MD_RECOVERY_RESHAPE, &recovery)) {
-			r = mddev->reshape_position;
-			if (r != MaxSector) {
-				/* Got to reverse on backward reshape */
-				if (mddev->reshape_backwards)
-					r = mddev->array_sectors - r;
-
-				/* Divide by # of data stripes unless raid1 */
-				if (!rs_is_raid1(rs))
-					sector_div(r, mddev_data_stripes(rs));
-			}
-
-		/*
-		 * Sync/recover is relative to the component device size.
-		 *
-		 * MD_RECOVERY_NEEDED for https://bugzilla.redhat.com/show_bug.cgi?id=1508070
-		 */
-		} else if (test_bit(MD_RECOVERY_NEEDED, &recovery) ||
-			   test_bit(MD_RECOVERY_RUNNING, &recovery))
+		if (test_bit(MD_RECOVERY_NEEDED, &recovery) ||
+		    test_bit(MD_RECOVERY_RESHAPE, &recovery) ||
+		    test_bit(MD_RECOVERY_RUNNING, &recovery))
 			r = mddev->curr_resync_completed;
 		else
 			r = mddev->recovery_cp;
Signature · 1 line
2.13.6
#5 lore raw

PATCH 5/5 dm raid: use rs_is_raid*() / comment

In reply to Heinz Mauelshagen

Cleanup, no functional change.

---
 drivers/md/dm-raid.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)
drivers/md/dm-raid.c +9 -11
index 41a411526b27..6c9e3d9e56c2 100644
@@ -588,7 +588,7 @@ static const char *raid10_md_layout_to_format(int layout)
 }
 
 /* Return md raid10 algorithm for @name */
-static int raid10_name_to_format(const char *name)
+static const int raid10_name_to_format(const char *name)
 {
 	if (!strcasecmp(name, "near"))
 		return ALGORITHM_RAID10_NEAR;
@@ -1913,7 +1913,7 @@ static bool rs_reshape_requested(struct raid_set *rs)
 	if (rs_takeover_requested(rs))
 		return false;
 
-	if (!mddev->level)
+	if (rs_is_raid0(rs))
 		return false;
 
 	change = mddev->new_layout != mddev->layout ||
@@ -1921,7 +1921,7 @@ static bool rs_reshape_requested(struct raid_set *rs)
 		 rs->delta_disks;
 
 	/* Historical case to support raid1 reshape without delta disks */
-	if (mddev->level == 1) {
+	if (rs_is_raid1(rs)) {
 		if (rs->delta_disks)
 			return !!rs->delta_disks;
 
@@ -1929,7 +1929,7 @@ static bool rs_reshape_requested(struct raid_set *rs)
 		       mddev->raid_disks != rs->raid_disks;
 	}
 
-	if (mddev->level == 10)
+	if (rs_is_raid10(rs))
 		return change &&
 		       !__is_raid10_far(mddev->new_layout) &&
 		       rs->delta_disks >= 0;
@@ -2742,14 +2742,14 @@ static int rs_setup_takeover(struct raid_set *rs)
 	sector_t new_data_offset = rs->dev[0].rdev.data_offset ? 0 : rs->data_offset;
 
 	if (rt_is_raid10(rs->raid_type)) {
-		if (mddev->level == 0) {
+		if (rs_is_raid0(rs)) {
 			/* Userpace reordered disks -> adjust raid_disk indexes */
 			__reorder_raid_disk_indexes(rs);
 
 			/* raid0 -> raid10_far layout */
 			mddev->layout = raid10_format_to_md_layout(rs, ALGORITHM_RAID10_FAR,
 								   rs->raid10_copies);
-		} else if (mddev->level == 1)
+		} else if (rs_is_raid1(rs))
 			/* raid1 -> raid10_near layout */
 			mddev->layout = raid10_format_to_md_layout(rs, ALGORITHM_RAID10_NEAR,
 								   rs->raid_disks);
@@ -2974,10 +2974,8 @@ static void configure_discard_support(struct raid_set *rs)
 	bool raid456;
 	struct dm_target *ti = rs->ti;
 
-	/*
-	 * XXX: RAID level 4,5,6 require zeroing for safety.
-	 */
-	raid456 = (rs->md.level == 4 || rs->md.level == 5 || rs->md.level == 6);
+	/* RAID level 4,5,6 require discard_zeroes_data for data integrity! */
+	raid456 = rs_is_raid456(rs);
 
 	for (i = 0; i < rs->raid_disks; i++) {
 		struct request_queue *q;
@@ -3002,7 +3000,7 @@ static void configure_discard_support(struct raid_set *rs)
 	 * RAID1 and RAID10 personalities require bio splitting,
 	 * RAID0/4/5/6 don't and process large discard bios properly.
 	 */
-	ti->split_discard_bios = !!(rs->md.level == 1 || rs->md.level == 10);
+	ti->split_discard_bios = !!(rs_is_raid1(rs) || rs_is_raid10(rs));
 	ti->num_discard_bios = 1;
 }
 
Signature · 1 line
2.13.6