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 +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 +--- + 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 + #include + #include ++#include + + #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 -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 ---- - 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 -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 ---- - 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\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 +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 +--- + 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 -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 ---- - 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 +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 +--- + 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 +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 +--- + 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 -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 ---- - 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 +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 +--- + 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 -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 ---- - 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 -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 ---- - 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\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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +-#include +-#include +-#include +-#include +-#include +- +-#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 ++#include ++#include ++#include ++#include ++#include ++ ++#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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 +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 +Signed-off-by: Benjamin Marzinski +--- + 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 +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 +--- + 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 similarity index 98% rename from 0007-RH-fixup-udev-rules-for-redhat.patch rename to 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 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 similarity index 96% rename from 0008-RH-Remove-the-property-blacklist-exception-builtin.patch rename to 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 similarity index 90% rename from 0009-RH-don-t-start-without-a-config-file.patch rename to 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 --- - 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 similarity index 93% rename from 0010-RH-use-rpm-optflags-if-present.patch rename to 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 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 similarity index 98% rename from 0011-RH-add-mpathconf.patch rename to 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 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 similarity index 97% rename from 0012-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch rename to 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 similarity index 79% rename from 0013-RH-trigger-change-uevent-on-new-device-creation.patch rename to 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 --- 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 similarity index 93% rename from 0014-RH-warn-on-invalid-regex-instead-of-failing.patch rename to 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 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 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 - 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