summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Marzinski <bmarzins@redhat.com>2018-02-15 13:17:53 -0600
committerBenjamin Marzinski <bmarzins@redhat.com>2018-02-15 13:17:53 -0600
commit5bea53fe7ed7dd7afa8e76f7f84f76fdb89d59d9 (patch)
tree9a89c87df6336311ebe30ae2c51af13f92d6a3d6
parent7e8f34e1813a9ae89b5acc012fa7d45c3d7bbdb8 (diff)
downloaddevice-mapper-multipath-5bea53fe7ed7dd7afa8e76f7f84f76fdb89d59d9.tar.gz
device-mapper-multipath-5bea53fe7ed7dd7afa8e76f7f84f76fdb89d59d9.tar.xz
device-mapper-multipath-5bea53fe7ed7dd7afa8e76f7f84f76fdb89d59d9.zip
device-mapper-multipath-0.7.4-1.git07e7bd5master
Update Source to the latest upstream commit * Previous patches 0001-0006 are included in this commit * Previous patches 0007-0014 are now patches 0015-0022 Add 0001-libmultipath-fix-tur-checker-locking.patch * Fixed spinlock bug. posted upstream Add 0002-multipath-fix-DEF_TIMEOUT-use.patch * Add missing sec to ms conversion. posted upstream Add 0003-multipathd-remove-coalesce_paths-from-ev_add_map.patch * Remove unused code. posted upstream Add 0004-multipathd-remove-unused-configure-parameter.patch * Remove unused code. posted upstream Add 0005-Fix-set_no_path_retry-regression.patch * Fix issue with queueing and path addition. posted upstream Add 0006-multipathd-change-spurious-uevent-msg-priority.patch * Change message priority to Notice. posted upstream Add 0007-multipath-print-sysfs-state-in-fast-list-mode.patch * Show sysfs state correctly in fast list mode (-l). posted upstream Add 0008-libmultipath-move-remove_map-waiter-code-to-multipat.patch * Move code around. posted upstream Add 0009-move-waiter-code-from-libmultipath-to-multipathd.patch * Move code around. posted upstream Add 0010-call-start_waiter_thread-before-setup_multipath.patch * Fix race on multipath device creations. posted upstream Add 0011-libmultipath-add-helper-functions.patch * posted upstream Add 0012-multipathd-RFC-add-new-polling-dmevents-waiter-threa.patch * Add alternate method of getting dmevents, that doesn't require a thread per device. posted upstream Add 0013-libmultipath-condlog-log-to-stderr.patch * change condlog to log to stderr instead of stdout. posted upstream Add 0014-multipathd-fix-compiler-warning-for-uev_pathfail_che.patch * fix indentation issue. posted upstream
-rw-r--r--.gitignore1
-rw-r--r--0001-libmultipath-fix-tur-checker-locking.patch269
-rw-r--r--0001-mpathpersist-Fix-invalid-condition-check.patch35
-rw-r--r--0002-multipath-add-man-page-info-for-my-prkey-changes.patch79
-rw-r--r--0002-multipath-fix-DEF_TIMEOUT-use.patch32
-rw-r--r--0003-multipath-there-is-no-none-path-state.patch27
-rw-r--r--0003-multipathd-remove-coalesce_paths-from-ev_add_map.patch98
-rw-r--r--0004-multipathd-remove-unused-configure-parameter.patch53
-rw-r--r--0004-mutipath-updated-Huawei-storage-config.patch30
-rw-r--r--0005-Fix-set_no_path_retry-regression.patch81
-rw-r--r--0005-multipath-fix-doc-typo.patch29
-rw-r--r--0006-multipath-add-ghost_delay-parameter.patch397
-rw-r--r--0006-multipathd-change-spurious-uevent-msg-priority.patch29
-rw-r--r--0007-multipath-print-sysfs-state-in-fast-list-mode.patch68
-rw-r--r--0008-libmultipath-move-remove_map-waiter-code-to-multipat.patch148
-rw-r--r--0009-move-waiter-code-from-libmultipath-to-multipathd.patch793
-rw-r--r--0010-call-start_waiter_thread-before-setup_multipath.patch129
-rw-r--r--0011-libmultipath-add-helper-functions.patch155
-rw-r--r--0012-multipathd-RFC-add-new-polling-dmevents-waiter-threa.patch643
-rw-r--r--0013-libmultipath-condlog-log-to-stderr.patch35
-rw-r--r--0014-multipathd-fix-compiler-warning-for-uev_pathfail_che.patch31
-rw-r--r--0015-RH-fixup-udev-rules-for-redhat.patch (renamed from 0007-RH-fixup-udev-rules-for-redhat.patch)2
-rw-r--r--0016-RH-Remove-the-property-blacklist-exception-builtin.patch (renamed from 0008-RH-Remove-the-property-blacklist-exception-builtin.patch)4
-rw-r--r--0017-RH-don-t-start-without-a-config-file.patch (renamed from 0009-RH-don-t-start-without-a-config-file.patch)12
-rw-r--r--0018-RH-use-rpm-optflags-if-present.patch (renamed from 0010-RH-use-rpm-optflags-if-present.patch)6
-rw-r--r--0019-RH-add-mpathconf.patch (renamed from 0011-RH-add-mpathconf.patch)8
-rw-r--r--0020-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch (renamed from 0012-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch)6
-rw-r--r--0021-RH-trigger-change-uevent-on-new-device-creation.patch (renamed from 0013-RH-trigger-change-uevent-on-new-device-creation.patch)40
-rw-r--r--0022-RH-warn-on-invalid-regex-instead-of-failing.patch (renamed from 0014-RH-warn-on-invalid-regex-instead-of-failing.patch)8
-rw-r--r--device-mapper-multipath.spec89
-rw-r--r--sources2
31 files changed, 2687 insertions, 652 deletions
diff --git a/.gitignore b/.gitignore
index 7ff8a6c..4f88485 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ multipath-tools-091027.tar.gz
/multipath.conf
/multipath-tools-git847cc43.tgz
/multipath-tools-0.7.3.tgz
+/multipath-tools-07e7bd5.tgz
diff --git a/0001-libmultipath-fix-tur-checker-locking.patch b/0001-libmultipath-fix-tur-checker-locking.patch
new file mode 100644
index 0000000..f6a255f
--- /dev/null
+++ b/0001-libmultipath-fix-tur-checker-locking.patch
@@ -0,0 +1,269 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Thu, 8 Feb 2018 16:56:45 -0600
+Subject: [PATCH] libmultipath: fix tur checker locking
+
+Commit 6e2423fd fixed a bug where the tur checker could cancel a
+detached thread after it had exitted. However in fixing this, the new
+code grabbed a mutex (to call condlog) while holding a spin_lock. To
+deal with this, I've done away with the holder spin_lock completely, and
+replaced it with two atomic variables, based on a suggestion by Martin
+Wilck.
+
+The holder variable works exactly like before. When the checker is
+initialized, it is set to 1. When a thread is created it is incremented.
+When either the thread or the checker are done with the context, they
+atomically decrement the holder variable and check its value. If it
+is 0, they free the context. If it is 1, they never touch the context
+again.
+
+The other variable has changed. First, ct->running and ct->thread have
+switched uses. ct->thread is now only ever accessed by the checker,
+never the thread. If it is non-NULL, a thread has started up, but
+hasn't been dealt with by the checker yet. It is also obviously used
+by the checker to cancel the thread.
+
+ct->running is now an atomic variable. When the thread is started
+it is set to 1. When the checker wants to kill a thread, it atomically
+sets the value to 0 and reads the previous value. If it was 1,
+the checker cancels the thread. If it was 0, the nothing needs to be
+done. After the checker has dealt with the thread, it sets ct->thread
+to NULL.
+
+Right before the thread finishes and pops the cleanup handler, it
+atomically sets the value of ct->running to 0 and reads the previous
+value. If it was 1, the thread just pops the cleanup handler and exits.
+If it was 0, then the checker is trying to cancel the thread, and so the
+thread calls pause(), which is a cancellation point.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ libmultipath/checkers/tur.c | 107 ++++++++++++++++++--------------------------
+ 1 file changed, 43 insertions(+), 64 deletions(-)
+
+diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c
+index b4a5cb2..9155960 100644
+--- a/libmultipath/checkers/tur.c
++++ b/libmultipath/checkers/tur.c
+@@ -15,6 +15,7 @@
+ #include <errno.h>
+ #include <sys/time.h>
+ #include <pthread.h>
++#include <urcu/uatomic.h>
+
+ #include "checkers.h"
+
+@@ -44,7 +45,6 @@ struct tur_checker_context {
+ pthread_t thread;
+ pthread_mutex_t lock;
+ pthread_cond_t active;
+- pthread_spinlock_t hldr_lock;
+ int holders;
+ char message[CHECKER_MSG_LEN];
+ };
+@@ -74,13 +74,12 @@ int libcheck_init (struct checker * c)
+
+ ct->state = PATH_UNCHECKED;
+ ct->fd = -1;
+- ct->holders = 1;
++ uatomic_set(&ct->holders, 1);
+ pthread_cond_init_mono(&ct->active);
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&ct->lock, &attr);
+ pthread_mutexattr_destroy(&attr);
+- pthread_spin_init(&ct->hldr_lock, PTHREAD_PROCESS_PRIVATE);
+ c->context = ct;
+
+ return 0;
+@@ -90,7 +89,6 @@ static void cleanup_context(struct tur_checker_context *ct)
+ {
+ pthread_mutex_destroy(&ct->lock);
+ pthread_cond_destroy(&ct->active);
+- pthread_spin_destroy(&ct->hldr_lock);
+ free(ct);
+ }
+
+@@ -99,16 +97,14 @@ void libcheck_free (struct checker * c)
+ if (c->context) {
+ struct tur_checker_context *ct = c->context;
+ int holders;
+- pthread_t thread;
+-
+- pthread_spin_lock(&ct->hldr_lock);
+- ct->holders--;
+- holders = ct->holders;
+- thread = ct->thread;
+- pthread_spin_unlock(&ct->hldr_lock);
+- if (holders)
+- pthread_cancel(thread);
+- else
++ int running;
++
++ running = uatomic_xchg(&ct->running, 0);
++ if (running)
++ pthread_cancel(ct->thread);
++ ct->thread = 0;
++ holders = uatomic_sub_return(&ct->holders, 1);
++ if (!holders)
+ cleanup_context(ct);
+ c->context = NULL;
+ }
+@@ -220,26 +216,12 @@ static void cleanup_func(void *data)
+ {
+ int holders;
+ struct tur_checker_context *ct = data;
+- pthread_spin_lock(&ct->hldr_lock);
+- ct->holders--;
+- holders = ct->holders;
+- ct->thread = 0;
+- pthread_spin_unlock(&ct->hldr_lock);
++
++ holders = uatomic_sub_return(&ct->holders, 1);
+ if (!holders)
+ cleanup_context(ct);
+ }
+
+-static int tur_running(struct tur_checker_context *ct)
+-{
+- pthread_t thread;
+-
+- pthread_spin_lock(&ct->hldr_lock);
+- thread = ct->thread;
+- pthread_spin_unlock(&ct->hldr_lock);
+-
+- return thread != 0;
+-}
+-
+ static void copy_msg_to_tcc(void *ct_p, const char *msg)
+ {
+ struct tur_checker_context *ct = ct_p;
+@@ -252,7 +234,7 @@ static void copy_msg_to_tcc(void *ct_p, const char *msg)
+ static void *tur_thread(void *ctx)
+ {
+ struct tur_checker_context *ct = ctx;
+- int state;
++ int state, running;
+ char devt[32];
+
+ condlog(3, "%s: tur checker starting up",
+@@ -278,6 +260,11 @@ static void *tur_thread(void *ctx)
+
+ condlog(3, "%s: tur checker finished, state %s",
+ tur_devt(devt, sizeof(devt), ct), checker_state_name(state));
++
++ running = uatomic_xchg(&ct->running, 0);
++ if (!running)
++ pause();
++
+ tur_thread_cleanup_pop(ct);
+
+ return ((void *)0);
+@@ -325,7 +312,6 @@ int libcheck_check(struct checker * c)
+ int tur_status, r;
+ char devt[32];
+
+-
+ if (!ct)
+ return PATH_UNCHECKED;
+
+@@ -349,38 +335,29 @@ int libcheck_check(struct checker * c)
+ return PATH_WILD;
+ }
+
+- if (ct->running) {
+- /*
+- * Check if TUR checker is still running. Hold hldr_lock
+- * around the pthread_cancel() call to avoid that
+- * pthread_cancel() gets called after the (detached) TUR
+- * thread has exited.
+- */
+- pthread_spin_lock(&ct->hldr_lock);
+- if (ct->thread) {
+- if (tur_check_async_timeout(c)) {
+- condlog(3, "%s: tur checker timeout",
+- tur_devt(devt, sizeof(devt), ct));
++ if (ct->thread) {
++ if (tur_check_async_timeout(c)) {
++ int running = uatomic_xchg(&ct->running, 0);
++ if (running)
+ pthread_cancel(ct->thread);
+- ct->running = 0;
+- MSG(c, MSG_TUR_TIMEOUT);
+- tur_status = PATH_TIMEOUT;
+- } else {
+- condlog(3, "%s: tur checker not finished",
++ condlog(3, "%s: tur checker timeout",
++ tur_devt(devt, sizeof(devt), ct));
++ ct->thread = 0;
++ MSG(c, MSG_TUR_TIMEOUT);
++ tur_status = PATH_TIMEOUT;
++ } else if (uatomic_read(&ct->running) != 0) {
++ condlog(3, "%s: tur checker not finished",
+ tur_devt(devt, sizeof(devt), ct));
+- ct->running++;
+- tur_status = PATH_PENDING;
+- }
++ tur_status = PATH_PENDING;
+ } else {
+ /* TUR checker done */
+- ct->running = 0;
++ ct->thread = 0;
+ tur_status = ct->state;
+ strlcpy(c->message, ct->message, sizeof(c->message));
+ }
+- pthread_spin_unlock(&ct->hldr_lock);
+ pthread_mutex_unlock(&ct->lock);
+ } else {
+- if (tur_running(ct)) {
++ if (uatomic_read(&ct->running) != 0) {
+ /* pthread cancel failed. continue in sync mode */
+ pthread_mutex_unlock(&ct->lock);
+ condlog(3, "%s: tur thread not responding",
+@@ -391,19 +368,17 @@ int libcheck_check(struct checker * c)
+ ct->state = PATH_UNCHECKED;
+ ct->fd = c->fd;
+ ct->timeout = c->timeout;
+- pthread_spin_lock(&ct->hldr_lock);
+- ct->holders++;
+- pthread_spin_unlock(&ct->hldr_lock);
++ uatomic_add(&ct->holders, 1);
++ uatomic_set(&ct->running, 1);
+ tur_set_async_timeout(c);
+ setup_thread_attr(&attr, 32 * 1024, 1);
+ r = pthread_create(&ct->thread, &attr, tur_thread, ct);
+ pthread_attr_destroy(&attr);
+ if (r) {
+- pthread_spin_lock(&ct->hldr_lock);
+- ct->holders--;
+- pthread_spin_unlock(&ct->hldr_lock);
+- pthread_mutex_unlock(&ct->lock);
++ uatomic_sub(&ct->holders, 1);
++ uatomic_set(&ct->running, 0);
+ ct->thread = 0;
++ pthread_mutex_unlock(&ct->lock);
+ condlog(3, "%s: failed to start tur thread, using"
+ " sync mode", tur_devt(devt, sizeof(devt), ct));
+ return tur_check(c->fd, c->timeout,
+@@ -414,12 +389,16 @@ int libcheck_check(struct checker * c)
+ tur_status = ct->state;
+ strlcpy(c->message, ct->message, sizeof(c->message));
+ pthread_mutex_unlock(&ct->lock);
+- if (tur_running(ct) &&
++ if (uatomic_read(&ct->running) != 0 &&
+ (tur_status == PATH_PENDING || tur_status == PATH_UNCHECKED)) {
+ condlog(3, "%s: tur checker still running",
+ tur_devt(devt, sizeof(devt), ct));
+- ct->running = 1;
+ tur_status = PATH_PENDING;
++ } else {
++ int running = uatomic_xchg(&ct->running, 0);
++ if (running)
++ pthread_cancel(ct->thread);
++ ct->thread = 0;
+ }
+ }
+
+--
+2.7.4
+
diff --git a/0001-mpathpersist-Fix-invalid-condition-check.patch b/0001-mpathpersist-Fix-invalid-condition-check.patch
deleted file mode 100644
index 4f7b6bb..0000000
--- a/0001-mpathpersist-Fix-invalid-condition-check.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Benjamin Marzinski <bmarzins@redhat.com>
-Date: Wed, 6 Sep 2017 16:27:36 -0500
-Subject: [PATCH] mpathpersist: Fix invalid condition check
-
-In commit 1990257c (mpathpersist: add support for prkeys file), the
-check to see if mpathpersist needed to tell multipathd to update a
-device's prkey was wrong. It had a typo that made it evaluate to true
-for any service action, instead of just for registrations. This is the
-correct check.
-
-Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
----
- libmpathpersist/mpath_persist.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
-index b5ed556..84ab293 100644
---- a/libmpathpersist/mpath_persist.c
-+++ b/libmpathpersist/mpath_persist.c
-@@ -339,8 +339,9 @@ int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
-
- memcpy(&prkey, paramp->sa_key, 8);
- if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey &&
-- ((!get_be64(mpp->reservation_key) && MPATH_PROUT_REG_SA) ||
-- MPATH_PROUT_REG_IGN_SA)) {
-+ ((!get_be64(mpp->reservation_key) &&
-+ rq_servact == MPATH_PROUT_REG_SA) ||
-+ rq_servact == MPATH_PROUT_REG_IGN_SA)) {
- memcpy(&mpp->reservation_key, paramp->sa_key, 8);
- if (update_prkey(alias, get_be64(mpp->reservation_key))) {
- condlog(0, "%s: failed to set prkey for multipathd.",
---
-2.7.4
-
diff --git a/0002-multipath-add-man-page-info-for-my-prkey-changes.patch b/0002-multipath-add-man-page-info-for-my-prkey-changes.patch
deleted file mode 100644
index 0ce4f81..0000000
--- a/0002-multipath-add-man-page-info-for-my-prkey-changes.patch
+++ /dev/null
@@ -1,79 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Benjamin Marzinski <bmarzins@redhat.com>
-Date: Tue, 19 Sep 2017 16:29:18 -0500
-Subject: [PATCH] multipath: add man page info for my prkey changes
-
-Update the man pages to list the new configuration options and
-multipathd commands.
-
-Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
----
- multipath/multipath.conf.5 | 17 +++++++++++++++++
- multipathd/multipathd.8 | 16 ++++++++++++++++
- 2 files changed, 33 insertions(+)
-
-diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
-index 5b6dde7..92ad8b1 100644
---- a/multipath/multipath.conf.5
-+++ b/multipath/multipath.conf.5
-@@ -682,6 +682,17 @@ The default is: \fB/etc/multipath/wwids\fR
- .
- .
- .TP
-+.B prkeys_file
-+The full pathname of the prkeys file, which is used by multipathd to keep
-+track of the persistent reservation key used for a specific WWID, when
-+\fIreservation_key\fR is set to \fBfile\fR.
-+.RS
-+.TP
-+The default is \fB/etc/multipath/prkeys\fR
-+.RE
-+.
-+.
-+.TP
- .B log_checker_err
- If set to
- .I once
-@@ -703,6 +714,12 @@ the same as the RESERVATION KEY field of the PERSISTENT RESERVE OUT parameter
- list which contains an 8-byte value provided by the application client to the
- device server to identify the I_T nexus.
- .RS
-+.PP
-+Alternatively, this can be set to \fBfile\fR, which will store the RESERVATION
-+KEY registered by mpathpersist in the \fIprkeys_file\fR. multipathd will then
-+use this key to register additional paths as they appear. When the
-+registration is removed, the RESERVATION KEY is removed from the
-+\fIprkeys_file\fR.
- .TP
- The default is: \fB<unset>\fR
- .RE
-diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8
-index 2615728..5c96680 100644
---- a/multipathd/multipathd.8
-+++ b/multipathd/multipathd.8
-@@ -247,6 +247,22 @@ Disable persistent reservation management on $map.
- Get the current persistent reservation management status of $map.
- .
- .TP
-+.B map|multipath $map getprkey
-+Get the current persistent reservation key associated with $map.
-+.
-+.TP
-+.B map|multipath $map setprkey key $key
-+Set the persistent reservation key associated with $map to $key in the
-+\fIprkeys_file\fR. This key will only be used by multipathd if
-+\fIreservation_key\fR is set to \fBfile\fR in \fI/etc/multipath.conf\fR.
-+.
-+.TP
-+.B map|multipath $map unsetprkey
-+Remove the persistent reservation key associated with $map from the
-+\fIprkeys_file\fR. This will only unset the key used by multipathd if
-+\fIreservation_key\fR is set to \fBfile\fR in \fI/etc/multipath.conf\fR.
-+.
-+.TP
- .B quit|exit
- End interactive session.
- .
---
-2.7.4
-
diff --git a/0002-multipath-fix-DEF_TIMEOUT-use.patch b/0002-multipath-fix-DEF_TIMEOUT-use.patch
new file mode 100644
index 0000000..9df8ceb
--- /dev/null
+++ b/0002-multipath-fix-DEF_TIMEOUT-use.patch
@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Thu, 18 Jan 2018 13:13:54 -0600
+Subject: [PATCH] multipath: fix DEF_TIMEOUT use
+
+DEF_TIMEOUT is specified in seconds. The io_hdr timeout is specified in
+milliseconds, so we need to convert it. Multipath should be waiting
+longer than 30 milliseconds here. If there are concerns that 30 seconds
+may be too long, we could always make this configurable, using
+conf->checker_timeout if set.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ libmultipath/discovery.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
+index 4b31dde..f118800 100644
+--- a/libmultipath/discovery.c
++++ b/libmultipath/discovery.c
+@@ -766,7 +766,7 @@ do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sense_b;
+- io_hdr.timeout = DEF_TIMEOUT;
++ io_hdr.timeout = DEF_TIMEOUT * 1000;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
+ return -1;
+--
+2.7.4
+
diff --git a/0003-multipath-there-is-no-none-path-state.patch b/0003-multipath-there-is-no-none-path-state.patch
deleted file mode 100644
index e7bbcd4..0000000
--- a/0003-multipath-there-is-no-none-path-state.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Benjamin Marzinski <bmarzins@redhat.com>
-Date: Thu, 26 Oct 2017 17:00:20 -0500
-Subject: [PATCH] multipath: there is no "none" path state
-
-There is a "none" path checker, but not a "none" path state.
-
-Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
----
- libmultipath/checkers.c | 1 -
- 1 file changed, 1 deletion(-)
-
-diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c
-index cd6d6a3..94d8486 100644
---- a/libmultipath/checkers.c
-+++ b/libmultipath/checkers.c
-@@ -19,7 +19,6 @@ char *checker_state_names[] = {
- "timeout",
- "removed",
- "delayed",
-- "none",
- };
-
- static LIST_HEAD(checkers);
---
-2.7.4
-
diff --git a/0003-multipathd-remove-coalesce_paths-from-ev_add_map.patch b/0003-multipathd-remove-coalesce_paths-from-ev_add_map.patch
new file mode 100644
index 0000000..b03576a
--- /dev/null
+++ b/0003-multipathd-remove-coalesce_paths-from-ev_add_map.patch
@@ -0,0 +1,98 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Fri, 19 Jan 2018 22:35:26 -0600
+Subject: [PATCH] multipathd: remove coalesce_paths from ev_add_map
+
+If ev_add_map is called for a multipath device that doesn't exist in
+device-mapper, it will call coalesce_paths to add it. This doesn't work
+and hasn't for years. It doesn't add the map to the mpvec, or start up
+waiters, or do any of the necessary things that do get done when you
+call ev_add_map for a map that does exist in device mapper.
+
+Fortunately, there are only two things that call ev_add_map. uev_add_map
+makes sure that the device does exist in device-mapper before calling
+ev_add_map, and cli_add_map creates the device first and then calls
+ev_add_map, if the device doesn't exist.
+
+So, there is no reason for coalesce_paths to be in ev_add_map. This
+removes it.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ multipathd/main.c | 46 ++++++++++++++--------------------------------
+ 1 file changed, 14 insertions(+), 32 deletions(-)
+
+diff --git a/multipathd/main.c b/multipathd/main.c
+index 27cf234..dbf9890 100644
+--- a/multipathd/main.c
++++ b/multipathd/main.c
+@@ -412,18 +412,19 @@ uev_add_map (struct uevent * uev, struct vectors * vecs)
+ return rc;
+ }
+
++/*
++ * ev_add_map expects that the multipath device already exists in kernel
++ * before it is called. It just adds a device to multipathd or updates an
++ * existing device.
++ */
+ int
+ ev_add_map (char * dev, char * alias, struct vectors * vecs)
+ {
+- char * refwwid;
+ struct multipath * mpp;
+- int map_present;
+- int r = 1, delayed_reconfig, reassign_maps;
++ int delayed_reconfig, reassign_maps;
+ struct config *conf;
+
+- map_present = dm_map_present(alias);
+-
+- if (map_present && !dm_is_mpath(alias)) {
++ if (!dm_is_mpath(alias)) {
+ condlog(4, "%s: not a multipath map", alias);
+ return 0;
+ }
+@@ -468,33 +469,14 @@ ev_add_map (char * dev, char * alias, struct vectors * vecs)
+ /*
+ * now we can register the map
+ */
+- if (map_present) {
+- if ((mpp = add_map_without_path(vecs, alias))) {
+- sync_map_state(mpp);
+- condlog(2, "%s: devmap %s registered", alias, dev);
+- return 0;
+- } else {
+- condlog(2, "%s: uev_add_map failed", dev);
+- return 1;
+- }
+- }
+- r = get_refwwid(CMD_NONE, dev, DEV_DEVMAP, vecs->pathvec, &refwwid);
+-
+- if (refwwid) {
+- r = coalesce_paths(vecs, NULL, refwwid, FORCE_RELOAD_NONE,
+- CMD_NONE);
+- dm_lib_release();
++ if ((mpp = add_map_without_path(vecs, alias))) {
++ sync_map_state(mpp);
++ condlog(2, "%s: devmap %s registered", alias, dev);
++ return 0;
++ } else {
++ condlog(2, "%s: ev_add_map failed", dev);
++ return 1;
+ }
+-
+- if (!r)
+- condlog(2, "%s: devmap %s added", alias, dev);
+- else if (r == 2)
+- condlog(2, "%s: uev_add_map %s blacklisted", alias, dev);
+- else
+- condlog(0, "%s: uev_add_map %s failed", alias, dev);
+-
+- FREE(refwwid);
+- return r;
+ }
+
+ static int
+--
+2.7.4
+
diff --git a/0004-multipathd-remove-unused-configure-parameter.patch b/0004-multipathd-remove-unused-configure-parameter.patch
new file mode 100644
index 0000000..d2a8b58
--- /dev/null
+++ b/0004-multipathd-remove-unused-configure-parameter.patch
@@ -0,0 +1,53 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Fri, 2 Feb 2018 15:04:01 -0600
+Subject: [PATCH] multipathd: remove unused configure parameter
+
+configure() is always called with start_waiters=1, so there is no point
+in having the parameter. Remove it.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ multipathd/main.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+diff --git a/multipathd/main.c b/multipathd/main.c
+index dbf9890..51e0f5e 100644
+--- a/multipathd/main.c
++++ b/multipathd/main.c
+@@ -1955,7 +1955,7 @@ checkerloop (void *ap)
+ }
+
+ int
+-configure (struct vectors * vecs, int start_waiters)
++configure (struct vectors * vecs)
+ {
+ struct multipath * mpp;
+ struct path * pp;
+@@ -2054,11 +2054,9 @@ configure (struct vectors * vecs, int start_waiters)
+ i--;
+ continue;
+ }
+- if (start_waiters) {
+- if (start_waiter_thread(mpp, vecs)) {
+- remove_map(mpp, vecs, 1);
+- i--;
+- }
++ if (start_waiter_thread(mpp, vecs)) {
++ remove_map(mpp, vecs, 1);
++ i--;
+ }
+ }
+ return 0;
+@@ -2125,7 +2123,7 @@ reconfigure (struct vectors * vecs)
+ rcu_assign_pointer(multipath_conf, conf);
+ call_rcu(&old->rcu, rcu_free_config);
+
+- configure(vecs, 1);
++ configure(vecs);
+
+
+ return 0;
+--
+2.7.4
+
diff --git a/0004-mutipath-updated-Huawei-storage-config.patch b/0004-mutipath-updated-Huawei-storage-config.patch
deleted file mode 100644
index dd5e74c..0000000
--- a/0004-mutipath-updated-Huawei-storage-config.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Benjamin Marzinski <bmarzins@redhat.com>
-Date: Wed, 1 Nov 2017 19:53:11 -0500
-Subject: [PATCH] mutipath: updated Huawei storage config
-
-I was given this updated built-in config by Zhou Weigang from
-Huawei.
-
-Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
----
- libmultipath/hwtable.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
-index b018ddf..78de1fa 100644
---- a/libmultipath/hwtable.c
-+++ b/libmultipath/hwtable.c
-@@ -940,7 +940,8 @@ static struct hwentry default_hw[] = {
- /* OceanStor V3 */
- .vendor = "HUAWEI",
- .product = "XSG1",
-- .pgpolicy = MULTIBUS,
-+ .pgpolicy = GROUP_BY_PRIO,
-+ .prio_name = PRIO_ALUA,
- },
- /*
- * Red Hat
---
-2.7.4
-
diff --git a/0005-Fix-set_no_path_retry-regression.patch b/0005-Fix-set_no_path_retry-regression.patch
new file mode 100644
index 0000000..1cf6f09
--- /dev/null
+++ b/0005-Fix-set_no_path_retry-regression.patch
@@ -0,0 +1,81 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Tue, 6 Feb 2018 20:53:17 -0600
+Subject: [PATCH] Fix set_no_path_retry() regression
+
+commit 0f850db7fceb6b2bf4968f3831efd250c17c6138 "multipathd: clean up
+set_no_path_retry" has a bug in it. It made set_no_path_retry
+never reset mpp->retry_ticks, even if the device was in recovery mode,
+and there were valid paths. This meant that adding new paths didn't
+remove a device from recovery mode, and queueing could get disabled,
+even while there were valid paths. This patch fixes that.
+
+This patch also fixes a bug in cli_restore_queueing() and
+cli_restore_all_queueing(), where a device that had no_path_retry
+set to "queue" would enter recovery mode (although queueing would
+never actually get disabled).
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ libmultipath/structs_vec.c | 5 +++--
+ multipathd/cli_handlers.c | 20 ++++++++++++--------
+ 2 files changed, 15 insertions(+), 10 deletions(-)
+
+diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
+index fbab61f..0de2221 100644
+--- a/libmultipath/structs_vec.c
++++ b/libmultipath/structs_vec.c
+@@ -343,9 +343,10 @@ static void set_no_path_retry(struct multipath *mpp)
+ dm_queue_if_no_path(mpp->alias, 1);
+ break;
+ default:
+- if (mpp->nr_active > 0)
++ if (mpp->nr_active > 0) {
++ mpp->retry_tick = 0;
+ dm_queue_if_no_path(mpp->alias, 1);
+- else if (is_queueing && mpp->retry_tick == 0)
++ } else if (is_queueing && mpp->retry_tick == 0)
+ enter_recovery_mode(mpp);
+ break;
+ }
+diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
+index 7f13bc9..80519b1 100644
+--- a/multipathd/cli_handlers.c
++++ b/multipathd/cli_handlers.c
+@@ -995,10 +995,12 @@ cli_restore_queueing(void *v, char **reply, int *len, void *data)
+ if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
+ mpp->no_path_retry != NO_PATH_RETRY_FAIL) {
+ dm_queue_if_no_path(mpp->alias, 1);
+- if (mpp->nr_active > 0)
+- mpp->retry_tick = 0;
+- else
+- enter_recovery_mode(mpp);
++ if (mpp->no_path_retry > 0) {
++ if (mpp->nr_active > 0)
++ mpp->retry_tick = 0;
++ else
++ enter_recovery_mode(mpp);
++ }
+ }
+ return 0;
+ }
+@@ -1019,10 +1021,12 @@ cli_restore_all_queueing(void *v, char **reply, int *len, void *data)
+ if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
+ mpp->no_path_retry != NO_PATH_RETRY_FAIL) {
+ dm_queue_if_no_path(mpp->alias, 1);
+- if (mpp->nr_active > 0)
+- mpp->retry_tick = 0;
+- else
+- enter_recovery_mode(mpp);
++ if (mpp->no_path_retry > 0) {
++ if (mpp->nr_active > 0)
++ mpp->retry_tick = 0;
++ else
++ enter_recovery_mode(mpp);
++ }
+ }
+ }
+ return 0;
+--
+2.7.4
+
diff --git a/0005-multipath-fix-doc-typo.patch b/0005-multipath-fix-doc-typo.patch
deleted file mode 100644
index 30cf241..0000000
--- a/0005-multipath-fix-doc-typo.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Benjamin Marzinski <bmarzins@redhat.com>
-Date: Wed, 1 Nov 2017 19:58:10 -0500
-Subject: [PATCH] multipath: fix doc typo
-
-The dev_loss_tmo cap if fast_io_fail_tmo isn't set is 600 seconds,
-not 300 seconds.
-
-Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
----
- multipath/multipath.conf.5 | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
-index 92ad8b1..4bd1a8d 100644
---- a/multipath/multipath.conf.5
-+++ b/multipath/multipath.conf.5
-@@ -653,7 +653,7 @@ seconds, or 68 years. It will be automatically adjusted to the overall
- retry interval \fIno_path_retry\fR * \fIpolling_interval\fR
- if a number of retries is given with \fIno_path_retry\fR and the
- overall retry interval is longer than the specified \fIdev_loss_tmo\fR value.
--The Linux kernel will cap this value to \fI300\fR if \fIfast_io_fail_tmo\fR
-+The Linux kernel will cap this value to \fI600\fR if \fIfast_io_fail_tmo\fR
- is not set. See KNOWN ISSUES.
- .RS
- .TP
---
-2.7.4
-
diff --git a/0006-multipath-add-ghost_delay-parameter.patch b/0006-multipath-add-ghost_delay-parameter.patch
deleted file mode 100644
index 5bb211a..0000000
--- a/0006-multipath-add-ghost_delay-parameter.patch
+++ /dev/null
@@ -1,397 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Benjamin Marzinski <bmarzins@redhat.com>
-Date: Thu, 2 Nov 2017 18:02:56 -0500
-Subject: [PATCH] multipath: add "ghost_delay" parameter
-
-If the lower-priority passive paths for a multipath device appear first,
-IO can go to them and cause the hardware handler to activate them,
-before the higher priority paths appear, causing the devices to
-failback. Setting the "ghost_delay" parameter to a value greater than
-0 can avoid this ping-ponging by causing udev to not mark the device as
-Ready after its initial creation until either an active path appears,
-or ghost_delay seconds have passed. Multipathd does this by setting
-the MPATH_UDEV_NO_PATHS_FLAG.
-
-Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
----
- libmultipath/config.c | 3 +++
- libmultipath/config.h | 3 +++
- libmultipath/configure.c | 11 +++++++++++
- libmultipath/defaults.h | 1 +
- libmultipath/devmapper.c | 2 +-
- libmultipath/dict.c | 14 ++++++++++++++
- libmultipath/hwtable.c | 1 +
- libmultipath/propsel.c | 15 +++++++++++++++
- libmultipath/propsel.h | 1 +
- libmultipath/structs.h | 7 +++++++
- multipath/multipath.conf.5 | 19 +++++++++++++++++++
- multipathd/main.c | 28 +++++++++++++++++++++++++++-
- 12 files changed, 103 insertions(+), 2 deletions(-)
-
-diff --git a/libmultipath/config.c b/libmultipath/config.c
-index ea2359a..9486116 100644
---- a/libmultipath/config.c
-+++ b/libmultipath/config.c
-@@ -351,6 +351,7 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
- merge_num(delay_wait_checks);
- merge_num(skip_kpartx);
- merge_num(max_sectors_kb);
-+ merge_num(ghost_delay);
- merge_num(san_path_err_threshold);
- merge_num(san_path_err_forget_rate);
- merge_num(san_path_err_recovery_time);
-@@ -422,6 +423,7 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
- hwe->retain_hwhandler = dhwe->retain_hwhandler;
- hwe->detect_prio = dhwe->detect_prio;
- hwe->detect_checker = dhwe->detect_checker;
-+ hwe->ghost_delay = dhwe->ghost_delay;
-
- if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
- goto out;
-@@ -622,6 +624,7 @@ load_config (char * file)
- conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
- conf->disable_changed_wwids = DEFAULT_DISABLE_CHANGED_WWIDS;
- conf->remove_retries = 0;
-+ conf->ghost_delay = DEFAULT_GHOST_DELAY;
-
- /*
- * preload default hwtable
-diff --git a/libmultipath/config.h b/libmultipath/config.h
-index 240730b..67ff983 100644
---- a/libmultipath/config.h
-+++ b/libmultipath/config.h
-@@ -80,6 +80,7 @@ struct hwentry {
- int san_path_err_recovery_time;
- int skip_kpartx;
- int max_sectors_kb;
-+ int ghost_delay;
- char * bl_product;
- };
-
-@@ -112,6 +113,7 @@ struct mpentry {
- int san_path_err_recovery_time;
- int skip_kpartx;
- int max_sectors_kb;
-+ int ghost_delay;
- uid_t uid;
- gid_t gid;
- mode_t mode;
-@@ -170,6 +172,7 @@ struct config {
- int disable_changed_wwids;
- int remove_retries;
- int max_sectors_kb;
-+ int ghost_delay;
- unsigned int version[3];
-
- char * multipath_dir;
-diff --git a/libmultipath/configure.c b/libmultipath/configure.c
-index 7a3db31..e2f393f 100644
---- a/libmultipath/configure.c
-+++ b/libmultipath/configure.c
-@@ -300,6 +300,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size)
- select_san_path_err_recovery_time(conf, mpp);
- select_skip_kpartx(conf, mpp);
- select_max_sectors_kb(conf, mpp);
-+ select_ghost_delay(conf, mpp);
-
- sysfs_set_scsi_tmo(mpp, conf->checkint);
- put_multipath_config(conf);
-@@ -760,6 +761,9 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
- }
-
- sysfs_set_max_sectors_kb(mpp, 0);
-+ if (is_daemon && mpp->ghost_delay > 0 && mpp->nr_active &&
-+ pathcount(mpp, PATH_GHOST) == mpp->nr_active)
-+ mpp->ghost_delay_tick = mpp->ghost_delay;
- r = dm_addmap_create(mpp, params);
-
- lock_multipath(mpp, 0);
-@@ -767,11 +771,15 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
-
- case ACT_RELOAD:
- sysfs_set_max_sectors_kb(mpp, 1);
-+ if (mpp->ghost_delay_tick > 0 && pathcount(mpp, PATH_UP))
-+ mpp->ghost_delay_tick = 0;
- r = dm_addmap_reload(mpp, params, 0);
- break;
-
- case ACT_RESIZE:
- sysfs_set_max_sectors_kb(mpp, 1);
-+ if (mpp->ghost_delay_tick > 0 && pathcount(mpp, PATH_UP))
-+ mpp->ghost_delay_tick = 0;
- r = dm_addmap_reload(mpp, params, 1);
- break;
-
-@@ -789,6 +797,9 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
- put_multipath_config(conf);
- if (r) {
- sysfs_set_max_sectors_kb(mpp, 1);
-+ if (mpp->ghost_delay_tick > 0 &&
-+ pathcount(mpp, PATH_UP))
-+ mpp->ghost_delay_tick = 0;
- r = dm_addmap_reload(mpp, params, 0);
- }
- break;
-diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
-index 740ccf4..c9e3411 100644
---- a/libmultipath/defaults.h
-+++ b/libmultipath/defaults.h
-@@ -40,6 +40,7 @@
- #define DEFAULT_SKIP_KPARTX SKIP_KPARTX_OFF
- #define DEFAULT_DISABLE_CHANGED_WWIDS 0
- #define DEFAULT_MAX_SECTORS_KB MAX_SECTORS_KB_UNDEF
-+#define DEFAULT_GHOST_DELAY GHOST_DELAY_OFF
-
- #define DEFAULT_CHECKINT 5
- #define MAX_CHECKINT(a) (a << 2)
-diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
-index fcac6bc..573fc75 100644
---- a/libmultipath/devmapper.c
-+++ b/libmultipath/devmapper.c
-@@ -378,7 +378,7 @@ static uint16_t build_udev_flags(const struct multipath *mpp, int reload)
- /* DM_UDEV_DISABLE_LIBRARY_FALLBACK is added in dm_addmap */
- return (mpp->skip_kpartx == SKIP_KPARTX_ON ?
- MPATH_UDEV_NO_KPARTX_FLAG : 0) |
-- (mpp->nr_active == 0 ?
-+ ((mpp->nr_active == 0 || mpp->ghost_delay_tick > 0)?
- MPATH_UDEV_NO_PATHS_FLAG : 0) |
- (reload && !mpp->force_udev_reload ?
- MPATH_UDEV_RELOAD_FLAG : 0);
-diff --git a/libmultipath/dict.c b/libmultipath/dict.c
-index 36cccc9..54652d4 100644
---- a/libmultipath/dict.c
-+++ b/libmultipath/dict.c
-@@ -1110,6 +1110,16 @@ declare_hw_handler(san_path_err_recovery_time, set_off_int_undef)
- declare_hw_snprint(san_path_err_recovery_time, print_off_int_undef)
- declare_mp_handler(san_path_err_recovery_time, set_off_int_undef)
- declare_mp_snprint(san_path_err_recovery_time, print_off_int_undef)
-+
-+declare_def_handler(ghost_delay, set_off_int_undef)
-+declare_def_snprint(ghost_delay, print_off_int_undef)
-+declare_ovr_handler(ghost_delay, set_off_int_undef)
-+declare_ovr_snprint(ghost_delay, print_off_int_undef)
-+declare_hw_handler(ghost_delay, set_off_int_undef)
-+declare_hw_snprint(ghost_delay, print_off_int_undef)
-+declare_mp_handler(ghost_delay, set_off_int_undef)
-+declare_mp_snprint(ghost_delay, print_off_int_undef)
-+
- static int
- def_uxsock_timeout_handler(struct config *conf, vector strvec)
- {
-@@ -1456,6 +1466,7 @@ init_keywords(vector keywords)
- install_keyword("disable_changed_wwids", &def_disable_changed_wwids_handler, &snprint_def_disable_changed_wwids);
- install_keyword("remove_retries", &def_remove_retries_handler, &snprint_def_remove_retries);
- install_keyword("max_sectors_kb", &def_max_sectors_kb_handler, &snprint_def_max_sectors_kb);
-+ install_keyword("ghost_delay", &def_ghost_delay_handler, &snprint_def_ghost_delay);
- __deprecated install_keyword("default_selector", &def_selector_handler, NULL);
- __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
- __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
-@@ -1535,6 +1546,7 @@ init_keywords(vector keywords)
- install_keyword("san_path_err_recovery_time", &hw_san_path_err_recovery_time_handler, &snprint_hw_san_path_err_recovery_time);
- install_keyword("skip_kpartx", &hw_skip_kpartx_handler, &snprint_hw_skip_kpartx);
- install_keyword("max_sectors_kb", &hw_max_sectors_kb_handler, &snprint_hw_max_sectors_kb);
-+ install_keyword("ghost_delay", &hw_ghost_delay_handler, &snprint_hw_ghost_delay);
- install_sublevel_end();
-
- install_keyword_root("overrides", &overrides_handler);
-@@ -1569,6 +1581,7 @@ init_keywords(vector keywords)
-
- install_keyword("skip_kpartx", &ovr_skip_kpartx_handler, &snprint_ovr_skip_kpartx);
- install_keyword("max_sectors_kb", &ovr_max_sectors_kb_handler, &snprint_ovr_max_sectors_kb);
-+ install_keyword("ghost_delay", &ovr_ghost_delay_handler, &snprint_ovr_ghost_delay);
-
- install_keyword_root("multipaths", &multipaths_handler);
- install_keyword_multi("multipath", &multipath_handler, NULL);
-@@ -1600,5 +1613,6 @@ init_keywords(vector keywords)
- install_keyword("san_path_err_recovery_time", &mp_san_path_err_recovery_time_handler, &snprint_mp_san_path_err_recovery_time);
- install_keyword("skip_kpartx", &mp_skip_kpartx_handler, &snprint_mp_skip_kpartx);
- install_keyword("max_sectors_kb", &mp_max_sectors_kb_handler, &snprint_mp_max_sectors_kb);
-+ install_keyword("ghost_delay", &mp_ghost_delay_handler, &snprint_mp_ghost_delay);
- install_sublevel_end();
- }
-diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
-index 78de1fa..7226fb1 100644
---- a/libmultipath/hwtable.c
-+++ b/libmultipath/hwtable.c
-@@ -72,6 +72,7 @@
- .delay_wait_checks = DELAY_CHECKS_OFF,
- .skip_kpartx = SKIP_KPARTX_OFF,
- .max_sectors_kb = MAX_SECTORS_KB_UNDEF,
-+ .ghost_delay = GHOST_DELAY_OFF
- },
- #endif
-
-diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
-index 00adc0d..6721cc6 100644
---- a/libmultipath/propsel.c
-+++ b/libmultipath/propsel.c
-@@ -835,3 +835,18 @@ out:
- origin);
- return 0;
- }
-+
-+int select_ghost_delay (struct config *conf, struct multipath * mp)
-+{
-+ char *origin, buff[12];
-+
-+ mp_set_mpe(ghost_delay);
-+ mp_set_ovr(ghost_delay);
-+ mp_set_hwe(ghost_delay);
-+ mp_set_conf(ghost_delay);
-+ mp_set_default(ghost_delay, DEFAULT_GHOST_DELAY);
-+out:
-+ print_off_int_undef(buff, 12, &mp->ghost_delay);
-+ condlog(3, "%s: ghost_delay = %s %s", mp->alias, buff, origin);
-+ return 0;
-+}
-diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h
-index f8e96d8..494fb10 100644
---- a/libmultipath/propsel.h
-+++ b/libmultipath/propsel.h
-@@ -25,6 +25,7 @@ int select_delay_watch_checks (struct config *conf, struct multipath * mp);
- int select_delay_wait_checks (struct config *conf, struct multipath * mp);
- int select_skip_kpartx (struct config *conf, struct multipath * mp);
- int select_max_sectors_kb (struct config *conf, struct multipath * mp);
-+int select_ghost_delay(struct config *conf, struct multipath * mp);
- int select_san_path_err_forget_rate(struct config *conf, struct multipath *mp);
- int select_san_path_err_threshold(struct config *conf, struct multipath *mp);
- int select_san_path_err_recovery_time(struct config *conf, struct multipath *mp);
-diff --git a/libmultipath/structs.h b/libmultipath/structs.h
-index f06824a..d2d7701 100644
---- a/libmultipath/structs.h
-+++ b/libmultipath/structs.h
-@@ -167,6 +167,11 @@ enum no_undef_states {
- NU_UNDEF = 0,
- };
-
-+enum ghost_delay_states {
-+ GHOST_DELAY_OFF = NU_NO,
-+ GHOST_DELAY_UNDEF = NU_UNDEF,
-+};
-+
- enum initialized_states {
- INIT_FAILED,
- INIT_MISSING_UDEV,
-@@ -282,6 +287,8 @@ struct multipath {
- int max_sectors_kb;
- int force_readonly;
- int force_udev_reload;
-+ int ghost_delay;
-+ int ghost_delay_tick;
- unsigned int dev_loss;
- uid_t uid;
- gid_t gid;
-diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
-index 4bd1a8d..8783124 100644
---- a/multipath/multipath.conf.5
-+++ b/multipath/multipath.conf.5
-@@ -1017,6 +1017,19 @@ The default is: \fB<device dependent>\fR
- .RE
- .
- .
-+.TP
-+.B ghost_delay
-+Sets the number of seconds that multipath will wait after creating a device
-+with only ghost paths before marking it ready for use in systemd. This gives
-+the active paths time to appear before the multipath runs the hardware handler
-+to switch the ghost paths to active ones. Setting this to \fI0\fR or \fIon\fR
-+makes multipath immediately mark a device with only ghost paths as ready.
-+.RS
-+.TP
-+The default is \fBno\fR
-+.RE
-+.
-+.
- .\" ----------------------------------------------------------------------------
- .SH "blacklist section"
- .\" ----------------------------------------------------------------------------
-@@ -1157,6 +1170,8 @@ are taken from the \fIdefaults\fR or \fIdevices\fR section:
- .B skip_kpartx
- .TP
- .B max_sectors_kb
-+.TP
-+.B ghost_delay
- .RE
- .PD
- .LP
-@@ -1284,6 +1299,8 @@ section:
- .B skip_kpartx
- .TP
- .B max_sectors_kb
-+.TP
-+.B ghost_delay
- .RE
- .PD
- .LP
-@@ -1354,6 +1371,8 @@ the values are taken from the \fIdevices\fR or \fIdefaults\fR sections:
- .B delay_wait_checks
- .TP
- .B skip_kpartx
-+.TP
-+.B ghost_delay
- .RE
- .PD
- .LP
-diff --git a/multipathd/main.c b/multipathd/main.c
-index 8049da2..c475fcd 100644
---- a/multipathd/main.c
-+++ b/multipathd/main.c
-@@ -351,6 +351,8 @@ sync_map_state(struct multipath *mpp)
- pp->state == PATH_WILD ||
- pp->state == PATH_DELAYED)
- continue;
-+ if (mpp->ghost_delay_tick > 0)
-+ continue;
- if ((pp->dmstate == PSTATE_FAILED ||
- pp->dmstate == PSTATE_UNDEF) &&
- (pp->state == PATH_UP || pp->state == PATH_GHOST))
-@@ -735,7 +737,8 @@ ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map)
- mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
- if (mpp && mpp->wait_for_udev &&
- (pathcount(mpp, PATH_UP) > 0 ||
-- (pathcount(mpp, PATH_GHOST) > 0 && pp->tpgs != TPGS_IMPLICIT))) {
-+ (pathcount(mpp, PATH_GHOST) > 0 && pp->tpgs != TPGS_IMPLICIT &&
-+ mpp->ghost_delay_tick <= 0))) {
- /* if wait_for_udev is set and valid paths exist */
- condlog(2, "%s: delaying path addition until %s is fully initialized", pp->dev, mpp->alias);
- mpp->wait_for_udev = 2;
-@@ -1416,6 +1419,28 @@ missing_uev_wait_tick(struct vectors *vecs)
- }
-
- static void
-+ghost_delay_tick(struct vectors *vecs)
-+{
-+ struct multipath * mpp;
-+ unsigned int i;
-+
-+ vector_foreach_slot (vecs->mpvec, mpp, i) {
-+ if (mpp->ghost_delay_tick <= 0)
-+ continue;
-+ if (--mpp->ghost_delay_tick <= 0) {
-+ condlog(0, "%s: timed out waiting for active path",
-+ mpp->alias);
-+ mpp->force_udev_reload = 1;
-+ if (update_map(mpp, vecs) != 0) {
-+ /* update_map removed map */
-+ i--;
-+ continue;
-+ }
-+ }
-+ }
-+}
-+
-+static void
- defered_failback_tick (vector mpvec)
- {
- struct multipath * mpp;
-@@ -1961,6 +1986,7 @@ checkerloop (void *ap)
- defered_failback_tick(vecs->mpvec);
- retry_count_tick(vecs->mpvec);
- missing_uev_wait_tick(vecs);
-+ ghost_delay_tick(vecs);
- lock_cleanup_pop(vecs->lock);
-
- if (count)
---
-2.7.4
-
diff --git a/0006-multipathd-change-spurious-uevent-msg-priority.patch b/0006-multipathd-change-spurious-uevent-msg-priority.patch
new file mode 100644
index 0000000..1e53803
--- /dev/null
+++ b/0006-multipathd-change-spurious-uevent-msg-priority.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Wed, 7 Feb 2018 14:20:11 -0600
+Subject: [PATCH] multipathd: change spurious uevent msg priority
+
+The "spurious uevent, path already in pathvec" is not anything to worry
+about, so it should not have the error priority.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ multipathd/main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/multipathd/main.c b/multipathd/main.c
+index 51e0f5e..7ac59d9 100644
+--- a/multipathd/main.c
++++ b/multipathd/main.c
+@@ -562,7 +562,7 @@ uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map)
+ if (pp) {
+ int r;
+
+- condlog(0, "%s: spurious uevent, path already in pathvec",
++ condlog(2, "%s: spurious uevent, path already in pathvec",
+ uev->kernel);
+ if (!pp->mpp && !strlen(pp->wwid)) {
+ condlog(3, "%s: reinitialize path", uev->kernel);
+--
+2.7.4
+
diff --git a/0007-multipath-print-sysfs-state-in-fast-list-mode.patch b/0007-multipath-print-sysfs-state-in-fast-list-mode.patch
new file mode 100644
index 0000000..890793c
--- /dev/null
+++ b/0007-multipath-print-sysfs-state-in-fast-list-mode.patch
@@ -0,0 +1,68 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Wed, 7 Feb 2018 16:06:06 -0600
+Subject: [PATCH] multipath: print sysfs state in fast list mode
+
+commit b123e711ea2a4b471a98ff5e26815df3773636b5 "libmultipath: cleanup
+orphan device states" stopped multipathd from showing old state for
+orphan paths by checking if pp->mpp was set, and only printing the state
+if it was. Unfortunately, when "multipath -l" is run, pp->mpp isn't
+set. While the checker state isn't checked and shouldn't be printed with
+"-l", the sysfs state can be, and was before b123e711. This patch sets
+pp->mpp in fast list mode, so that the sysfs state gets printed. It
+also verifies that the path exists in sysfs, and if not, marks it as
+faulty.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ multipath/main.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/multipath/main.c b/multipath/main.c
+index bffe065..d2415a9 100644
+--- a/multipath/main.c
++++ b/multipath/main.c
+@@ -149,7 +149,7 @@ usage (char * progname)
+ }
+
+ static int
+-update_paths (struct multipath * mpp)
++update_paths (struct multipath * mpp, int quick)
+ {
+ int i, j;
+ struct pathgroup * pgp;
+@@ -171,9 +171,12 @@ update_paths (struct multipath * mpp)
+ * path is not in sysfs anymore
+ */
+ pp->chkrstate = pp->state = PATH_DOWN;
++ pp->offline = 1;
+ continue;
+ }
+ pp->mpp = mpp;
++ if (quick)
++ continue;
+ conf = get_multipath_config();
+ if (pathinfo(pp, conf, DI_ALL))
+ pp->state = PATH_UNCHECKED;
+@@ -181,6 +184,8 @@ update_paths (struct multipath * mpp)
+ continue;
+ }
+ pp->mpp = mpp;
++ if (quick)
++ continue;
+ if (pp->state == PATH_UNCHECKED ||
+ pp->state == PATH_WILD) {
+ conf = get_multipath_config();
+@@ -238,8 +243,7 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
+ * If not in "fast list mode", we need to fetch information
+ * about them
+ */
+- if (cmd != CMD_LIST_SHORT)
+- update_paths(mpp);
++ update_paths(mpp, (cmd == CMD_LIST_SHORT));
+
+ if (cmd == CMD_LIST_LONG)
+ mpp->bestpg = select_path_group(mpp);
+--
+2.7.4
+
diff --git a/0008-libmultipath-move-remove_map-waiter-code-to-multipat.patch b/0008-libmultipath-move-remove_map-waiter-code-to-multipat.patch
new file mode 100644
index 0000000..314b7c0
--- /dev/null
+++ b/0008-libmultipath-move-remove_map-waiter-code-to-multipat.patch
@@ -0,0 +1,148 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Mon, 5 Feb 2018 16:07:36 -0600
+Subject: [PATCH] libmultipath: move remove_map waiter code to multipathd
+
+Only multipathd needs to worry about the multipath waiter code. There is
+no point in having remove_map_and_stop_waiter() or
+remove_maps_and_stop_waiters() in libmultipath, since they should never
+be use outside of multipathd.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ libmultipath/structs_vec.c | 40 +++++-----------------------------------
+ libmultipath/structs_vec.h | 2 --
+ multipathd/main.c | 23 +++++++++++++++++++++++
+ 3 files changed, 28 insertions(+), 37 deletions(-)
+
+diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
+index 0de2221..abf5327 100644
+--- a/libmultipath/structs_vec.c
++++ b/libmultipath/structs_vec.c
+@@ -116,25 +116,16 @@ set_multipath_wwid (struct multipath * mpp)
+ dm_get_uuid(mpp->alias, mpp->wwid);
+ }
+
+-#define KEEP_WAITER 0
+-#define STOP_WAITER 1
+ #define PURGE_VEC 1
+
+-static void
+-_remove_map (struct multipath * mpp, struct vectors * vecs,
+- int stop_waiter, int purge_vec)
++void
++remove_map(struct multipath * mpp, struct vectors * vecs, int purge_vec)
+ {
+ int i;
+
+ condlog(4, "%s: remove multipath map", mpp->alias);
+
+ /*
+- * stop the DM event waiter thread
+- */
+- if (stop_waiter)
+- stop_waiter_thread(mpp, vecs);
+-
+- /*
+ * clear references to this map
+ */
+ orphan_paths(vecs->pathvec, mpp);
+@@ -149,19 +140,8 @@ _remove_map (struct multipath * mpp, struct vectors * vecs,
+ free_multipath(mpp, KEEP_PATHS);
+ }
+
+-void remove_map(struct multipath *mpp, struct vectors *vecs, int purge_vec)
+-{
+- _remove_map(mpp, vecs, KEEP_WAITER, purge_vec);
+-}
+-
+-void remove_map_and_stop_waiter(struct multipath *mpp, struct vectors *vecs,
+- int purge_vec)
+-{
+- _remove_map(mpp, vecs, STOP_WAITER, purge_vec);
+-}
+-
+-static void
+-_remove_maps (struct vectors * vecs, int stop_waiter)
++void
++remove_maps(struct vectors * vecs)
+ {
+ int i;
+ struct multipath * mpp;
+@@ -170,7 +150,7 @@ _remove_maps (struct vectors * vecs, int stop_waiter)
+ return;
+
+ vector_foreach_slot (vecs->mpvec, mpp, i) {
+- _remove_map(mpp, vecs, stop_waiter, 1);
++ remove_map(mpp, vecs, 1);
+ i--;
+ }
+
+@@ -178,16 +158,6 @@ _remove_maps (struct vectors * vecs, int stop_waiter)
+ vecs->mpvec = NULL;
+ }
+
+-void remove_maps(struct vectors *vecs)
+-{
+- _remove_maps(vecs, KEEP_WAITER);
+-}
+-
+-void remove_maps_and_stop_waiters(struct vectors *vecs)
+-{
+- _remove_maps(vecs, STOP_WAITER);
+-}
+-
+ void
+ extract_hwe_from_path(struct multipath * mpp)
+ {
+diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h
+index b81413b..d6e17bb 100644
+--- a/libmultipath/structs_vec.h
++++ b/libmultipath/structs_vec.h
+@@ -27,9 +27,7 @@ int update_multipath_strings (struct multipath *mpp, vector pathvec,
+ void extract_hwe_from_path(struct multipath * mpp);
+
+ void remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec);
+-void remove_map_and_stop_waiter (struct multipath * mpp, struct vectors * vecs, int purge_vec);
+ void remove_maps (struct vectors * vecs);
+-void remove_maps_and_stop_waiters (struct vectors * vecs);
+
+ void sync_map_state (struct multipath *);
+ int update_map (struct multipath *mpp, struct vectors *vecs);
+diff --git a/multipathd/main.c b/multipathd/main.c
+index 7ac59d9..72c3c2f 100644
+--- a/multipathd/main.c
++++ b/multipathd/main.c
+@@ -288,6 +288,29 @@ switch_pathgroup (struct multipath * mpp)
+ mpp->alias, mpp->bestpg);
+ }
+
++static void
++remove_map_and_stop_waiter(struct multipath *mpp, struct vectors *vecs,
++ int purge_vec)
++{
++ stop_waiter_thread(mpp, vecs);
++ remove_map(mpp, vecs, purge_vec);
++}
++
++static void
++remove_maps_and_stop_waiters(struct vectors *vecs)
++{
++ int i;
++ struct multipath * mpp;
++
++ if (!vecs)
++ return;
++
++ vector_foreach_slot(vecs->mpvec, mpp, i)
++ stop_waiter_thread(mpp, vecs);
++
++ remove_maps(vecs);
++}
++
+ static int
+ coalesce_maps(struct vectors *vecs, vector nmpv)
+ {
+--
+2.7.4
+
diff --git a/0009-move-waiter-code-from-libmultipath-to-multipathd.patch b/0009-move-waiter-code-from-libmultipath-to-multipathd.patch
new file mode 100644
index 0000000..4012267
--- /dev/null
+++ b/0009-move-waiter-code-from-libmultipath-to-multipathd.patch
@@ -0,0 +1,793 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Mon, 5 Feb 2018 18:50:45 -0600
+Subject: [PATCH] move waiter code from libmultipath to multipathd
+
+Only multipathd uses the code in waiter.[ch] and the functions that call
+it directly, so they should all live in the multipathd directory. This
+patch is simply moving the waiter.[ch] files and the functions in
+structs_vec that use them. None of the moved code has been changed.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ libmultipath/Makefile | 2 +-
+ libmultipath/structs_vec.c | 98 ---------------------
+ libmultipath/structs_vec.h | 4 +-
+ libmultipath/waiter.c | 215 ---------------------------------------------
+ libmultipath/waiter.h | 17 ----
+ multipathd/Makefile | 2 +-
+ multipathd/main.c | 96 ++++++++++++++++++++
+ multipathd/waiter.c | 215 +++++++++++++++++++++++++++++++++++++++++++++
+ multipathd/waiter.h | 17 ++++
+ 9 files changed, 332 insertions(+), 334 deletions(-)
+ delete mode 100644 libmultipath/waiter.c
+ delete mode 100644 libmultipath/waiter.h
+ create mode 100644 multipathd/waiter.c
+ create mode 100644 multipathd/waiter.h
+
+diff --git a/libmultipath/Makefile b/libmultipath/Makefile
+index 6447d8d..a1005b2 100644
+--- a/libmultipath/Makefile
++++ b/libmultipath/Makefile
+@@ -42,7 +42,7 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.o \
+ pgpolicies.o debug.o defaults.o uevent.o time-util.o \
+ switchgroup.o uxsock.o print.o alias.o log_pthread.o \
+ log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
+- lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \
++ lock.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \
+ io_err_stat.o
+
+ all: $(LIBS)
+diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
+index abf5327..77b045b 100644
+--- a/libmultipath/structs_vec.c
++++ b/libmultipath/structs_vec.c
+@@ -10,7 +10,6 @@
+ #include "structs.h"
+ #include "structs_vec.h"
+ #include "sysfs.h"
+-#include "waiter.h"
+ #include "devmapper.h"
+ #include "dmparser.h"
+ #include "propsel.h"
+@@ -107,17 +106,6 @@ void orphan_paths(vector pathvec, struct multipath *mpp)
+ }
+ }
+
+-static void
+-set_multipath_wwid (struct multipath * mpp)
+-{
+- if (strlen(mpp->wwid))
+- return;
+-
+- dm_get_uuid(mpp->alias, mpp->wwid);
+-}
+-
+-#define PURGE_VEC 1
+-
+ void
+ remove_map(struct multipath * mpp, struct vectors * vecs, int purge_vec)
+ {
+@@ -379,92 +367,6 @@ sync_map_state(struct multipath *mpp)
+ }
+ }
+
+-int
+-update_map (struct multipath *mpp, struct vectors *vecs)
+-{
+- int retries = 3;
+- char params[PARAMS_SIZE] = {0};
+-
+-retry:
+- condlog(4, "%s: updating new map", mpp->alias);
+- if (adopt_paths(vecs->pathvec, mpp)) {
+- condlog(0, "%s: failed to adopt paths for new map update",
+- mpp->alias);
+- retries = -1;
+- goto fail;
+- }
+- verify_paths(mpp, vecs);
+- mpp->action = ACT_RELOAD;
+-
+- extract_hwe_from_path(mpp);
+- if (setup_map(mpp, params, PARAMS_SIZE)) {
+- condlog(0, "%s: failed to setup new map in update", mpp->alias);
+- retries = -1;
+- goto fail;
+- }
+- if (domap(mpp, params, 1) <= 0 && retries-- > 0) {
+- condlog(0, "%s: map_udate sleep", mpp->alias);
+- sleep(1);
+- goto retry;
+- }
+- dm_lib_release();
+-
+-fail:
+- if (setup_multipath(vecs, mpp))
+- return 1;
+-
+- sync_map_state(mpp);
+-
+- if (retries < 0)
+- condlog(0, "%s: failed reload in new map update", mpp->alias);
+- return 0;
+-}
+-
+-struct multipath *add_map_without_path (struct vectors *vecs, char *alias)
+-{
+- struct multipath * mpp = alloc_multipath();
+- struct config *conf;
+-
+- if (!mpp)
+- return NULL;
+- if (!alias) {
+- FREE(mpp);
+- return NULL;
+- }
+-
+- mpp->alias = STRDUP(alias);
+-
+- if (dm_get_info(mpp->alias, &mpp->dmi)) {
+- condlog(3, "%s: cannot access table", mpp->alias);
+- goto out;
+- }
+- set_multipath_wwid(mpp);
+- conf = get_multipath_config();
+- mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
+- put_multipath_config(conf);
+-
+- if (update_multipath_table(mpp, vecs->pathvec, 1))
+- goto out;
+- if (update_multipath_status(mpp))
+- goto out;
+-
+- if (!vector_alloc_slot(vecs->mpvec))
+- goto out;
+-
+- vector_set_slot(vecs->mpvec, mpp);
+-
+- if (update_map(mpp, vecs) != 0) /* map removed */
+- return NULL;
+-
+- if (start_waiter_thread(mpp, vecs))
+- goto out;
+-
+- return mpp;
+-out:
+- remove_map(mpp, vecs, PURGE_VEC);
+- return NULL;
+-}
+-
+ static void
+ find_existing_alias (struct multipath * mpp,
+ struct vectors *vecs)
+diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h
+index d6e17bb..ceab6d9 100644
+--- a/libmultipath/structs_vec.h
++++ b/libmultipath/structs_vec.h
+@@ -26,12 +26,12 @@ int update_multipath_strings (struct multipath *mpp, vector pathvec,
+ int is_daemon);
+ void extract_hwe_from_path(struct multipath * mpp);
+
++#define PURGE_VEC 1
++
+ void remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec);
+ void remove_maps (struct vectors * vecs);
+
+ void sync_map_state (struct multipath *);
+-int update_map (struct multipath *mpp, struct vectors *vecs);
+-struct multipath * add_map_without_path (struct vectors * vecs, char * alias);
+ struct multipath * add_map_with_path (struct vectors * vecs,
+ struct path * pp, int add_vec);
+ int update_multipath (struct vectors *vecs, char *mapname, int reset);
+diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c
+deleted file mode 100644
+index cb9708b..0000000
+--- a/libmultipath/waiter.c
++++ /dev/null
+@@ -1,215 +0,0 @@
+-/*
+- * Copyright (c) 2004, 2005 Christophe Varoqui
+- * Copyright (c) 2005 Kiyoshi Ueda, NEC
+- * Copyright (c) 2005 Benjamin Marzinski, Redhat
+- * Copyright (c) 2005 Edward Goggin, EMC
+- */
+-#include <unistd.h>
+-#include <libdevmapper.h>
+-#include <sys/mman.h>
+-#include <pthread.h>
+-#include <signal.h>
+-#include <urcu.h>
+-
+-#include "vector.h"
+-#include "memory.h"
+-#include "checkers.h"
+-#include "config.h"
+-#include "structs.h"
+-#include "structs_vec.h"
+-#include "devmapper.h"
+-#include "debug.h"
+-#include "lock.h"
+-#include "waiter.h"
+-
+-pthread_attr_t waiter_attr;
+-
+-static struct event_thread *alloc_waiter (void)
+-{
+-
+- struct event_thread *wp;
+-
+- wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
+- memset(wp, 0, sizeof(struct event_thread));
+-
+- return wp;
+-}
+-
+-static void free_waiter (void *data)
+-{
+- struct event_thread *wp = (struct event_thread *)data;
+-
+- if (wp->dmt)
+- dm_task_destroy(wp->dmt);
+-
+- rcu_unregister_thread();
+- FREE(wp);
+-}
+-
+-void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+-{
+- pthread_t thread;
+-
+- if (mpp->waiter == (pthread_t)0) {
+- condlog(3, "%s: event checker thread already stopped",
+- mpp->alias);
+- return;
+- }
+- condlog(2, "%s: stop event checker thread (%lu)", mpp->alias,
+- mpp->waiter);
+- thread = mpp->waiter;
+- mpp->waiter = (pthread_t)0;
+- pthread_cancel(thread);
+- pthread_kill(thread, SIGUSR2);
+-}
+-
+-/*
+- * returns the reschedule delay
+- * negative means *stop*
+- */
+-static int waiteventloop (struct event_thread *waiter)
+-{
+- sigset_t set, oldset;
+- int event_nr;
+- int r;
+-
+- if (!waiter->event_nr)
+- waiter->event_nr = dm_geteventnr(waiter->mapname);
+-
+- if (!(waiter->dmt = libmp_dm_task_create(DM_DEVICE_WAITEVENT))) {
+- condlog(0, "%s: devmap event #%i dm_task_create error",
+- waiter->mapname, waiter->event_nr);
+- return 1;
+- }
+-
+- if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
+- condlog(0, "%s: devmap event #%i dm_task_set_name error",
+- waiter->mapname, waiter->event_nr);
+- dm_task_destroy(waiter->dmt);
+- waiter->dmt = NULL;
+- return 1;
+- }
+-
+- if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
+- waiter->event_nr)) {
+- condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
+- waiter->mapname, waiter->event_nr);
+- dm_task_destroy(waiter->dmt);
+- waiter->dmt = NULL;
+- return 1;
+- }
+-
+- dm_task_no_open_count(waiter->dmt);
+-
+- /* wait */
+- sigemptyset(&set);
+- sigaddset(&set, SIGUSR2);
+- pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
+-
+- pthread_testcancel();
+- r = dm_task_run(waiter->dmt);
+- pthread_testcancel();
+-
+- pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+- dm_task_destroy(waiter->dmt);
+- waiter->dmt = NULL;
+-
+- if (!r) /* wait interrupted by signal */
+- return -1;
+-
+- waiter->event_nr++;
+-
+- /*
+- * upon event ...
+- */
+- while (1) {
+- condlog(3, "%s: devmap event #%i",
+- waiter->mapname, waiter->event_nr);
+-
+- /*
+- * event might be :
+- *
+- * 1) a table reload, which means our mpp structure is
+- * obsolete : refresh it through update_multipath()
+- * 2) a path failed by DM : mark as such through
+- * update_multipath()
+- * 3) map has gone away : stop the thread.
+- * 4) a path reinstate : nothing to do
+- * 5) a switch group : nothing to do
+- */
+- pthread_cleanup_push(cleanup_lock, &waiter->vecs->lock);
+- lock(&waiter->vecs->lock);
+- pthread_testcancel();
+- r = update_multipath(waiter->vecs, waiter->mapname, 1);
+- lock_cleanup_pop(waiter->vecs->lock);
+-
+- if (r) {
+- condlog(2, "%s: event checker exit",
+- waiter->mapname);
+- return -1; /* stop the thread */
+- }
+-
+- event_nr = dm_geteventnr(waiter->mapname);
+-
+- if (waiter->event_nr == event_nr)
+- return 1; /* upon problem reschedule 1s later */
+-
+- waiter->event_nr = event_nr;
+- }
+- return -1; /* never reach there */
+-}
+-
+-static void *waitevent (void *et)
+-{
+- int r;
+- struct event_thread *waiter;
+-
+- mlockall(MCL_CURRENT | MCL_FUTURE);
+-
+- waiter = (struct event_thread *)et;
+- pthread_cleanup_push(free_waiter, et);
+-
+- rcu_register_thread();
+- while (1) {
+- r = waiteventloop(waiter);
+-
+- if (r < 0)
+- break;
+-
+- sleep(r);
+- }
+-
+- pthread_cleanup_pop(1);
+- return NULL;
+-}
+-
+-int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+-{
+- struct event_thread *wp;
+-
+- if (!mpp)
+- return 0;
+-
+- wp = alloc_waiter();
+-
+- if (!wp)
+- goto out;
+-
+- strncpy(wp->mapname, mpp->alias, WWID_SIZE - 1);
+- wp->vecs = vecs;
+-
+- if (pthread_create(&wp->thread, &waiter_attr, waitevent, wp)) {
+- condlog(0, "%s: cannot create event checker", wp->mapname);
+- goto out1;
+- }
+- mpp->waiter = wp->thread;
+- condlog(2, "%s: event checker started", wp->mapname);
+-
+- return 0;
+-out1:
+- free_waiter(wp);
+- mpp->waiter = (pthread_t)0;
+-out:
+- condlog(0, "failed to start waiter thread");
+- return 1;
+-}
+diff --git a/libmultipath/waiter.h b/libmultipath/waiter.h
+deleted file mode 100644
+index 0cfae46..0000000
+--- a/libmultipath/waiter.h
++++ /dev/null
+@@ -1,17 +0,0 @@
+-#ifndef _WAITER_H
+-#define _WAITER_H
+-
+-extern pthread_attr_t waiter_attr;
+-
+-struct event_thread {
+- struct dm_task *dmt;
+- pthread_t thread;
+- int event_nr;
+- char mapname[WWID_SIZE];
+- struct vectors *vecs;
+-};
+-
+-void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs);
+-int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
+-
+-#endif /* _WAITER_H */
+diff --git a/multipathd/Makefile b/multipathd/Makefile
+index e6f140b..85f29a7 100644
+--- a/multipathd/Makefile
++++ b/multipathd/Makefile
+@@ -22,7 +22,7 @@ ifdef SYSTEMD
+ endif
+ endif
+
+-OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o
++OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o
+
+ EXEC = multipathd
+
+diff --git a/multipathd/main.c b/multipathd/main.c
+index 72c3c2f..94b2406 100644
+--- a/multipathd/main.c
++++ b/multipathd/main.c
+@@ -311,6 +311,102 @@ remove_maps_and_stop_waiters(struct vectors *vecs)
+ remove_maps(vecs);
+ }
+
++static void
++set_multipath_wwid (struct multipath * mpp)
++{
++ if (strlen(mpp->wwid))
++ return;
++
++ dm_get_uuid(mpp->alias, mpp->wwid);
++}
++
++static int
++update_map (struct multipath *mpp, struct vectors *vecs)
++{
++ int retries = 3;
++ char params[PARAMS_SIZE] = {0};
++
++retry:
++ condlog(4, "%s: updating new map", mpp->alias);
++ if (adopt_paths(vecs->pathvec, mpp)) {
++ condlog(0, "%s: failed to adopt paths for new map update",
++ mpp->alias);
++ retries = -1;
++ goto fail;
++ }
++ verify_paths(mpp, vecs);
++ mpp->action = ACT_RELOAD;
++
++ extract_hwe_from_path(mpp);
++ if (setup_map(mpp, params, PARAMS_SIZE)) {
++ condlog(0, "%s: failed to setup new map in update", mpp->alias);
++ retries = -1;
++ goto fail;
++ }
++ if (domap(mpp, params, 1) <= 0 && retries-- > 0) {
++ condlog(0, "%s: map_udate sleep", mpp->alias);
++ sleep(1);
++ goto retry;
++ }
++ dm_lib_release();
++
++fail:
++ if (setup_multipath(vecs, mpp))
++ return 1;
++
++ sync_map_state(mpp);
++
++ if (retries < 0)
++ condlog(0, "%s: failed reload in new map update", mpp->alias);
++ return 0;
++}
++
++static struct multipath *
++add_map_without_path (struct vectors *vecs, char *alias)
++{
++ struct multipath * mpp = alloc_multipath();
++ struct config *conf;
++
++ if (!mpp)
++ return NULL;
++ if (!alias) {
++ FREE(mpp);
++ return NULL;
++ }
++
++ mpp->alias = STRDUP(alias);
++
++ if (dm_get_info(mpp->alias, &mpp->dmi)) {
++ condlog(3, "%s: cannot access table", mpp->alias);
++ goto out;
++ }
++ set_multipath_wwid(mpp);
++ conf = get_multipath_config();
++ mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
++ put_multipath_config(conf);
++
++ if (update_multipath_table(mpp, vecs->pathvec, 1))
++ goto out;
++ if (update_multipath_status(mpp))
++ goto out;
++
++ if (!vector_alloc_slot(vecs->mpvec))
++ goto out;
++
++ vector_set_slot(vecs->mpvec, mpp);
++
++ if (update_map(mpp, vecs) != 0) /* map removed */
++ return NULL;
++
++ if (start_waiter_thread(mpp, vecs))
++ goto out;
++
++ return mpp;
++out:
++ remove_map(mpp, vecs, PURGE_VEC);
++ return NULL;
++}
++
+ static int
+ coalesce_maps(struct vectors *vecs, vector nmpv)
+ {
+diff --git a/multipathd/waiter.c b/multipathd/waiter.c
+new file mode 100644
+index 0000000..cb9708b
+--- /dev/null
++++ b/multipathd/waiter.c
+@@ -0,0 +1,215 @@
++/*
++ * Copyright (c) 2004, 2005 Christophe Varoqui
++ * Copyright (c) 2005 Kiyoshi Ueda, NEC
++ * Copyright (c) 2005 Benjamin Marzinski, Redhat
++ * Copyright (c) 2005 Edward Goggin, EMC
++ */
++#include <unistd.h>
++#include <libdevmapper.h>
++#include <sys/mman.h>
++#include <pthread.h>
++#include <signal.h>
++#include <urcu.h>
++
++#include "vector.h"
++#include "memory.h"
++#include "checkers.h"
++#include "config.h"
++#include "structs.h"
++#include "structs_vec.h"
++#include "devmapper.h"
++#include "debug.h"
++#include "lock.h"
++#include "waiter.h"
++
++pthread_attr_t waiter_attr;
++
++static struct event_thread *alloc_waiter (void)
++{
++
++ struct event_thread *wp;
++
++ wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
++ memset(wp, 0, sizeof(struct event_thread));
++
++ return wp;
++}
++
++static void free_waiter (void *data)
++{
++ struct event_thread *wp = (struct event_thread *)data;
++
++ if (wp->dmt)
++ dm_task_destroy(wp->dmt);
++
++ rcu_unregister_thread();
++ FREE(wp);
++}
++
++void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
++{
++ pthread_t thread;
++
++ if (mpp->waiter == (pthread_t)0) {
++ condlog(3, "%s: event checker thread already stopped",
++ mpp->alias);
++ return;
++ }
++ condlog(2, "%s: stop event checker thread (%lu)", mpp->alias,
++ mpp->waiter);
++ thread = mpp->waiter;
++ mpp->waiter = (pthread_t)0;
++ pthread_cancel(thread);
++ pthread_kill(thread, SIGUSR2);
++}
++
++/*
++ * returns the reschedule delay
++ * negative means *stop*
++ */
++static int waiteventloop (struct event_thread *waiter)
++{
++ sigset_t set, oldset;
++ int event_nr;
++ int r;
++
++ if (!waiter->event_nr)
++ waiter->event_nr = dm_geteventnr(waiter->mapname);
++
++ if (!(waiter->dmt = libmp_dm_task_create(DM_DEVICE_WAITEVENT))) {
++ condlog(0, "%s: devmap event #%i dm_task_create error",
++ waiter->mapname, waiter->event_nr);
++ return 1;
++ }
++
++ if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
++ condlog(0, "%s: devmap event #%i dm_task_set_name error",
++ waiter->mapname, waiter->event_nr);
++ dm_task_destroy(waiter->dmt);
++ waiter->dmt = NULL;
++ return 1;
++ }
++
++ if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
++ waiter->event_nr)) {
++ condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
++ waiter->mapname, waiter->event_nr);
++ dm_task_destroy(waiter->dmt);
++ waiter->dmt = NULL;
++ return 1;
++ }
++
++ dm_task_no_open_count(waiter->dmt);
++
++ /* wait */
++ sigemptyset(&set);
++ sigaddset(&set, SIGUSR2);
++ pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
++
++ pthread_testcancel();
++ r = dm_task_run(waiter->dmt);
++ pthread_testcancel();
++
++ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
++ dm_task_destroy(waiter->dmt);
++ waiter->dmt = NULL;
++
++ if (!r) /* wait interrupted by signal */
++ return -1;
++
++ waiter->event_nr++;
++
++ /*
++ * upon event ...
++ */
++ while (1) {
++ condlog(3, "%s: devmap event #%i",
++ waiter->mapname, waiter->event_nr);
++
++ /*
++ * event might be :
++ *
++ * 1) a table reload, which means our mpp structure is
++ * obsolete : refresh it through update_multipath()
++ * 2) a path failed by DM : mark as such through
++ * update_multipath()
++ * 3) map has gone away : stop the thread.
++ * 4) a path reinstate : nothing to do
++ * 5) a switch group : nothing to do
++ */
++ pthread_cleanup_push(cleanup_lock, &waiter->vecs->lock);
++ lock(&waiter->vecs->lock);
++ pthread_testcancel();
++ r = update_multipath(waiter->vecs, waiter->mapname, 1);
++ lock_cleanup_pop(waiter->vecs->lock);
++
++ if (r) {
++ condlog(2, "%s: event checker exit",
++ waiter->mapname);
++ return -1; /* stop the thread */
++ }
++
++ event_nr = dm_geteventnr(waiter->mapname);
++
++ if (waiter->event_nr == event_nr)
++ return 1; /* upon problem reschedule 1s later */
++
++ waiter->event_nr = event_nr;
++ }
++ return -1; /* never reach there */
++}
++
++static void *waitevent (void *et)
++{
++ int r;
++ struct event_thread *waiter;
++
++ mlockall(MCL_CURRENT | MCL_FUTURE);
++
++ waiter = (struct event_thread *)et;
++ pthread_cleanup_push(free_waiter, et);
++
++ rcu_register_thread();
++ while (1) {
++ r = waiteventloop(waiter);
++
++ if (r < 0)
++ break;
++
++ sleep(r);
++ }
++
++ pthread_cleanup_pop(1);
++ return NULL;
++}
++
++int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
++{
++ struct event_thread *wp;
++
++ if (!mpp)
++ return 0;
++
++ wp = alloc_waiter();
++
++ if (!wp)
++ goto out;
++
++ strncpy(wp->mapname, mpp->alias, WWID_SIZE - 1);
++ wp->vecs = vecs;
++
++ if (pthread_create(&wp->thread, &waiter_attr, waitevent, wp)) {
++ condlog(0, "%s: cannot create event checker", wp->mapname);
++ goto out1;
++ }
++ mpp->waiter = wp->thread;
++ condlog(2, "%s: event checker started", wp->mapname);
++
++ return 0;
++out1:
++ free_waiter(wp);
++ mpp->waiter = (pthread_t)0;
++out:
++ condlog(0, "failed to start waiter thread");
++ return 1;
++}
+diff --git a/multipathd/waiter.h b/multipathd/waiter.h
+new file mode 100644
+index 0000000..0cfae46
+--- /dev/null
++++ b/multipathd/waiter.h
+@@ -0,0 +1,17 @@
++#ifndef _WAITER_H
++#define _WAITER_H
++
++extern pthread_attr_t waiter_attr;
++
++struct event_thread {
++ struct dm_task *dmt;
++ pthread_t thread;
++ int event_nr;
++ char mapname[WWID_SIZE];
++ struct vectors *vecs;
++};
++
++void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs);
++int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
++
++#endif /* _WAITER_H */
+--
+2.7.4
+
diff --git a/0010-call-start_waiter_thread-before-setup_multipath.patch b/0010-call-start_waiter_thread-before-setup_multipath.patch
new file mode 100644
index 0000000..bb5a479
--- /dev/null
+++ b/0010-call-start_waiter_thread-before-setup_multipath.patch
@@ -0,0 +1,129 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Mon, 5 Feb 2018 21:59:16 -0600
+Subject: [PATCH] call start_waiter_thread() before setup_multipath()
+
+If setup_multipath() is called before the waiter thread has started,
+there is a window where a dm event can occur between when
+setup_multipath() updates the device state and when the waiter thread
+starts waiting for new events, causing the new event to be missed and
+the multipath device to not get updated.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ multipathd/main.c | 37 ++++++++++++++++++++-----------------
+ 1 file changed, 20 insertions(+), 17 deletions(-)
+
+diff --git a/multipathd/main.c b/multipathd/main.c
+index 94b2406..efc39d7 100644
+--- a/multipathd/main.c
++++ b/multipathd/main.c
+@@ -321,7 +321,7 @@ set_multipath_wwid (struct multipath * mpp)
+ }
+
+ static int
+-update_map (struct multipath *mpp, struct vectors *vecs)
++update_map (struct multipath *mpp, struct vectors *vecs, int new_map)
+ {
+ int retries = 3;
+ char params[PARAMS_SIZE] = {0};
+@@ -351,6 +351,12 @@ retry:
+ dm_lib_release();
+
+ fail:
++ if (new_map && (retries < 0 || start_waiter_thread(mpp, vecs))) {
++ condlog(0, "%s: failed to create new map", mpp->alias);
++ remove_map(mpp, vecs, 1);
++ return 1;
++ }
++
+ if (setup_multipath(vecs, mpp))
+ return 1;
+
+@@ -395,12 +401,9 @@ add_map_without_path (struct vectors *vecs, char *alias)
+
+ vector_set_slot(vecs->mpvec, mpp);
+
+- if (update_map(mpp, vecs) != 0) /* map removed */
++ if (update_map(mpp, vecs, 1) != 0) /* map removed */
+ return NULL;
+
+- if (start_waiter_thread(mpp, vecs))
+- goto out;
+-
+ return mpp;
+ out:
+ remove_map(mpp, vecs, PURGE_VEC);
+@@ -554,7 +557,7 @@ ev_add_map (char * dev, char * alias, struct vectors * vecs)
+ if (mpp->wait_for_udev > 1) {
+ condlog(2, "%s: performing delayed actions",
+ mpp->alias);
+- if (update_map(mpp, vecs))
++ if (update_map(mpp, vecs, 0))
+ /* setup multipathd removed the map */
+ return 1;
+ }
+@@ -865,6 +868,11 @@ retry:
+ }
+ dm_lib_release();
+
++ if ((mpp->action == ACT_CREATE ||
++ (mpp->action == ACT_NOTHING && start_waiter && !mpp->waiter)) &&
++ start_waiter_thread(mpp, vecs))
++ goto fail_map;
++
+ /*
+ * update our state from kernel regardless of create or reload
+ */
+@@ -873,11 +881,6 @@ retry:
+
+ sync_map_state(mpp);
+
+- if ((mpp->action == ACT_CREATE ||
+- (mpp->action == ACT_NOTHING && start_waiter && !mpp->waiter)) &&
+- start_waiter_thread(mpp, vecs))
+- goto fail_map;
+-
+ if (retries >= 0) {
+ condlog(2, "%s [%s]: path added to devmap %s",
+ pp->dev, pp->dev_t, mpp->alias);
+@@ -1479,7 +1482,8 @@ missing_uev_wait_tick(struct vectors *vecs)
+ if (mpp->wait_for_udev && --mpp->uev_wait_tick <= 0) {
+ timed_out = 1;
+ condlog(0, "%s: timeout waiting on creation uevent. enabling reloads", mpp->alias);
+- if (mpp->wait_for_udev > 1 && update_map(mpp, vecs)) {
++ if (mpp->wait_for_udev > 1 &&
++ update_map(mpp, vecs, 0)) {
+ /* update_map removed map */
+ i--;
+ continue;
+@@ -1511,7 +1515,7 @@ ghost_delay_tick(struct vectors *vecs)
+ condlog(0, "%s: timed out waiting for active path",
+ mpp->alias);
+ mpp->force_udev_reload = 1;
+- if (update_map(mpp, vecs) != 0) {
++ if (update_map(mpp, vecs, 0) != 0) {
+ /* update_map removed map */
+ i--;
+ continue;
+@@ -2169,14 +2173,13 @@ configure (struct vectors * vecs)
+ * start dm event waiter threads for these new maps
+ */
+ vector_foreach_slot(vecs->mpvec, mpp, i) {
+- if (setup_multipath(vecs, mpp)) {
+- i--;
+- continue;
+- }
+ if (start_waiter_thread(mpp, vecs)) {
+ remove_map(mpp, vecs, 1);
+ i--;
++ continue;
+ }
++ if (setup_multipath(vecs, mpp))
++ i--;
+ }
+ return 0;
+ }
+--
+2.7.4
+
diff --git a/0011-libmultipath-add-helper-functions.patch b/0011-libmultipath-add-helper-functions.patch
new file mode 100644
index 0000000..aa62edf
--- /dev/null
+++ b/0011-libmultipath-add-helper-functions.patch
@@ -0,0 +1,155 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Mon, 5 Feb 2018 10:40:24 -0600
+Subject: [PATCH] libmultipath: add helper functions
+
+Add the ability to reset a vector without completely freeing it, and to
+check the version of the device-mapper module. The existing version
+checking code checks the version of a specific device mapper target, and
+has been renamed for clarity's sake. These functions will be used in a
+later patch.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ libmultipath/devmapper.c | 28 ++++++++++++++++++++++++----
+ libmultipath/devmapper.h | 3 ++-
+ libmultipath/vector.c | 16 ++++++++++++----
+ libmultipath/vector.h | 1 +
+ multipathd/main.c | 2 +-
+ 5 files changed, 40 insertions(+), 10 deletions(-)
+
+diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
+index 573fc75..2960bf5 100644
+--- a/libmultipath/devmapper.c
++++ b/libmultipath/devmapper.c
+@@ -132,7 +132,27 @@ dm_lib_prereq (void)
+ }
+
+ int
+-dm_drv_version (unsigned int * version, char * str)
++dm_drv_version(unsigned int *v)
++{
++ char buff[64];
++
++ v[0] = 0;
++ v[1] = 0;
++ v[2] = 0;
++
++ if (!dm_driver_version(buff, sizeof(buff))) {
++ condlog(0, "cannot get kernel dm version");
++ return 1;
++ }
++ if (sscanf(buff, "%u.%u.%u ", &v[0], &v[1], &v[2]) != 3) {
++ condlog(0, "invalid kernel dm version '%s'", buff);
++ return 1;
++ }
++ return 0;
++}
++
++int
++dm_tgt_version (unsigned int * version, char * str)
+ {
+ int r = 2;
+ struct dm_task *dmt;
+@@ -179,13 +199,13 @@ out:
+ }
+
+ static int
+-dm_drv_prereq (unsigned int *ver)
++dm_tgt_prereq (unsigned int *ver)
+ {
+ unsigned int minv[3] = {1, 0, 3};
+ unsigned int version[3] = {0, 0, 0};
+ unsigned int * v = version;
+
+- if (dm_drv_version(v, TGT_MPATH)) {
++ if (dm_tgt_version(v, TGT_MPATH)) {
+ /* in doubt return not capable */
+ return 1;
+ }
+@@ -210,7 +230,7 @@ static int dm_prereq(unsigned int *v)
+ {
+ if (dm_lib_prereq())
+ return 1;
+- return dm_drv_prereq(v);
++ return dm_tgt_prereq(v);
+ }
+
+ static int libmp_dm_udev_sync = 0;
+diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
+index 62e14d1..52d4af8 100644
+--- a/libmultipath/devmapper.h
++++ b/libmultipath/devmapper.h
+@@ -28,7 +28,8 @@ void dm_init(int verbosity);
+ void libmp_dm_init(void);
+ void libmp_udev_set_sync_support(int on);
+ struct dm_task *libmp_dm_task_create(int task);
+-int dm_drv_version (unsigned int * version, char * str);
++int dm_drv_version (unsigned int * version);
++int dm_tgt_version (unsigned int * version, char * str);
+ int dm_simplecmd_flush (int, const char *, uint16_t);
+ int dm_simplecmd_noflush (int, const char *, uint16_t);
+ int dm_addmap_create (struct multipath *mpp, char *params);
+diff --git a/libmultipath/vector.c b/libmultipath/vector.c
+index 6266e0a..f741ae0 100644
+--- a/libmultipath/vector.c
++++ b/libmultipath/vector.c
+@@ -145,18 +145,26 @@ vector_repack(vector v)
+ vector_del_slot(v, i--);
+ }
+
+-/* Free memory vector allocation */
+-void
+-vector_free(vector v)
++vector
++vector_reset(vector v)
+ {
+ if (!v)
+- return;
++ return NULL;
+
+ if (v->slot)
+ FREE(v->slot);
+
+ v->allocated = 0;
+ v->slot = NULL;
++ return v;
++}
++
++/* Free memory vector allocation */
++void
++vector_free(vector v)
++{
++ if (!vector_reset(v))
++ return;
+ FREE(v);
+ }
+
+diff --git a/libmultipath/vector.h b/libmultipath/vector.h
+index 5cfd4d0..d69cd0b 100644
+--- a/libmultipath/vector.h
++++ b/libmultipath/vector.h
+@@ -45,6 +45,7 @@ typedef struct _vector *vector;
+ /* Prototypes */
+ extern vector vector_alloc(void);
+ extern void *vector_alloc_slot(vector v);
++vector vector_reset(vector v);
+ extern void vector_free(vector v);
+ extern void free_strvec(vector strvec);
+ extern void vector_set_slot(vector v, void *value);
+diff --git a/multipathd/main.c b/multipathd/main.c
+index efc39d7..2963bde 100644
+--- a/multipathd/main.c
++++ b/multipathd/main.c
+@@ -2228,7 +2228,7 @@ reconfigure (struct vectors * vecs)
+ /* Re-read any timezone changes */
+ tzset();
+
+- dm_drv_version(conf->version, TGT_MPATH);
++ dm_tgt_version(conf->version, TGT_MPATH);
+ if (verbosity)
+ conf->verbosity = verbosity;
+ if (bindings_read_only)
+--
+2.7.4
+
diff --git a/0012-multipathd-RFC-add-new-polling-dmevents-waiter-threa.patch b/0012-multipathd-RFC-add-new-polling-dmevents-waiter-threa.patch
new file mode 100644
index 0000000..64db4ad
--- /dev/null
+++ b/0012-multipathd-RFC-add-new-polling-dmevents-waiter-threa.patch
@@ -0,0 +1,643 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Tue, 6 Feb 2018 15:36:39 -0600
+Subject: [PATCH] multipathd: RFC add new polling dmevents waiter thread
+
+The current method of waiting for dmevents on multipath devices involves
+creating a seperate thread for each device. This can become very
+wasteful when there are large numbers of multipath devices. Also, since
+multipathd needs to grab the vecs lock to update the devices, the
+additional threads don't actually provide much parallelism.
+
+The patch adds a new method of updating multipath devices on dmevents,
+which uses the new device-mapper event polling interface. This means
+that there is only one dmevent waiting thread which will wait for events
+on all of the multipath devices. Currently the code to get the event
+number from the list of device names and to re-arm the polling interface
+is not in libdevmapper, so the patch does that work. Obviously, these
+bits need to go into libdevmapper, so that multipathd can use a standard
+interface.
+
+I haven't touched any of the existing event waiting code, since event
+polling was only added to device-mapper in version 4.37.0. multipathd
+checks this version, and defaults to using the polling code if
+device-mapper supports it. This can be overridden by running multipathd
+with "-w", to force it to use the old event waiting code.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ multipathd/Makefile | 3 +-
+ multipathd/dmevents.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ multipathd/dmevents.h | 13 ++
+ multipathd/main.c | 58 +++++++-
+ 4 files changed, 461 insertions(+), 9 deletions(-)
+ create mode 100644 multipathd/dmevents.c
+ create mode 100644 multipathd/dmevents.h
+
+diff --git a/multipathd/Makefile b/multipathd/Makefile
+index 85f29a7..4c438f0 100644
+--- a/multipathd/Makefile
++++ b/multipathd/Makefile
+@@ -22,7 +22,8 @@ ifdef SYSTEMD
+ endif
+ endif
+
+-OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o
++OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o \
++ dmevents.o
+
+ EXEC = multipathd
+
+diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c
+new file mode 100644
+index 0000000..a56c055
+--- /dev/null
++++ b/multipathd/dmevents.c
+@@ -0,0 +1,396 @@
++/*
++ * Copyright (c) 2004, 2005 Christophe Varoqui
++ * Copyright (c) 2005 Kiyoshi Ueda, NEC
++ * Copyright (c) 2005 Edward Goggin, EMC
++ * Copyright (c) 2005, 2018 Benjamin Marzinski, Redhat
++ */
++#include <unistd.h>
++#include <libdevmapper.h>
++#include <sys/mman.h>
++#include <pthread.h>
++#include <urcu.h>
++#include <poll.h>
++#include <sys/ioctl.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <linux/dm-ioctl.h>
++#include <errno.h>
++
++#include "vector.h"
++#include "structs.h"
++#include "structs_vec.h"
++#include "devmapper.h"
++#include "debug.h"
++#include "dmevents.h"
++
++#ifndef DM_DEV_ARM_POLL
++#define DM_DEV_ARM_POLL _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD + 1, struct dm_ioctl)
++#endif
++
++enum event_actions {
++ EVENT_NOTHING,
++ EVENT_REMOVE,
++ EVENT_UPDATE,
++};
++
++struct dev_event {
++ char name[WWID_SIZE];
++ uint32_t evt_nr;
++ enum event_actions action;
++};
++
++struct dmevent_waiter {
++ int fd;
++ struct vectors *vecs;
++ vector events;
++ pthread_mutex_t events_lock;
++};
++
++static struct dmevent_waiter *waiter;
++
++int dmevent_poll_supported(void)
++{
++ unsigned int minv[3] = {4, 37, 0};
++ unsigned int v[3];
++
++ if (dm_drv_version(v))
++ return 0;
++
++ if (VERSION_GE(v, minv))
++ return 1;
++ return 0;
++}
++
++
++int alloc_dmevent_waiter(struct vectors *vecs)
++{
++ if (!vecs) {
++ condlog(0, "can't create waiter structure. invalid vectors");
++ goto fail;
++ }
++ waiter = (struct dmevent_waiter *)malloc(sizeof(struct dmevent_waiter));
++ if (!waiter) {
++ condlog(0, "failed to allocate waiter structure");
++ goto fail;
++ }
++ memset(waiter, 0, sizeof(struct dmevent_waiter));
++ waiter->events = vector_alloc();
++ if (!waiter->events) {
++ condlog(0, "failed to allocate waiter events vector");
++ goto fail_waiter;
++ }
++ waiter->fd = open("/dev/mapper/control", O_RDWR);
++ if (waiter->fd < 0) {
++ condlog(0, "failed to open /dev/mapper/control for waiter");
++ goto fail_events;
++ }
++ pthread_mutex_init(&waiter->events_lock, NULL);
++ waiter->vecs = vecs;
++
++ return 0;
++fail_events:
++ vector_free(waiter->events);
++fail_waiter:
++ free(waiter);
++fail:
++ waiter = NULL;
++ return -1;
++}
++
++void free_dmevent_waiter(void)
++{
++ struct dev_event *dev_evt;
++ int i;
++
++ if (!waiter)
++ return;
++ pthread_mutex_destroy(&waiter->events_lock);
++ close(waiter->fd);
++ vector_foreach_slot(waiter->events, dev_evt, i)
++ free(dev_evt);
++ vector_free(waiter->events);
++ free(waiter);
++ waiter = NULL;
++}
++
++static int arm_dm_event_poll(int fd)
++{
++ struct dm_ioctl dmi;
++ memset(&dmi, 0, sizeof(dmi));
++ dmi.version[0] = DM_VERSION_MAJOR;
++ dmi.version[1] = DM_VERSION_MINOR;
++ dmi.version[2] = DM_VERSION_PATCHLEVEL;
++ dmi.flags = 0x4;
++ dmi.data_start = offsetof(struct dm_ioctl, data);
++ dmi.data_size = sizeof(dmi);
++ return ioctl(fd, DM_DEV_ARM_POLL, &dmi);
++}
++
++/*
++ * As of version 4.37.0 device-mapper stores the event number in the
++ * dm_names structure after the name, when DM_DEVICE_LIST is called
++ */
++static uint32_t dm_event_nr(struct dm_names *n)
++{
++ return *(uint32_t *)(((uintptr_t)(strchr(n->name, 0) + 1) + 7) & ~7);
++}
++
++static int dm_get_events(void)
++{
++ struct dm_task *dmt;
++ struct dm_names *names;
++ struct dev_event *dev_evt;
++ int i;
++
++ if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
++ return -1;
++
++ dm_task_no_open_count(dmt);
++
++ if (!dm_task_run(dmt))
++ goto fail;
++
++ if (!(names = dm_task_get_names(dmt)))
++ goto fail;
++
++ pthread_mutex_lock(&waiter->events_lock);
++ vector_foreach_slot(waiter->events, dev_evt, i)
++ dev_evt->action = EVENT_REMOVE;
++ while (names->dev) {
++ uint32_t event_nr;
++
++ if (!dm_is_mpath(names->name))
++ goto next;
++
++ event_nr = dm_event_nr(names);
++ vector_foreach_slot(waiter->events, dev_evt, i) {
++ if (!strcmp(dev_evt->name, names->name)) {
++ if (event_nr != dev_evt->evt_nr) {
++ dev_evt->evt_nr = event_nr;
++ dev_evt->action = EVENT_UPDATE;
++ } else
++ dev_evt->action = EVENT_NOTHING;
++ break;
++ }
++ }
++next:
++ if (!names->next)
++ break;
++ names = (void *)names + names->next;
++ }
++ pthread_mutex_unlock(&waiter->events_lock);
++ dm_task_destroy(dmt);
++ return 0;
++
++fail:
++ dm_task_destroy(dmt);
++ return -1;
++}
++
++/* You must call update_multipath() after calling this function, to
++ * deal with any events that came in before the device was added */
++int watch_dmevents(char *name)
++{
++ int event_nr;
++ struct dev_event *dev_evt, *old_dev_evt;
++ int i;
++
++ if (!dm_is_mpath(name)) {
++ condlog(0, "%s: not a multipath device. can't watch events",
++ name);
++ return -1;
++ }
++
++ if ((event_nr = dm_geteventnr(name)) < 0)
++ return -1;
++
++ dev_evt = (struct dev_event *)malloc(sizeof(struct dev_event));
++ if (!dev_evt) {
++ condlog(0, "%s: can't allocate event waiter structure", name);
++ return -1;
++ }
++
++ strncpy(dev_evt->name, name, WWID_SIZE);
++ dev_evt->name[WWID_SIZE - 1] = 0;
++ dev_evt->evt_nr = event_nr;
++ dev_evt->action = EVENT_NOTHING;
++
++ pthread_mutex_lock(&waiter->events_lock);
++ vector_foreach_slot(waiter->events, old_dev_evt, i){
++ if (!strcmp(dev_evt->name, old_dev_evt->name)) {
++ /* caller will be updating this device */
++ old_dev_evt->evt_nr = event_nr;
++ old_dev_evt->action = EVENT_NOTHING;
++ pthread_mutex_unlock(&waiter->events_lock);
++ condlog(2, "%s: already waiting for events on device",
++ name);
++ free(dev_evt);
++ return 0;
++ }
++ }
++ if (!vector_alloc_slot(waiter->events)) {
++ pthread_mutex_unlock(&waiter->events_lock);
++ free(dev_evt);
++ return -1;
++ }
++ vector_set_slot(waiter->events, dev_evt);
++ pthread_mutex_unlock(&waiter->events_lock);
++ return 0;
++}
++
++void unwatch_all_dmevents(void)
++{
++ struct dev_event *dev_evt;
++ int i;
++
++ pthread_mutex_lock(&waiter->events_lock);
++ vector_foreach_slot(waiter->events, dev_evt, i)
++ free(dev_evt);
++ vector_reset(waiter->events);
++ pthread_mutex_unlock(&waiter->events_lock);
++}
++
++static void unwatch_dmevents(char *name)
++{
++ struct dev_event *dev_evt;
++ int i;
++
++ pthread_mutex_lock(&waiter->events_lock);
++ vector_foreach_slot(waiter->events, dev_evt, i) {
++ if (!strcmp(dev_evt->name, name)) {
++ vector_del_slot(waiter->events, i);
++ free(dev_evt);
++ break;
++ }
++ }
++ pthread_mutex_unlock(&waiter->events_lock);
++}
++
++/*
++ * returns the reschedule delay
++ * negative means *stop*
++ */
++
++/* poll, arm, update, return */
++static int dmevent_loop (void)
++{
++ int r, i = 0;
++ struct pollfd pfd;
++ struct dev_event *dev_evt;
++
++ pfd.fd = waiter->fd;
++ pfd.events = POLLIN;
++ r = poll(&pfd, 1, -1);
++ if (r <= 0) {
++ condlog(0, "failed polling for dm events: %s", strerror(errno));
++ /* sleep 1s and hope things get better */
++ return 1;
++ }
++
++ if (arm_dm_event_poll(waiter->fd) != 0) {
++ condlog(0, "Cannot re-arm event polling: %s", strerror(errno));
++ /* sleep 1s and hope things get better */
++ return 1;
++ }
++
++ if (dm_get_events() != 0) {
++ condlog(0, "failed getting dm events: %s", strerror(errno));
++ /* sleep 1s and hope things get better */
++ return 1;
++ }
++
++ /*
++ * upon event ...
++ */
++
++ while (1) {
++ int done = 1;
++ struct dev_event curr_dev;
++ struct multipath *mpp;
++
++ pthread_mutex_lock(&waiter->events_lock);
++ vector_foreach_slot(waiter->events, dev_evt, i) {
++ if (dev_evt->action != EVENT_NOTHING) {
++ curr_dev = *dev_evt;
++ if (dev_evt->action == EVENT_REMOVE) {
++ vector_del_slot(waiter->events, i);
++ free(dev_evt);
++ } else
++ dev_evt->action = EVENT_NOTHING;
++ done = 0;
++ break;
++ }
++ }
++ pthread_mutex_unlock(&waiter->events_lock);
++ if (done)
++ return 1;
++
++ condlog(3, "%s: devmap event #%i", curr_dev.name,
++ curr_dev.evt_nr);
++
++ /*
++ * event might be :
++ *
++ * 1) a table reload, which means our mpp structure is
++ * obsolete : refresh it through update_multipath()
++ * 2) a path failed by DM : mark as such through
++ * update_multipath()
++ * 3) map has gone away : stop the thread.
++ * 4) a path reinstate : nothing to do
++ * 5) a switch group : nothing to do
++ */
++ pthread_cleanup_push(cleanup_lock, &waiter->vecs->lock);
++ lock(&waiter->vecs->lock);
++ pthread_testcancel();
++ r = 0;
++ if (curr_dev.action == EVENT_REMOVE) {
++ mpp = find_mp_by_alias(waiter->vecs->mpvec,
++ curr_dev.name);
++ if (mpp)
++ remove_map(mpp, waiter->vecs, 1);
++ } else
++ r = update_multipath(waiter->vecs, curr_dev.name, 1);
++ lock_cleanup_pop(&waiter->vecs->lock);
++
++ if (r) {
++ condlog(2, "%s: stopped watching dmevents",
++ curr_dev.name);
++ unwatch_dmevents(curr_dev.name);
++ }
++ }
++ condlog(0, "dmevent waiter thread unexpectedly quit");
++ return -1; /* never reach there */
++}
++
++static void rcu_unregister(void *param)
++{
++ rcu_unregister_thread();
++}
++
++void *wait_dmevents (void *unused)
++{
++ int r;
++
++
++ if (!waiter) {
++ condlog(0, "dmevents waiter not intialized");
++ return NULL;
++ }
++
++ pthread_cleanup_push(rcu_unregister, NULL);
++ rcu_register_thread();
++ mlockall(MCL_CURRENT | MCL_FUTURE);
++
++ while (1) {
++ r = dmevent_loop();
++
++ if (r < 0)
++ break;
++
++ sleep(r);
++ }
++
++ pthread_cleanup_pop(1);
++ return NULL;
++}
+diff --git a/multipathd/dmevents.h b/multipathd/dmevents.h
+new file mode 100644
+index 0000000..569e855
+--- /dev/null
++++ b/multipathd/dmevents.h
+@@ -0,0 +1,13 @@
++#ifndef _DMEVENTS_H
++#define _DMEVENTS_H
++
++#include "structs_vec.h"
++
++int dmevent_poll_supported(void);
++int alloc_dmevent_waiter(struct vectors *vecs);
++void free_dmevent_waiter(void);
++int watch_dmevents(char *name);
++void unwatch_all_dmevents(void);
++void *wait_dmevents (void *unused);
++
++#endif /* _DMEVENTS_H */
+diff --git a/multipathd/main.c b/multipathd/main.c
+index 2963bde..6dabf2c 100644
+--- a/multipathd/main.c
++++ b/multipathd/main.c
+@@ -82,6 +82,7 @@ static int use_watchdog;
+ #include "cli_handlers.h"
+ #include "lock.h"
+ #include "waiter.h"
++#include "dmevents.h"
+ #include "io_err_stat.h"
+ #include "wwids.h"
+ #include "../third-party/valgrind/drd.h"
+@@ -108,6 +109,7 @@ int uxsock_timeout;
+ int verbosity;
+ int bindings_read_only;
+ int ignore_new_devs;
++int poll_dmevents = 1;
+ enum daemon_status running_state = DAEMON_INIT;
+ pid_t daemon_pid;
+ pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER;
+@@ -288,11 +290,23 @@ switch_pathgroup (struct multipath * mpp)
+ mpp->alias, mpp->bestpg);
+ }
+
++static int
++wait_for_events(struct multipath *mpp, struct vectors *vecs)
++{
++ if (poll_dmevents)
++ return watch_dmevents(mpp->alias);
++ else
++ return start_waiter_thread(mpp, vecs);
++}
++
+ static void
+ remove_map_and_stop_waiter(struct multipath *mpp, struct vectors *vecs,
+ int purge_vec)
+ {
+- stop_waiter_thread(mpp, vecs);
++ /* devices are automatically removed by the dmevent polling code,
++ * so they don't need to be manually removed here */
++ if (!poll_dmevents)
++ stop_waiter_thread(mpp, vecs);
+ remove_map(mpp, vecs, purge_vec);
+ }
+
+@@ -305,8 +319,12 @@ remove_maps_and_stop_waiters(struct vectors *vecs)
+ if (!vecs)
+ return;
+
+- vector_foreach_slot(vecs->mpvec, mpp, i)
+- stop_waiter_thread(mpp, vecs);
++ if (!poll_dmevents) {
++ vector_foreach_slot(vecs->mpvec, mpp, i)
++ stop_waiter_thread(mpp, vecs);
++ }
++ else
++ unwatch_all_dmevents();
+
+ remove_maps(vecs);
+ }
+@@ -351,7 +369,7 @@ retry:
+ dm_lib_release();
+
+ fail:
+- if (new_map && (retries < 0 || start_waiter_thread(mpp, vecs))) {
++ if (new_map && (retries < 0 || wait_for_events(mpp, vecs))) {
+ condlog(0, "%s: failed to create new map", mpp->alias);
+ remove_map(mpp, vecs, 1);
+ return 1;
+@@ -870,7 +888,7 @@ retry:
+
+ if ((mpp->action == ACT_CREATE ||
+ (mpp->action == ACT_NOTHING && start_waiter && !mpp->waiter)) &&
+- start_waiter_thread(mpp, vecs))
++ wait_for_events(mpp, vecs))
+ goto fail_map;
+
+ /*
+@@ -2173,7 +2191,7 @@ configure (struct vectors * vecs)
+ * start dm event waiter threads for these new maps
+ */
+ vector_foreach_slot(vecs->mpvec, mpp, i) {
+- if (start_waiter_thread(mpp, vecs)) {
++ if (wait_for_events(mpp, vecs)) {
+ remove_map(mpp, vecs, 1);
+ i--;
+ continue;
+@@ -2414,7 +2432,7 @@ set_oom_adj (void)
+ static int
+ child (void * param)
+ {
+- pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr;
++ pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr;
+ pthread_attr_t log_attr, misc_attr, uevent_attr;
+ struct vectors * vecs;
+ struct multipath * mpp;
+@@ -2476,6 +2494,8 @@ child (void * param)
+ goto failed;
+ }
+
++ if (poll_dmevents)
++ poll_dmevents = dmevent_poll_supported();
+ setlogmask(LOG_UPTO(conf->verbosity + 3));
+
+ envp = getenv("LimitNOFILE");
+@@ -2542,6 +2562,19 @@ child (void * param)
+
+ init_path_check_interval(vecs);
+
++ if (poll_dmevents) {
++ if (alloc_dmevent_waiter(vecs)) {
++ condlog(0, "failed to allocate dmevents waiter info");
++ goto failed;
++ }
++ if ((rc = pthread_create(&dmevent_thr, &misc_attr,
++ wait_dmevents, NULL))) {
++ condlog(0, "failed to create dmevent waiter thread: %d",
++ rc);
++ goto failed;
++ }
++ }
++
+ /*
+ * Start uevent listener early to catch events
+ */
+@@ -2615,11 +2648,15 @@ child (void * param)
+ pthread_cancel(uevent_thr);
+ pthread_cancel(uxlsnr_thr);
+ pthread_cancel(uevq_thr);
++ if (poll_dmevents)
++ pthread_cancel(dmevent_thr);
+
+ pthread_join(check_thr, NULL);
+ pthread_join(uevent_thr, NULL);
+ pthread_join(uxlsnr_thr, NULL);
+ pthread_join(uevq_thr, NULL);
++ if (poll_dmevents)
++ pthread_join(dmevent_thr, NULL);
+
+ stop_io_err_stat_thread();
+
+@@ -2634,6 +2671,8 @@ child (void * param)
+
+ cleanup_checkers();
+ cleanup_prio();
++ if (poll_dmevents)
++ free_dmevent_waiter();
+
+ dm_lib_release();
+ dm_lib_exit();
+@@ -2765,7 +2804,7 @@ main (int argc, char *argv[])
+ udev = udev_new();
+ libmp_udev_set_sync_support(0);
+
+- while ((arg = getopt(argc, argv, ":dsv:k::Bn")) != EOF ) {
++ while ((arg = getopt(argc, argv, ":dsv:k::Bniw")) != EOF ) {
+ switch(arg) {
+ case 'd':
+ foreground = 1;
+@@ -2799,6 +2838,9 @@ main (int argc, char *argv[])
+ case 'n':
+ ignore_new_devs = 1;
+ break;
++ case 'w':
++ poll_dmevents = 0;
++ break;
+ default:
+ fprintf(stderr, "Invalid argument '-%c'\n",
+ optopt);
+--
+2.7.4
+
diff --git a/0013-libmultipath-condlog-log-to-stderr.patch b/0013-libmultipath-condlog-log-to-stderr.patch
new file mode 100644
index 0000000..8819730
--- /dev/null
+++ b/0013-libmultipath-condlog-log-to-stderr.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Sat, 13 Jan 2018 22:19:21 +0100
+Subject: [PATCH] libmultipath: condlog: log to stderr
+
+Calling 'multipath' might result in various error messages, all
+of which should be directed to stderr.
+Having them intermixed with the actual output on stdout makes
+parsing really hard.
+
+Signed-off-by: Martin Wilck <mwilck@suse.com>
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ libmultipath/debug.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/libmultipath/debug.c b/libmultipath/debug.c
+index f89b264..f95a3e5 100644
+--- a/libmultipath/debug.c
++++ b/libmultipath/debug.c
+@@ -37,9 +37,9 @@ void dlog (int sink, int prio, const char * fmt, ...)
+ "%b %d %H:%M:%S", tb);
+ buff[sizeof(buff)-1] = '\0';
+
+- fprintf(stdout, "%s | ", buff);
++ fprintf(stderr, "%s | ", buff);
+ }
+- vfprintf(stdout, fmt, ap);
++ vfprintf(stderr, fmt, ap);
+ }
+ else
+ log_safe(prio + 3, fmt, ap);
+--
+2.7.4
+
diff --git a/0014-multipathd-fix-compiler-warning-for-uev_pathfail_che.patch b/0014-multipathd-fix-compiler-warning-for-uev_pathfail_che.patch
new file mode 100644
index 0000000..1f16290
--- /dev/null
+++ b/0014-multipathd-fix-compiler-warning-for-uev_pathfail_che.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Sat, 13 Jan 2018 22:19:32 +0100
+Subject: [PATCH] multipathd: fix compiler warning for uev_pathfail_check
+
+gcc7 spits out an indentation warning for this function.
+
+Fixes: 8392431 "multipath-tools: check null path before handle path-failed event"
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ multipathd/main.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/multipathd/main.c b/multipathd/main.c
+index 6dabf2c..596654c 100644
+--- a/multipathd/main.c
++++ b/multipathd/main.c
+@@ -1142,8 +1142,8 @@ uev_pathfail_check(struct uevent *uev, struct vectors *vecs)
+ lock(&vecs->lock);
+ pthread_testcancel();
+ pp = find_path_by_devt(vecs->pathvec, devt);
+- if (!pp)
+- goto out_lock;
++ if (!pp)
++ goto out_lock;
+ r = io_err_stat_handle_pathfail(pp);
+ if (r)
+ condlog(3, "io_err_stat: %s: cannot handle pathfail uevent",
+--
+2.7.4
+
diff --git a/0007-RH-fixup-udev-rules-for-redhat.patch b/0015-RH-fixup-udev-rules-for-redhat.patch
index 005ccb1..d9e33c7 100644
--- a/0007-RH-fixup-udev-rules-for-redhat.patch
+++ b/0015-RH-fixup-udev-rules-for-redhat.patch
@@ -15,7 +15,7 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc
-index 29c290a..cea015b 100644
+index d953f5e..5145909 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -48,7 +48,7 @@ endif
diff --git a/0008-RH-Remove-the-property-blacklist-exception-builtin.patch b/0016-RH-Remove-the-property-blacklist-exception-builtin.patch
index a4b5770..d52d3fa 100644
--- a/0008-RH-Remove-the-property-blacklist-exception-builtin.patch
+++ b/0016-RH-Remove-the-property-blacklist-exception-builtin.patch
@@ -51,10 +51,10 @@ index ee396e2..19d4697 100644
void
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
-index 8783124..fa4333d 100644
+index ab151e7..2201d7f 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
-@@ -1085,10 +1085,6 @@ The \fIWorld Wide Identification\fR of a device.
+@@ -1114,10 +1114,6 @@ The \fIWorld Wide Identification\fR of a device.
.TP
.B property
Regular expression of the udev property to be whitelisted.
diff --git a/0009-RH-don-t-start-without-a-config-file.patch b/0017-RH-don-t-start-without-a-config-file.patch
index 38cbbf0..55f1f57 100644
--- a/0009-RH-don-t-start-without-a-config-file.patch
+++ b/0017-RH-don-t-start-without-a-config-file.patch
@@ -12,15 +12,15 @@ simple way to disable multipath. Simply removing or renaming
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
- libmultipath/config.c | 17 +++++++++++++++++
+ libmultipath/config.c | 15 +++++++++++++++
libmultipath/config.h | 1 +
multipath/multipath.rules | 1 +
multipathd/multipathd.8 | 2 ++
multipathd/multipathd.service | 1 +
- 5 files changed, 22 insertions(+)
+ 5 files changed, 20 insertions(+)
diff --git a/libmultipath/config.c b/libmultipath/config.c
-index 9486116..85e32ee 100644
+index 3d6a24c..27826fa 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -26,6 +26,7 @@
@@ -31,14 +31,12 @@ index 9486116..85e32ee 100644
static int
hwe_strmatch (struct hwentry *hwe1, struct hwentry *hwe2)
-@@ -659,6 +660,22 @@ load_config (char * file)
+@@ -656,6 +657,20 @@ load_config (char * file)
factorize_hwtable(conf->hwtable, builtin_hwtable_size);
}
+ } else {
+ condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
-+ condlog(0, "A default multipath.conf file is located at");
-+ condlog(0, "/usr/share/doc/device-mapper-multipath-%d.%d.%d/multipath.conf", MULTIPATH_VERSION(VERSION_CODE));
+ if (conf->blist_devnode == NULL) {
+ conf->blist_devnode = vector_alloc();
+ if (!conf->blist_devnode) {
@@ -55,7 +53,7 @@ index 9486116..85e32ee 100644
conf->processed_main_config = 1;
diff --git a/libmultipath/config.h b/libmultipath/config.h
-index 67ff983..1dbb9a7 100644
+index a20ac2a..21a3bbd 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -9,6 +9,7 @@
diff --git a/0010-RH-use-rpm-optflags-if-present.patch b/0018-RH-use-rpm-optflags-if-present.patch
index 6ec413c..99e0a7e 100644
--- a/0010-RH-use-rpm-optflags-if-present.patch
+++ b/0018-RH-use-rpm-optflags-if-present.patch
@@ -13,7 +13,7 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc
-index cea015b..d6b4ef7 100644
+index 5145909..0b4ee17 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -82,13 +82,21 @@ TEST_CC_OPTION = $(shell \
@@ -43,8 +43,8 @@ index cea015b..d6b4ef7 100644
+ -Werror=implicit-function-declaration -Wno-sign-compare \
+ -Wno-unused-parameter
- CFLAGS = $(OPTFLAGS) -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\"
- BIN_CFLAGS = -fPIE -DPIE
+ CFLAGS := $(OPTFLAGS) -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
+ $(CFLAGS)
--
2.7.4
diff --git a/0011-RH-add-mpathconf.patch b/0019-RH-add-mpathconf.patch
index cd3fca0..fc199fa 100644
--- a/0011-RH-add-mpathconf.patch
+++ b/0019-RH-add-mpathconf.patch
@@ -21,13 +21,13 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
create mode 100644 multipath/mpathconf.8
diff --git a/libmultipath/config.c b/libmultipath/config.c
-index 85e32ee..f1a6ca8 100644
+index 27826fa..9bf4fb7 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
-@@ -664,6 +664,7 @@ load_config (char * file)
+@@ -659,6 +659,7 @@ load_config (char * file)
+
+ } else {
condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
- condlog(0, "A default multipath.conf file is located at");
- condlog(0, "/usr/share/doc/device-mapper-multipath-%d.%d.%d/multipath.conf", MULTIPATH_VERSION(VERSION_CODE));
+ condlog(0, "You can run /sbin/mpathconf to create or modify /etc/multipath.conf");
if (conf->blist_devnode == NULL) {
conf->blist_devnode = vector_alloc();
diff --git a/0012-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch b/0020-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch
index a5ef7bd..d9dc69a 100644
--- a/0012-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch
+++ b/0020-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch
@@ -85,7 +85,7 @@ index 9527012..b665232 100644
#endif /* _WWIDS_H */
diff --git a/multipath/main.c b/multipath/main.c
-index bffe065..2e69300 100644
+index d2415a9..ff570ac 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -102,7 +102,7 @@ usage (char * progname)
@@ -106,7 +106,7 @@ index bffe065..2e69300 100644
" -c check if a device should be a path in a multipath device\n"
" -C check if a multipath device has usable paths\n"
" -q allow queue_if_no_path when multipathd is not running\n"
-@@ -598,7 +600,7 @@ main (int argc, char *argv[])
+@@ -602,7 +604,7 @@ main (int argc, char *argv[])
exit(1);
multipath_conf = conf;
conf->retrigger_tries = 0;
@@ -115,7 +115,7 @@ index bffe065..2e69300 100644
switch(arg) {
case 1: printf("optarg : %s\n",optarg);
break;
-@@ -665,6 +667,10 @@ main (int argc, char *argv[])
+@@ -669,6 +671,10 @@ main (int argc, char *argv[])
case 't':
r = dump_config(conf);
goto out_free_config;
diff --git a/0013-RH-trigger-change-uevent-on-new-device-creation.patch b/0021-RH-trigger-change-uevent-on-new-device-creation.patch
index 391485e..54c6d57 100644
--- a/0013-RH-trigger-change-uevent-on-new-device-creation.patch
+++ b/0021-RH-trigger-change-uevent-on-new-device-creation.patch
@@ -9,22 +9,23 @@ that it will not claim the device in udev. If the device is eventually
multipathed, multipath should trigger a change uevent to update the udev
database to claim the device.
-This also reverts commit 64e27ec066a001012f44550f095c93443e91d845.
+This also reverts commit 64e27ec066a001012f44550f095c93443e91d845 and
+commit ffbb886a8a16cb063d669cd76a1e656fd3ec8c4b.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/configure.c | 26 ++++++++++++++++++++++++--
libmultipath/configure.h | 1 +
libmultipath/wwids.c | 4 ++--
- multipath/main.c | 2 +-
+ multipath/main.c | 12 +-----------
multipathd/main.c | 7 ++-----
- 5 files changed, 30 insertions(+), 10 deletions(-)
+ 5 files changed, 30 insertions(+), 20 deletions(-)
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
-index e2f393f..64d7751 100644
+index 22c11a2..7011ef7 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
-@@ -423,6 +423,28 @@ trigger_udev_change(const struct multipath *mpp)
+@@ -427,6 +427,28 @@ trigger_udev_change(const struct multipath *mpp)
udev_device_unref(udd);
}
@@ -53,7 +54,7 @@ index e2f393f..64d7751 100644
static int
is_mpp_known_to_udev(const struct multipath *mpp)
{
-@@ -814,8 +836,8 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
+@@ -821,8 +843,8 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
* succeeded
*/
mpp->force_udev_reload = 0;
@@ -96,10 +97,10 @@ index 88bb72b..249c6c1 100644
}
else {
diff --git a/multipath/main.c b/multipath/main.c
-index 2e69300..4dde5af 100644
+index ff570ac..ae6b06e 100644
--- a/multipath/main.c
+++ b/multipath/main.c
-@@ -412,7 +412,7 @@ configure (struct config *conf, enum mpath_cmds cmd,
+@@ -416,7 +416,7 @@ configure (struct config *conf, enum mpath_cmds cmd,
}
if (cmd == CMD_ADD_WWID) {
r = remember_wwid(refwwid);
@@ -108,11 +109,28 @@ index 2e69300..4dde5af 100644
printf("wwid '%s' added\n", refwwid);
else
printf("failed adding '%s' to wwids file\n",
+@@ -712,16 +712,6 @@ main (int argc, char *argv[])
+ }
+ }
+
+- /*
+- * FIXME: new device detection with find_multipaths currently
+- * doesn't work reliably.
+- */
+- if (cmd == CMD_VALID_PATH &&
+- conf->find_multipaths && conf->ignore_wwids) {
+- condlog(2, "ignoring -i flag because find_multipath is set in multipath.conf");
+- conf->ignore_wwids = 0;
+- }
+-
+ if (getuid() != 0) {
+ fprintf(stderr, "need to be root\n");
+ exit(1);
diff --git a/multipathd/main.c b/multipathd/main.c
-index c475fcd..50749a8 100644
+index 596654c..c860e88 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
-@@ -2138,7 +2138,8 @@ configure (struct vectors * vecs, int start_waiters)
+@@ -2172,7 +2172,8 @@ configure (struct vectors * vecs)
sync_maps_state(mpvec);
vector_foreach_slot(mpvec, mpp, i){
@@ -122,7 +140,7 @@ index c475fcd..50749a8 100644
update_map_pr(mpp);
}
-@@ -2220,10 +2221,6 @@ reconfigure (struct vectors * vecs)
+@@ -2251,10 +2252,6 @@ reconfigure (struct vectors * vecs)
conf->verbosity = verbosity;
if (bindings_read_only)
conf->bindings_read_only = bindings_read_only;
diff --git a/0014-RH-warn-on-invalid-regex-instead-of-failing.patch b/0022-RH-warn-on-invalid-regex-instead-of-failing.patch
index 22a66a2..5c680c1 100644
--- a/0014-RH-warn-on-invalid-regex-instead-of-failing.patch
+++ b/0022-RH-warn-on-invalid-regex-instead-of-failing.patch
@@ -16,7 +16,7 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
3 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
-index 54652d4..8d97602 100644
+index e52f1f7..31897cd 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -52,6 +52,21 @@ set_str(vector strvec, void *ptr)
@@ -41,7 +41,7 @@ index 54652d4..8d97602 100644
set_yes_no(vector strvec, void *ptr)
{
char * buff;
-@@ -1190,7 +1205,7 @@ ble_ ## option ## _handler (struct config *conf, vector strvec) \
+@@ -1200,7 +1215,7 @@ ble_ ## option ## _handler (struct config *conf, vector strvec) \
if (!conf->option) \
return 1; \
\
@@ -50,7 +50,7 @@ index 54652d4..8d97602 100644
if (!buff) \
return 1; \
\
-@@ -1206,7 +1221,7 @@ ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \
+@@ -1216,7 +1231,7 @@ ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \
if (!conf->option) \
return 1; \
\
@@ -59,7 +59,7 @@ index 54652d4..8d97602 100644
if (!buff) \
return 1; \
\
-@@ -1301,16 +1316,16 @@ device_handler(struct config *conf, vector strvec)
+@@ -1311,16 +1326,16 @@ device_handler(struct config *conf, vector strvec)
return 0;
}
diff --git a/device-mapper-multipath.spec b/device-mapper-multipath.spec
index bf2594c..4adf7c9 100644
--- a/device-mapper-multipath.spec
+++ b/device-mapper-multipath.spec
@@ -1,30 +1,38 @@
Summary: Tools to manage multipath devices using device-mapper
Name: device-mapper-multipath
-Version: 0.7.3
-Release: 3%{?dist}
+Version: 0.7.4
+Release: 1.git07e7bd5%{?dist}
License: GPL+
Group: System Environment/Base
URL: http://christophe.varoqui.free.fr/
# The source for this package was pulled from upstream's git repo. Use the
# following command to generate the tarball
-# curl "https://git.opensvc.com/?p=multipath-tools/.git;a=snapshot;h=refs/tags/0.7.3;sf=tgz" -o multipath-tools-0.7.3.tgz
-Source0: multipath-tools-0.7.3.tgz
+# curl "https://git.opensvc.com/?p=multipath-tools/.git;a=snapshot;h=07e7bd5;sf=tgz" -o multipath-tools-07e7bd5.tgz
+Source0: multipath-tools-07e7bd5.tgz
Source1: multipath.conf
-Patch0001: 0001-mpathpersist-Fix-invalid-condition-check.patch
-Patch0002: 0002-multipath-add-man-page-info-for-my-prkey-changes.patch
-Patch0003: 0003-multipath-there-is-no-none-path-state.patch
-Patch0004: 0004-mutipath-updated-Huawei-storage-config.patch
-Patch0005: 0005-multipath-fix-doc-typo.patch
-Patch0006: 0006-multipath-add-ghost_delay-parameter.patch
-Patch0007: 0007-RH-fixup-udev-rules-for-redhat.patch
-Patch0008: 0008-RH-Remove-the-property-blacklist-exception-builtin.patch
-Patch0009: 0009-RH-don-t-start-without-a-config-file.patch
-Patch0010: 0010-RH-use-rpm-optflags-if-present.patch
-Patch0011: 0011-RH-add-mpathconf.patch
-Patch0012: 0012-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch
-Patch0013: 0013-RH-trigger-change-uevent-on-new-device-creation.patch
-Patch0014: 0014-RH-warn-on-invalid-regex-instead-of-failing.patch
+Patch0001: 0001-libmultipath-fix-tur-checker-locking.patch
+Patch0002: 0002-multipath-fix-DEF_TIMEOUT-use.patch
+Patch0003: 0003-multipathd-remove-coalesce_paths-from-ev_add_map.patch
+Patch0004: 0004-multipathd-remove-unused-configure-parameter.patch
+Patch0005: 0005-Fix-set_no_path_retry-regression.patch
+Patch0006: 0006-multipathd-change-spurious-uevent-msg-priority.patch
+Patch0007: 0007-multipath-print-sysfs-state-in-fast-list-mode.patch
+Patch0008: 0008-libmultipath-move-remove_map-waiter-code-to-multipat.patch
+Patch0009: 0009-move-waiter-code-from-libmultipath-to-multipathd.patch
+Patch0010: 0010-call-start_waiter_thread-before-setup_multipath.patch
+Patch0011: 0011-libmultipath-add-helper-functions.patch
+Patch0012: 0012-multipathd-RFC-add-new-polling-dmevents-waiter-threa.patch
+Patch0013: 0013-libmultipath-condlog-log-to-stderr.patch
+Patch0014: 0014-multipathd-fix-compiler-warning-for-uev_pathfail_che.patch
+Patch0015: 0015-RH-fixup-udev-rules-for-redhat.patch
+Patch0016: 0016-RH-Remove-the-property-blacklist-exception-builtin.patch
+Patch0017: 0017-RH-don-t-start-without-a-config-file.patch
+Patch0018: 0018-RH-use-rpm-optflags-if-present.patch
+Patch0019: 0019-RH-add-mpathconf.patch
+Patch0020: 0020-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch
+Patch0021: 0021-RH-trigger-change-uevent-on-new-device-creation.patch
+Patch0022: 0022-RH-warn-on-invalid-regex-instead-of-failing.patch
# runtime
Requires: %{name}-libs = %{version}-%{release}
@@ -102,7 +110,7 @@ This package contains the files needed to develop applications that use
device-mapper-multipath's libdmmp C API library
%prep
-%setup -q -n multipath-tools-0.7.3
+%setup -q -n multipath-tools-07e7bd5
%patch0001 -p1
%patch0002 -p1
%patch0003 -p1
@@ -117,6 +125,14 @@ device-mapper-multipath's libdmmp C API library
%patch0012 -p1
%patch0013 -p1
%patch0014 -p1
+%patch0015 -p1
+%patch0016 -p1
+%patch0017 -p1
+%patch0018 -p1
+%patch0019 -p1
+%patch0020 -p1
+%patch0021 -p1
+%patch0022 -p1
cp %{SOURCE1} .
%build
@@ -178,6 +194,7 @@ fi
%{!?_licensedir:%global license %%doc}
%license COPYING
%doc README
+%doc README.alua
%doc multipath.conf
%dir /etc/multipath
@@ -239,6 +256,40 @@ fi
%{_pkgconfdir}/libdmmp.pc
%changelog
+* Thu Feb 15 2018 Benjamin Marzinski <bmarzins@redhat.com> 0.7.4-1.git07e7bd5
+- Update Source to the latest upstream commit
+ * Previous patches 0001-0006 are included in this commit
+ * Previous patches 0007-0014 are now patches 0015-0022
+- Add 0001-libmultipath-fix-tur-checker-locking.patch
+ * Fixed spinlock bug. posted upstream
+- Add 0002-multipath-fix-DEF_TIMEOUT-use.patch
+ * Add missing sec to ms conversion. posted upstream
+- Add 0003-multipathd-remove-coalesce_paths-from-ev_add_map.patch
+ * Remove unused code. posted upstream
+- Add 0004-multipathd-remove-unused-configure-parameter.patch
+ * Remove unused code. posted upstream
+- Add 0005-Fix-set_no_path_retry-regression.patch
+ * Fix issue with queueing and path addition. posted upstream
+- Add 0006-multipathd-change-spurious-uevent-msg-priority.patch
+ * Change message priority to Notice. posted upstream
+- Add 0007-multipath-print-sysfs-state-in-fast-list-mode.patch
+ * Show sysfs state correctly in fast list mode (-l). posted upstream
+- Add 0008-libmultipath-move-remove_map-waiter-code-to-multipat.patch
+ * Move code around. posted upstream
+- Add 0009-move-waiter-code-from-libmultipath-to-multipathd.patch
+ * Move code around. posted upstream
+- Add 0010-call-start_waiter_thread-before-setup_multipath.patch
+ * Fix race on multipath device creations. posted upstream
+- Add 0011-libmultipath-add-helper-functions.patch
+ * posted upstream
+- Add 0012-multipathd-RFC-add-new-polling-dmevents-waiter-threa.patch
+ * Add alternate method of getting dmevents, that doesn't
+ require a thread per device. posted upstream
+- Add 0013-libmultipath-condlog-log-to-stderr.patch
+ * change condlog to log to stderr instead of stdout. posted upstream
+- Add 0014-multipathd-fix-compiler-warning-for-uev_pathfail_che.patch
+ * fix indentation issue. posted upstream
+
* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.7.3-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
diff --git a/sources b/sources
index cc13e36..a7ce09f 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
+SHA512 (multipath-tools-07e7bd5.tgz) = e84d451c8927119bac6612585d15497325da08d762ea6cde20d400a651fac599cb6edf4f9144204d91f92e04fec4ea3b955b9a9216ae82b513437b8ce516136a
SHA512 (multipath.conf) = 71953dce5a68adcf60a942305f5a66023e6f4c4baf53b1bfdb4edf65ed5b8e03db804363c36d1dcfd85591f4766f52b515269904c53b84d7b076da0b80b09942
-SHA512 (multipath-tools-0.7.3.tgz) = d1e1f4e57ead7a79accf55173263138a78b86c3b846bac8ad2526f36f01fe32a8b7e6bb5bb785b083f3bdbf39c34c06032b7a0d6db6c4cc99e5bc98f67a7e7f3