device-mapper-multipath-0.7.6-1.git1cb704b

Update Source to the latest upstream commit
  * Previous patches 0001-0014 are included in this commit
  * Previous patches 0015-0022 are now patches 0007-0014
0001-multipathd-remove-incorrect-pthread_testcancel.patch
  * Fixed pthread cancellation issue. posted upstream
0002-multipath-add-comments.patch
  * Posted upstream
0003-multipathd-minor-dmevents-polling-code-cleanups.patch
  * Fixed minor polling issues. posted upstream
0004-multipathd-remove-unneeded-function-parameter.patch
  * Posted upstream
0005-mpathcmd-fix-libmpathcmd-license.patch
  * License clarification. posted upstream
0006-libmultipath-don-t-print-undefined-values.patch
  * Fixed bug in 'multipath show config'. posted upstream
This commit is contained in:
Benjamin Marzinski 2018-04-02 17:29:20 -05:00
parent 5dbff48724
commit e5cbd1f107
31 changed files with 761 additions and 2653 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ multipath-tools-091027.tar.gz
/multipath-tools-git847cc43.tgz
/multipath-tools-0.7.3.tgz
/multipath-tools-07e7bd5.tgz
/multipath-tools-1cb704b.tgz

View File

@ -1,269 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 8 Feb 2018 16:56:45 -0600
Subject: [PATCH] libmultipath: fix tur checker locking
Commit 6e2423fd fixed a bug where the tur checker could cancel a
detached thread after it had exitted. However in fixing this, the new
code grabbed a mutex (to call condlog) while holding a spin_lock. To
deal with this, I've done away with the holder spin_lock completely, and
replaced it with two atomic variables, based on a suggestion by Martin
Wilck.
The holder variable works exactly like before. When the checker is
initialized, it is set to 1. When a thread is created it is incremented.
When either the thread or the checker are done with the context, they
atomically decrement the holder variable and check its value. If it
is 0, they free the context. If it is 1, they never touch the context
again.
The other variable has changed. First, ct->running and ct->thread have
switched uses. ct->thread is now only ever accessed by the checker,
never the thread. If it is non-NULL, a thread has started up, but
hasn't been dealt with by the checker yet. It is also obviously used
by the checker to cancel the thread.
ct->running is now an atomic variable. When the thread is started
it is set to 1. When the checker wants to kill a thread, it atomically
sets the value to 0 and reads the previous value. If it was 1,
the checker cancels the thread. If it was 0, the nothing needs to be
done. After the checker has dealt with the thread, it sets ct->thread
to NULL.
Right before the thread finishes and pops the cleanup handler, it
atomically sets the value of ct->running to 0 and reads the previous
value. If it was 1, the thread just pops the cleanup handler and exits.
If it was 0, then the checker is trying to cancel the thread, and so the
thread calls pause(), which is a cancellation point.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/checkers/tur.c | 107 ++++++++++++++++++--------------------------
1 file changed, 43 insertions(+), 64 deletions(-)
diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c
index b4a5cb2..9155960 100644
--- a/libmultipath/checkers/tur.c
+++ b/libmultipath/checkers/tur.c
@@ -15,6 +15,7 @@
#include <errno.h>
#include <sys/time.h>
#include <pthread.h>
+#include <urcu/uatomic.h>
#include "checkers.h"
@@ -44,7 +45,6 @@ struct tur_checker_context {
pthread_t thread;
pthread_mutex_t lock;
pthread_cond_t active;
- pthread_spinlock_t hldr_lock;
int holders;
char message[CHECKER_MSG_LEN];
};
@@ -74,13 +74,12 @@ int libcheck_init (struct checker * c)
ct->state = PATH_UNCHECKED;
ct->fd = -1;
- ct->holders = 1;
+ uatomic_set(&ct->holders, 1);
pthread_cond_init_mono(&ct->active);
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&ct->lock, &attr);
pthread_mutexattr_destroy(&attr);
- pthread_spin_init(&ct->hldr_lock, PTHREAD_PROCESS_PRIVATE);
c->context = ct;
return 0;
@@ -90,7 +89,6 @@ static void cleanup_context(struct tur_checker_context *ct)
{
pthread_mutex_destroy(&ct->lock);
pthread_cond_destroy(&ct->active);
- pthread_spin_destroy(&ct->hldr_lock);
free(ct);
}
@@ -99,16 +97,14 @@ void libcheck_free (struct checker * c)
if (c->context) {
struct tur_checker_context *ct = c->context;
int holders;
- pthread_t thread;
-
- pthread_spin_lock(&ct->hldr_lock);
- ct->holders--;
- holders = ct->holders;
- thread = ct->thread;
- pthread_spin_unlock(&ct->hldr_lock);
- if (holders)
- pthread_cancel(thread);
- else
+ int running;
+
+ running = uatomic_xchg(&ct->running, 0);
+ if (running)
+ pthread_cancel(ct->thread);
+ ct->thread = 0;
+ holders = uatomic_sub_return(&ct->holders, 1);
+ if (!holders)
cleanup_context(ct);
c->context = NULL;
}
@@ -220,26 +216,12 @@ static void cleanup_func(void *data)
{
int holders;
struct tur_checker_context *ct = data;
- pthread_spin_lock(&ct->hldr_lock);
- ct->holders--;
- holders = ct->holders;
- ct->thread = 0;
- pthread_spin_unlock(&ct->hldr_lock);
+
+ holders = uatomic_sub_return(&ct->holders, 1);
if (!holders)
cleanup_context(ct);
}
-static int tur_running(struct tur_checker_context *ct)
-{
- pthread_t thread;
-
- pthread_spin_lock(&ct->hldr_lock);
- thread = ct->thread;
- pthread_spin_unlock(&ct->hldr_lock);
-
- return thread != 0;
-}
-
static void copy_msg_to_tcc(void *ct_p, const char *msg)
{
struct tur_checker_context *ct = ct_p;
@@ -252,7 +234,7 @@ static void copy_msg_to_tcc(void *ct_p, const char *msg)
static void *tur_thread(void *ctx)
{
struct tur_checker_context *ct = ctx;
- int state;
+ int state, running;
char devt[32];
condlog(3, "%s: tur checker starting up",
@@ -278,6 +260,11 @@ static void *tur_thread(void *ctx)
condlog(3, "%s: tur checker finished, state %s",
tur_devt(devt, sizeof(devt), ct), checker_state_name(state));
+
+ running = uatomic_xchg(&ct->running, 0);
+ if (!running)
+ pause();
+
tur_thread_cleanup_pop(ct);
return ((void *)0);
@@ -325,7 +312,6 @@ int libcheck_check(struct checker * c)
int tur_status, r;
char devt[32];
-
if (!ct)
return PATH_UNCHECKED;
@@ -349,38 +335,29 @@ int libcheck_check(struct checker * c)
return PATH_WILD;
}
- if (ct->running) {
- /*
- * Check if TUR checker is still running. Hold hldr_lock
- * around the pthread_cancel() call to avoid that
- * pthread_cancel() gets called after the (detached) TUR
- * thread has exited.
- */
- pthread_spin_lock(&ct->hldr_lock);
- if (ct->thread) {
- if (tur_check_async_timeout(c)) {
- condlog(3, "%s: tur checker timeout",
- tur_devt(devt, sizeof(devt), ct));
+ if (ct->thread) {
+ if (tur_check_async_timeout(c)) {
+ int running = uatomic_xchg(&ct->running, 0);
+ if (running)
pthread_cancel(ct->thread);
- ct->running = 0;
- MSG(c, MSG_TUR_TIMEOUT);
- tur_status = PATH_TIMEOUT;
- } else {
- condlog(3, "%s: tur checker not finished",
+ condlog(3, "%s: tur checker timeout",
+ tur_devt(devt, sizeof(devt), ct));
+ ct->thread = 0;
+ MSG(c, MSG_TUR_TIMEOUT);
+ tur_status = PATH_TIMEOUT;
+ } else if (uatomic_read(&ct->running) != 0) {
+ condlog(3, "%s: tur checker not finished",
tur_devt(devt, sizeof(devt), ct));
- ct->running++;
- tur_status = PATH_PENDING;
- }
+ tur_status = PATH_PENDING;
} else {
/* TUR checker done */
- ct->running = 0;
+ ct->thread = 0;
tur_status = ct->state;
strlcpy(c->message, ct->message, sizeof(c->message));
}
- pthread_spin_unlock(&ct->hldr_lock);
pthread_mutex_unlock(&ct->lock);
} else {
- if (tur_running(ct)) {
+ if (uatomic_read(&ct->running) != 0) {
/* pthread cancel failed. continue in sync mode */
pthread_mutex_unlock(&ct->lock);
condlog(3, "%s: tur thread not responding",
@@ -391,19 +368,17 @@ int libcheck_check(struct checker * c)
ct->state = PATH_UNCHECKED;
ct->fd = c->fd;
ct->timeout = c->timeout;
- pthread_spin_lock(&ct->hldr_lock);
- ct->holders++;
- pthread_spin_unlock(&ct->hldr_lock);
+ uatomic_add(&ct->holders, 1);
+ uatomic_set(&ct->running, 1);
tur_set_async_timeout(c);
setup_thread_attr(&attr, 32 * 1024, 1);
r = pthread_create(&ct->thread, &attr, tur_thread, ct);
pthread_attr_destroy(&attr);
if (r) {
- pthread_spin_lock(&ct->hldr_lock);
- ct->holders--;
- pthread_spin_unlock(&ct->hldr_lock);
- pthread_mutex_unlock(&ct->lock);
+ uatomic_sub(&ct->holders, 1);
+ uatomic_set(&ct->running, 0);
ct->thread = 0;
+ pthread_mutex_unlock(&ct->lock);
condlog(3, "%s: failed to start tur thread, using"
" sync mode", tur_devt(devt, sizeof(devt), ct));
return tur_check(c->fd, c->timeout,
@@ -414,12 +389,16 @@ int libcheck_check(struct checker * c)
tur_status = ct->state;
strlcpy(c->message, ct->message, sizeof(c->message));
pthread_mutex_unlock(&ct->lock);
- if (tur_running(ct) &&
+ if (uatomic_read(&ct->running) != 0 &&
(tur_status == PATH_PENDING || tur_status == PATH_UNCHECKED)) {
condlog(3, "%s: tur checker still running",
tur_devt(devt, sizeof(devt), ct));
- ct->running = 1;
tur_status = PATH_PENDING;
+ } else {
+ int running = uatomic_xchg(&ct->running, 0);
+ if (running)
+ pthread_cancel(ct->thread);
+ ct->thread = 0;
}
}
--
2.7.4

View File

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 28 Mar 2018 16:47:05 -0500
Subject: [PATCH] multipathd: remove incorrect pthread_testcancel
As Martin Wilck pointed out, a thread that's trying to stop the waiter
thread should not cancel itself before it gets a chance to do so
Cc: Martin Wilck <mwilck@suse.com>
Fixes: c7625f92 "multipathd: fix waiter thread cancelling"
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/waiter.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/multipathd/waiter.c b/multipathd/waiter.c
index 595c69a..0ef8b25 100644
--- a/multipathd/waiter.c
+++ b/multipathd/waiter.c
@@ -68,7 +68,6 @@ void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
mpp->waiter = (pthread_t)0;
pthread_cleanup_push(cleanup_lock, &waiter_lock);
lock(&waiter_lock);
- pthread_testcancel();
pthread_kill(thread, SIGUSR2);
pthread_cancel(thread);
lock_cleanup_pop(&waiter_lock);
--
2.7.4

View File

@ -0,0 +1,389 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 29 Mar 2018 12:07:11 -0500
Subject: [PATCH] multipath: add comments
This commit simply adds a number of comments based on suggestions by
Martin Wilck.
Cc: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/dmevents.c | 4 ++-
tests/dmevents.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++-
tests/util.c | 2 ++
3 files changed, 76 insertions(+), 2 deletions(-)
diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c
index 2281a10..0b0d0ce 100644
--- a/multipathd/dmevents.c
+++ b/multipathd/dmevents.c
@@ -122,6 +122,8 @@ static int arm_dm_event_poll(int fd)
dmi.version[0] = DM_VERSION_MAJOR;
dmi.version[1] = DM_VERSION_MINOR;
dmi.version[2] = DM_VERSION_PATCHLEVEL;
+ /* This flag currently does nothing. It simply exists to
+ * duplicate the behavior of libdevmapper */
dmi.flags = 0x4;
dmi.data_start = offsetof(struct dm_ioctl, data);
dmi.data_size = sizeof(dmi);
@@ -189,7 +191,7 @@ fail:
return -1;
}
-/* You must call update_multipath() after calling this function, to
+/* You must call __setup_multipath() after calling this function, to
* deal with any events that came in before the device was added */
int watch_dmevents(char *name)
{
diff --git a/tests/dmevents.c b/tests/dmevents.c
index 4442fc2..bba51dc 100644
--- a/tests/dmevents.c
+++ b/tests/dmevents.c
@@ -33,10 +33,13 @@
/* I have to do this to get at the static variables */
#include "../multipathd/dmevents.c"
+/* pretend dm device */
struct dm_device {
char name[WWID_SIZE];
+ /* is this a mpath device, or other dm device */
int is_mpath;
uint32_t evt_nr;
+ /* tracks the event number when the multipath device was updated */
uint32_t update_nr;
};
@@ -48,6 +51,9 @@ struct test_data {
struct test_data data;
+/* Add a pretend dm device, or update its event number. This is used to build
+ * up the dm devices that the dmevents code queries with dm_task_get_names,
+ * dm_geteventnr, and dm_is_mpath */
int add_dm_device_event(char *name, int is_mpath, uint32_t evt_nr)
{
struct dm_device *dev;
@@ -77,6 +83,7 @@ int add_dm_device_event(char *name, int is_mpath, uint32_t evt_nr)
return 0;
}
+/* helper function for pretend dm devices */
struct dm_device *find_dm_device(const char *name)
{
struct dm_device *dev;
@@ -88,6 +95,7 @@ struct dm_device *find_dm_device(const char *name)
return NULL;
}
+/* helper function for pretend dm devices */
int remove_dm_device_event(const char *name)
{
struct dm_device *dev;
@@ -103,6 +111,7 @@ int remove_dm_device_event(const char *name)
return -1;
}
+/* helper function for pretend dm devices */
void remove_all_dm_device_events(void)
{
struct dm_device *dev;
@@ -122,7 +131,9 @@ static inline void *align_ptr(void *ptr)
return (void *)align_val((size_t)ptr);
}
-/* copied off of list_devices in dm-ioctl.c */
+/* copied off of list_devices in dm-ioctl.c except that it uses
+ * the pretend dm devices, and saves the output to the test_data
+ * structure */
struct dm_names *build_dm_names(void)
{
struct dm_names *names, *np, *old_np = NULL;
@@ -199,12 +210,16 @@ int __wrap_open(const char *pathname, int flags)
return mock_type(int);
}
+/* We never check the result of the close(), so there's no need to
+ * to mock a return value */
int __wrap_close(int fd)
{
assert_int_equal(fd, waiter->fd);
return 0;
}
+/* the pretend dm device code checks the input and supplies the
+ * return value, so there's no need to do that here */
int __wrap_dm_is_mpath(const char *name)
{
struct dm_device *dev;
@@ -216,6 +231,8 @@ int __wrap_dm_is_mpath(const char *name)
return 0;
}
+/* either get return info from the pretend dm device, or
+ * override it to test -1 return */
int __wrap_dm_geteventnr(const char *name)
{
struct dm_device *dev;
@@ -257,6 +274,8 @@ int __wrap_dm_task_run(struct dm_task *dmt)
return mock_type(int);
}
+/* either get return info from the pretend dm device, or
+ * override it to test NULL return */
struct dm_names * __wrap_dm_task_get_names(struct dm_task *dmt)
{
int good = mock_type(int);
@@ -299,6 +318,9 @@ void __wrap_remove_map_by_alias(const char *alias, struct vectors * vecs,
assert_int_equal(purge_vec, 1);
}
+/* pretend update the pretend dm devices. If fail is set, it
+ * simulates having the dm device removed. Otherwise it just sets
+ * update_nr to record when the update happened */
int __wrap_update_multipath(struct vectors *vecs, char *mapname, int reset)
{
int fail;
@@ -325,6 +347,9 @@ int __wrap_update_multipath(struct vectors *vecs, char *mapname, int reset)
return fail;
}
+/* helper function used to check if the dmevents list of devices
+ * includes a specific device. To make sure that dmevents is
+ * in the correct state after running a function */
struct dev_event *find_dmevents(const char *name)
{
struct dev_event *dev_evt;
@@ -336,14 +361,19 @@ struct dev_event *find_dmevents(const char *name)
return NULL;
}
+/* null vecs pointer when initialized dmevents */
static void test_init_waiter_bad0(void **state)
{
+ /* this boilerplate code just skips the test if
+ * dmevents polling is not supported */
struct test_data *datap = (struct test_data *)(*state);
if (datap == NULL)
skip();
+
assert_int_equal(init_dmevent_waiter(NULL), -1);
}
+/* fail to open /dev/mapper/control */
static void test_init_waiter_bad1(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
@@ -354,6 +384,7 @@ static void test_init_waiter_bad1(void **state)
assert_ptr_equal(waiter, NULL);
}
+/* waiter remains initialized after this test */
static void test_init_waiter_good0(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
@@ -364,6 +395,7 @@ static void test_init_waiter_good0(void **state)
assert_ptr_not_equal(waiter, NULL);
}
+/* No dm device named foo */
static void test_watch_dmevents_bad0(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
@@ -373,6 +405,7 @@ static void test_watch_dmevents_bad0(void **state)
assert_ptr_equal(find_dmevents("foo"), NULL);
}
+/* foo is not a multipath device */
static void test_watch_dmevents_bad1(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
@@ -384,6 +417,7 @@ static void test_watch_dmevents_bad1(void **state)
assert_ptr_equal(find_dmevents("foo"), NULL);
}
+/* failed getting the dmevent number */
static void test_watch_dmevents_bad2(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
@@ -396,6 +430,8 @@ static void test_watch_dmevents_bad2(void **state)
assert_int_equal(watch_dmevents("foo"), -1);
assert_ptr_equal(find_dmevents("foo"), NULL);
}
+
+/* verify that you can watch and unwatch dm multipath device "foo" */
static void test_watch_dmevents_good0(void **state)
{
struct dev_event *dev_evt;
@@ -407,16 +443,20 @@ static void test_watch_dmevents_good0(void **state)
assert_int_equal(add_dm_device_event("foo", 1, 5), 0);
will_return(__wrap_dm_geteventnr, 0);
assert_int_equal(watch_dmevents("foo"), 0);
+ /* verify foo is being watched */
dev_evt = find_dmevents("foo");
assert_ptr_not_equal(dev_evt, NULL);
assert_int_equal(dev_evt->evt_nr, 5);
assert_int_equal(dev_evt->action, EVENT_NOTHING);
assert_int_equal(VECTOR_SIZE(waiter->events), 1);
unwatch_dmevents("foo");
+ /* verify foo is no longer being watched */
assert_int_equal(VECTOR_SIZE(waiter->events), 0);
assert_ptr_equal(find_dmevents("foo"), NULL);
}
+/* verify that if you try to watch foo multiple times, it only
+ * is placed on the waiter list once */
static void test_watch_dmevents_good1(void **state)
{
struct dev_event *dev_evt;
@@ -445,6 +485,7 @@ static void test_watch_dmevents_good1(void **state)
assert_ptr_equal(find_dmevents("foo"), NULL);
}
+/* watch and then unwatch multiple devices */
static void test_watch_dmevents_good2(void **state)
{
struct dev_event *dev_evt;
@@ -480,6 +521,7 @@ static void test_watch_dmevents_good2(void **state)
assert_ptr_equal(find_dmevents("bar"), NULL);
}
+/* dm_task_create fails */
static void test_get_events_bad0(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
@@ -493,6 +535,7 @@ static void test_get_events_bad0(void **state)
assert_int_equal(dm_get_events(), -1);
}
+/* dm_task_run fails */
static void test_get_events_bad1(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
@@ -505,6 +548,7 @@ static void test_get_events_bad1(void **state)
assert_int_equal(dm_get_events(), -1);
}
+/* dm_task_get_names fails */
static void test_get_events_bad2(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
@@ -518,6 +562,7 @@ static void test_get_events_bad2(void **state)
assert_int_equal(dm_get_events(), -1);
}
+/* If the device isn't being watched, dm_get_events returns NULL */
static void test_get_events_good0(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
@@ -534,6 +579,11 @@ static void test_get_events_good0(void **state)
assert_int_equal(VECTOR_SIZE(waiter->events), 0);
}
+/* There are 5 dm devices. 4 of them are multipath devices.
+ * Only 3 of them are being watched. "foo" has a new event
+ * "xyzzy" gets removed. Nothing happens to bar. Verify
+ * that all the events are properly set, and that nothing
+ * happens with the two devices that aren't being watched */
static void test_get_events_good1(void **state)
{
struct dev_event *dev_evt;
@@ -577,6 +627,8 @@ static void test_get_events_good1(void **state)
assert_int_equal(VECTOR_SIZE(waiter->events), 3);
}
+/* poll does not return an event. nothing happens. The
+ * devices remain after this test */
static void test_dmevent_loop_bad0(void **state)
{
struct dm_device *dev;
@@ -603,6 +655,7 @@ static void test_dmevent_loop_bad0(void **state)
assert_int_equal(dev->update_nr, 5);
}
+/* arm_dm_event_poll's ioctl fails. Nothing happens */
static void test_dmevent_loop_bad1(void **state)
{
struct dm_device *dev;
@@ -624,6 +677,7 @@ static void test_dmevent_loop_bad1(void **state)
assert_int_equal(dev->update_nr, 5);
}
+/* dm_get_events fails. Nothing happens */
static void test_dmevent_loop_bad2(void **state)
{
struct dm_device *dev;
@@ -646,6 +700,8 @@ static void test_dmevent_loop_bad2(void **state)
assert_int_equal(dev->update_nr, 5);
}
+/* verify dmevent_loop runs successfully when no devices are being
+ * watched */
static void test_dmevent_loop_good0(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
@@ -663,6 +719,11 @@ static void test_dmevent_loop_good0(void **state)
assert_int_equal(dmevent_loop(), 1);
}
+/* Watch 3 devices, where one device has an event (foo), one device is
+ * removed (xyzzy), and one device does nothing (bar). Verify that
+ * the device with the event gets updated, the device that is removed
+ * gets unwatched, and the device with no events stays the same.
+ * The devices remain after this test */
static void test_dmevent_loop_good1(void **state)
{
struct dm_device *dev;
@@ -717,6 +778,10 @@ static void test_dmevent_loop_good1(void **state)
assert_ptr_equal(find_dm_device("xyzzy"), NULL);
}
+/* watch another dm device and add events to two of them, so bar and
+ * baz have new events, and foo doesn't. Set update_multipath to
+ * fail for baz. Verify that baz is unwatched, bar is updated, and
+ * foo stays the same. */
static void test_dmevent_loop_good2(void **state)
{
struct dm_device *dev;
@@ -762,6 +827,8 @@ static void test_dmevent_loop_good2(void **state)
assert_ptr_equal(find_dm_device("baz"), NULL);
}
+/* remove dm device foo, and unwatch events on bar. Verify that
+ * foo is cleaned up and unwatched, and bar is no longer updated */
static void test_dmevent_loop_good3(void **state)
{
struct dm_device *dev;
@@ -790,6 +857,8 @@ static void test_dmevent_loop_good3(void **state)
assert_ptr_equal(find_dm_device("foo"), NULL);
}
+
+/* verify that rearming the dmevents polling works */
static void test_arm_poll(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
@@ -799,6 +868,7 @@ static void test_arm_poll(void **state)
assert_int_equal(arm_dm_event_poll(waiter->fd), 0);
}
+/* verify that the waiter is cleaned up */
static void test_cleanup_waiter(void **state)
{
struct test_data *datap = (struct test_data *)(*state);
diff --git a/tests/util.c b/tests/util.c
index e9a004f..113b134 100644
--- a/tests/util.c
+++ b/tests/util.c
@@ -74,6 +74,8 @@ static void test_basenamecpy_good5(void **state)
assert_string_equal(dst, "bar");
}
+/* multipath expects any trailing whitespace to be stripped off the basename,
+ * so that it will match pp->dev */
static void test_basenamecpy_good6(void **state)
{
char dst[6];
--
2.7.4

View File

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 18 Jan 2018 13:13:54 -0600
Subject: [PATCH] multipath: fix DEF_TIMEOUT use
DEF_TIMEOUT is specified in seconds. The io_hdr timeout is specified in
milliseconds, so we need to convert it. Multipath should be waiting
longer than 30 milliseconds here. If there are concerns that 30 seconds
may be too long, we could always make this configurable, using
conf->checker_timeout if set.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 4b31dde..f118800 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -766,7 +766,7 @@ do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
io_hdr.dxferp = resp;
io_hdr.cmdp = inqCmdBlk;
io_hdr.sbp = sense_b;
- io_hdr.timeout = DEF_TIMEOUT;
+ io_hdr.timeout = DEF_TIMEOUT * 1000;
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
return -1;
--
2.7.4

View File

@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 29 Mar 2018 12:48:08 -0500
Subject: [PATCH] multipathd: minor dmevents polling code cleanups
Change strncpy to strlcpy and lock_cleanup_pop to pthread_cleanup_pop,
based on suggestions by Martin Wilck
Cc: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/dmevents.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c
index 0b0d0ce..e98a974 100644
--- a/multipathd/dmevents.c
+++ b/multipathd/dmevents.c
@@ -24,6 +24,7 @@
#include "debug.h"
#include "main.h"
#include "dmevents.h"
+#include "util.h"
#ifndef DM_DEV_ARM_POLL
#define DM_DEV_ARM_POLL _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD + 1, struct dm_ioctl)
@@ -214,8 +215,7 @@ int watch_dmevents(char *name)
return -1;
}
- strncpy(dev_evt->name, name, WWID_SIZE);
- dev_evt->name[WWID_SIZE - 1] = 0;
+ strlcpy(dev_evt->name, name, WWID_SIZE);
dev_evt->evt_nr = event_nr;
dev_evt->action = EVENT_NOTHING;
@@ -350,7 +350,7 @@ static int dmevent_loop (void)
remove_map_by_alias(curr_dev.name, waiter->vecs, 1);
else
r = update_multipath(waiter->vecs, curr_dev.name, 1);
- lock_cleanup_pop(&waiter->vecs->lock);
+ pthread_cleanup_pop(1);
if (r) {
condlog(2, "%s: stopped watching dmevents",
--
2.7.4

View File

@ -1,98 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 19 Jan 2018 22:35:26 -0600
Subject: [PATCH] multipathd: remove coalesce_paths from ev_add_map
If ev_add_map is called for a multipath device that doesn't exist in
device-mapper, it will call coalesce_paths to add it. This doesn't work
and hasn't for years. It doesn't add the map to the mpvec, or start up
waiters, or do any of the necessary things that do get done when you
call ev_add_map for a map that does exist in device mapper.
Fortunately, there are only two things that call ev_add_map. uev_add_map
makes sure that the device does exist in device-mapper before calling
ev_add_map, and cli_add_map creates the device first and then calls
ev_add_map, if the device doesn't exist.
So, there is no reason for coalesce_paths to be in ev_add_map. This
removes it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/main.c | 46 ++++++++++++++--------------------------------
1 file changed, 14 insertions(+), 32 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index 27cf234..dbf9890 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -412,18 +412,19 @@ uev_add_map (struct uevent * uev, struct vectors * vecs)
return rc;
}
+/*
+ * ev_add_map expects that the multipath device already exists in kernel
+ * before it is called. It just adds a device to multipathd or updates an
+ * existing device.
+ */
int
ev_add_map (char * dev, char * alias, struct vectors * vecs)
{
- char * refwwid;
struct multipath * mpp;
- int map_present;
- int r = 1, delayed_reconfig, reassign_maps;
+ int delayed_reconfig, reassign_maps;
struct config *conf;
- map_present = dm_map_present(alias);
-
- if (map_present && !dm_is_mpath(alias)) {
+ if (!dm_is_mpath(alias)) {
condlog(4, "%s: not a multipath map", alias);
return 0;
}
@@ -468,33 +469,14 @@ ev_add_map (char * dev, char * alias, struct vectors * vecs)
/*
* now we can register the map
*/
- if (map_present) {
- if ((mpp = add_map_without_path(vecs, alias))) {
- sync_map_state(mpp);
- condlog(2, "%s: devmap %s registered", alias, dev);
- return 0;
- } else {
- condlog(2, "%s: uev_add_map failed", dev);
- return 1;
- }
- }
- r = get_refwwid(CMD_NONE, dev, DEV_DEVMAP, vecs->pathvec, &refwwid);
-
- if (refwwid) {
- r = coalesce_paths(vecs, NULL, refwwid, FORCE_RELOAD_NONE,
- CMD_NONE);
- dm_lib_release();
+ if ((mpp = add_map_without_path(vecs, alias))) {
+ sync_map_state(mpp);
+ condlog(2, "%s: devmap %s registered", alias, dev);
+ return 0;
+ } else {
+ condlog(2, "%s: ev_add_map failed", dev);
+ return 1;
}
-
- if (!r)
- condlog(2, "%s: devmap %s added", alias, dev);
- else if (r == 2)
- condlog(2, "%s: uev_add_map %s blacklisted", alias, dev);
- else
- condlog(0, "%s: uev_add_map %s failed", alias, dev);
-
- FREE(refwwid);
- return r;
}
static int
--
2.7.4

View File

@ -0,0 +1,83 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 29 Mar 2018 14:01:30 -0500
Subject: [PATCH] multipathd: remove unneeded function parameter
remove_map_and_stop_waiter was always called with purge_vecs = 1, so
it can simply be removed, as suggested by Martin Wilck
Cc: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/main.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index 9a4f671..841d3e9 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -311,14 +311,13 @@ wait_for_events(struct multipath *mpp, struct vectors *vecs)
}
static void
-remove_map_and_stop_waiter(struct multipath *mpp, struct vectors *vecs,
- int purge_vec)
+remove_map_and_stop_waiter(struct multipath *mpp, struct vectors *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);
+ remove_map(mpp, vecs, PURGE_VEC);
}
static void
@@ -400,7 +399,7 @@ int __setup_multipath(struct vectors *vecs, struct multipath *mpp,
return 0;
out:
- remove_map_and_stop_waiter(mpp, vecs, PURGE_VEC);
+ remove_map_and_stop_waiter(mpp, vecs);
return 1;
}
@@ -637,7 +636,7 @@ flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths)
}
orphan_paths(vecs->pathvec, mpp);
- remove_map_and_stop_waiter(mpp, vecs, 1);
+ remove_map_and_stop_waiter(mpp, vecs);
return 0;
}
@@ -769,7 +768,7 @@ uev_remove_map (struct uevent * uev, struct vectors * vecs)
}
orphan_paths(vecs->pathvec, mpp);
- remove_map_and_stop_waiter(mpp, vecs, 1);
+ remove_map_and_stop_waiter(mpp, vecs);
out:
lock_cleanup_pop(vecs->lock);
FREE(alias);
@@ -1154,7 +1153,7 @@ out:
return retval;
fail:
- remove_map_and_stop_waiter(mpp, vecs, 1);
+ remove_map_and_stop_waiter(mpp, vecs);
return 1;
}
@@ -1612,7 +1611,7 @@ mpvec_garbage_collector (struct vectors * vecs)
vector_foreach_slot (vecs->mpvec, mpp, i) {
if (mpp && mpp->alias && !dm_map_present(mpp->alias)) {
condlog(2, "%s: remove dead map", mpp->alias);
- remove_map_and_stop_waiter(mpp, vecs, 1);
+ remove_map_and_stop_waiter(mpp, vecs);
i--;
}
}
--
2.7.4

View File

@ -1,53 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 2 Feb 2018 15:04:01 -0600
Subject: [PATCH] multipathd: remove unused configure parameter
configure() is always called with start_waiters=1, so there is no point
in having the parameter. Remove it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/main.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index dbf9890..51e0f5e 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -1955,7 +1955,7 @@ checkerloop (void *ap)
}
int
-configure (struct vectors * vecs, int start_waiters)
+configure (struct vectors * vecs)
{
struct multipath * mpp;
struct path * pp;
@@ -2054,11 +2054,9 @@ configure (struct vectors * vecs, int start_waiters)
i--;
continue;
}
- if (start_waiters) {
- if (start_waiter_thread(mpp, vecs)) {
- remove_map(mpp, vecs, 1);
- i--;
- }
+ if (start_waiter_thread(mpp, vecs)) {
+ remove_map(mpp, vecs, 1);
+ i--;
}
}
return 0;
@@ -2125,7 +2123,7 @@ reconfigure (struct vectors * vecs)
rcu_assign_pointer(multipath_conf, conf);
call_rcu(&old->rcu, rcu_free_config);
- configure(vecs, 1);
+ configure(vecs);
return 0;
--
2.7.4

View File

@ -1,81 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 6 Feb 2018 20:53:17 -0600
Subject: [PATCH] Fix set_no_path_retry() regression
commit 0f850db7fceb6b2bf4968f3831efd250c17c6138 "multipathd: clean up
set_no_path_retry" has a bug in it. It made set_no_path_retry
never reset mpp->retry_ticks, even if the device was in recovery mode,
and there were valid paths. This meant that adding new paths didn't
remove a device from recovery mode, and queueing could get disabled,
even while there were valid paths. This patch fixes that.
This patch also fixes a bug in cli_restore_queueing() and
cli_restore_all_queueing(), where a device that had no_path_retry
set to "queue" would enter recovery mode (although queueing would
never actually get disabled).
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/structs_vec.c | 5 +++--
multipathd/cli_handlers.c | 20 ++++++++++++--------
2 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index fbab61f..0de2221 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -343,9 +343,10 @@ static void set_no_path_retry(struct multipath *mpp)
dm_queue_if_no_path(mpp->alias, 1);
break;
default:
- if (mpp->nr_active > 0)
+ if (mpp->nr_active > 0) {
+ mpp->retry_tick = 0;
dm_queue_if_no_path(mpp->alias, 1);
- else if (is_queueing && mpp->retry_tick == 0)
+ } else if (is_queueing && mpp->retry_tick == 0)
enter_recovery_mode(mpp);
break;
}
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 7f13bc9..80519b1 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -995,10 +995,12 @@ cli_restore_queueing(void *v, char **reply, int *len, void *data)
if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
mpp->no_path_retry != NO_PATH_RETRY_FAIL) {
dm_queue_if_no_path(mpp->alias, 1);
- if (mpp->nr_active > 0)
- mpp->retry_tick = 0;
- else
- enter_recovery_mode(mpp);
+ if (mpp->no_path_retry > 0) {
+ if (mpp->nr_active > 0)
+ mpp->retry_tick = 0;
+ else
+ enter_recovery_mode(mpp);
+ }
}
return 0;
}
@@ -1019,10 +1021,12 @@ cli_restore_all_queueing(void *v, char **reply, int *len, void *data)
if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
mpp->no_path_retry != NO_PATH_RETRY_FAIL) {
dm_queue_if_no_path(mpp->alias, 1);
- if (mpp->nr_active > 0)
- mpp->retry_tick = 0;
- else
- enter_recovery_mode(mpp);
+ if (mpp->no_path_retry > 0) {
+ if (mpp->nr_active > 0)
+ mpp->retry_tick = 0;
+ else
+ enter_recovery_mode(mpp);
+ }
}
}
return 0;
--
2.7.4

View File

@ -0,0 +1,58 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 29 Mar 2018 15:00:12 -0500
Subject: [PATCH] mpathcmd: fix libmpathcmd license
There is no version 2 of the GNU Lesser General Public License, so
change the license header to version 2.1, which does exist. Also copy
the license header to mpath_cmd.c.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathcmd/mpath_cmd.c | 19 +++++++++++++++++++
libmpathcmd/mpath_cmd.h | 2 +-
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/libmpathcmd/mpath_cmd.c b/libmpathcmd/mpath_cmd.c
index 29d148c..61e6a98 100644
--- a/libmpathcmd/mpath_cmd.c
+++ b/libmpathcmd/mpath_cmd.c
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * This file is part of the device-mapper multipath userspace tools.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
diff --git a/libmpathcmd/mpath_cmd.h b/libmpathcmd/mpath_cmd.h
index b57b708..aaa8da9 100644
--- a/libmpathcmd/mpath_cmd.h
+++ b/libmpathcmd/mpath_cmd.h
@@ -5,7 +5,7 @@
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2
+ * as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
--
2.7.4

View File

@ -0,0 +1,60 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 29 Mar 2018 18:26:12 -0500
Subject: [PATCH] libmultipath: don't print undefined values
commit 48e9fd9f ("libmultipath: parser: use call-by-value for "snprint"
methods") removed some of the code that checked for undefined values to
avoid printing them. This lead to device configurations that printed
out values for parameters that they hadn't configured. This patch adds
that code back in.
Fixes: 48e9fd9f ("libmultipath: parser: use call-by-value for "snprint" methods")
Cc: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/dict.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index ac9216c..1a18337 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -101,12 +101,16 @@ print_int (char *buff, int len, long v)
static int
print_nonzero (char *buff, int len, long v)
{
+ if (!v)
+ return 0;
return snprintf(buff, len, "%li", v);
}
static int
print_str (char *buff, int len, const char *ptr)
{
+ if (!ptr)
+ return 0;
return snprintf(buff, len, "\"%s\"", ptr);
}
@@ -120,6 +124,8 @@ print_yes_no (char *buff, int len, long v)
static int
print_yes_no_undef (char *buff, int len, long v)
{
+ if (!v)
+ return 0;
return snprintf(buff, len, "\"%s\"",
(v == YNU_NO)? "no" : "yes");
}
@@ -665,6 +671,8 @@ set_dev_loss(vector strvec, void *ptr)
int
print_dev_loss(char * buff, int len, unsigned long v)
{
+ if (!v)
+ return 0;
if (v >= MAX_DEV_LOSS_TMO)
return snprintf(buff, len, "\"infinity\"");
return snprintf(buff, len, "%lu", v);
--
2.7.4

View File

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 7 Feb 2018 14:20:11 -0600
Subject: [PATCH] multipathd: change spurious uevent msg priority
The "spurious uevent, path already in pathvec" is not anything to worry
about, so it should not have the error priority.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index 51e0f5e..7ac59d9 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -562,7 +562,7 @@ uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map)
if (pp) {
int r;
- condlog(0, "%s: spurious uevent, path already in pathvec",
+ condlog(2, "%s: spurious uevent, path already in pathvec",
uev->kernel);
if (!pp->mpp && !strlen(pp->wwid)) {
condlog(3, "%s: reinitialize path", uev->kernel);
--
2.7.4

View File

@ -15,10 +15,10 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc
index d953f5e..5145909 100644
index 57a1835..f589ab0 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -48,7 +48,7 @@ endif
@@ -51,7 +51,7 @@ endif
prefix =
exec_prefix = $(prefix)
usr_prefix = $(prefix)
@ -40,7 +40,7 @@ index 8f99049..8a3a171 100644
LABEL="kpartx_end"
diff --git a/multipath/Makefile b/multipath/Makefile
index 468c056..dda5565 100644
index 0828a8f..b9bbb3c 100644
--- a/multipath/Makefile
+++ b/multipath/Makefile
@@ -24,7 +24,7 @@ install:

View File

@ -1,68 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 7 Feb 2018 16:06:06 -0600
Subject: [PATCH] multipath: print sysfs state in fast list mode
commit b123e711ea2a4b471a98ff5e26815df3773636b5 "libmultipath: cleanup
orphan device states" stopped multipathd from showing old state for
orphan paths by checking if pp->mpp was set, and only printing the state
if it was. Unfortunately, when "multipath -l" is run, pp->mpp isn't
set. While the checker state isn't checked and shouldn't be printed with
"-l", the sysfs state can be, and was before b123e711. This patch sets
pp->mpp in fast list mode, so that the sysfs state gets printed. It
also verifies that the path exists in sysfs, and if not, marks it as
faulty.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/main.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/multipath/main.c b/multipath/main.c
index bffe065..d2415a9 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -149,7 +149,7 @@ usage (char * progname)
}
static int
-update_paths (struct multipath * mpp)
+update_paths (struct multipath * mpp, int quick)
{
int i, j;
struct pathgroup * pgp;
@@ -171,9 +171,12 @@ update_paths (struct multipath * mpp)
* path is not in sysfs anymore
*/
pp->chkrstate = pp->state = PATH_DOWN;
+ pp->offline = 1;
continue;
}
pp->mpp = mpp;
+ if (quick)
+ continue;
conf = get_multipath_config();
if (pathinfo(pp, conf, DI_ALL))
pp->state = PATH_UNCHECKED;
@@ -181,6 +184,8 @@ update_paths (struct multipath * mpp)
continue;
}
pp->mpp = mpp;
+ if (quick)
+ continue;
if (pp->state == PATH_UNCHECKED ||
pp->state == PATH_WILD) {
conf = get_multipath_config();
@@ -238,8 +243,7 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
* If not in "fast list mode", we need to fetch information
* about them
*/
- if (cmd != CMD_LIST_SHORT)
- update_paths(mpp);
+ update_paths(mpp, (cmd == CMD_LIST_SHORT));
if (cmd == CMD_LIST_LONG)
mpp->bestpg = select_path_group(mpp);
--
2.7.4

View File

@ -51,10 +51,10 @@ index ee396e2..19d4697 100644
void
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index ab151e7..2201d7f 100644
index c4d0789..f046a54 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -1114,10 +1114,6 @@ The \fIWorld Wide Identification\fR of a device.
@@ -1131,10 +1131,6 @@ The \fIWorld Wide Identification\fR of a device.
.TP
.B property
Regular expression of the udev property to be whitelisted.

View File

@ -1,148 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 5 Feb 2018 16:07:36 -0600
Subject: [PATCH] libmultipath: move remove_map waiter code to multipathd
Only multipathd needs to worry about the multipath waiter code. There is
no point in having remove_map_and_stop_waiter() or
remove_maps_and_stop_waiters() in libmultipath, since they should never
be use outside of multipathd.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/structs_vec.c | 40 +++++-----------------------------------
libmultipath/structs_vec.h | 2 --
multipathd/main.c | 23 +++++++++++++++++++++++
3 files changed, 28 insertions(+), 37 deletions(-)
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 0de2221..abf5327 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -116,25 +116,16 @@ set_multipath_wwid (struct multipath * mpp)
dm_get_uuid(mpp->alias, mpp->wwid);
}
-#define KEEP_WAITER 0
-#define STOP_WAITER 1
#define PURGE_VEC 1
-static void
-_remove_map (struct multipath * mpp, struct vectors * vecs,
- int stop_waiter, int purge_vec)
+void
+remove_map(struct multipath * mpp, struct vectors * vecs, int purge_vec)
{
int i;
condlog(4, "%s: remove multipath map", mpp->alias);
/*
- * stop the DM event waiter thread
- */
- if (stop_waiter)
- stop_waiter_thread(mpp, vecs);
-
- /*
* clear references to this map
*/
orphan_paths(vecs->pathvec, mpp);
@@ -149,19 +140,8 @@ _remove_map (struct multipath * mpp, struct vectors * vecs,
free_multipath(mpp, KEEP_PATHS);
}
-void remove_map(struct multipath *mpp, struct vectors *vecs, int purge_vec)
-{
- _remove_map(mpp, vecs, KEEP_WAITER, purge_vec);
-}
-
-void remove_map_and_stop_waiter(struct multipath *mpp, struct vectors *vecs,
- int purge_vec)
-{
- _remove_map(mpp, vecs, STOP_WAITER, purge_vec);
-}
-
-static void
-_remove_maps (struct vectors * vecs, int stop_waiter)
+void
+remove_maps(struct vectors * vecs)
{
int i;
struct multipath * mpp;
@@ -170,7 +150,7 @@ _remove_maps (struct vectors * vecs, int stop_waiter)
return;
vector_foreach_slot (vecs->mpvec, mpp, i) {
- _remove_map(mpp, vecs, stop_waiter, 1);
+ remove_map(mpp, vecs, 1);
i--;
}
@@ -178,16 +158,6 @@ _remove_maps (struct vectors * vecs, int stop_waiter)
vecs->mpvec = NULL;
}
-void remove_maps(struct vectors *vecs)
-{
- _remove_maps(vecs, KEEP_WAITER);
-}
-
-void remove_maps_and_stop_waiters(struct vectors *vecs)
-{
- _remove_maps(vecs, STOP_WAITER);
-}
-
void
extract_hwe_from_path(struct multipath * mpp)
{
diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h
index b81413b..d6e17bb 100644
--- a/libmultipath/structs_vec.h
+++ b/libmultipath/structs_vec.h
@@ -27,9 +27,7 @@ int update_multipath_strings (struct multipath *mpp, vector pathvec,
void extract_hwe_from_path(struct multipath * mpp);
void remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec);
-void remove_map_and_stop_waiter (struct multipath * mpp, struct vectors * vecs, int purge_vec);
void remove_maps (struct vectors * vecs);
-void remove_maps_and_stop_waiters (struct vectors * vecs);
void sync_map_state (struct multipath *);
int update_map (struct multipath *mpp, struct vectors *vecs);
diff --git a/multipathd/main.c b/multipathd/main.c
index 7ac59d9..72c3c2f 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -288,6 +288,29 @@ switch_pathgroup (struct multipath * mpp)
mpp->alias, mpp->bestpg);
}
+static void
+remove_map_and_stop_waiter(struct multipath *mpp, struct vectors *vecs,
+ int purge_vec)
+{
+ stop_waiter_thread(mpp, vecs);
+ remove_map(mpp, vecs, purge_vec);
+}
+
+static void
+remove_maps_and_stop_waiters(struct vectors *vecs)
+{
+ int i;
+ struct multipath * mpp;
+
+ if (!vecs)
+ return;
+
+ vector_foreach_slot(vecs->mpvec, mpp, i)
+ stop_waiter_thread(mpp, vecs);
+
+ remove_maps(vecs);
+}
+
static int
coalesce_maps(struct vectors *vecs, vector nmpv)
{
--
2.7.4

View File

@ -20,7 +20,7 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
5 files changed, 20 insertions(+)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 3d6a24c..27826fa 100644
index 085a3e1..83d26be 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -26,6 +26,7 @@
@ -53,7 +53,7 @@ index 3d6a24c..27826fa 100644
conf->processed_main_config = 1;
diff --git a/libmultipath/config.h b/libmultipath/config.h
index a20ac2a..21a3bbd 100644
index 329f3ed..bc34eb7 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -9,6 +9,7 @@
@ -65,7 +65,7 @@ index a20ac2a..21a3bbd 100644
/*
* In kernel, fast_io_fail == 0 means immediate failure on rport delete.
diff --git a/multipath/multipath.rules b/multipath/multipath.rules
index bc1a852..2bc0348 100644
index 6f8ee2b..d1a484e 100644
--- a/multipath/multipath.rules
+++ b/multipath/multipath.rules
@@ -7,6 +7,7 @@ IMPORT{cmdline}="nompath"
@ -90,11 +90,11 @@ index 5c96680..0515211 100644
.
.\" ----------------------------------------------------------------------------
diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service
index fd66cf6..fafd088 100644
index ba24983..17434ce 100644
--- a/multipathd/multipathd.service
+++ b/multipathd/multipathd.service
@@ -4,6 +4,7 @@ Wants=systemd-udev-trigger.service systemd-udev-settle.service
Before=iscsi.service iscsid.service lvm2-lvmetad.service lvm2-activation-early.service
Before=iscsi.service iscsid.service lvm2-activation-early.service
Before=local-fs-pre.target blk-availability.service
After=multipathd.socket systemd-udev-trigger.service systemd-udev-settle.service
+ConditionPathExists=/etc/multipath.conf

View File

@ -1,793 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 5 Feb 2018 18:50:45 -0600
Subject: [PATCH] move waiter code from libmultipath to multipathd
Only multipathd uses the code in waiter.[ch] and the functions that call
it directly, so they should all live in the multipathd directory. This
patch is simply moving the waiter.[ch] files and the functions in
structs_vec that use them. None of the moved code has been changed.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/Makefile | 2 +-
libmultipath/structs_vec.c | 98 ---------------------
libmultipath/structs_vec.h | 4 +-
libmultipath/waiter.c | 215 ---------------------------------------------
libmultipath/waiter.h | 17 ----
multipathd/Makefile | 2 +-
multipathd/main.c | 96 ++++++++++++++++++++
multipathd/waiter.c | 215 +++++++++++++++++++++++++++++++++++++++++++++
multipathd/waiter.h | 17 ++++
9 files changed, 332 insertions(+), 334 deletions(-)
delete mode 100644 libmultipath/waiter.c
delete mode 100644 libmultipath/waiter.h
create mode 100644 multipathd/waiter.c
create mode 100644 multipathd/waiter.h
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
index 6447d8d..a1005b2 100644
--- a/libmultipath/Makefile
+++ b/libmultipath/Makefile
@@ -42,7 +42,7 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.o \
pgpolicies.o debug.o defaults.o uevent.o time-util.o \
switchgroup.o uxsock.o print.o alias.o log_pthread.o \
log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
- lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \
+ lock.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \
io_err_stat.o
all: $(LIBS)
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index abf5327..77b045b 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -10,7 +10,6 @@
#include "structs.h"
#include "structs_vec.h"
#include "sysfs.h"
-#include "waiter.h"
#include "devmapper.h"
#include "dmparser.h"
#include "propsel.h"
@@ -107,17 +106,6 @@ void orphan_paths(vector pathvec, struct multipath *mpp)
}
}
-static void
-set_multipath_wwid (struct multipath * mpp)
-{
- if (strlen(mpp->wwid))
- return;
-
- dm_get_uuid(mpp->alias, mpp->wwid);
-}
-
-#define PURGE_VEC 1
-
void
remove_map(struct multipath * mpp, struct vectors * vecs, int purge_vec)
{
@@ -379,92 +367,6 @@ sync_map_state(struct multipath *mpp)
}
}
-int
-update_map (struct multipath *mpp, struct vectors *vecs)
-{
- int retries = 3;
- char params[PARAMS_SIZE] = {0};
-
-retry:
- condlog(4, "%s: updating new map", mpp->alias);
- if (adopt_paths(vecs->pathvec, mpp)) {
- condlog(0, "%s: failed to adopt paths for new map update",
- mpp->alias);
- retries = -1;
- goto fail;
- }
- verify_paths(mpp, vecs);
- mpp->action = ACT_RELOAD;
-
- extract_hwe_from_path(mpp);
- if (setup_map(mpp, params, PARAMS_SIZE)) {
- condlog(0, "%s: failed to setup new map in update", mpp->alias);
- retries = -1;
- goto fail;
- }
- if (domap(mpp, params, 1) <= 0 && retries-- > 0) {
- condlog(0, "%s: map_udate sleep", mpp->alias);
- sleep(1);
- goto retry;
- }
- dm_lib_release();
-
-fail:
- if (setup_multipath(vecs, mpp))
- return 1;
-
- sync_map_state(mpp);
-
- if (retries < 0)
- condlog(0, "%s: failed reload in new map update", mpp->alias);
- return 0;
-}
-
-struct multipath *add_map_without_path (struct vectors *vecs, char *alias)
-{
- struct multipath * mpp = alloc_multipath();
- struct config *conf;
-
- if (!mpp)
- return NULL;
- if (!alias) {
- FREE(mpp);
- return NULL;
- }
-
- mpp->alias = STRDUP(alias);
-
- if (dm_get_info(mpp->alias, &mpp->dmi)) {
- condlog(3, "%s: cannot access table", mpp->alias);
- goto out;
- }
- set_multipath_wwid(mpp);
- conf = get_multipath_config();
- mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
- put_multipath_config(conf);
-
- if (update_multipath_table(mpp, vecs->pathvec, 1))
- goto out;
- if (update_multipath_status(mpp))
- goto out;
-
- if (!vector_alloc_slot(vecs->mpvec))
- goto out;
-
- vector_set_slot(vecs->mpvec, mpp);
-
- if (update_map(mpp, vecs) != 0) /* map removed */
- return NULL;
-
- if (start_waiter_thread(mpp, vecs))
- goto out;
-
- return mpp;
-out:
- remove_map(mpp, vecs, PURGE_VEC);
- return NULL;
-}
-
static void
find_existing_alias (struct multipath * mpp,
struct vectors *vecs)
diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h
index d6e17bb..ceab6d9 100644
--- a/libmultipath/structs_vec.h
+++ b/libmultipath/structs_vec.h
@@ -26,12 +26,12 @@ int update_multipath_strings (struct multipath *mpp, vector pathvec,
int is_daemon);
void extract_hwe_from_path(struct multipath * mpp);
+#define PURGE_VEC 1
+
void remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec);
void remove_maps (struct vectors * vecs);
void sync_map_state (struct multipath *);
-int update_map (struct multipath *mpp, struct vectors *vecs);
-struct multipath * add_map_without_path (struct vectors * vecs, char * alias);
struct multipath * add_map_with_path (struct vectors * vecs,
struct path * pp, int add_vec);
int update_multipath (struct vectors *vecs, char *mapname, int reset);
diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c
deleted file mode 100644
index cb9708b..0000000
--- a/libmultipath/waiter.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (c) 2004, 2005 Christophe Varoqui
- * Copyright (c) 2005 Kiyoshi Ueda, NEC
- * Copyright (c) 2005 Benjamin Marzinski, Redhat
- * Copyright (c) 2005 Edward Goggin, EMC
- */
-#include <unistd.h>
-#include <libdevmapper.h>
-#include <sys/mman.h>
-#include <pthread.h>
-#include <signal.h>
-#include <urcu.h>
-
-#include "vector.h"
-#include "memory.h"
-#include "checkers.h"
-#include "config.h"
-#include "structs.h"
-#include "structs_vec.h"
-#include "devmapper.h"
-#include "debug.h"
-#include "lock.h"
-#include "waiter.h"
-
-pthread_attr_t waiter_attr;
-
-static struct event_thread *alloc_waiter (void)
-{
-
- struct event_thread *wp;
-
- wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
- memset(wp, 0, sizeof(struct event_thread));
-
- return wp;
-}
-
-static void free_waiter (void *data)
-{
- struct event_thread *wp = (struct event_thread *)data;
-
- if (wp->dmt)
- dm_task_destroy(wp->dmt);
-
- rcu_unregister_thread();
- FREE(wp);
-}
-
-void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
-{
- pthread_t thread;
-
- if (mpp->waiter == (pthread_t)0) {
- condlog(3, "%s: event checker thread already stopped",
- mpp->alias);
- return;
- }
- condlog(2, "%s: stop event checker thread (%lu)", mpp->alias,
- mpp->waiter);
- thread = mpp->waiter;
- mpp->waiter = (pthread_t)0;
- pthread_cancel(thread);
- pthread_kill(thread, SIGUSR2);
-}
-
-/*
- * returns the reschedule delay
- * negative means *stop*
- */
-static int waiteventloop (struct event_thread *waiter)
-{
- sigset_t set, oldset;
- int event_nr;
- int r;
-
- if (!waiter->event_nr)
- waiter->event_nr = dm_geteventnr(waiter->mapname);
-
- if (!(waiter->dmt = libmp_dm_task_create(DM_DEVICE_WAITEVENT))) {
- condlog(0, "%s: devmap event #%i dm_task_create error",
- waiter->mapname, waiter->event_nr);
- return 1;
- }
-
- if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
- condlog(0, "%s: devmap event #%i dm_task_set_name error",
- waiter->mapname, waiter->event_nr);
- dm_task_destroy(waiter->dmt);
- waiter->dmt = NULL;
- return 1;
- }
-
- if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
- waiter->event_nr)) {
- condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
- waiter->mapname, waiter->event_nr);
- dm_task_destroy(waiter->dmt);
- waiter->dmt = NULL;
- return 1;
- }
-
- dm_task_no_open_count(waiter->dmt);
-
- /* wait */
- sigemptyset(&set);
- sigaddset(&set, SIGUSR2);
- pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
-
- pthread_testcancel();
- r = dm_task_run(waiter->dmt);
- pthread_testcancel();
-
- pthread_sigmask(SIG_SETMASK, &oldset, NULL);
- dm_task_destroy(waiter->dmt);
- waiter->dmt = NULL;
-
- if (!r) /* wait interrupted by signal */
- return -1;
-
- waiter->event_nr++;
-
- /*
- * upon event ...
- */
- while (1) {
- condlog(3, "%s: devmap event #%i",
- waiter->mapname, waiter->event_nr);
-
- /*
- * event might be :
- *
- * 1) a table reload, which means our mpp structure is
- * obsolete : refresh it through update_multipath()
- * 2) a path failed by DM : mark as such through
- * update_multipath()
- * 3) map has gone away : stop the thread.
- * 4) a path reinstate : nothing to do
- * 5) a switch group : nothing to do
- */
- pthread_cleanup_push(cleanup_lock, &waiter->vecs->lock);
- lock(&waiter->vecs->lock);
- pthread_testcancel();
- r = update_multipath(waiter->vecs, waiter->mapname, 1);
- lock_cleanup_pop(waiter->vecs->lock);
-
- if (r) {
- condlog(2, "%s: event checker exit",
- waiter->mapname);
- return -1; /* stop the thread */
- }
-
- event_nr = dm_geteventnr(waiter->mapname);
-
- if (waiter->event_nr == event_nr)
- return 1; /* upon problem reschedule 1s later */
-
- waiter->event_nr = event_nr;
- }
- return -1; /* never reach there */
-}
-
-static void *waitevent (void *et)
-{
- int r;
- struct event_thread *waiter;
-
- mlockall(MCL_CURRENT | MCL_FUTURE);
-
- waiter = (struct event_thread *)et;
- pthread_cleanup_push(free_waiter, et);
-
- rcu_register_thread();
- while (1) {
- r = waiteventloop(waiter);
-
- if (r < 0)
- break;
-
- sleep(r);
- }
-
- pthread_cleanup_pop(1);
- return NULL;
-}
-
-int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
-{
- struct event_thread *wp;
-
- if (!mpp)
- return 0;
-
- wp = alloc_waiter();
-
- if (!wp)
- goto out;
-
- strncpy(wp->mapname, mpp->alias, WWID_SIZE - 1);
- wp->vecs = vecs;
-
- if (pthread_create(&wp->thread, &waiter_attr, waitevent, wp)) {
- condlog(0, "%s: cannot create event checker", wp->mapname);
- goto out1;
- }
- mpp->waiter = wp->thread;
- condlog(2, "%s: event checker started", wp->mapname);
-
- return 0;
-out1:
- free_waiter(wp);
- mpp->waiter = (pthread_t)0;
-out:
- condlog(0, "failed to start waiter thread");
- return 1;
-}
diff --git a/libmultipath/waiter.h b/libmultipath/waiter.h
deleted file mode 100644
index 0cfae46..0000000
--- a/libmultipath/waiter.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _WAITER_H
-#define _WAITER_H
-
-extern pthread_attr_t waiter_attr;
-
-struct event_thread {
- struct dm_task *dmt;
- pthread_t thread;
- int event_nr;
- char mapname[WWID_SIZE];
- struct vectors *vecs;
-};
-
-void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs);
-int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
-
-#endif /* _WAITER_H */
diff --git a/multipathd/Makefile b/multipathd/Makefile
index e6f140b..85f29a7 100644
--- a/multipathd/Makefile
+++ b/multipathd/Makefile
@@ -22,7 +22,7 @@ ifdef SYSTEMD
endif
endif
-OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o
+OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o
EXEC = multipathd
diff --git a/multipathd/main.c b/multipathd/main.c
index 72c3c2f..94b2406 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -311,6 +311,102 @@ remove_maps_and_stop_waiters(struct vectors *vecs)
remove_maps(vecs);
}
+static void
+set_multipath_wwid (struct multipath * mpp)
+{
+ if (strlen(mpp->wwid))
+ return;
+
+ dm_get_uuid(mpp->alias, mpp->wwid);
+}
+
+static int
+update_map (struct multipath *mpp, struct vectors *vecs)
+{
+ int retries = 3;
+ char params[PARAMS_SIZE] = {0};
+
+retry:
+ condlog(4, "%s: updating new map", mpp->alias);
+ if (adopt_paths(vecs->pathvec, mpp)) {
+ condlog(0, "%s: failed to adopt paths for new map update",
+ mpp->alias);
+ retries = -1;
+ goto fail;
+ }
+ verify_paths(mpp, vecs);
+ mpp->action = ACT_RELOAD;
+
+ extract_hwe_from_path(mpp);
+ if (setup_map(mpp, params, PARAMS_SIZE)) {
+ condlog(0, "%s: failed to setup new map in update", mpp->alias);
+ retries = -1;
+ goto fail;
+ }
+ if (domap(mpp, params, 1) <= 0 && retries-- > 0) {
+ condlog(0, "%s: map_udate sleep", mpp->alias);
+ sleep(1);
+ goto retry;
+ }
+ dm_lib_release();
+
+fail:
+ if (setup_multipath(vecs, mpp))
+ return 1;
+
+ sync_map_state(mpp);
+
+ if (retries < 0)
+ condlog(0, "%s: failed reload in new map update", mpp->alias);
+ return 0;
+}
+
+static struct multipath *
+add_map_without_path (struct vectors *vecs, char *alias)
+{
+ struct multipath * mpp = alloc_multipath();
+ struct config *conf;
+
+ if (!mpp)
+ return NULL;
+ if (!alias) {
+ FREE(mpp);
+ return NULL;
+ }
+
+ mpp->alias = STRDUP(alias);
+
+ if (dm_get_info(mpp->alias, &mpp->dmi)) {
+ condlog(3, "%s: cannot access table", mpp->alias);
+ goto out;
+ }
+ set_multipath_wwid(mpp);
+ conf = get_multipath_config();
+ mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
+ put_multipath_config(conf);
+
+ if (update_multipath_table(mpp, vecs->pathvec, 1))
+ goto out;
+ if (update_multipath_status(mpp))
+ goto out;
+
+ if (!vector_alloc_slot(vecs->mpvec))
+ goto out;
+
+ vector_set_slot(vecs->mpvec, mpp);
+
+ if (update_map(mpp, vecs) != 0) /* map removed */
+ return NULL;
+
+ if (start_waiter_thread(mpp, vecs))
+ goto out;
+
+ return mpp;
+out:
+ remove_map(mpp, vecs, PURGE_VEC);
+ return NULL;
+}
+
static int
coalesce_maps(struct vectors *vecs, vector nmpv)
{
diff --git a/multipathd/waiter.c b/multipathd/waiter.c
new file mode 100644
index 0000000..cb9708b
--- /dev/null
+++ b/multipathd/waiter.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Edward Goggin, EMC
+ */
+#include <unistd.h>
+#include <libdevmapper.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <signal.h>
+#include <urcu.h>
+
+#include "vector.h"
+#include "memory.h"
+#include "checkers.h"
+#include "config.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "devmapper.h"
+#include "debug.h"
+#include "lock.h"
+#include "waiter.h"
+
+pthread_attr_t waiter_attr;
+
+static struct event_thread *alloc_waiter (void)
+{
+
+ struct event_thread *wp;
+
+ wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
+ memset(wp, 0, sizeof(struct event_thread));
+
+ return wp;
+}
+
+static void free_waiter (void *data)
+{
+ struct event_thread *wp = (struct event_thread *)data;
+
+ if (wp->dmt)
+ dm_task_destroy(wp->dmt);
+
+ rcu_unregister_thread();
+ FREE(wp);
+}
+
+void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+{
+ pthread_t thread;
+
+ if (mpp->waiter == (pthread_t)0) {
+ condlog(3, "%s: event checker thread already stopped",
+ mpp->alias);
+ return;
+ }
+ condlog(2, "%s: stop event checker thread (%lu)", mpp->alias,
+ mpp->waiter);
+ thread = mpp->waiter;
+ mpp->waiter = (pthread_t)0;
+ pthread_cancel(thread);
+ pthread_kill(thread, SIGUSR2);
+}
+
+/*
+ * returns the reschedule delay
+ * negative means *stop*
+ */
+static int waiteventloop (struct event_thread *waiter)
+{
+ sigset_t set, oldset;
+ int event_nr;
+ int r;
+
+ if (!waiter->event_nr)
+ waiter->event_nr = dm_geteventnr(waiter->mapname);
+
+ if (!(waiter->dmt = libmp_dm_task_create(DM_DEVICE_WAITEVENT))) {
+ condlog(0, "%s: devmap event #%i dm_task_create error",
+ waiter->mapname, waiter->event_nr);
+ return 1;
+ }
+
+ if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
+ condlog(0, "%s: devmap event #%i dm_task_set_name error",
+ waiter->mapname, waiter->event_nr);
+ dm_task_destroy(waiter->dmt);
+ waiter->dmt = NULL;
+ return 1;
+ }
+
+ if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
+ waiter->event_nr)) {
+ condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
+ waiter->mapname, waiter->event_nr);
+ dm_task_destroy(waiter->dmt);
+ waiter->dmt = NULL;
+ return 1;
+ }
+
+ dm_task_no_open_count(waiter->dmt);
+
+ /* wait */
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR2);
+ pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
+
+ pthread_testcancel();
+ r = dm_task_run(waiter->dmt);
+ pthread_testcancel();
+
+ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ dm_task_destroy(waiter->dmt);
+ waiter->dmt = NULL;
+
+ if (!r) /* wait interrupted by signal */
+ return -1;
+
+ waiter->event_nr++;
+
+ /*
+ * upon event ...
+ */
+ while (1) {
+ condlog(3, "%s: devmap event #%i",
+ waiter->mapname, waiter->event_nr);
+
+ /*
+ * event might be :
+ *
+ * 1) a table reload, which means our mpp structure is
+ * obsolete : refresh it through update_multipath()
+ * 2) a path failed by DM : mark as such through
+ * update_multipath()
+ * 3) map has gone away : stop the thread.
+ * 4) a path reinstate : nothing to do
+ * 5) a switch group : nothing to do
+ */
+ pthread_cleanup_push(cleanup_lock, &waiter->vecs->lock);
+ lock(&waiter->vecs->lock);
+ pthread_testcancel();
+ r = update_multipath(waiter->vecs, waiter->mapname, 1);
+ lock_cleanup_pop(waiter->vecs->lock);
+
+ if (r) {
+ condlog(2, "%s: event checker exit",
+ waiter->mapname);
+ return -1; /* stop the thread */
+ }
+
+ event_nr = dm_geteventnr(waiter->mapname);
+
+ if (waiter->event_nr == event_nr)
+ return 1; /* upon problem reschedule 1s later */
+
+ waiter->event_nr = event_nr;
+ }
+ return -1; /* never reach there */
+}
+
+static void *waitevent (void *et)
+{
+ int r;
+ struct event_thread *waiter;
+
+ mlockall(MCL_CURRENT | MCL_FUTURE);
+
+ waiter = (struct event_thread *)et;
+ pthread_cleanup_push(free_waiter, et);
+
+ rcu_register_thread();
+ while (1) {
+ r = waiteventloop(waiter);
+
+ if (r < 0)
+ break;
+
+ sleep(r);
+ }
+
+ pthread_cleanup_pop(1);
+ return NULL;
+}
+
+int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+{
+ struct event_thread *wp;
+
+ if (!mpp)
+ return 0;
+
+ wp = alloc_waiter();
+
+ if (!wp)
+ goto out;
+
+ strncpy(wp->mapname, mpp->alias, WWID_SIZE - 1);
+ wp->vecs = vecs;
+
+ if (pthread_create(&wp->thread, &waiter_attr, waitevent, wp)) {
+ condlog(0, "%s: cannot create event checker", wp->mapname);
+ goto out1;
+ }
+ mpp->waiter = wp->thread;
+ condlog(2, "%s: event checker started", wp->mapname);
+
+ return 0;
+out1:
+ free_waiter(wp);
+ mpp->waiter = (pthread_t)0;
+out:
+ condlog(0, "failed to start waiter thread");
+ return 1;
+}
diff --git a/multipathd/waiter.h b/multipathd/waiter.h
new file mode 100644
index 0000000..0cfae46
--- /dev/null
+++ b/multipathd/waiter.h
@@ -0,0 +1,17 @@
+#ifndef _WAITER_H
+#define _WAITER_H
+
+extern pthread_attr_t waiter_attr;
+
+struct event_thread {
+ struct dm_task *dmt;
+ pthread_t thread;
+ int event_nr;
+ char mapname[WWID_SIZE];
+ struct vectors *vecs;
+};
+
+void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs);
+int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
+
+#endif /* _WAITER_H */
--
2.7.4

