Blame SOURCES/0004-libmultipath-fix-marginal-paths-queueing-errors.patch

b7ef27
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
b7ef27
From: Benjamin Marzinski <bmarzins@redhat.com>
b7ef27
Date: Mon, 28 Jan 2019 00:20:53 -0600
b7ef27
Subject: [PATCH] libmultipath: fix marginal paths queueing errors
b7ef27
b7ef27
The current marginal paths code tries to enqueue paths for io error
b7ef27
checking when multipathd receives a uevent on path failure. This can run
b7ef27
into a couple of problems. First, this uevent could happen before or
b7ef27
after multipathd actually fails the path, so simply checking nr_active
b7ef27
doesn't tell us if this is the last active path. Also, The code to fail
b7ef27
the path in enqueue_io_err_stat_by_path() doesn't ever update the path
b7ef27
state. This can cause the path to get failed twice, temporarily leading
b7ef27
to incorrect nr_active counts. Further, The point when multipathd should
b7ef27
care if this is the last active path is when the path has come up again,
b7ef27
not when it goes down. Lastly, if the path is down, it is often
b7ef27
impossible to open the path device, causing setup_directio_ctx() to
b7ef27
fail, which causes multipathd to skip io error checking and mark the
b7ef27
path as not marginal.
b7ef27
b7ef27
Instead, multipathd should just make sure that if the path is marginal,
b7ef27
it gets failed in the uevent, so as not to race with the checkerloop
b7ef27
thread. Then, when the path comes back up, check_path() can enqueue it,
b7ef27
just like it does for paths that need to get rechecked. To make it
b7ef27
obvious that the state PATH_IO_ERR_IN_POLLING_RECHECK and the function
b7ef27
hit_io_err_recheck_time() now apply to paths waiting to be enqueued for
b7ef27
the first time as well, I've also changed their names to
b7ef27
PATH_IO_ERR_WAITING_TO_CHECK and need_io_err_check(), respectively.
b7ef27
b7ef27
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
b7ef27
---
b7ef27
 libmultipath/io_err_stat.c | 55 +++++++++++++++++---------------------
b7ef27
 libmultipath/io_err_stat.h |  2 +-
b7ef27
 multipathd/main.c          |  2 +-
b7ef27
 3 files changed, 27 insertions(+), 32 deletions(-)
b7ef27
b7ef27
diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c
b7ef27
index 416e13a..72aacf3 100644
b7ef27
--- a/libmultipath/io_err_stat.c
b7ef27
+++ b/libmultipath/io_err_stat.c
b7ef27
@@ -41,7 +41,7 @@
b7ef27
 #define CONCUR_NR_EVENT			32
b7ef27
 
b7ef27
 #define PATH_IO_ERR_IN_CHECKING		-1
b7ef27
-#define PATH_IO_ERR_IN_POLLING_RECHECK	-2
b7ef27
+#define PATH_IO_ERR_WAITING_TO_CHECK	-2
b7ef27
 
b7ef27
 #define io_err_stat_log(prio, fmt, args...) \
