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

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