View File

@ -9,14 +9,14 @@ still being generic.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile.inc | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
Makefile.inc | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc
index 5145909..0b4ee17 100644
index f589ab0..c07023a 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -82,13 +82,21 @@ TEST_CC_OPTION = $(shell \
@@ -85,14 +85,22 @@ TEST_CC_OPTION = $(shell \
echo "$(2)"; \
fi)
@ -25,6 +25,7 @@ index 5145909..0b4ee17 100644
-OPTFLAGS = -O2 -g -pipe -Wall -Wextra -Wformat=2 -Werror=implicit-int \
- -Werror=implicit-function-declaration -Werror=format-security \
- -Wno-sign-compare -Wno-unused-parameter -Wno-clobbered \
- -Werror=cast-qual -Werror=discarded-qualifiers \
- -Wp,-D_FORTIFY_SOURCE=2 $(STACKPROT) \
- --param=ssp-buffer-size=4
+ifndef RPM_OPT_FLAGS
@ -41,10 +42,11 @@ index 5145909..0b4ee17 100644
+endif
+OPTFLAGS += -Wextra -Wstrict-prototypes -Wformat=2 -Werror=implicit-int \
+ -Werror=implicit-function-declaration -Wno-sign-compare \
+ -Wno-unused-parameter
+ -Wno-unused-parameter -Werror=cast-qual \
+ -Werror=discarded-qualifiers
CFLAGS := $(OPTFLAGS) -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
$(CFLAGS)
CFLAGS := $(OPTFLAGS) -DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
-MMD -MP $(CFLAGS)
--
2.7.4

View File

@ -1,129 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 5 Feb 2018 21:59:16 -0600
Subject: [PATCH] call start_waiter_thread() before setup_multipath()
If setup_multipath() is called before the waiter thread has started,
there is a window where a dm event can occur between when
setup_multipath() updates the device state and when the waiter thread
starts waiting for new events, causing the new event to be missed and
the multipath device to not get updated.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/main.c | 37 ++++++++++++++++++++-----------------
1 file changed, 20 insertions(+), 17 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index 94b2406..efc39d7 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -321,7 +321,7 @@ set_multipath_wwid (struct multipath * mpp)
}
static int
-update_map (struct multipath *mpp, struct vectors *vecs)
+update_map (struct multipath *mpp, struct vectors *vecs, int new_map)
{
int retries = 3;
char params[PARAMS_SIZE] = {0};
@@ -351,6 +351,12 @@ retry:
dm_lib_release();
fail:
+ if (new_map && (retries < 0 || start_waiter_thread(mpp, vecs))) {
+ condlog(0, "%s: failed to create new map", mpp->alias);
+ remove_map(mpp, vecs, 1);
+ return 1;
+ }
+
if (setup_multipath(vecs, mpp))
return 1;
@@ -395,12 +401,9 @@ add_map_without_path (struct vectors *vecs, char *alias)
vector_set_slot(vecs->mpvec, mpp);
- if (update_map(mpp, vecs) != 0) /* map removed */
+ if (update_map(mpp, vecs, 1) != 0) /* map removed */
return NULL;
- if (start_waiter_thread(mpp, vecs))
- goto out;
-
return mpp;
out:
remove_map(mpp, vecs, PURGE_VEC);
@@ -554,7 +557,7 @@ ev_add_map (char * dev, char * alias, struct vectors * vecs)
if (mpp->wait_for_udev > 1) {
condlog(2, "%s: performing delayed actions",
mpp->alias);
- if (update_map(mpp, vecs))
+ if (update_map(mpp, vecs, 0))
/* setup multipathd removed the map */
return 1;
}
@@ -865,6 +868,11 @@ retry:
}
dm_lib_release();
+ if ((mpp->action == ACT_CREATE ||
+ (mpp->action == ACT_NOTHING && start_waiter && !mpp->waiter)) &&
+ start_waiter_thread(mpp, vecs))
+ goto fail_map;
+
/*
* update our state from kernel regardless of create or reload
*/
@@ -873,11 +881,6 @@ retry:
sync_map_state(mpp);
- if ((mpp->action == ACT_CREATE ||
- (mpp->action == ACT_NOTHING && start_waiter && !mpp->waiter)) &&
- start_waiter_thread(mpp, vecs))
- goto fail_map;
-
if (retries >= 0) {
condlog(2, "%s [%s]: path added to devmap %s",
pp->dev, pp->dev_t, mpp->alias);
@@ -1479,7 +1482,8 @@ missing_uev_wait_tick(struct vectors *vecs)
if (mpp->wait_for_udev && --mpp->uev_wait_tick <= 0) {
timed_out = 1;
condlog(0, "%s: timeout waiting on creation uevent. enabling reloads", mpp->alias);
- if (mpp->wait_for_udev > 1 && update_map(mpp, vecs)) {
+ if (mpp->wait_for_udev > 1 &&
+ update_map(mpp, vecs, 0)) {
/* update_map removed map */
i--;
continue;
@@ -1511,7 +1515,7 @@ ghost_delay_tick(struct vectors *vecs)
condlog(0, "%s: timed out waiting for active path",
mpp->alias);
mpp->force_udev_reload = 1;
- if (update_map(mpp, vecs) != 0) {
+ if (update_map(mpp, vecs, 0) != 0) {
/* update_map removed map */
i--;
continue;
@@ -2169,14 +2173,13 @@ configure (struct vectors * vecs)
* start dm event waiter threads for these new maps
*/
vector_foreach_slot(vecs->mpvec, mpp, i) {
- if (setup_multipath(vecs, mpp)) {
- i--;
- continue;
- }
if (start_waiter_thread(mpp, vecs)) {
remove_map(mpp, vecs, 1);
i--;
+ continue;
}
+ if (setup_multipath(vecs, mpp))
+ i--;
}
return 0;
}
--
2.7.4

View File

@ -21,7 +21,7 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
create mode 100644 multipath/mpathconf.8
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 27826fa..9bf4fb7 100644
index 83d26be..a50f41a 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -659,6 +659,7 @@ load_config (char * file)
@ -33,10 +33,10 @@ index 27826fa..9bf4fb7 100644
conf->blist_devnode = vector_alloc();
if (!conf->blist_devnode) {
diff --git a/multipath/Makefile b/multipath/Makefile
index dda5565..d35127a 100644
index b9bbb3c..e720c7f 100644
--- a/multipath/Makefile
+++ b/multipath/Makefile
@@ -18,10 +18,12 @@ $(EXEC): $(OBJS)
@@ -18,10 +18,12 @@ $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
$(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
$(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz
@ -64,7 +64,7 @@ index dda5565..d35127a 100644
$(RM) $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz
+ $(RM) $(DESTDIR)$(man8dir)/mpathconf.8.gz
clean:
clean: dep_clean
$(RM) core *.o $(EXEC) *.gz
diff --git a/multipath/mpathconf b/multipath/mpathconf
new file mode 100644

View File

@ -1,155 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 5 Feb 2018 10:40:24 -0600
Subject: [PATCH] libmultipath: add helper functions
Add the ability to reset a vector without completely freeing it, and to
check the version of the device-mapper module. The existing version
checking code checks the version of a specific device mapper target, and
has been renamed for clarity's sake. These functions will be used in a
later patch.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/devmapper.c | 28 ++++++++++++++++++++++++----
libmultipath/devmapper.h | 3 ++-
libmultipath/vector.c | 16 ++++++++++++----
libmultipath/vector.h | 1 +
multipathd/main.c | 2 +-
5 files changed, 40 insertions(+), 10 deletions(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 573fc75..2960bf5 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -132,7 +132,27 @@ dm_lib_prereq (void)
}
int
-dm_drv_version (unsigned int * version, char * str)
+dm_drv_version(unsigned int *v)
+{
+ char buff[64];
+
+ v[0] = 0;
+ v[1] = 0;
+ v[2] = 0;
+
+ if (!dm_driver_version(buff, sizeof(buff))) {
+ condlog(0, "cannot get kernel dm version");
+ return 1;
+ }
+ if (sscanf(buff, "%u.%u.%u ", &v[0], &v[1], &v[2]) != 3) {
+ condlog(0, "invalid kernel dm version '%s'", buff);
+ return 1;
+ }
+ return 0;
+}
+
+int
+dm_tgt_version (unsigned int * version, char * str)
{
int r = 2;
struct dm_task *dmt;
@@ -179,13 +199,13 @@ out:
}
static int
-dm_drv_prereq (unsigned int *ver)
+dm_tgt_prereq (unsigned int *ver)
{
unsigned int minv[3] = {1, 0, 3};
unsigned int version[3] = {0, 0, 0};
unsigned int * v = version;
- if (dm_drv_version(v, TGT_MPATH)) {
+ if (dm_tgt_version(v, TGT_MPATH)) {
/* in doubt return not capable */
return 1;
}
@@ -210,7 +230,7 @@ static int dm_prereq(unsigned int *v)
{
if (dm_lib_prereq())
return 1;
- return dm_drv_prereq(v);
+ return dm_tgt_prereq(v);
}
static int libmp_dm_udev_sync = 0;
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 62e14d1..52d4af8 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -28,7 +28,8 @@ void dm_init(int verbosity);
void libmp_dm_init(void);
void libmp_udev_set_sync_support(int on);
struct dm_task *libmp_dm_task_create(int task);
-int dm_drv_version (unsigned int * version, char * str);
+int dm_drv_version (unsigned int * version);
+int dm_tgt_version (unsigned int * version, char * str);
int dm_simplecmd_flush (int, const char *, uint16_t);
int dm_simplecmd_noflush (int, const char *, uint16_t);
int dm_addmap_create (struct multipath *mpp, char *params);
diff --git a/libmultipath/vector.c b/libmultipath/vector.c
index 6266e0a..f741ae0 100644
--- a/libmultipath/vector.c
+++ b/libmultipath/vector.c
@@ -145,18 +145,26 @@ vector_repack(vector v)
vector_del_slot(v, i--);
}
-/* Free memory vector allocation */
-void
-vector_free(vector v)
+vector
+vector_reset(vector v)
{
if (!v)
- return;
+ return NULL;
if (v->slot)
FREE(v->slot);
v->allocated = 0;
v->slot = NULL;
+ return v;
+}
+
+/* Free memory vector allocation */
+void
+vector_free(vector v)
+{
+ if (!vector_reset(v))
+ return;
FREE(v);
}
diff --git a/libmultipath/vector.h b/libmultipath/vector.h
index 5cfd4d0..d69cd0b 100644
--- a/libmultipath/vector.h
+++ b/libmultipath/vector.h
@@ -45,6 +45,7 @@ typedef struct _vector *vector;
/* Prototypes */
extern vector vector_alloc(void);
extern void *vector_alloc_slot(vector v);
+vector vector_reset(vector v);
extern void vector_free(vector v);
extern void free_strvec(vector strvec);
extern void vector_set_slot(vector v, void *value);
diff --git a/multipathd/main.c b/multipathd/main.c
index efc39d7..2963bde 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -2228,7 +2228,7 @@ reconfigure (struct vectors * vecs)
/* Re-read any timezone changes */
tzset();
- dm_drv_version(conf->version, TGT_MPATH);
+ dm_tgt_version(conf->version, TGT_MPATH);
if (verbosity)
conf->verbosity = verbosity;
if (bindings_read_only)
--
2.7.4

View File

@ -22,10 +22,10 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
5 files changed, 58 insertions(+), 3 deletions(-)
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
index bc70a27..88bb72b 100644
index 0ec9f25..9722714 100644
--- a/libmultipath/wwids.c
+++ b/libmultipath/wwids.c
@@ -321,3 +321,47 @@ remember_wwid(char *wwid)
@@ -323,3 +323,47 @@ remember_wwid(char *wwid)
condlog(4, "wwid %s already in wwids file", wwid);
return 0;
}
@ -85,10 +85,10 @@ index 9527012..b665232 100644
#endif /* _WWIDS_H */
diff --git a/multipath/main.c b/multipath/main.c
index d2415a9..ff570ac 100644
index d08c688..baf6759 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -102,7 +102,7 @@ usage (char * progname)
@@ -104,7 +104,7 @@ usage (char * progname)
{
fprintf (stderr, VERSION_STRING);
fprintf (stderr, "Usage:\n");
@ -97,7 +97,7 @@ index d2415a9..ff570ac 100644
fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [-R num] [dev]\n", progname);
fprintf (stderr, " %s -F [-v lvl] [-R num]\n", progname);
fprintf (stderr, " %s -t\n", progname);
@@ -116,6 +116,8 @@ usage (char * progname)
@@ -118,6 +118,8 @@ usage (char * progname)
" -f flush a multipath device map\n"
" -F flush all multipath device maps\n"
" -a add a device wwid to the wwids file\n"
@ -106,7 +106,7 @@ index d2415a9..ff570ac 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"
@@ -602,7 +604,7 @@ main (int argc, char *argv[])
@@ -672,7 +674,7 @@ main (int argc, char *argv[])
exit(1);
multipath_conf = conf;
conf->retrigger_tries = 0;
@ -115,7 +115,7 @@ index d2415a9..ff570ac 100644
switch(arg) {
case 1: printf("optarg : %s\n",optarg);
break;
@@ -669,6 +671,10 @@ main (int argc, char *argv[])
@@ -739,6 +741,10 @@ main (int argc, char *argv[])
case 't':
r = dump_config(conf);
goto out_free_config;
@ -150,7 +150,7 @@ index 56f8703..9fc2317 100644
.B \-U
Check if the device specified in the program environment is a multipath device
diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service
index fafd088..a623a3f 100644
index 17434ce..0fbcc46 100644
--- a/multipathd/multipathd.service
+++ b/multipathd/multipathd.service
@@ -15,6 +15,7 @@ Type=notify
@ -160,7 +160,7 @@ index fafd088..a623a3f 100644
+ExecStartPre=-/sbin/multipath -A
ExecStart=/sbin/multipathd -d -s
ExecReload=/sbin/multipathd reconfigure
TasksMax=infinity
--
2.7.4

View File

@ -1,643 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 6 Feb 2018 15:36:39 -0600
Subject: [PATCH] multipathd: RFC add new polling dmevents waiter thread
The current method of waiting for dmevents on multipath devices involves
creating a seperate thread for each device. This can become very
wasteful when there are large numbers of multipath devices. Also, since
multipathd needs to grab the vecs lock to update the devices, the
additional threads don't actually provide much parallelism.
The patch adds a new method of updating multipath devices on dmevents,
which uses the new device-mapper event polling interface. This means
that there is only one dmevent waiting thread which will wait for events
on all of the multipath devices. Currently the code to get the event
number from the list of device names and to re-arm the polling interface
is not in libdevmapper, so the patch does that work. Obviously, these
bits need to go into libdevmapper, so that multipathd can use a standard
interface.
I haven't touched any of the existing event waiting code, since event
polling was only added to device-mapper in version 4.37.0. multipathd
checks this version, and defaults to using the polling code if
device-mapper supports it. This can be overridden by running multipathd
with "-w", to force it to use the old event waiting code.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/Makefile | 3 +-
multipathd/dmevents.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++
multipathd/dmevents.h | 13 ++
multipathd/main.c | 58 +++++++-
4 files changed, 461 insertions(+), 9 deletions(-)
create mode 100644 multipathd/dmevents.c
create mode 100644 multipathd/dmevents.h
diff --git a/multipathd/Makefile b/multipathd/Makefile
index 85f29a7..4c438f0 100644
--- a/multipathd/Makefile
+++ b/multipathd/Makefile
@@ -22,7 +22,8 @@ ifdef SYSTEMD
endif
endif
-OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o
+OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o \
+ dmevents.o
EXEC = multipathd
diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c
new file mode 100644
index 0000000..a56c055
--- /dev/null
+++ b/multipathd/dmevents.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ * Copyright (c) 2005 Edward Goggin, EMC
+ * Copyright (c) 2005, 2018 Benjamin Marzinski, Redhat
+ */
+#include <unistd.h>
+#include <libdevmapper.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <urcu.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/dm-ioctl.h>
+#include <errno.h>
+
+#include "vector.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "devmapper.h"
+#include "debug.h"
+#include "dmevents.h"
+
+#ifndef DM_DEV_ARM_POLL
+#define DM_DEV_ARM_POLL _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD + 1, struct dm_ioctl)
+#endif
+
+enum event_actions {
+ EVENT_NOTHING,
+ EVENT_REMOVE,
+ EVENT_UPDATE,
+};
+
+struct dev_event {
+ char name[WWID_SIZE];
+ uint32_t evt_nr;
+ enum event_actions action;
+};
+
+struct dmevent_waiter {
+ int fd;
+ struct vectors *vecs;
+ vector events;
+ pthread_mutex_t events_lock;
+};
+
+static struct dmevent_waiter *waiter;
+
+int dmevent_poll_supported(void)
+{
+ unsigned int minv[3] = {4, 37, 0};
+ unsigned int v[3];
+
+ if (dm_drv_version(v))
+ return 0;
+
+ if (VERSION_GE(v, minv))
+ return 1;
+ return 0;
+}
+
+
+int alloc_dmevent_waiter(struct vectors *vecs)
+{
+ if (!vecs) {
+ condlog(0, "can't create waiter structure. invalid vectors");
+ goto fail;
+ }
+ waiter = (struct dmevent_waiter *)malloc(sizeof(struct dmevent_waiter));
+ if (!waiter) {
+ condlog(0, "failed to allocate waiter structure");
+ goto fail;
+ }
+ memset(waiter, 0, sizeof(struct dmevent_waiter));
+ waiter->events = vector_alloc();
+ if (!waiter->events) {
+ condlog(0, "failed to allocate waiter events vector");
+ goto fail_waiter;
+ }
+ waiter->fd = open("/dev/mapper/control", O_RDWR);
+ if (waiter->fd < 0) {
+ condlog(0, "failed to open /dev/mapper/control for waiter");
+ goto fail_events;
+ }
+ pthread_mutex_init(&waiter->events_lock, NULL);
+ waiter->vecs = vecs;
+
+ return 0;
+fail_events:
+ vector_free(waiter->events);
+fail_waiter:
+ free(waiter);
+fail:
+ waiter = NULL;
+ return -1;
+}
+
+void free_dmevent_waiter(void)
+{
+ struct dev_event *dev_evt;
+ int i;
+
+ if (!waiter)
+ return;
+ pthread_mutex_destroy(&waiter->events_lock);
+ close(waiter->fd);
+ vector_foreach_slot(waiter->events, dev_evt, i)
+ free(dev_evt);
+ vector_free(waiter->events);
+ free(waiter);
+ waiter = NULL;
+}
+
+static int arm_dm_event_poll(int fd)
+{
+ struct dm_ioctl dmi;
+ memset(&dmi, 0, sizeof(dmi));
+ dmi.version[0] = DM_VERSION_MAJOR;
+ dmi.version[1] = DM_VERSION_MINOR;
+ dmi.version[2] = DM_VERSION_PATCHLEVEL;
+ dmi.flags = 0x4;
+ dmi.data_start = offsetof(struct dm_ioctl, data);
+ dmi.data_size = sizeof(dmi);
+ return ioctl(fd, DM_DEV_ARM_POLL, &dmi);
+}
+
+/*
+ * As of version 4.37.0 device-mapper stores the event number in the
+ * dm_names structure after the name, when DM_DEVICE_LIST is called
+ */
+static uint32_t dm_event_nr(struct dm_names *n)
+{
+ return *(uint32_t *)(((uintptr_t)(strchr(n->name, 0) + 1) + 7) & ~7);
+}
+
+static int dm_get_events(void)
+{
+ struct dm_task *dmt;
+ struct dm_names *names;
+ struct dev_event *dev_evt;
+ int i;
+
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
+ return -1;
+
+ dm_task_no_open_count(dmt);
+
+ if (!dm_task_run(dmt))
+ goto fail;
+
+ if (!(names = dm_task_get_names(dmt)))
+ goto fail;
+
+ pthread_mutex_lock(&waiter->events_lock);
+ vector_foreach_slot(waiter->events, dev_evt, i)
+ dev_evt->action = EVENT_REMOVE;
+ while (names->dev) {
+ uint32_t event_nr;
+
+ if (!dm_is_mpath(names->name))
+ goto next;
+
+ event_nr = dm_event_nr(names);
+ vector_foreach_slot(waiter->events, dev_evt, i) {
+ if (!strcmp(dev_evt->name, names->name)) {
+ if (event_nr != dev_evt->evt_nr) {
+ dev_evt->evt_nr = event_nr;
+ dev_evt->action = EVENT_UPDATE;
+ } else
+ dev_evt->action = EVENT_NOTHING;
+ break;
+ }
+ }
+next:
+ if (!names->next)
+ break;
+ names = (void *)names + names->next;
+ }
+ pthread_mutex_unlock(&waiter->events_lock);
+ dm_task_destroy(dmt);
+ return 0;
+
+fail:
+ dm_task_destroy(dmt);
+ return -1;
+}
+
+/* You must call update_multipath() after calling this function, to
+ * deal with any events that came in before the device was added */
+int watch_dmevents(char *name)
+{
+ int event_nr;
+ struct dev_event *dev_evt, *old_dev_evt;
+ int i;
+
+ if (!dm_is_mpath(name)) {
+ condlog(0, "%s: not a multipath device. can't watch events",
+ name);
+ return -1;
+ }
+
+ if ((event_nr = dm_geteventnr(name)) < 0)
+ return -1;
+
+ dev_evt = (struct dev_event *)malloc(sizeof(struct dev_event));
+ if (!dev_evt) {
+ condlog(0, "%s: can't allocate event waiter structure", name);
+ return -1;
+ }
+
+ strncpy(dev_evt->name, name, WWID_SIZE);
+ dev_evt->name[WWID_SIZE - 1] = 0;
+ dev_evt->evt_nr = event_nr;
+ dev_evt->action = EVENT_NOTHING;
+
+ pthread_mutex_lock(&waiter->events_lock);
+ vector_foreach_slot(waiter->events, old_dev_evt, i){
+ if (!strcmp(dev_evt->name, old_dev_evt->name)) {
+ /* caller will be updating this device */
+ old_dev_evt->evt_nr = event_nr;
+ old_dev_evt->action = EVENT_NOTHING;
+ pthread_mutex_unlock(&waiter->events_lock);
+ condlog(2, "%s: already waiting for events on device",
+ name);
+ free(dev_evt);
+ return 0;
+ }
+ }
+ if (!vector_alloc_slot(waiter->events)) {
+ pthread_mutex_unlock(&waiter->events_lock);
+ free(dev_evt);
+ return -1;
+ }
+ vector_set_slot(waiter->events, dev_evt);
+ pthread_mutex_unlock(&waiter->events_lock);
+ return 0;
+}
+
+void unwatch_all_dmevents(void)
+{
+ struct dev_event *dev_evt;
+ int i;
+
+ pthread_mutex_lock(&waiter->events_lock);
+ vector_foreach_slot(waiter->events, dev_evt, i)
+ free(dev_evt);
+ vector_reset(waiter->events);
+ pthread_mutex_unlock(&waiter->events_lock);
+}
+
+static void unwatch_dmevents(char *name)
+{
+ struct dev_event *dev_evt;
+ int i;
+
+ pthread_mutex_lock(&waiter->events_lock);
+ vector_foreach_slot(waiter->events, dev_evt, i) {
+ if (!strcmp(dev_evt->name, name)) {
+ vector_del_slot(waiter->events, i);
+ free(dev_evt);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&waiter->events_lock);
+}
+
+/*
+ * returns the reschedule delay
+ * negative means *stop*
+ */
+
+/* poll, arm, update, return */
+static int dmevent_loop (void)
+{
+ int r, i = 0;
+ struct pollfd pfd;
+ struct dev_event *dev_evt;
+
+ pfd.fd = waiter->fd;
+ pfd.events = POLLIN;
+ r = poll(&pfd, 1, -1);
+ if (r <= 0) {
+ condlog(0, "failed polling for dm events: %s", strerror(errno));
+ /* sleep 1s and hope things get better */
+ return 1;
+ }
+
+ if (arm_dm_event_poll(waiter->fd) != 0) {
+ condlog(0, "Cannot re-arm event polling: %s", strerror(errno));
+ /* sleep 1s and hope things get better */
+ return 1;
+ }
+
+ if (dm_get_events() != 0) {
+ condlog(0, "failed getting dm events: %s", strerror(errno));
+ /* sleep 1s and hope things get better */
+ return 1;
+ }
+
+ /*
+ * upon event ...
+ */
+
+ while (1) {
+ int done = 1;
+ struct dev_event curr_dev;
+ struct multipath *mpp;
+
+ pthread_mutex_lock(&waiter->events_lock);
+ vector_foreach_slot(waiter->events, dev_evt, i) {
+ if (dev_evt->action != EVENT_NOTHING) {
+ curr_dev = *dev_evt;
+ if (dev_evt->action == EVENT_REMOVE) {
+ vector_del_slot(waiter->events, i);
+ free(dev_evt);
+ } else
+ dev_evt->action = EVENT_NOTHING;
+ done = 0;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&waiter->events_lock);
+ if (done)
+ return 1;
+
+ condlog(3, "%s: devmap event #%i", curr_dev.name,
+ curr_dev.evt_nr);
+
+ /*
+ * event might be :
+ *
+ * 1) a table reload, which means our mpp structure is
+ * obsolete : refresh it through update_multipath()
+ * 2) a path failed by DM : mark as such through
+ * update_multipath()
+ * 3) map has gone away : stop the thread.
+ * 4) a path reinstate : nothing to do
+ * 5) a switch group : nothing to do
+ */
+ pthread_cleanup_push(cleanup_lock, &waiter->vecs->lock);
+ lock(&waiter->vecs->lock);
+ pthread_testcancel();
+ r = 0;
+ if (curr_dev.action == EVENT_REMOVE) {
+ mpp = find_mp_by_alias(waiter->vecs->mpvec,
+ curr_dev.name);
+ if (mpp)
+ remove_map(mpp, waiter->vecs, 1);
+ } else
+ r = update_multipath(waiter->vecs, curr_dev.name, 1);
+ lock_cleanup_pop(&waiter->vecs->lock);
+
+ if (r) {
+ condlog(2, "%s: stopped watching dmevents",
+ curr_dev.name);
+ unwatch_dmevents(curr_dev.name);
+ }
+ }
+ condlog(0, "dmevent waiter thread unexpectedly quit");
+ return -1; /* never reach there */
+}
+
+static void rcu_unregister(void *param)
+{
+ rcu_unregister_thread();
+}
+
+void *wait_dmevents (void *unused)
+{
+ int r;
+
+
+ if (!waiter) {
+ condlog(0, "dmevents waiter not intialized");
+ return NULL;
+ }
+
+ pthread_cleanup_push(rcu_unregister, NULL);
+ rcu_register_thread();
+ mlockall(MCL_CURRENT | MCL_FUTURE);
+
+ while (1) {
+ r = dmevent_loop();
+
+ if (r < 0)
+ break;
+
+ sleep(r);
+ }
+
+ pthread_cleanup_pop(1);
+ return NULL;
+}
diff --git a/multipathd/dmevents.h b/multipathd/dmevents.h
new file mode 100644
index 0000000..569e855
--- /dev/null
+++ b/multipathd/dmevents.h
@@ -0,0 +1,13 @@
+#ifndef _DMEVENTS_H
+#define _DMEVENTS_H
+
+#include "structs_vec.h"
+
+int dmevent_poll_supported(void);
+int alloc_dmevent_waiter(struct vectors *vecs);
+void free_dmevent_waiter(void);
+int watch_dmevents(char *name);
+void unwatch_all_dmevents(void);
+void *wait_dmevents (void *unused);
+
+#endif /* _DMEVENTS_H */
diff --git a/multipathd/main.c b/multipathd/main.c
index 2963bde..6dabf2c 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -82,6 +82,7 @@ static int use_watchdog;
#include "cli_handlers.h"
#include "lock.h"
#include "waiter.h"
+#include "dmevents.h"
#include "io_err_stat.h"
#include "wwids.h"
#include "../third-party/valgrind/drd.h"
@@ -108,6 +109,7 @@ int uxsock_timeout;
int verbosity;
int bindings_read_only;
int ignore_new_devs;
+int poll_dmevents = 1;
enum daemon_status running_state = DAEMON_INIT;
pid_t daemon_pid;
pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -288,11 +290,23 @@ switch_pathgroup (struct multipath * mpp)
mpp->alias, mpp->bestpg);
}
+static int
+wait_for_events(struct multipath *mpp, struct vectors *vecs)
+{
+ if (poll_dmevents)
+ return watch_dmevents(mpp->alias);
+ else
+ return start_waiter_thread(mpp, vecs);
+}
+
static void
remove_map_and_stop_waiter(struct multipath *mpp, struct vectors *vecs,
int purge_vec)
{
- stop_waiter_thread(mpp, vecs);
+ /* devices are automatically removed by the dmevent polling code,
+ * so they don't need to be manually removed here */
+ if (!poll_dmevents)
+ stop_waiter_thread(mpp, vecs);
remove_map(mpp, vecs, purge_vec);
}
@@ -305,8 +319,12 @@ remove_maps_and_stop_waiters(struct vectors *vecs)
if (!vecs)
return;
- vector_foreach_slot(vecs->mpvec, mpp, i)
- stop_waiter_thread(mpp, vecs);
+ if (!poll_dmevents) {
+ vector_foreach_slot(vecs->mpvec, mpp, i)
+ stop_waiter_thread(mpp, vecs);
+ }
+ else
+ unwatch_all_dmevents();
remove_maps(vecs);
}
@@ -351,7 +369,7 @@ retry:
dm_lib_release();
fail:
- if (new_map && (retries < 0 || start_waiter_thread(mpp, vecs))) {
+ if (new_map && (retries < 0 || wait_for_events(mpp, vecs))) {
condlog(0, "%s: failed to create new map", mpp->alias);
remove_map(mpp, vecs, 1);
return 1;
@@ -870,7 +888,7 @@ retry:
if ((mpp->action == ACT_CREATE ||
(mpp->action == ACT_NOTHING && start_waiter && !mpp->waiter)) &&
- start_waiter_thread(mpp, vecs))
+ wait_for_events(mpp, vecs))
goto fail_map;
/*
@@ -2173,7 +2191,7 @@ configure (struct vectors * vecs)
* start dm event waiter threads for these new maps
*/
vector_foreach_slot(vecs->mpvec, mpp, i) {
- if (start_waiter_thread(mpp, vecs)) {
+ if (wait_for_events(mpp, vecs)) {
remove_map(mpp, vecs, 1);
i--;
continue;
@@ -2414,7 +2432,7 @@ set_oom_adj (void)
static int
child (void * param)
{
- pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr;
+ pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr;
pthread_attr_t log_attr, misc_attr, uevent_attr;
struct vectors * vecs;
struct multipath * mpp;
@@ -2476,6 +2494,8 @@ child (void * param)
goto failed;
}
+ if (poll_dmevents)
+ poll_dmevents = dmevent_poll_supported();
setlogmask(LOG_UPTO(conf->verbosity + 3));
envp = getenv("LimitNOFILE");
@@ -2542,6 +2562,19 @@ child (void * param)
init_path_check_interval(vecs);
+ if (poll_dmevents) {
+ if (alloc_dmevent_waiter(vecs)) {
+ condlog(0, "failed to allocate dmevents waiter info");
+ goto failed;
+ }
+ if ((rc = pthread_create(&dmevent_thr, &misc_attr,
+ wait_dmevents, NULL))) {
+ condlog(0, "failed to create dmevent waiter thread: %d",
+ rc);
+ goto failed;
+ }
+ }
+
/*
* Start uevent listener early to catch events
*/
@@ -2615,11 +2648,15 @@ child (void * param)
pthread_cancel(uevent_thr);
pthread_cancel(uxlsnr_thr);
pthread_cancel(uevq_thr);
+ if (poll_dmevents)
+ pthread_cancel(dmevent_thr);
pthread_join(check_thr, NULL);
pthread_join(uevent_thr, NULL);
pthread_join(uxlsnr_thr, NULL);
pthread_join(uevq_thr, NULL);
+ if (poll_dmevents)
+ pthread_join(dmevent_thr, NULL);
stop_io_err_stat_thread();
@@ -2634,6 +2671,8 @@ child (void * param)
cleanup_checkers();
cleanup_prio();
+ if (poll_dmevents)
+ free_dmevent_waiter();
dm_lib_release();
dm_lib_exit();
@@ -2765,7 +2804,7 @@ main (int argc, char *argv[])
udev = udev_new();
libmp_udev_set_sync_support(0);
- while ((arg = getopt(argc, argv, ":dsv:k::Bn")) != EOF ) {
+ while ((arg = getopt(argc, argv, ":dsv:k::Bniw")) != EOF ) {
switch(arg) {
case 'd':
foreground = 1;
@@ -2799,6 +2838,9 @@ main (int argc, char *argv[])
case 'n':
ignore_new_devs = 1;
break;
+ case 'w':
+ poll_dmevents = 0;
+ break;
default:
fprintf(stderr, "Invalid argument '-%c'\n",
optopt);
--
2.7.4

View File

@ -22,10 +22,10 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
5 files changed, 30 insertions(+), 20 deletions(-)
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 22c11a2..7011ef7 100644
index 61f68f8..81b0bc4 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -427,6 +427,28 @@ trigger_udev_change(const struct multipath *mpp)
@@ -444,6 +444,28 @@ trigger_udev_change(const struct multipath *mpp)
udev_device_unref(udd);
}
@ -54,7 +54,7 @@ index 22c11a2..7011ef7 100644
static int
is_mpp_known_to_udev(const struct multipath *mpp)
{
@@ -821,8 +843,8 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
@@ -842,8 +864,8 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
* succeeded
*/
mpp->force_udev_reload = 0;
@ -66,19 +66,19 @@ index 22c11a2..7011ef7 100644
/* multipath client mode */
dm_switchgroup(mpp->alias, mpp->bestpg);
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
index 0ffc28e..09603ba 100644
index 27a7e6f..545cbc2 100644
--- a/libmultipath/configure.h
+++ b/libmultipath/configure.h
@@ -37,3 +37,4 @@ int get_refwwid (enum mpath_cmds cmd, char * dev, enum devtypes dev_type,
vector pathvec, char **wwid);
int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh, int is_daemon);
int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name);
struct udev_device *get_udev_device(const char *dev, enum devtypes dev_type);
+void trigger_paths_udev_change(const struct multipath *mpp);
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
index 88bb72b..249c6c1 100644
index 9722714..9e9baed 100644
--- a/libmultipath/wwids.c
+++ b/libmultipath/wwids.c
@@ -319,7 +319,7 @@ remember_wwid(char *wwid)
@@ -321,7 +321,7 @@ remember_wwid(char *wwid)
condlog(3, "wrote wwid %s to wwids file", wwid);
else
condlog(4, "wwid %s already in wwids file", wwid);
@ -87,7 +87,7 @@ index 88bb72b..249c6c1 100644
}
int remember_cmdline_wwid(void)
@@ -353,7 +353,7 @@ int remember_cmdline_wwid(void)
@@ -355,7 +355,7 @@ int remember_cmdline_wwid(void)
next++;
}
if (strlen(ptr)) {
@ -97,10 +97,10 @@ index 88bb72b..249c6c1 100644
}
else {
diff --git a/multipath/main.c b/multipath/main.c
index ff570ac..ae6b06e 100644
index baf6759..12d6f15 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -416,7 +416,7 @@ configure (struct config *conf, enum mpath_cmds cmd,
@@ -427,7 +427,7 @@ configure (struct config *conf, enum mpath_cmds cmd,
}
if (cmd == CMD_ADD_WWID) {
r = remember_wwid(refwwid);
@ -109,7 +109,7 @@ index ff570ac..ae6b06e 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[])
@@ -782,16 +782,6 @@ main (int argc, char *argv[])
}
}
@ -127,10 +127,10 @@ index ff570ac..ae6b06e 100644
fprintf(stderr, "need to be root\n");
exit(1);
diff --git a/multipathd/main.c b/multipathd/main.c
index 596654c..c860e88 100644
index 841d3e9..417fc7e 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -2172,7 +2172,8 @@ configure (struct vectors * vecs)
@@ -2323,7 +2323,8 @@ configure (struct vectors * vecs)
sync_maps_state(mpvec);
vector_foreach_slot(mpvec, mpp, i){
@ -140,7 +140,7 @@ index 596654c..c860e88 100644
update_map_pr(mpp);
}
@@ -2251,10 +2252,6 @@ reconfigure (struct vectors * vecs)
@@ -2403,10 +2404,6 @@ reconfigure (struct vectors * vecs)
conf->verbosity = verbosity;
if (bindings_read_only)
conf->bindings_read_only = bindings_read_only;

View File

@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Sat, 13 Jan 2018 22:19:21 +0100
Subject: [PATCH] libmultipath: condlog: log to stderr
Calling 'multipath' might result in various error messages, all
of which should be directed to stderr.
Having them intermixed with the actual output on stdout makes
parsing really hard.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/debug.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libmultipath/debug.c b/libmultipath/debug.c
index f89b264..f95a3e5 100644
--- a/libmultipath/debug.c
+++ b/libmultipath/debug.c
@@ -37,9 +37,9 @@ void dlog (int sink, int prio, const char * fmt, ...)
"%b %d %H:%M:%S", tb);
buff[sizeof(buff)-1] = '\0';
- fprintf(stdout, "%s | ", buff);
+ fprintf(stderr, "%s | ", buff);
}
- vfprintf(stdout, fmt, ap);
+ vfprintf(stderr, fmt, ap);
}
else
log_safe(prio + 3, fmt, ap);
--
2.7.4

View File

@ -16,10 +16,10 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
3 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index e52f1f7..31897cd 100644
index 1a18337..167696a 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -52,6 +52,21 @@ set_str(vector strvec, void *ptr)
@@ -53,6 +53,21 @@ set_str(vector strvec, void *ptr)
}
static int
@ -41,7 +41,7 @@ index e52f1f7..31897cd 100644
set_yes_no(vector strvec, void *ptr)
{
char * buff;
@@ -1200,7 +1215,7 @@ ble_ ## option ## _handler (struct config *conf, vector strvec) \
@@ -1199,7 +1214,7 @@ ble_ ## option ## _handler (struct config *conf, vector strvec) \
if (!conf->option) \
return 1; \
\
@ -50,7 +50,7 @@ index e52f1f7..31897cd 100644
if (!buff) \
return 1; \
\
@@ -1216,7 +1231,7 @@ ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \
@@ -1215,7 +1230,7 @@ ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \
if (!conf->option) \
return 1; \
\
@ -59,7 +59,7 @@ index e52f1f7..31897cd 100644
if (!buff) \
return 1; \
\
@@ -1311,16 +1326,16 @@ device_handler(struct config *conf, vector strvec)
@@ -1316,16 +1331,16 @@ device_handler(struct config *conf, vector strvec)
return 0;
}
@ -81,10 +81,10 @@ index e52f1f7..31897cd 100644
declare_hw_handler(hwhandler, set_str)
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index c47d891..74b4efe 100644
index b8b7e0d..34b4ad2 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -346,6 +346,19 @@ set_value(vector strvec)
@@ -380,6 +380,19 @@ set_value(vector strvec)
return alloc;
}
@ -105,10 +105,10 @@ index c47d891..74b4efe 100644
static int kw_level = 0;
diff --git a/libmultipath/parser.h b/libmultipath/parser.h
index 519b805..96f40bd 100644
index 62906e9..b791705 100644
--- a/libmultipath/parser.h
+++ b/libmultipath/parser.h
@@ -73,6 +73,7 @@ extern void dump_keywords(vector keydump, int level);
@@ -77,6 +77,7 @@ extern void dump_keywords(vector keydump, int level);
extern void free_keywords(vector keywords);
extern vector alloc_strvec(char *string);
extern void *set_value(vector strvec);

View File

@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Sat, 13 Jan 2018 22:19:32 +0100
Subject: [PATCH] multipathd: fix compiler warning for uev_pathfail_check
gcc7 spits out an indentation warning for this function.
Fixes: 8392431 "multipath-tools: check null path before handle path-failed event"
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index 6dabf2c..596654c 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -1142,8 +1142,8 @@ uev_pathfail_check(struct uevent *uev, struct vectors *vecs)
lock(&vecs->lock);
pthread_testcancel();
pp = find_path_by_devt(vecs->pathvec, devt);
- if (!pp)
- goto out_lock;
+ if (!pp)
+ goto out_lock;
r = io_err_stat_handle_pathfail(pp);
if (r)
condlog(3, "io_err_stat: %s: cannot handle pathfail uevent",
--
2.7.4

View File

@ -1,38 +1,30 @@
Summary: Tools to manage multipath devices using device-mapper
Name: device-mapper-multipath
Version: 0.7.4
Release: 2.git07e7bd5%{?dist}
Version: 0.7.6
Release: 1.git1cb704b%{?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=07e7bd5;sf=tgz" -o multipath-tools-07e7bd5.tgz
Source0: multipath-tools-07e7bd5.tgz
# curl "https://git.opensvc.com/?p=multipath-tools/.git;a=snapshot;h=1cb704b;sf=tgz" -o multipath-tools-1cb704b.tgz
Source0: multipath-tools-1cb704b.tgz
Source1: multipath.conf
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
Patch0001: 0001-multipathd-remove-incorrect-pthread_testcancel.patch
Patch0002: 0002-multipath-add-comments.patch
Patch0003: 0003-multipathd-minor-dmevents-polling-code-cleanups.patch
Patch0004: 0004-multipathd-remove-unneeded-function-parameter.patch
Patch0005: 0005-mpathcmd-fix-libmpathcmd-license.patch
Patch0006: 0006-libmultipath-don-t-print-undefined-values.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
# runtime
Requires: %{name}-libs = %{version}-%{release}
@ -110,7 +102,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-07e7bd5
%setup -q -n multipath-tools-1cb704b
%patch0001 -p1
%patch0002 -p1
%patch0003 -p1
@ -125,14 +117,6 @@ 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
@ -256,6 +240,23 @@ fi
%{_pkgconfdir}/libdmmp.pc
%changelog
* Tue Apr 02 2018 Björn Esser <besser82@fedoraproject.org> - 0.7.6-1.git1cb704b
- Update Source to the latest upstream commit
* Previous patches 0001-0014 are included in this commit
* Previous patches 0015-0022 are now patches 0007-0014
- 0001-multipathd-remove-incorrect-pthread_testcancel.patch
* Fixed pthread cancellation issue. posted upstream
- 0002-multipath-add-comments.patch
* Posted upstream
- 0003-multipathd-minor-dmevents-polling-code-cleanups.patch
* Fixed minor polling issues. posted upstream
- 0004-multipathd-remove-unneeded-function-parameter.patch
* Posted upstream
- 0005-mpathcmd-fix-libmpathcmd-license.patch
* License clarification. posted upstream
- 0006-libmultipath-don-t-print-undefined-values.patch
* Fixed bug in 'multipath show config'. posted upstream
* Tue Mar 06 2018 Björn Esser <besser82@fedoraproject.org> - 0.7.4-2.git07e7bd5
- Rebuilt for libjson-c.so.4 (json-c v0.13.1)

View File

@ -1,2 +1,2 @@
SHA512 (multipath-tools-07e7bd5.tgz) = e84d451c8927119bac6612585d15497325da08d762ea6cde20d400a651fac599cb6edf4f9144204d91f92e04fec4ea3b955b9a9216ae82b513437b8ce516136a
SHA512 (multipath-tools-1cb704b.tgz) = dd4779a35681b4f9c0ba1f7fd3c0e6eac3407cb6b24e684659df27d8d3ae2bb024552611f44fefa90b38e02d2dfaf90e7f608b9868cce24c70b6be405b5ac989
SHA512 (multipath.conf) = 71953dce5a68adcf60a942305f5a66023e6f4c4baf53b1bfdb4edf65ed5b8e03db804363c36d1dcfd85591f4766f52b515269904c53b84d7b076da0b80b09942