[PATCH 1/1] raid456: avoid second retry of read-error

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The MD driver for level-456 should prevent re-reading read errors.

For redundant raid it makes no sense to retry the operation:
When one of the disks in the array hits a read error, that will
cause a stall for the reading process:
- either the read succeeds (e.g. after 4 seconds the HDD error
strategy could read the sector)
- or it fails after HDD imposed timeout (w/TLER, e.g. after 7
seconds (might be even longer)

The user can enable/disable this functionality by the following
commands:
To Enable:
echo 1 > /proc/sys/dev/raid/raid456_retry_read_error

To Disable, type the following at anytime:
echo 0 > /proc/sys/dev/raid/raid456_retry_read_error

Signed-off-by: Nigel Croxon <ncroxon@xxxxxxxxxx>
---
 drivers/md/md.c    | 43 +++++++++++++++++++++++++++++++++++++++++++
 drivers/md/md.h    |  2 ++
 drivers/md/raid5.c |  3 ++-
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/drivers/md/md.c b/drivers/md/md.c
index 18153647e6a1..4e92996f773e 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -132,6 +132,12 @@ static inline int speed_max(struct mddev *mddev)
 		mddev->sync_speed_max : sysctl_speed_limit_max;
 }
 
+static int sysctl_raid456_retry_read_error = 0;
+static inline void set_raid456_retry_read_error(struct mddev *mddev, int re)
+{
+	(re ? set_bit : clear_bit)(MD_RAID456_RETRY_RE, &mddev->flags);
+}
+
 static int rdev_init_wb(struct md_rdev *rdev)
 {
 	if (rdev->bdev->bd_queue->nr_hw_queues == 1)
@@ -220,6 +226,13 @@ static struct ctl_table raid_table[] = {
 		.mode		= S_IRUGO|S_IWUSR,
 		.proc_handler	= proc_dointvec,
 	},
+	{
+		.procname	= "raid456_retry_read_error",
+		.data		= &sysctl_raid456_retry_read_error,
+		.maxlen		= sizeof(int),
+		.mode		= S_IRUGO|S_IWUSR,
+		.proc_handler	= proc_dointvec,
+	},
 	{ }
 };
 
@@ -4701,6 +4714,32 @@ mismatch_cnt_show(struct mddev *mddev, char *page)
 
 static struct md_sysfs_entry md_mismatches = __ATTR_RO(mismatch_cnt);
 
+static ssize_t
+raid456_retry_re_show(struct mddev *mddev, char *page)
+{
+	return sprintf(page, "RAID456 retry Read Error = %u\n",
+		       test_bit(MD_RAID456_RETRY_RE, &mddev->flags));
+}
+
+static ssize_t raid456_retry_re_store(struct mddev *mddev, const char *buf, size_t len)
+{
+	int retry;
+
+	if (!mddev->private)
+		return -ENODEV;
+
+	if (len > 1 ||
+	    kstrtoint(buf, 10, &retry) ||
+	    retry < 0 || retry > 1)
+		return -EINVAL;
+
+	set_raid456_retry_read_error(mddev, retry);
+	return len;
+}
+
+static struct md_sysfs_entry md_raid456_retry_read_error =
+__ATTR(raid456_retry_read_error, S_IRUGO|S_IWUSR, raid456_retry_re_show, raid456_retry_re_store);
+
 static ssize_t
 sync_min_show(struct mddev *mddev, char *page)
 {
@@ -5223,6 +5262,7 @@ static struct attribute *md_redundancy_attrs[] = {
 	&md_suspend_hi.attr,
 	&md_bitmap.attr,
 	&md_degraded.attr,
+	&md_raid456_retry_read_error.attr,
 	NULL,
 };
 static struct attribute_group md_redundancy_group = {
@@ -5785,6 +5825,8 @@ static int do_md_run(struct mddev *mddev)
 	if (mddev_is_clustered(mddev))
 		md_allow_write(mddev);
 
+	set_raid456_retry_read_error(mddev, sysctl_raid456_retry_read_error);
+
 	/* run start up tasks that require md_thread */
 	md_start(mddev);
 
@@ -8355,6 +8397,7 @@ void md_do_sync(struct md_thread *thread)
 	else
 		desc = "recovery";
 
+	set_raid456_retry_read_error(mddev, sysctl_raid456_retry_read_error);
 	mddev->last_sync_action = action ?: desc;
 
 	/* we overload curr_resync somewhat here.
diff --git a/drivers/md/md.h b/drivers/md/md.h
index fcb6cce5a459..013d4f758cb5 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -255,6 +255,8 @@ enum mddev_flags {
 	MD_UPDATING_SB,		/* md_check_recovery is updating the metadata
 				 * without explicitly holding reconfig_mutex.
 				 */
+	MD_RAID456_RETRY_RE,	/* allow user-space to request RAID456
+				 * retry read errors */
 };
 
 enum mddev_sb_flags {
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 0e52f1dbbc14..9fb6d29fa046 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2566,7 +2566,8 @@ static void raid5_end_read_request(struct bio * bi)
 		    && !test_bit(R5_ReadNoMerge, &sh->dev[i].flags))
 			retry = 1;
 		if (retry)
-			if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) {
+			if ((test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) ||
+			    (test_bit(MD_RAID456_RETRY_RE, &conf->mddev->recovery))) {
 				set_bit(R5_ReadError, &sh->dev[i].flags);
 				clear_bit(R5_ReadNoMerge, &sh->dev[i].flags);
 			} else
-- 
2.20.1





[Index of Archives]     [Linux RAID Wiki]     [ATA RAID]     [Linux SCSI Target Infrastructure]     [Linux Block]     [Linux IDE]     [Linux SCSI]     [Linux Hams]     [Device Mapper]     [Device Mapper Cryptographics]     [Kernel]     [Linux Admin]     [Linux Net]     [GFS]     [RPM]     [git]     [Yosemite Forum]


  Powered by Linux