b7ef27
 	condlog(prio, "io error statistic: " fmt, ##args)
b7ef27
@@ -283,24 +283,6 @@ static int enqueue_io_err_stat_by_path(struct path *path)
b7ef27
 	vector_set_slot(paths->pathvec, p);
b7ef27
 	pthread_mutex_unlock(&paths->mutex);
b7ef27
 
b7ef27
-	if (!path->io_err_disable_reinstate) {
b7ef27
-		/*
b7ef27
-		 *fail the path in the kernel for the time of the to make
b7ef27
-		 *the test more reliable
b7ef27
-		 */
b7ef27
-		io_err_stat_log(3, "%s: fail dm path %s before checking",
b7ef27
-				path->mpp->alias, path->dev);
b7ef27
-		path->io_err_disable_reinstate = 1;
b7ef27
-		dm_fail_path(path->mpp->alias, path->dev_t);
b7ef27
-		update_queue_mode_del_path(path->mpp);
b7ef27
-
b7ef27
-		/*
b7ef27
-		 * schedule path check as soon as possible to
b7ef27
-		 * update path state to delayed state
b7ef27
-		 */
b7ef27
-		path->tick = 1;
b7ef27
-
b7ef27
-	}
b7ef27
 	io_err_stat_log(2, "%s: enqueue path %s to check",
b7ef27
 			path->mpp->alias, path->dev);
b7ef27
 	return 0;
b7ef27
@@ -317,7 +299,6 @@ free_ioerr_path:
b7ef27
 int io_err_stat_handle_pathfail(struct path *path)
b7ef27
 {
b7ef27
 	struct timespec curr_time;
b7ef27
-	int res;
b7ef27
 
b7ef27
 	if (uatomic_read(&io_err_thread_running) == 0)
b7ef27
 		return 1;
b7ef27
@@ -332,8 +313,6 @@ int io_err_stat_handle_pathfail(struct path *path)
b7ef27
 
b7ef27
 	if (!path->mpp)
b7ef27
 		return 1;
b7ef27
-	if (path->mpp->nr_active <= 1)
b7ef27
-		return 1;
b7ef27
 	if (path->mpp->marginal_path_double_failed_time <= 0 ||
b7ef27
 		path->mpp->marginal_path_err_sample_time <= 0 ||
b7ef27
 		path->mpp->marginal_path_err_recheck_gap_time <= 0 ||
b7ef27
@@ -371,17 +350,33 @@ int io_err_stat_handle_pathfail(struct path *path)
b7ef27
 	}
b7ef27
 	path->io_err_pathfail_cnt++;
b7ef27
 	if (path->io_err_pathfail_cnt >= FLAKY_PATHFAIL_THRESHOLD) {
b7ef27
-		res = enqueue_io_err_stat_by_path(path);
b7ef27
-		if (!res)
b7ef27
-			path->io_err_pathfail_cnt = PATH_IO_ERR_IN_CHECKING;
b7ef27
-		else
b7ef27
-			path->io_err_pathfail_cnt = 0;
b7ef27
+		path->io_err_disable_reinstate = 1;
b7ef27
+		path->io_err_pathfail_cnt = PATH_IO_ERR_WAITING_TO_CHECK;
b7ef27
+		/* enqueue path as soon as it comes up */
b7ef27
+		path->io_err_dis_reinstate_time = 0;
b7ef27
+		if (path->state != PATH_DOWN) {
b7ef27
+			struct config *conf;
b7ef27
+			int oldstate = path->state;
b7ef27
+			int checkint;
b7ef27
+
b7ef27
+			conf = get_multipath_config();
b7ef27
+			checkint = conf->checkint;
b7ef27
+			put_multipath_config(conf);
b7ef27
+			io_err_stat_log(2, "%s: mark as failed", path->dev);
b7ef27
+			path->mpp->stat_path_failures++;
b7ef27
+			path->state = PATH_DOWN;
b7ef27
+			path->dmstate = PSTATE_FAILED;
b7ef27
+			if (oldstate == PATH_UP || oldstate == PATH_GHOST)
b7ef27
+				update_queue_mode_del_path(path->mpp);
b7ef27
+			if (path->tick > checkint)
b7ef27
+				path->tick = checkint;
b7ef27
+		}
b7ef27
 	}
b7ef27
 
b7ef27
 	return 0;
b7ef27
 }
b7ef27
 
b7ef27
-int hit_io_err_recheck_time(struct path *pp)
b7ef27
+int need_io_err_check(struct path *pp)
b7ef27
 {
b7ef27
 	struct timespec curr_time;
b7ef27
 	int r;
b7ef27
@@ -392,7 +387,7 @@ int hit_io_err_recheck_time(struct path *pp)
b7ef27
 		io_err_stat_log(2, "%s: recover path early", pp->dev);
b7ef27
 		goto recover;
b7ef27
 	}
b7ef27
-	if (pp->io_err_pathfail_cnt != PATH_IO_ERR_IN_POLLING_RECHECK)
b7ef27
+	if (pp->io_err_pathfail_cnt != PATH_IO_ERR_WAITING_TO_CHECK)
b7ef27
 		return 1;
b7ef27
 	if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0 ||
b7ef27
 	    (curr_time.tv_sec - pp->io_err_dis_reinstate_time) >
b7ef27
@@ -489,7 +484,7 @@ static int poll_io_err_stat(struct vectors *vecs, struct io_err_stat_path *pp)
b7ef27
 	} else if (path->mpp && path->mpp->nr_active > 1) {
b7ef27
 		io_err_stat_log(3, "%s: keep failing the dm path %s",
b7ef27
 				path->mpp->alias, path->dev);
b7ef27
-		path->io_err_pathfail_cnt = PATH_IO_ERR_IN_POLLING_RECHECK;
b7ef27
+		path->io_err_pathfail_cnt = PATH_IO_ERR_WAITING_TO_CHECK;
b7ef27
 		path->io_err_disable_reinstate = 1;
b7ef27
 		path->io_err_dis_reinstate_time = currtime.tv_sec;
b7ef27
 		io_err_stat_log(3, "%s: disable reinstating of %s",
b7ef27
diff --git a/libmultipath/io_err_stat.h b/libmultipath/io_err_stat.h
b7ef27
index bbf31b4..53d6d7d 100644
b7ef27
--- a/libmultipath/io_err_stat.h
b7ef27
+++ b/libmultipath/io_err_stat.h
b7ef27
@@ -10,6 +10,6 @@ extern pthread_attr_t io_err_stat_attr;
b7ef27
 int start_io_err_stat_thread(void *data);
b7ef27
 void stop_io_err_stat_thread(void);
b7ef27
 int io_err_stat_handle_pathfail(struct path *path);
b7ef27
-int hit_io_err_recheck_time(struct path *pp);
b7ef27
+int need_io_err_check(struct path *pp);
b7ef27
 
b7ef27
 #endif /* _IO_ERR_STAT_H */
b7ef27
diff --git a/multipathd/main.c b/multipathd/main.c
b7ef27
index fe6d8ef..43830e8 100644
b7ef27
--- a/multipathd/main.c
b7ef27
+++ b/multipathd/main.c
b7ef27
@@ -2080,7 +2080,7 @@ check_path (struct vectors * vecs, struct path * pp, int ticks)
b7ef27
 	}
b7ef27
 
b7ef27
 	if ((newstate == PATH_UP || newstate == PATH_GHOST) &&
b7ef27
-	    pp->io_err_disable_reinstate && hit_io_err_recheck_time(pp)) {
b7ef27
+	    pp->io_err_disable_reinstate && need_io_err_check(pp)) {
b7ef27
 		pp->state = PATH_SHAKY;
b7ef27
 		/*
b7ef27
 		 * to reschedule as soon as possible,so that this path can
b7ef27
-- 
b7ef27
2.17.2
b7ef27