Compare commits

...

13 Commits

Author SHA1 Message Date
eabdullin dc49a6be55 import UBI device-mapper-multipath-0.8.4-41.el8 2024-05-22 14:51:55 +00:00
eabdullin 4860584d27 import UBI device-mapper-multipath-0.8.4-39.el8 2023-11-14 20:01:57 +00:00
CentOS Sources 5da6aa984c import device-mapper-multipath-0.8.4-37.el8 2023-05-17 01:17:31 +00:00
CentOS Sources 32d1b0b0f4 import device-mapper-multipath-0.8.4-28.el8_7.3 2023-04-04 08:52:33 +00:00
CentOS Sources ddd9059e05 import device-mapper-multipath-0.8.4-28.el8_7.1 2022-11-14 08:46:30 +00:00
CentOS Sources c4feb9e3de import device-mapper-multipath-0.8.4-28.el8 2022-11-08 10:40:58 +00:00
CentOS Sources 87c6f1c74b import device-mapper-multipath-0.8.4-22.el8_6.2 2022-10-25 15:11:26 +00:00
CentOS Sources 37e52d8465 import device-mapper-multipath-0.8.4-22.el8_6.1 2022-08-02 07:02:57 +00:00
CentOS Sources 0b161a7a67 import device-mapper-multipath-0.8.4-22.el8 2022-05-10 10:04:16 +00:00
CentOS Sources 4feeab1ad4 import device-mapper-multipath-0.8.4-17.el8_5.1 2022-04-26 13:51:16 +00:00
CentOS Sources 33978456d2 import device-mapper-multipath-0.8.4-17.el8 2021-11-16 04:19:45 +00:00
CentOS Sources 21a06b324d import device-mapper-multipath-0.8.4-10.el8 2021-09-09 15:58:46 +00:00
CentOS Sources ba9a474de2 import device-mapper-multipath-0.8.4-5.el8 2021-09-09 15:58:43 +00:00
150 changed files with 15656 additions and 1310 deletions

View File

@ -1 +1 @@
f700dc1e4ce1d6952051467d4b245f9bd80286e3 SOURCES/multipath-tools-0.8.3.tgz
b52c2be340449664f0a122070838f6d8edd42e4a SOURCES/multipath-tools-0.8.4.tgz

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/multipath-tools-0.8.3.tgz
SOURCES/multipath-tools-0.8.4.tgz

View File

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 17 Mar 2020 17:28:24 -0500
Subject: [PATCH] libmultipath: assign variable to make gcc happy
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
There is nothing wrong with is_queueing not being set at the start
of __set_no_path_retry(), it will always get set before it is accessed,
but gcc 8.2.1 is failing with
structs_vec.c: In function __set_no_path_retry:
structs_vec.c:339:7: error: is_queueing may be used uninitialized in
this function [-Werror=maybe-uninitialized]
bool is_queueing;
^~~~~~~~~~~
so, assign a value to make it happy.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/structs_vec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 3dbbaa0f..077f2e42 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -336,7 +336,7 @@ static void leave_recovery_mode(struct multipath *mpp)
void __set_no_path_retry(struct multipath *mpp, bool check_features)
{
- bool is_queueing;
+ bool is_queueing = false; /* assign a value to make gcc happy */
check_features = check_features && mpp->features != NULL;
if (check_features)
--
2.17.2

View File

@ -1,277 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 19 Sep 2019 13:46:03 -0500
Subject: [PATCH] multipathd: warn when configuration has been changed.
It would be helpful if multipathd could log a message when
multipath.conf or files in the config_dir have been written to, both so
that it can be used to send a notification to users, and to help with
determining after the fact if multipathd was running with an older
config, when the logs of multipathd's behaviour don't match with the
current multipath.conf.
To do this, the multipathd uxlsnr thread now sets up inotify watches on
both /etc/multipath.conf and the config_dir to watch if the files are
deleted or closed after being opened for writing. In order to keep
uxlsnr from polling repeatedly if the multipath.conf or the config_dir
aren't present, it will only set up the watches once per reconfigure.
However, since multipath.conf is far more likely to be replaced by a
text editor than modified in place, if it gets removed, multipathd will
immediately try to restart the watch on it (which will succeed if the
file was simply replaced by a new copy). This does mean that if
multipath.conf or the config_dir are actually removed and then later
re-added, multipathd won't log any more messages for changes until the
next reconfigure. But that seems like a fair trade-off to avoid
repeatedly polling for files that aren't likely to appear.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.h | 1 +
multipathd/main.c | 1 +
multipathd/uxlsnr.c | 134 ++++++++++++++++++++++++++++++++++++++++--
3 files changed, 130 insertions(+), 6 deletions(-)
diff --git a/libmultipath/config.h b/libmultipath/config.h
index ffec3103..e69aa07c 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -188,6 +188,7 @@ struct config {
int find_multipaths_timeout;
int marginal_pathgroups;
unsigned int version[3];
+ unsigned int sequence_nr;
char * multipath_dir;
char * selector;
diff --git a/multipathd/main.c b/multipathd/main.c
index 34a57689..7b364cfe 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -2618,6 +2618,7 @@ reconfigure (struct vectors * vecs)
uxsock_timeout = conf->uxsock_timeout;
old = rcu_dereference(multipath_conf);
+ conf->sequence_nr = old->sequence_nr + 1;
rcu_assign_pointer(multipath_conf, conf);
call_rcu(&old->rcu, rcu_free_config);
diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c
index bc71679e..92d9a79a 100644
--- a/multipathd/uxlsnr.c
+++ b/multipathd/uxlsnr.c
@@ -23,6 +23,7 @@
#include <sys/time.h>
#include <signal.h>
#include <stdbool.h>
+#include <sys/inotify.h>
#include "checkers.h"
#include "memory.h"
#include "debug.h"
@@ -51,6 +52,8 @@ struct client {
LIST_HEAD(clients);
pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER;
struct pollfd *polls;
+int notify_fd = -1;
+char *config_dir;
static bool _socket_client_is_root(int fd);
@@ -151,6 +154,8 @@ void uxsock_cleanup(void *arg)
long ux_sock = (long)arg;
close(ux_sock);
+ close(notify_fd);
+ free(config_dir);
pthread_mutex_lock(&client_lock);
list_for_each_entry_safe(client_loop, client_tmp, &clients, node) {
@@ -162,6 +167,106 @@ void uxsock_cleanup(void *arg)
free_polls();
}
+/* failing to set the watch descriptor is o.k. we just miss a warning
+ * message */
+void reset_watch(int notify_fd, int *wds, unsigned int *sequence_nr)
+{
+ struct config *conf;
+ int dir_reset = 0;
+ int conf_reset = 0;
+
+ if (notify_fd == -1)
+ return;
+
+ conf = get_multipath_config();
+ /* instead of repeatedly try to reset the inotify watch if
+ * the config directory or multipath.conf isn't there, just
+ * do it once per reconfigure */
+ if (*sequence_nr != conf->sequence_nr) {
+ *sequence_nr = conf->sequence_nr;
+ if (wds[0] == -1)
+ conf_reset = 1;
+ if (!config_dir || !conf->config_dir ||
+ strcmp(config_dir, conf->config_dir)) {
+ dir_reset = 1;
+ if (config_dir)
+ free(config_dir);
+ if (conf->config_dir)
+ config_dir = strdup(conf->config_dir);
+ else
+ config_dir = NULL;
+ } else if (wds[1] == -1)
+ dir_reset = 1;
+ }
+ put_multipath_config(conf);
+
+ if (dir_reset) {
+ if (wds[1] != -1) {
+ inotify_rm_watch(notify_fd, wds[1]);
+ wds[1] = -1;
+ }
+ if (config_dir) {
+ wds[1] = inotify_add_watch(notify_fd, config_dir,
+ IN_CLOSE_WRITE | IN_DELETE |
+ IN_ONLYDIR);
+ if (wds[1] == -1)
+ condlog(3, "didn't set up notifications on %s: %s", config_dir, strerror(errno));
+ }
+ }
+ if (conf_reset) {
+ wds[0] = inotify_add_watch(notify_fd, DEFAULT_CONFIGFILE,
+ IN_CLOSE_WRITE);
+ if (wds[0] == -1)
+ condlog(3, "didn't set up notifications on /etc/multipath.conf: %s", strerror(errno));
+ }
+ return;
+}
+
+void handle_inotify(int fd, int *wds)
+{
+ char buff[1024]
+ __attribute__ ((aligned(__alignof__(struct inotify_event))));
+ const struct inotify_event *event;
+ ssize_t len;
+ char *ptr;
+ int i, got_notify = 0;
+
+ for (;;) {
+ len = read(fd, buff, sizeof(buff));
+ if (len <= 0) {
+ if (len < 0 && errno != EAGAIN) {
+ condlog(3, "error reading from inotify_fd");
+ for (i = 0; i < 2; i++) {
+ if (wds[i] != -1) {
+ inotify_rm_watch(fd, wds[i]);
+ wds[i] = -1;
+ }
+ }
+ }
+ break;
+ }
+
+ got_notify = 1;
+ for (ptr = buff; ptr < buff + len;
+ ptr += sizeof(struct inotify_event) + event->len) {
+ event = (const struct inotify_event *) ptr;
+
+ if (event->mask & IN_IGNORED) {
+ /* multipathd.conf may have been overwritten.
+ * Try once to reset the notification */
+ if (wds[0] == event->wd)
+ wds[0] = inotify_add_watch(notify_fd,
+ DEFAULT_CONFIGFILE,
+ IN_CLOSE_WRITE);
+ else if (wds[1] == event->wd)
+ wds[1] = -1;
+ }
+ }
+ }
+ if (got_notify)
+ condlog(1, "Multipath configuration updated.\nReload multipathd for changes to take effect");
+}
+
/*
* entry point
*/
@@ -173,13 +278,19 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
char *reply;
sigset_t mask;
int old_clients = MIN_POLLS;
+ /* conf->sequence_nr will be 1 when uxsock_listen is first called */
+ unsigned int sequence_nr = 0;
+ int wds[2] = { -1, -1 };
condlog(3, "uxsock: startup listener");
- polls = (struct pollfd *)MALLOC((MIN_POLLS + 1) * sizeof(struct pollfd));
+ polls = (struct pollfd *)MALLOC((MIN_POLLS + 2) * sizeof(struct pollfd));
if (!polls) {
condlog(0, "uxsock: failed to allocate poll fds");
exit_daemon();
}
+ notify_fd = inotify_init1(IN_NONBLOCK);
+ if (notify_fd == -1) /* it's fine if notifications fail */
+ condlog(3, "failed to start up configuration notifications");
sigfillset(&mask);
sigdelset(&mask, SIGINT);
sigdelset(&mask, SIGTERM);
@@ -198,18 +309,18 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
if (num_clients != old_clients) {
struct pollfd *new;
if (num_clients <= MIN_POLLS && old_clients > MIN_POLLS) {
- new = REALLOC(polls, (1 + MIN_POLLS) *
+ new = REALLOC(polls, (2 + MIN_POLLS) *
sizeof(struct pollfd));
} else if (num_clients <= MIN_POLLS && old_clients <= MIN_POLLS) {
new = polls;
} else {
- new = REALLOC(polls, (1+num_clients) *
+ new = REALLOC(polls, (2 + num_clients) *
sizeof(struct pollfd));
}
if (!new) {
pthread_mutex_unlock(&client_lock);
condlog(0, "%s: failed to realloc %d poll fds",
- "uxsock", 1 + num_clients);
+ "uxsock", 2 + num_clients);
sched_yield();
continue;
}
@@ -219,8 +330,15 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
polls[0].fd = ux_sock;
polls[0].events = POLLIN;
+ reset_watch(notify_fd, wds, &sequence_nr);
+ if (notify_fd == -1 || (wds[0] == -1 && wds[1] == -1))
+ polls[1].fd = -1;
+ else
+ polls[1].fd = notify_fd;
+ polls[1].events = POLLIN;
+
/* setup the clients */
- i = 1;
+ i = 2;
list_for_each_entry(c, &clients, node) {
polls[i].fd = c->fd;
polls[i].events = POLLIN;
@@ -262,7 +380,7 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
}
/* see if a client wants to speak to us */
- for (i = 1; i < num_clients + 1; i++) {
+ for (i = 2; i < num_clients + 2; i++) {
if (polls[i].revents & POLLIN) {
struct timespec start_time;
@@ -321,6 +439,10 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
if (polls[0].revents & POLLIN) {
new_client(ux_sock);
}
+
+ /* handle inotify events on config files */
+ if (polls[1].revents & POLLIN)
+ handle_inotify(notify_fd, wds);
}
return NULL;
--
2.17.2

View File

@ -1,59 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 7 Oct 2019 17:17:13 -0500
Subject: [PATCH] libmultipath: fix leak in foreign code
If scandir fails or finds no foreign libraries, enable_re needs to be
freed before exitting.
Fixes: 8d03eda4 'multipath.conf: add "enable_foreign" parameter'
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/foreign.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/libmultipath/foreign.c b/libmultipath/foreign.c
index 4b34e141..68e9a9b8 100644
--- a/libmultipath/foreign.c
+++ b/libmultipath/foreign.c
@@ -129,7 +129,7 @@ static int _init_foreign(const char *multipath_dir, const char *enable)
char pathbuf[PATH_MAX];
struct dirent **di;
struct scandir_result sr;
- int r, i;
+ int r, i, ret = 0;
regex_t *enable_re = NULL;
foreigns = vector_alloc();
@@ -157,13 +157,15 @@ static int _init_foreign(const char *multipath_dir, const char *enable)
if (r == 0) {
condlog(3, "%s: no foreign multipath libraries found",
__func__);
- return 0;
+ ret = 0;
+ goto out;
} else if (r < 0) {
r = errno;
condlog(1, "%s: error %d scanning foreign multipath libraries",
__func__, r);
_cleanup_foreign();
- return -r;
+ ret = -r;
+ goto out;
}
sr.di = di;
@@ -250,8 +252,9 @@ static int _init_foreign(const char *multipath_dir, const char *enable)
free_foreign(fgn);
}
pthread_cleanup_pop(1); /* free_scandir_result */
+out:
pthread_cleanup_pop(1); /* free_pre */
- return 0;
+ return ret;
}
int init_foreign(const char *multipath_dir, const char *enable)
--
2.17.2

View File

@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Sat, 21 Mar 2020 23:49:59 -0500
Subject: [PATCH] libmutipath: don't close fd on dm_lib_release
If dm_hold_control_open() isn't set, when dm_lib_release() is called, it
will close the control fd. The control fd will get re-opened on the next
dm_task_run() call, but if there is a dm_task_run() call already
in progress in another thread, it can fail. Since many of the
device-mapper callouts happen with the vecs lock held, this wasn't too
noticeable, but there is code that calls dm_task_run() without the
vecs lock held, notably the dmevent waiter code.
Since, as Martin pointed out, dm_hold_control_open() hasn't always
existed in libdevmapper, check if it's supported on compilation,
and update the version requirements if so.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/Makefile | 4 ++++
libmultipath/devmapper.c | 7 ++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
index e5651e49..ad690a49 100644
--- a/libmultipath/Makefile
+++ b/libmultipath/Makefile
@@ -36,6 +36,10 @@ ifneq ($(call check_func,dm_task_deferred_remove,/usr/include/libdevmapper.h),0)
CFLAGS += -DLIBDM_API_DEFERRED
endif
+ifneq ($(call check_func,dm_hold_control_dev,/usr/include/libdevmapper.h),0)
+ CFLAGS += -DLIBDM_API_HOLD_CONTROL
+endif
+
OBJS = memory.o parser.o vector.o devmapper.o callout.o \
hwtable.o blacklist.o util.o dmparser.o config.o \
structs.o discovery.o propsel.o dict.o \
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index bed8ddc6..13a1cf53 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -108,7 +108,9 @@ dm_lib_prereq (void)
{
char version[64];
int v[3];
-#if defined(LIBDM_API_DEFERRED)
+#if defined(LIBDM_API_HOLD_CONTROL)
+ int minv[3] = {1, 2, 111};
+#elif defined(LIBDM_API_DEFERRED)
int minv[3] = {1, 2, 89};
#elif defined(DM_SUBSYSTEM_UDEV_FLAG0)
int minv[3] = {1, 2, 82};
@@ -254,6 +256,9 @@ void libmp_dm_init(void)
memcpy(conf->version, version, sizeof(version));
put_multipath_config(conf);
dm_init(verbosity);
+#ifdef LIBDM_API_HOLD_CONTROL
+ dm_hold_control_dev(1);
+#endif
dm_udev_set_sync_support(libmp_dm_udev_sync);
}
--
2.17.2

View File

@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 8 Oct 2019 10:17:11 -0500
Subject: [PATCH] Fix leak in mpathpersist
If the persistent in command fails, the response buffer must be freed.
Found by Coverity
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
mpathpersist/main.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/mpathpersist/main.c b/mpathpersist/main.c
index 278b8d51..920e686c 100644
--- a/mpathpersist/main.c
+++ b/mpathpersist/main.c
@@ -499,6 +499,7 @@ static int handle_args(int argc, char * argv[], int nline)
if (ret != MPATH_PR_SUCCESS )
{
fprintf (stderr, "Persistent Reserve IN command failed\n");
+ free(resp);
goto out_fd;
}
--
2.17.2

View File

@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 19 Mar 2020 22:17:51 -0500
Subject: [PATCH] libmultipath: allow force reload with no active paths
If the partition information has changed on multipath devices (say,
because it was updated on another node that has access to the same
storage), users expect that running "multipathd reconfigure" will update
that. However, if the checkers for the multipath device are pending for
too long when the the device is reconfigured, multipathd will give up
waiting for them, and refuse to reload the device, since there are no
active paths. This means that no kpartx update will be triggered.
Multipath is fully capable of reloading a multipath device that has no
active paths. This has been possible for years. If multipath is supposed
to reload the device, it should do so, even if there are no active paths.
Generally, when multipath is force reloaded, kpartx will be updated.
However when a device is reloaded with no paths, the udev rules won't
run kpartx. But they also weren't running kpartx when the first valid
path appeared, even though the dm activation rules get run in this case.
This changes 11-dm-mpath.rules to run kpartx when a device goes from no
usable paths to having usable paths.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/configure.c | 6 ------
multipath/11-dm-mpath.rules | 2 +-
2 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index c95848a0..96c79610 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -710,12 +710,6 @@ select_action (struct multipath * mpp, vector curmp, int force_reload)
return;
}
- if (pathcount(mpp, PATH_UP) == 0) {
- mpp->action = ACT_IMPOSSIBLE;
- condlog(3, "%s: set ACT_IMPOSSIBLE (no usable path)",
- mpp->alias);
- return;
- }
if (force_reload) {
mpp->force_udev_reload = 1;
mpp->action = ACT_RELOAD;
diff --git a/multipath/11-dm-mpath.rules b/multipath/11-dm-mpath.rules
index 07320a14..cd522e8c 100644
--- a/multipath/11-dm-mpath.rules
+++ b/multipath/11-dm-mpath.rules
@@ -75,7 +75,7 @@ ENV{MPATH_DEVICE_READY}=="0", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1"
ENV{MPATH_DEVICE_READY}!="0", ENV{.MPATH_DEVICE_READY_OLD}=="0",\
ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="$env{DM_DISABLE_OTHER_RULES_FLAG_OLD}",\
ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="",\
- ENV{DM_ACTIVATION}="1"
+ ENV{DM_ACTIVATION}="1", ENV{MPATH_UNCHANGED}="0"
# The code to check multipath state ends here. We need to set
# properties and symlinks regardless whether the map is usable or
--
2.17.2

View File

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Christian Hesse <mail@eworm.de>
Date: Wed, 6 May 2020 09:35:47 +0200
Subject: [PATCH] libmpathpersist: depend on libmultipath
Without this the build fails with:
/usr/bin/ld: cannot find -lmultipath
Signed-off-by: Christian Hesse <mail@eworm.de>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 1dee3680..ba1d73ba 100644
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,7 @@ all: $(BUILDDIRS)
$(BUILDDIRS):
$(MAKE) -C $@
-multipath multipathd mpathpersist: libmultipath
+libmpathpersist multipath multipathd mpathpersist: libmultipath
mpathpersist: libmpathpersist
$(BUILDDIRS.clean):
--
2.17.2

View File

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 5 Nov 2019 13:53:29 -0600
Subject: [PATCH] libmultipath: remove unused path->prio_args
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/structs.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index a3adf906..1c32a799 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -272,7 +272,6 @@ struct path {
char * uid_attribute;
char * getuid;
struct prio prio;
- char * prio_args;
struct checker checker;
struct multipath * mpp;
int fd;
--
2.17.2

View File

@ -1,34 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 6 Nov 2019 16:49:40 -0600
Subject: [PATCH] libmultipath: constify get_unaligned_be*
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/unaligned.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libmultipath/unaligned.h b/libmultipath/unaligned.h
index 68c07742..b9eaa7cb 100644
--- a/libmultipath/unaligned.h
+++ b/libmultipath/unaligned.h
@@ -10,14 +10,14 @@ static inline uint16_t get_unaligned_be16(const void *ptr)
return p[0] << 8 | p[1];
}
-static inline uint32_t get_unaligned_be32(void *ptr)
+static inline uint32_t get_unaligned_be32(const void *ptr)
{
const uint8_t *p = ptr;
return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
}
-static inline uint64_t get_unaligned_be64(void *ptr)
+static inline uint64_t get_unaligned_be64(const void *ptr)
{
uint32_t low = get_unaligned_be32(ptr + 4);
uint64_t high = get_unaligned_be32(ptr);
--
2.17.2

View File

@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Tue, 12 May 2020 00:39:21 +0200
Subject: [PATCH] multipath-tools: Makefile: more dependency fixes for parallel
build
Extend the late fixes from Christian.
Cc: Christian Hesse <mail@eworm.de>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index ba1d73ba..fec3b73b 100644
--- a/Makefile
+++ b/Makefile
@@ -28,8 +28,9 @@ all: $(BUILDDIRS)
$(BUILDDIRS):
$(MAKE) -C $@
-libmpathpersist multipath multipathd mpathpersist: libmultipath
-mpathpersist: libmpathpersist
+libmultipath libdmmp: libmpathcmd
+libmpathpersist multipath multipathd: libmultipath
+mpathpersist multipathd: libmpathpersist
$(BUILDDIRS.clean):
$(MAKE) -C ${@:.clean=} clean
--
2.17.2

View File

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 5 Nov 2019 12:37:58 -0600
Subject: [PATCH] libmultipath: add missing hwe mpe variable merges
There were some variables in the hwe and mpe structs that weren't being
merged by merge_hwe() and merge_mpe().
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 20e3b8bf..85626e96 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -372,6 +372,10 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
merge_num(san_path_err_threshold);
merge_num(san_path_err_forget_rate);
merge_num(san_path_err_recovery_time);
+ merge_num(marginal_path_err_sample_time);
+ merge_num(marginal_path_err_rate_threshold);
+ merge_num(marginal_path_err_recheck_gap_time);
+ merge_num(marginal_path_double_failed_time);
snprintf(id, sizeof(id), "%s/%s", dst->vendor, dst->product);
reconcile_features_with_options(id, &dst->features,
@@ -397,6 +401,7 @@ merge_mpe(struct mpentry *dst, struct mpentry *src)
if (dst->prkey_source == PRKEY_SOURCE_NONE &&
src->prkey_source != PRKEY_SOURCE_NONE) {
dst->prkey_source = src->prkey_source;
+ dst->sa_flags = src->sa_flags;
memcpy(&dst->reservation_key, &src->reservation_key,
sizeof(dst->reservation_key));
}
@@ -413,6 +418,9 @@ merge_mpe(struct mpentry *dst, struct mpentry *src)
merge_num(deferred_remove);
merge_num(delay_watch_checks);
merge_num(delay_wait_checks);
+ merge_num(san_path_err_threshold);
+ merge_num(san_path_err_forget_rate);
+ merge_num(san_path_err_recovery_time);
merge_num(marginal_path_err_sample_time);
merge_num(marginal_path_err_rate_threshold);
merge_num(marginal_path_err_recheck_gap_time);
--
2.17.2

View File

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Tue, 12 May 2020 00:39:24 +0200
Subject: [PATCH] multipath-tools: Makefile.inc: set -Wno-error=clobbered
We need to ignore -Wclobbered because gcc has trouble dealing with glibc's
implementation of pthread_cleanup_push().
For some variants of gcc, -Wno-clobbered alone isn't enough if -Werror is also
set. Compilation with -Wno-error=clobbered works, though.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.inc b/Makefile.inc
index d4d1e0dd..9060ac9b 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -91,7 +91,7 @@ TEST_CC_OPTION = $(shell \
STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
ERROR_DISCARDED_QUALIFIERS := $(call TEST_CC_OPTION,-Werror=discarded-qualifiers,)
-WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered,)
+WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered -Wno-error=clobbered,)
OPTFLAGS = -O2 -g -pipe -Werror -Wall -Wextra -Wformat=2 -Werror=implicit-int \
-Werror=implicit-function-declaration -Werror=format-security \
--
2.17.2

View File

@ -0,0 +1,91 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Tue, 12 May 2020 00:39:25 +0200
Subject: [PATCH] libmultipath: discovery.c: use %z qualifier for size_t
Otherwise compilation for 32bit targets spits out warnings.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index ee3290cd..ffec5162 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -986,7 +986,7 @@ parse_vpd_pg80(const unsigned char *in, char *out, size_t out_len)
}
if (len >= out_len) {
- condlog(2, "vpd pg80 overflow, %lu/%lu bytes required",
+ condlog(2, "vpd pg80 overflow, %zu/%zu bytes required",
len + 1, out_len);
len = out_len - 1;
}
@@ -1087,7 +1087,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
len = sprintf(out, "%d", vpd_type);
if (2 * vpd_len >= out_len - len) {
- condlog(1, "%s: WWID overflow, type %d, %lu/%lu bytes required",
+ condlog(1, "%s: WWID overflow, type %d, %zu/%zu bytes required",
__func__, vpd_type,
2 * vpd_len + len + 1, out_len);
vpd_len = (out_len - len - 1) / 2;
@@ -1096,7 +1096,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
len += sprintf(out + len,
"%02x", vpd[i]);
} else if (vpd_type == 0x8 && vpd_len < 4) {
- condlog(1, "%s: VPD length %lu too small for designator type 8",
+ condlog(1, "%s: VPD length %zu too small for designator type 8",
__func__, vpd_len);
return -EINVAL;
} else if (vpd_type == 0x8) {
@@ -1112,7 +1112,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
while (len > 2 && vpd[len - 2] == '\0')
--len;
if (len > out_len - 1) {
- condlog(1, "%s: WWID overflow, type 8/%c, %lu/%lu bytes required",
+ condlog(1, "%s: WWID overflow, type 8/%c, %zu/%zu bytes required",
__func__, out[0], len + 1, out_len);
len = out_len - 1;
}
@@ -1136,7 +1136,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
while ((p = memchr(vpd, ' ', vpd_len))) {
p_len = p - vpd;
if (len + p_len > out_len - 1) {
- condlog(1, "%s: WWID overflow, type 1, %lu/%lu bytes required",
+ condlog(1, "%s: WWID overflow, type 1, %zu/%zu bytes required",
__func__, len + p_len, out_len);
p_len = out_len - len - 1;
}
@@ -1162,7 +1162,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
p_len = vpd_len;
if (p_len > 0 && len < out_len - 1) {
if (len + p_len > out_len - 1) {
- condlog(1, "%s: WWID overflow, type 1, %lu/%lu bytes required",
+ condlog(1, "%s: WWID overflow, type 1, %zu/%zu bytes required",
__func__, len + p_len + 1, out_len);
p_len = out_len - len - 1;
}
@@ -1186,14 +1186,14 @@ parse_vpd_c0_hp3par(const unsigned char *in, size_t in_len,
memset(out, 0x0, out_len);
if (in_len <= 4 || (in[4] > 3 && in_len < 44)) {
- condlog(3, "HP/3PAR vendor specific VPD page length too short: %lu", in_len);
+ condlog(3, "HP/3PAR vendor specific VPD page length too short: %zu", in_len);
return -EINVAL;
}
if (in[4] <= 3) /* revision must be > 3 to have Vomlume Name */
return -ENODATA;
len = get_unaligned_be32(&in[40]);
if (len > out_len || len + 44 > in_len) {
- condlog(3, "HP/3PAR vendor specific Volume name too long: %lu",
+ condlog(3, "HP/3PAR vendor specific Volume name too long: %zu",
len);
return -EINVAL;
}
--
2.17.2

View File

@ -1,204 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 1 Nov 2019 10:33:04 -0500
Subject: [PATCH] libmultipath: fix sgio_get_vpd looping
If do_inq returns a page with a length that is less than maxlen, but
larger than DEFAULT_SGIO_LEN, this function will loop forever. Also
if do_inq returns with a length equal to or greater than maxlen,
sgio_get_vpd will exit immediately, even if it hasn't read the entire
page. Fix these issues, modify the tests to verify the new behavior.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 12 +++---
tests/vpd.c | 84 ++++++++++++++++++++++++----------------
2 files changed, 57 insertions(+), 39 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 72f455e8..3c72a80a 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -870,6 +870,7 @@ static int
sgio_get_vpd (unsigned char * buff, int maxlen, int fd, int pg)
{
int len = DEFAULT_SGIO_LEN;
+ int rlen;
if (fd < 0) {
errno = EBADF;
@@ -877,12 +878,11 @@ sgio_get_vpd (unsigned char * buff, int maxlen, int fd, int pg)
}
retry:
if (0 == do_inq(fd, 0, 1, pg, buff, len)) {
- len = get_unaligned_be16(&buff[2]) + 4;
- if (len >= maxlen)
- return len;
- if (len > DEFAULT_SGIO_LEN)
- goto retry;
- return len;
+ rlen = get_unaligned_be16(&buff[2]) + 4;
+ if (rlen <= len || len >= maxlen)
+ return rlen;
+ len = (rlen < maxlen)? rlen : maxlen;
+ goto retry;
}
return -1;
}
diff --git a/tests/vpd.c b/tests/vpd.c
index d9f80eaa..4dbce010 100644
--- a/tests/vpd.c
+++ b/tests/vpd.c
@@ -306,7 +306,7 @@ static int create_vpd83(unsigned char *buf, size_t bufsiz, const char *id,
default:
break;
}
- put_unaligned_be16(n, buf + 2);
+ put_unaligned_be16(bufsiz, buf + 2);
return n + 4;
}
@@ -429,6 +429,8 @@ static void test_vpd_vnd_ ## len ## _ ## wlen(void **state) \
free(exp_wwid); \
will_return(__wrap_ioctl, n); \
will_return(__wrap_ioctl, vt->vpdbuf); \
+ will_return(__wrap_ioctl, n); \
+ will_return(__wrap_ioctl, vt->vpdbuf); \
ret = get_vpd_sgio(10, 0x83, vt->wwid, wlen); \
assert_correct_wwid("test_vpd_vnd_" #len "_" #wlen, \
exp_len, ret, '1', 0, false, \
@@ -459,6 +461,8 @@ static void test_vpd_str_ ## typ ## _ ## len ## _ ## wlen(void **state) \
exp_len = wlen - 1; \
will_return(__wrap_ioctl, n); \
will_return(__wrap_ioctl, vt->vpdbuf); \
+ will_return(__wrap_ioctl, n); \
+ will_return(__wrap_ioctl, vt->vpdbuf); \
ret = get_vpd_sgio(10, 0x83, vt->wwid, wlen); \
assert_correct_wwid("test_vpd_str_" #typ "_" #len "_" #wlen, \
exp_len, ret, byte0[type], 0, \
@@ -496,6 +500,8 @@ static void test_vpd_naa_ ## naa ## _ ## wlen(void **state) \
3, naa, 0); \
will_return(__wrap_ioctl, n); \
will_return(__wrap_ioctl, vt->vpdbuf); \
+ will_return(__wrap_ioctl, n); \
+ will_return(__wrap_ioctl, vt->vpdbuf); \
ret = get_vpd_sgio(10, 0x83, vt->wwid, wlen); \
assert_correct_wwid("test_vpd_naa_" #naa "_" #wlen, \
exp_len, ret, '3', '0' + naa, true, \
@@ -506,22 +512,26 @@ static void test_vpd_naa_ ## naa ## _ ## wlen(void **state) \
* test_vpd_eui_LEN_WLEN() - test code for VPD 83, EUI64
* @LEN: EUI64 length (8, 12, or 16)
* @WLEN: WWID buffer size
+ * @SML: Use small VPD page size
*/
-#define make_test_vpd_eui(len, wlen) \
-static void test_vpd_eui_ ## len ## _ ## wlen(void **state) \
+#define make_test_vpd_eui(len, wlen, sml) \
+static void test_vpd_eui_ ## len ## _ ## wlen ## _ ## sml(void **state) \
{ \
struct vpdtest *vt = *state; \
int n, ret; \
/* returned size is always uneven */ \
int exp_len = wlen > 2 * len + 1 ? 2 * len + 1 : \
wlen % 2 == 0 ? wlen - 1 : wlen - 2; \
+ int bufsize = sml ? 255 : sizeof(vt->vpdbuf); \
\
- n = create_vpd83(vt->vpdbuf, sizeof(vt->vpdbuf), test_id, \
+ n = create_vpd83(vt->vpdbuf, bufsize, test_id, \
2, 0, len); \
will_return(__wrap_ioctl, n); \
will_return(__wrap_ioctl, vt->vpdbuf); \
+ will_return(__wrap_ioctl, n); \
+ will_return(__wrap_ioctl, vt->vpdbuf); \
ret = get_vpd_sgio(10, 0x83, vt->wwid, wlen); \
- assert_correct_wwid("test_vpd_eui_" #len "_" #wlen, \
+ assert_correct_wwid("test_vpd_eui_" #len "_" #wlen "_" #sml, \
exp_len, ret, '2', 0, true, \
test_id, vt->wwid); \
}
@@ -603,25 +613,30 @@ make_test_vpd_vnd(20, 10);
make_test_vpd_vnd(10, 10);
/* EUI64 tests */
+/* small vpd page test */
+make_test_vpd_eui(8, 32, 1);
+make_test_vpd_eui(12, 32, 1);
+make_test_vpd_eui(16, 40, 1);
+
/* 64bit, WWID size: 18 */
-make_test_vpd_eui(8, 32);
-make_test_vpd_eui(8, 18);
-make_test_vpd_eui(8, 17);
-make_test_vpd_eui(8, 16);
-make_test_vpd_eui(8, 10);
+make_test_vpd_eui(8, 32, 0);
+make_test_vpd_eui(8, 18, 0);
+make_test_vpd_eui(8, 17, 0);
+make_test_vpd_eui(8, 16, 0);
+make_test_vpd_eui(8, 10, 0);
/* 96 bit, WWID size: 26 */
-make_test_vpd_eui(12, 32);
-make_test_vpd_eui(12, 26);
-make_test_vpd_eui(12, 25);
-make_test_vpd_eui(12, 20);
-make_test_vpd_eui(12, 10);
+make_test_vpd_eui(12, 32, 0);
+make_test_vpd_eui(12, 26, 0);
+make_test_vpd_eui(12, 25, 0);
+make_test_vpd_eui(12, 20, 0);
+make_test_vpd_eui(12, 10, 0);
/* 128 bit, WWID size: 34 */
-make_test_vpd_eui(16, 40);
-make_test_vpd_eui(16, 34);
-make_test_vpd_eui(16, 33);
-make_test_vpd_eui(16, 20);
+make_test_vpd_eui(16, 40, 0);
+make_test_vpd_eui(16, 34, 0);
+make_test_vpd_eui(16, 33, 0);
+make_test_vpd_eui(16, 20, 0);
/* NAA IEEE registered extended (36), WWID size: 34 */
make_test_vpd_naa(6, 40);
@@ -722,20 +737,23 @@ static int test_vpd(void)
cmocka_unit_test(test_vpd_vnd_19_20),
cmocka_unit_test(test_vpd_vnd_20_10),
cmocka_unit_test(test_vpd_vnd_10_10),
- cmocka_unit_test(test_vpd_eui_8_32),
- cmocka_unit_test(test_vpd_eui_8_18),
- cmocka_unit_test(test_vpd_eui_8_17),
- cmocka_unit_test(test_vpd_eui_8_16),
- cmocka_unit_test(test_vpd_eui_8_10),
- cmocka_unit_test(test_vpd_eui_12_32),
- cmocka_unit_test(test_vpd_eui_12_26),
- cmocka_unit_test(test_vpd_eui_12_25),
- cmocka_unit_test(test_vpd_eui_12_20),
- cmocka_unit_test(test_vpd_eui_12_10),
- cmocka_unit_test(test_vpd_eui_16_40),
- cmocka_unit_test(test_vpd_eui_16_34),
- cmocka_unit_test(test_vpd_eui_16_33),
- cmocka_unit_test(test_vpd_eui_16_20),
+ cmocka_unit_test(test_vpd_eui_8_32_1),
+ cmocka_unit_test(test_vpd_eui_12_32_1),
+ cmocka_unit_test(test_vpd_eui_16_40_1),
+ cmocka_unit_test(test_vpd_eui_8_32_0),
+ cmocka_unit_test(test_vpd_eui_8_18_0),
+ cmocka_unit_test(test_vpd_eui_8_17_0),
+ cmocka_unit_test(test_vpd_eui_8_16_0),
+ cmocka_unit_test(test_vpd_eui_8_10_0),
+ cmocka_unit_test(test_vpd_eui_12_32_0),
+ cmocka_unit_test(test_vpd_eui_12_26_0),
+ cmocka_unit_test(test_vpd_eui_12_25_0),
+ cmocka_unit_test(test_vpd_eui_12_20_0),
+ cmocka_unit_test(test_vpd_eui_12_10_0),
+ cmocka_unit_test(test_vpd_eui_16_40_0),
+ cmocka_unit_test(test_vpd_eui_16_34_0),
+ cmocka_unit_test(test_vpd_eui_16_33_0),
+ cmocka_unit_test(test_vpd_eui_16_20_0),
cmocka_unit_test(test_vpd_naa_6_40),
cmocka_unit_test(test_vpd_naa_6_34),
cmocka_unit_test(test_vpd_naa_6_33),
--
2.17.2

View File

@ -1,116 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 1 Nov 2019 12:35:47 -0500
Subject: [PATCH] libmultipath: add vend_id to get_vpd_sgio
This tells multipath how it should decode vendor specific pages. It will
be used by a future patch.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 4 ++--
libmultipath/discovery.h | 2 +-
libmultipath/propsel.c | 2 +-
tests/vpd.c | 10 +++++-----
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 3c72a80a..1d79cbae 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1135,7 +1135,7 @@ get_vpd_sysfs (struct udev_device *parent, int pg, char * str, int maxlen)
}
int
-get_vpd_sgio (int fd, int pg, char * str, int maxlen)
+get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen)
{
int len, buff_len;
unsigned char buff[4096];
@@ -1810,7 +1810,7 @@ static ssize_t uid_fallback(struct path *pp, int path_state,
if (len < 0 && path_state == PATH_UP) {
condlog(1, "%s: failed to get sysfs uid: %s",
pp->dev, strerror(-len));
- len = get_vpd_sgio(pp->fd, 0x83, pp->wwid,
+ len = get_vpd_sgio(pp->fd, 0x83, 0, pp->wwid,
WWID_SIZE);
*origin = "sgio";
}
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
index 8d04c2af..2f2fd9eb 100644
--- a/libmultipath/discovery.h
+++ b/libmultipath/discovery.h
@@ -35,7 +35,7 @@ int path_get_tpgs(struct path *pp); /* This function never returns TPGS_UNDEF */
int do_tur (char *);
int path_offline (struct path *);
int get_state (struct path * pp, struct config * conf, int daemon, int state);
-int get_vpd_sgio (int fd, int pg, char * str, int maxlen);
+int get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen);
int pathinfo (struct path * pp, struct config * conf, int mask);
int alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice,
const char *wwid, int flag, struct path **pp_ptr);
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index 27e8d68a..b5b5b89f 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -490,7 +490,7 @@ check_rdac(struct path * pp)
if (__do_set_from_hwe(checker_name, pp, checker_name) &&
strcmp(checker_name, RDAC))
return 0;
- len = get_vpd_sgio(pp->fd, 0xC9, buff, 44);
+ len = get_vpd_sgio(pp->fd, 0xC9, 0, buff, 44);
if (len <= 0)
return 0;
return !(memcmp(buff + 4, "vac1", 4));
diff --git a/tests/vpd.c b/tests/vpd.c
index 4dbce010..02d6e0bb 100644
--- a/tests/vpd.c
+++ b/tests/vpd.c
@@ -431,7 +431,7 @@ static void test_vpd_vnd_ ## len ## _ ## wlen(void **state) \
will_return(__wrap_ioctl, vt->vpdbuf); \
will_return(__wrap_ioctl, n); \
will_return(__wrap_ioctl, vt->vpdbuf); \
- ret = get_vpd_sgio(10, 0x83, vt->wwid, wlen); \
+ ret = get_vpd_sgio(10, 0x83, 0, vt->wwid, wlen); \
assert_correct_wwid("test_vpd_vnd_" #len "_" #wlen, \
exp_len, ret, '1', 0, false, \
exp_subst, vt->wwid); \
@@ -463,7 +463,7 @@ static void test_vpd_str_ ## typ ## _ ## len ## _ ## wlen(void **state) \
will_return(__wrap_ioctl, vt->vpdbuf); \
will_return(__wrap_ioctl, n); \
will_return(__wrap_ioctl, vt->vpdbuf); \
- ret = get_vpd_sgio(10, 0x83, vt->wwid, wlen); \
+ ret = get_vpd_sgio(10, 0x83, 0, vt->wwid, wlen); \
assert_correct_wwid("test_vpd_str_" #typ "_" #len "_" #wlen, \
exp_len, ret, byte0[type], 0, \
type != STR_IQN, \
@@ -502,7 +502,7 @@ static void test_vpd_naa_ ## naa ## _ ## wlen(void **state) \
will_return(__wrap_ioctl, vt->vpdbuf); \
will_return(__wrap_ioctl, n); \
will_return(__wrap_ioctl, vt->vpdbuf); \
- ret = get_vpd_sgio(10, 0x83, vt->wwid, wlen); \
+ ret = get_vpd_sgio(10, 0x83, 0, vt->wwid, wlen); \
assert_correct_wwid("test_vpd_naa_" #naa "_" #wlen, \
exp_len, ret, '3', '0' + naa, true, \
test_id, vt->wwid); \
@@ -530,7 +530,7 @@ static void test_vpd_eui_ ## len ## _ ## wlen ## _ ## sml(void **state) \
will_return(__wrap_ioctl, vt->vpdbuf); \
will_return(__wrap_ioctl, n); \
will_return(__wrap_ioctl, vt->vpdbuf); \
- ret = get_vpd_sgio(10, 0x83, vt->wwid, wlen); \
+ ret = get_vpd_sgio(10, 0x83, 0, vt->wwid, wlen); \
assert_correct_wwid("test_vpd_eui_" #len "_" #wlen "_" #sml, \
exp_len, ret, '2', 0, true, \
test_id, vt->wwid); \
@@ -557,7 +557,7 @@ static void test_vpd80_ ## size ## _ ## len ## _ ## wlen(void **state) \
size, len); \
will_return(__wrap_ioctl, n); \
will_return(__wrap_ioctl, vt->vpdbuf); \
- ret = get_vpd_sgio(10, 0x80, vt->wwid, wlen); \
+ ret = get_vpd_sgio(10, 0x80, 0, vt->wwid, wlen); \
assert_correct_wwid("test_vpd80_" #size "_" #len "_" #wlen, \
exp_len, ret, 0, 0, false, \
input, vt->wwid); \
--
2.17.2

View File

@ -0,0 +1,185 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Tue, 12 May 2020 00:39:26 +0200
Subject: [PATCH] libmultipath: eliminate more signed/unsigned comparisons
Fix some more compiler warnings about signed/unsigned comparison.
I've observed these only on 32bit builds, therefore they went unnoticed
before.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/print.c | 12 ++++++------
libmultipath/prioritizers/alua_spc3.h | 2 +-
multipathd/cli_handlers.c | 20 ++++++++++----------
multipathd/main.c | 2 +-
4 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/libmultipath/print.c b/libmultipath/print.c
index b944ef32..298b3764 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -1958,25 +1958,25 @@ char *snprint_config(const struct config *conf, int *len,
}
c = reply + snprint_defaults(conf, reply, maxlen);
- if ((c - reply) == maxlen)
+ if (c == reply + maxlen)
continue;
c += snprint_blacklist(conf, c, reply + maxlen - c);
- if ((c - reply) == maxlen)
+ if (c == reply + maxlen)
continue;
c += snprint_blacklist_except(conf, c, reply + maxlen - c);
- if ((c - reply) == maxlen)
+ if (c == reply + maxlen)
continue;
c += snprint_hwtable(conf, c, reply + maxlen - c,
hwtable ? hwtable : conf->hwtable);
- if ((c - reply) == maxlen)
+ if (c == reply + maxlen)
continue;
c += snprint_overrides(conf, c, reply + maxlen - c,
conf->overrides);
- if ((c - reply) == maxlen)
+ if (c == reply + maxlen)
continue;
if (VECTOR_SIZE(conf->mptable) > 0 ||
@@ -1984,7 +1984,7 @@ char *snprint_config(const struct config *conf, int *len,
c += snprint_mptable(conf, c, reply + maxlen - c,
mpvec);
- if ((c - reply) < maxlen) {
+ if (c < reply + maxlen) {
if (len)
*len = c - reply;
return reply;
diff --git a/libmultipath/prioritizers/alua_spc3.h b/libmultipath/prioritizers/alua_spc3.h
index 18b495ef..7ba2cf4c 100644
--- a/libmultipath/prioritizers/alua_spc3.h
+++ b/libmultipath/prioritizers/alua_spc3.h
@@ -284,7 +284,7 @@ struct rtpg_data {
#define RTPG_FOR_EACH_PORT_GROUP(p, g) \
for( \
g = &(p->data[0]); \
- (((char *) g) - ((char *) p)) < get_unaligned_be32(p->length); \
+ ((char *) g) < ((char *) p) + get_unaligned_be32(p->length); \
g = (struct rtpg_tpg_dscr *) ( \
((char *) g) + \
sizeof(struct rtpg_tpg_dscr) + \
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 7d878c88..31c3d9fd 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -66,7 +66,7 @@ show_paths (char ** r, int * len, struct vectors * vecs, char * style,
c += snprint_foreign_paths(c, reply + maxlen - c,
style, pretty);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -102,7 +102,7 @@ show_path (char ** r, int * len, struct vectors * vecs, struct path *pp,
c += snprint_path(c, reply + maxlen - c, style, pp, 0);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -131,7 +131,7 @@ show_map_topology (char ** r, int * len, struct multipath * mpp,
c = reply;
c += snprint_multipath_topology(c, reply + maxlen - c, mpp, 2);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -171,7 +171,7 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs)
}
c += snprint_foreign_topology(c, reply + maxlen - c, 2);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -209,7 +209,7 @@ show_maps_json (char ** r, int * len, struct vectors * vecs)
c = reply;
c += snprint_multipath_topology_json(c, maxlen, vecs);
- again = ((c - reply) == maxlen);
+ again = (c == reply + maxlen);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -238,7 +238,7 @@ show_map_json (char ** r, int * len, struct multipath * mpp,
c = reply;
c += snprint_multipath_map_json(c, maxlen, mpp);
- again = ((c - reply) == maxlen);
+ again = (c == reply + maxlen);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -487,7 +487,7 @@ show_map (char ** r, int *len, struct multipath * mpp, char * style,
c += snprint_multipath(c, reply + maxlen - c, style,
mpp, pretty);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -533,7 +533,7 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style,
}
c += snprint_foreign_multipaths(c, reply + maxlen - c,
style, pretty);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -1297,7 +1297,7 @@ show_blacklist (char ** r, int * len)
c = reply;
c += snprint_blacklist_report(conf, c, maxlen);
- again = ((c - reply) == maxlen);
+ again = (c == reply + maxlen);
REALLOC_REPLY(reply, again, maxlen);
}
pthread_cleanup_pop(1);
@@ -1339,7 +1339,7 @@ show_devices (char ** r, int * len, struct vectors *vecs)
c = reply;
c += snprint_devices(conf, c, maxlen, vecs);
- again = ((c - reply) == maxlen);
+ again = (c == reply + maxlen);
REALLOC_REPLY(reply, again, maxlen);
}
pthread_cleanup_pop(1);
diff --git a/multipathd/main.c b/multipathd/main.c
index 8baf9abe..6b7db2c0 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -2374,7 +2374,7 @@ checkerloop (void *ap)
conf = get_multipath_config();
max_checkint = conf->max_checkint;
put_multipath_config(conf);
- if (diff_time.tv_sec > max_checkint)
+ if (diff_time.tv_sec > (time_t)max_checkint)
condlog(1, "path checkers took longer "
"than %lu seconds, consider "
"increasing max_polling_interval",
--
2.17.2

View File

@ -1,350 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 4 Nov 2019 15:38:25 -0600
Subject: [PATCH] libmultipath: add code to get vendor specific vpd data
This adds the wildcard 'g' for multipath and path formatted printing,
which returns extra data from a device's vendor specific vpd page. The
specific vendor vpd page to use, and the vendor/product id to decode it
can be set in the hwentry with vpd_vendor_pg and vpd_vendor_id. It can
be configured in the devices section of multipath.conf with the
vpd_vendor parameter. Currently, the only devices that use this are HPE
3PAR arrays, to return the Volume Name.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 4 ++++
libmultipath/config.h | 2 ++
libmultipath/dict.c | 34 ++++++++++++++++++++++++++++++++++
libmultipath/discovery.c | 34 +++++++++++++++++++++++++++++++++-
libmultipath/hwtable.c | 2 ++
libmultipath/print.c | 27 +++++++++++++++++++++++++++
libmultipath/propsel.c | 24 ++++++++++++++++++++++++
libmultipath/propsel.h | 2 ++
libmultipath/structs.h | 9 +++++++++
multipath/multipath.conf.5 | 8 ++++++++
10 files changed, 145 insertions(+), 1 deletion(-)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 85626e96..72b8d37c 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -369,6 +369,8 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
merge_num(max_sectors_kb);
merge_num(ghost_delay);
merge_num(all_tg_pt);
+ merge_num(vpd_vendor_pg);
+ merge_num(vpd_vendor_id);
merge_num(san_path_err_threshold);
merge_num(san_path_err_forget_rate);
merge_num(san_path_err_recovery_time);
@@ -517,6 +519,8 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
hwe->detect_prio = dhwe->detect_prio;
hwe->detect_checker = dhwe->detect_checker;
hwe->ghost_delay = dhwe->ghost_delay;
+ hwe->vpd_vendor_pg = dhwe->vpd_vendor_pg;
+ hwe->vpd_vendor_id = dhwe->vpd_vendor_id;
if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
goto out;
diff --git a/libmultipath/config.h b/libmultipath/config.h
index e69aa07c..589146de 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -87,6 +87,8 @@ struct hwentry {
int max_sectors_kb;
int ghost_delay;
int all_tg_pt;
+ int vpd_vendor_pg;
+ int vpd_vendor_id;
char * bl_product;
};
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 2b046e1d..d6d8b79b 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -1366,6 +1366,39 @@ def_uxsock_timeout_handler(struct config *conf, vector strvec)
return 0;
}
+static int
+hw_vpd_vendor_handler(struct config *conf, vector strvec)
+{
+ int rc = 0;
+ char *buff;
+
+ struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+ if (!hwe)
+ return 1;
+
+ buff = set_value(strvec);
+ if (!buff)
+ return 1;
+ if (strcmp(buff, "hp3par") == 0) {
+ hwe->vpd_vendor_pg = 0xc0;
+ hwe->vpd_vendor_id = VPD_VP_HP3PAR;
+ } else
+ rc = 1;
+ FREE(buff);
+ return rc;
+}
+
+static int
+snprint_hw_vpd_vendor(struct config *conf, char * buff, int len,
+ const void * data)
+{
+ const struct hwentry * hwe = (const struct hwentry *)data;
+
+ if (hwe->vpd_vendor_pg == 0xc0 && hwe->vpd_vendor_id == VPD_VP_HP3PAR)
+ return snprintf(buff, len, "hp3par");
+ return 0;
+}
+
/*
* blacklist block handlers
*/
@@ -1806,6 +1839,7 @@ init_keywords(vector keywords)
install_keyword("max_sectors_kb", &hw_max_sectors_kb_handler, &snprint_hw_max_sectors_kb);
install_keyword("ghost_delay", &hw_ghost_delay_handler, &snprint_hw_ghost_delay);
install_keyword("all_tg_pt", &hw_all_tg_pt_handler, &snprint_hw_all_tg_pt);
+ install_keyword("vpd_vendor", &hw_vpd_vendor_handler, &snprint_hw_vpd_vendor);
install_sublevel_end();
install_keyword_root("overrides", &overrides_handler);
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 1d79cbae..d2773c3a 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1103,6 +1103,30 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
return len;
}
+static int
+parse_vpd_c0_hp3par(const unsigned char *in, size_t in_len,
+ char *out, size_t out_len)
+{
+ size_t len;
+
+ memset(out, 0x0, out_len);
+ if (in_len <= 4 || (in[4] > 3 && in_len < 44)) {
+ condlog(3, "HP/3PAR vendor specific VPD page length too short: %lu", in_len);
+ return -EINVAL;
+ }
+ if (in[4] <= 3) /* revision must be > 3 to have Vomlume Name */
+ return -ENODATA;
+ len = get_unaligned_be32(&in[40]);
+ if (len > out_len || len + 44 > in_len) {
+ condlog(3, "HP/3PAR vendor specific Volume name too long: %lu",
+ len);
+ return -EINVAL;
+ }
+ memcpy(out, &in[44], len);
+ out[out_len - 1] = '\0';
+ return len;
+}
+
static int
get_vpd_sysfs (struct udev_device *parent, int pg, char * str, int maxlen)
{
@@ -1170,7 +1194,9 @@ get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen)
len = (buff_len <= maxlen)? buff_len : maxlen;
memcpy (str, buff, len);
}
- } else
+ } else if (pg == 0xc0 && vend_id == VPD_VP_HP3PAR)
+ len = parse_vpd_c0_hp3par(buff, buff_len, str, maxlen);
+ else
len = -ENOSYS;
return len;
@@ -1544,6 +1570,12 @@ scsi_ioctl_pathinfo (struct path * pp, struct config *conf, int mask)
if (!(mask & DI_SERIAL))
return;
+ select_vpd_vendor_pg(conf, pp);
+ select_vpd_vendor_id(conf, pp);
+
+ if (pp->vpd_vendor_pg != 0 && get_vpd_sgio(pp->fd, pp->vpd_vendor_pg, pp->vpd_vendor_id, pp->vpd_data, sizeof(pp->vpd_data)) < 0)
+ condlog(3, "%s: failed to get extra vpd data", pp->dev);
+
parent = pp->udev;
while (parent) {
const char *subsys = udev_device_get_subsystem(parent);
diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
index 16627ec5..1f27450c 100644
--- a/libmultipath/hwtable.c
+++ b/libmultipath/hwtable.c
@@ -117,6 +117,8 @@ static struct hwentry default_hw[] = {
.no_path_retry = 18,
.fast_io_fail = 10,
.dev_loss = MAX_DEV_LOSS_TMO,
+ .vpd_vendor_pg = 0xc0,
+ .vpd_vendor_id = VPD_VP_HP3PAR,
},
{
/* RA8000 / ESA12000 */
diff --git a/libmultipath/print.c b/libmultipath/print.c
index 907469ad..0aafe3cb 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -358,6 +358,23 @@ snprint_action (char * buff, size_t len, const struct multipath * mpp)
}
}
+static int
+snprint_multipath_vpd_data(char * buff, size_t len,
+ const struct multipath * mpp)
+{
+ struct pathgroup * pgp;
+ struct path * pp;
+ int i, j;
+
+ vector_foreach_slot(mpp->pg, pgp, i) {
+ vector_foreach_slot(pgp->paths, pp, j) {
+ if (strlen(pp->vpd_data))
+ return snprintf(buff, len, "%s", pp->vpd_data);
+ }
+ }
+ return 0;
+}
+
/*
* path info printing functions
*/
@@ -688,6 +705,14 @@ snprint_path_marginal(char * buff, size_t len, const struct path * pp)
return snprintf(buff, len, "normal");
}
+static int
+snprint_path_vpd_data(char * buff, size_t len, const struct path * pp)
+{
+ if (strlen(pp->vpd_data) > 0)
+ return snprintf(buff, len, "%s", pp->vpd_data);
+ return 0;
+}
+
struct multipath_data mpd[] = {
{'n', "name", 0, snprint_name},
{'w', "uuid", 0, snprint_multipath_uuid},
@@ -712,6 +737,7 @@ struct multipath_data mpd[] = {
{'p', "prod", 0, snprint_multipath_prod},
{'e', "rev", 0, snprint_multipath_rev},
{'G', "foreign", 0, snprint_multipath_foreign},
+ {'g', "vpd page data", 0, snprint_multipath_vpd_data},
{0, NULL, 0 , NULL}
};
@@ -737,6 +763,7 @@ struct path_data pd[] = {
{'r', "target WWPN", 0, snprint_tgt_wwpn},
{'a', "host adapter", 0, snprint_host_adapter},
{'G', "foreign", 0, snprint_path_foreign},
+ {'g', "vpd page data", 0, snprint_path_vpd_data},
{'0', "failures", 0, snprint_path_failures},
{'P', "protocol", 0, snprint_path_protocol},
{0, NULL, 0 , NULL}
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index b5b5b89f..3c99f2d4 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -1203,3 +1203,27 @@ out:
origin);
return 0;
}
+
+int select_vpd_vendor_pg (struct config *conf, struct path *pp)
+{
+ const char *origin;
+
+ pp_set_hwe(vpd_vendor_pg);
+ pp_set_default(vpd_vendor_pg, 0);
+out:
+ condlog(3, "%s: vpd_vendor_pg = 0x%x %s", pp->dev, pp->vpd_vendor_pg,
+ origin);
+ return 0;
+}
+
+int select_vpd_vendor_id (struct config *conf, struct path *pp)
+{
+ const char *origin;
+
+ pp_set_hwe(vpd_vendor_id);
+ pp_set_default(vpd_vendor_id, 0);
+out:
+ condlog(3, "%s: vpd_vendor_id = 0x%x %s", pp->dev, pp->vpd_vendor_id,
+ origin);
+ return 0;
+}
diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h
index ddfd6262..3f6d319a 100644
--- a/libmultipath/propsel.h
+++ b/libmultipath/propsel.h
@@ -37,3 +37,5 @@ void reconcile_features_with_options(const char *id, char **features,
int* no_path_retry,
int *retain_hwhandler);
int select_all_tg_pt (struct config *conf, struct multipath * mp);
+int select_vpd_vendor_pg (struct config *conf, struct path *pp);
+int select_vpd_vendor_id (struct config *conf, struct path *pp);
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 1c32a799..1ad5f64a 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -21,6 +21,7 @@
#define HOST_NAME_LEN 16
#define SLOT_NAME_SIZE 40
#define PRKEY_SIZE 19
+#define VPD_DATA_SIZE 128
#define SCSI_VENDOR_SIZE 9
#define SCSI_PRODUCT_SIZE 17
@@ -243,6 +244,11 @@ struct hd_geometry {
};
#endif
+/*
+ * from sg_vpd_vendor.c
+ */
+#define VPD_VP_HP3PAR 4
+
struct path {
char dev[FILE_NAME_SIZE];
char dev_t[BLK_DEV_SIZE];
@@ -255,6 +261,7 @@ struct path {
char rev[PATH_REV_SIZE];
char serial[SERIAL_SIZE];
char tgt_node_name[NODE_NAME_SIZE];
+ char vpd_data[VPD_DATA_SIZE];
unsigned long long size;
unsigned int checkint;
unsigned int tick;
@@ -287,6 +294,8 @@ struct path {
int io_err_pathfail_starttime;
int find_multipaths_timeout;
int marginal;
+ int vpd_vendor_pg;
+ int vpd_vendor_id;
/* configlet pointers */
vector hwe;
struct gen_path generic_path;
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index e866da23..dc103fd8 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -1472,6 +1472,14 @@ the \fIproduct\fR attribute set to the value of \fIproduct_blacklist\fR.
The user_friendly_names prefix to use for this
device type, instead of the default "mpath".
.TP
+.B vpd_vendor
+The vendor specific vpd page information, using the vpd page abbreviation.
+The vpd page abbreviation can be found by running \fIsg_vpd -e\fR. multipathd
+will use this information to gather device specific information that can be
+displayed with the \fI%g\fR wilcard for the \fImultipathd show maps format\fR
+and \fImultipathd show paths format\fR commands. Currently only the
+\fBhp3par\fR vpd page is supported.
+.TP
.B hardware_handler
The hardware handler to use for this device type.
The following hardware handler are implemented:
--
2.17.2

View File

@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Tue, 12 May 2020 00:39:27 +0200
Subject: [PATCH] libmultipath: set_uint: fix parsing for 32bit
On architectures where sizeof(long) == sizeof(int), the code wouldn't
work as intended. Use strtoul instead. As strtoul happily parses
negative numbers as input, require the number to begin with a digit.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/dict.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 3e25e74f..0e9ea387 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -60,19 +60,22 @@ static int
set_uint(vector strvec, void *ptr)
{
unsigned int *uint_ptr = (unsigned int *)ptr;
- char *buff, *eptr;
- long res;
+ char *buff, *eptr, *p;
+ unsigned long res;
int rc;
buff = set_value(strvec);
if (!buff)
return 1;
- res = strtol(buff, &eptr, 10);
+ p = buff;
+ while (isspace(*p))
+ p++;
+ res = strtoul(p, &eptr, 10);
if (eptr > buff)
while (isspace(*eptr))
eptr++;
- if (*buff == '\0' || *eptr != '\0' || res < 0 || res > UINT_MAX) {
+ if (*buff == '\0' || *eptr != '\0' || !isdigit(*p) || res > UINT_MAX) {
condlog(1, "%s: invalid value for %s: \"%s\"",
__func__, (char*)VECTOR_SLOT(strvec, 0), buff);
rc = 1;
--
2.17.2

View File

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Tue, 12 May 2020 22:38:22 +0200
Subject: [PATCH] multipath-tools Makefile: add install dependency
$(libdir) must exist before running "make install" on prioritizer, checker,
and foreign libraries.
Cc: Christian Hesse <mail@eworm.de>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Makefile b/Makefile
index fec3b73b..8bcaba66 100644
--- a/Makefile
+++ b/Makefile
@@ -32,6 +32,10 @@ libmultipath libdmmp: libmpathcmd
libmpathpersist multipath multipathd: libmultipath
mpathpersist multipathd: libmpathpersist
+libmultipath/checkers.install \
+ libmultipath/prioritizers.install \
+ libmultipath/foreign.install: libmultipath.install
+
$(BUILDDIRS.clean):
$(MAKE) -C ${@:.clean=} clean
--
2.17.2

View File

@ -15,7 +15,7 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc
index 56c3eda0..2e8946ca 100644
index 9060ac9b..034752d9 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -53,7 +53,7 @@ endif

View File

@ -46,10 +46,10 @@ index 00e8dbdb..d9691b17 100644
udev_device_get_properties_list_entry(udev)) {
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index dc103fd8..b8697d47 100644
index 05a5e8ff..3455b1cc 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -1285,9 +1285,14 @@ keywords. Both are regular expressions. For a full description of these keywords
@@ -1286,9 +1286,14 @@ keywords. Both are regular expressions. For a full description of these keywords
Regular expression for an udev property. All
devices that have matching udev properties will be excluded/included.
The handling of the \fIproperty\fR keyword is special,
@ -65,7 +65,7 @@ index dc103fd8..b8697d47 100644
.
.RS
.PP
@@ -1298,10 +1303,6 @@ Blacklisting by missing properties is only applied to devices which do have the
@@ -1299,10 +1304,6 @@ Blacklisting by missing properties is only applied to devices which do have the
property specified by \fIuid_attribute\fR (e.g. \fIID_SERIAL\fR)
set. Previously, it was applied to every device, possibly causing devices to be
blacklisted because of temporary I/O error conditions.
@ -77,10 +77,10 @@ index dc103fd8..b8697d47 100644
.TP
.B protocol
diff --git a/tests/blacklist.c b/tests/blacklist.c
index 362c44d9..ea284939 100644
index 6e7c1864..cc8a9a4a 100644
--- a/tests/blacklist.c
+++ b/tests/blacklist.c
@@ -291,7 +291,7 @@ static void test_property_missing(void **state)
@@ -271,7 +271,7 @@ static void test_property_missing(void **state)
conf.blist_property = blist_property_wwn;
expect_condlog(3, "sdb: blacklisted, udev property missing\n");
assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
@ -89,7 +89,7 @@ index 362c44d9..ea284939 100644
assert_int_equal(filter_property(&conf, &udev, 3, "ID_BLAH"),
MATCH_NOTHING);
assert_int_equal(filter_property(&conf, &udev, 3, ""),
@@ -383,9 +383,7 @@ static void test_filter_path_missing1(void **state)
@@ -363,9 +363,7 @@ static void test_filter_path_missing1(void **state)
conf.blist_device = blist_device_foo_bar;
conf.blist_protocol = blist_protocol_fcp;
conf.blist_wwid = blist_wwid_xyzzy;

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 72b8d37c..4032c4c4 100644
index b4d87689..b36778b0 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -26,6 +26,7 @@
@ -31,7 +31,7 @@ index 72b8d37c..4032c4c4 100644
static int
hwe_strmatch (const struct hwentry *hwe1, const struct hwentry *hwe2)
@@ -755,6 +756,20 @@ load_config (char * file)
@@ -778,6 +779,20 @@ load_config (char * file)
goto out;
}
factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
@ -53,7 +53,7 @@ index 72b8d37c..4032c4c4 100644
conf->processed_main_config = 1;
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 589146de..2adbd077 100644
index ceecff2d..3368d8c9 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -9,6 +9,7 @@

View File

@ -9,45 +9,56 @@ still being generic.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile.inc | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
Makefile.inc | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc
index 2e8946ca..1b2f47a8 100644
index 034752d9..c2abd301 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -88,15 +88,23 @@ TEST_CC_OPTION = $(shell \
@@ -89,16 +89,29 @@ TEST_CC_OPTION = $(shell \
echo "$(2)"; \
fi)
-STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
ERROR_DISCARDED_QUALIFIERS := $(call TEST_CC_OPTION,-Werror=discarded-qualifiers,)
-
-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 $(ERROR_DISCARDED_QUALIFIERS) \
- -Wp,-D_FORTIFY_SOURCE=2 $(STACKPROT) \
- --param=ssp-buffer-size=4
WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered -Wno-error=clobbered,)
+ifndef RPM_OPT_FLAGS
+ STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
+ OPTFLAGS = -O2 -g -pipe -Wall -Werror=format-security \
+ -Wp,-D_FORTIFY_SOURCE=2 -fexceptions \
+ $(STACKPROT) --param=ssp-buffer-size=4 \
+ -grecord-gcc-switches
+ $(STACKPROT) -grecord-gcc-switches \
+ -fasynchronous-unwind-tables
+ ifeq ($(shell test -f /usr/lib/rpm/redhat/redhat-hardened-cc1 && echo 1),1)
+ OPTFLAGS += -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1
+ endif
+ ifeq ($(shell test -f /usr/lib/rpm/redhat/redhat-annobin-cc1 && echo 1),1)
+ OPTFLAGS += -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1
+ endif
+else
+ OPTFLAGS = $(RPM_OPT_FLAGS)
+endif
+OPTFLAGS += -Wextra -Wstrict-prototypes -Wformat=2 -Werror=implicit-int \
+ -Werror=implicit-function-declaration -Wno-sign-compare \
+ -Wno-unused-parameter $(ERROR_DISCARDED_QUALIFIERS) \
+ -Werror=cast-qual
+OPTFLAGS += -Werror -Wextra -Wstrict-prototypes -Wformat=2 \
+ -Werror=implicit-int -Werror=implicit-function-declaration \
+ $(WNOCLOBBERED) \
+ -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) \
+ --param=ssp-buffer-size=4
-OPTFLAGS = -O2 -g -pipe -Werror -Wall -Wextra -Wformat=2 -Werror=implicit-int \
- -Werror=implicit-function-declaration -Werror=format-security \
- $(WNOCLOBBERED) \
- -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) \
- $(STACKPROT) --param=ssp-buffer-size=4
-CPPFLAGS := -Wp,-D_FORTIFY_SOURCE=2
CFLAGS := $(OPTFLAGS) -DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
-MMD -MP $(CFLAGS)
BIN_CFLAGS = -fPIE -DPIE
@@ -135,4 +148,4 @@ check_file = $(shell \
%.o: %.c
@echo building $@ because of $?
- $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+ $(CC) $(CFLAGS) -c -o $@ $<
--
2.17.2

View File

@ -21,10 +21,10 @@ 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 4032c4c4..2c32acf7 100644
index b36778b0..26f8e050 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -758,6 +758,8 @@ load_config (char * file)
@@ -781,6 +781,8 @@ load_config (char * file)
factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
} else {
condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
@ -630,7 +630,7 @@ index 00000000..f34003c9
+fi
diff --git a/multipath/mpathconf.8 b/multipath/mpathconf.8
new file mode 100644
index 00000000..7937ea05
index 00000000..b82961d6
--- /dev/null
+++ b/multipath/mpathconf.8
@@ -0,0 +1,135 @@
@ -705,7 +705,7 @@ index 00000000..7937ea05
+mpathconf will not be able to revert back to its previous state. Because
+of this, \fB--outfile\fP is required when using \fB--allow\fP.
+.TP
+.B --user_friendly_name \fP { \fBy\fP | \fBn\fP }
+.B --user_friendly_names \fP { \fBy\fP | \fBn\fP }
+If set to \fBy\fP, this adds the line
+.B user_friendly_names yes
+to the

View File

@ -22,10 +22,10 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
5 files changed, 60 insertions(+), 3 deletions(-)
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
index ef748125..349da8b7 100644
index 28a2150d..fab6fc8f 100644
--- a/libmultipath/wwids.c
+++ b/libmultipath/wwids.c
@@ -444,3 +444,47 @@ int op ## _wwid(const char *wwid) \
@@ -454,3 +454,47 @@ int op ## _wwid(const char *wwid) \
declare_failed_wwid_op(is_failed, false)
declare_failed_wwid_op(mark_failed, true)
declare_failed_wwid_op(unmark_failed, true)
@ -86,7 +86,7 @@ index 0c6ee54d..e32a0b0e 100644
enum {
WWID_IS_NOT_FAILED = 0,
diff --git a/multipath/main.c b/multipath/main.c
index 4f4d8e89..22aff7be 100644
index cf9d2a28..78822ee1 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -138,7 +138,7 @@ usage (char * progname)
@ -107,16 +107,16 @@ index 4f4d8e89..22aff7be 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"
@@ -905,7 +907,7 @@ main (int argc, char *argv[])
exit(RTVL_FAIL);
@@ -907,7 +909,7 @@ main (int argc, char *argv[])
multipath_conf = conf;
conf->retrigger_tries = 0;
conf->force_sync = 1;
- while ((arg = getopt(argc, argv, ":adcChl::FfM:v:p:b:BrR:itTquUwW")) != EOF ) {
+ while ((arg = getopt(argc, argv, ":aAdcChl::FfM:v:p:b:BrR:itTquUwW")) != EOF ) {
switch(arg) {
case 1: printf("optarg : %s\n",optarg);
break;
@@ -975,6 +977,10 @@ main (int argc, char *argv[])
@@ -977,6 +979,10 @@ main (int argc, char *argv[])
case 'T':
cmd = CMD_DUMP_CONFIG;
break;

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 d6d8b79b..07d2ba8f 100644
index 0e9ea387..184d4b22 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -58,6 +58,21 @@ set_str(vector strvec, void *ptr)
@@ -103,6 +103,21 @@ set_str(vector strvec, void *ptr)
return 0;
}
@ -41,7 +41,7 @@ index d6d8b79b..07d2ba8f 100644
static int
set_yes_no(vector strvec, void *ptr)
{
@@ -1455,7 +1470,7 @@ ble_ ## option ## _handler (struct config *conf, vector strvec) \
@@ -1504,7 +1519,7 @@ ble_ ## option ## _handler (struct config *conf, vector strvec) \
if (!conf->option) \
return 1; \
\
@ -50,7 +50,7 @@ index d6d8b79b..07d2ba8f 100644
if (!buff) \
return 1; \
\
@@ -1471,7 +1486,7 @@ ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \
@@ -1520,7 +1535,7 @@ ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \
if (!conf->option) \
return 1; \
\
@ -59,7 +59,7 @@ index d6d8b79b..07d2ba8f 100644
if (!buff) \
return 1; \
\
@@ -1574,16 +1589,16 @@ device_handler(struct config *conf, vector strvec)
@@ -1623,16 +1638,16 @@ device_handler(struct config *conf, vector strvec)
return 0;
}
@ -81,7 +81,7 @@ index d6d8b79b..07d2ba8f 100644
declare_hw_handler(hwhandler, set_str)
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index e00c5fff..15495d26 100644
index d478b177..a184511b 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -382,6 +382,19 @@ oom:

View File

@ -12,10 +12,10 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
index 4dfe007c..d910da51 100644
index e5ee6afe..52fe05b9 100644
--- a/libmultipath/defaults.h
+++ b/libmultipath/defaults.h
@@ -20,7 +20,7 @@
@@ -22,7 +22,7 @@
#define DEFAULT_NO_PATH_RETRY NO_PATH_RETRY_UNDEF
#define DEFAULT_VERBOSITY 2
#define DEFAULT_REASSIGN_MAPS 0

View File

@ -13,7 +13,7 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/libmultipath/prioritizers/ana.c b/libmultipath/prioritizers/ana.c
index 2673d9d9..f34ade28 100644
index b5c7873d..e139360c 100644
--- a/libmultipath/prioritizers/ana.c
+++ b/libmultipath/prioritizers/ana.c
@@ -24,6 +24,7 @@
@ -40,11 +40,11 @@ index 2673d9d9..f34ade28 100644
};
static const char *anas_string[] = {
@@ -106,6 +109,27 @@ static int get_ana_state(__u32 nsid, __u32 anagrpid, void *ana_log,
@@ -107,6 +110,27 @@ static int get_ana_state(__u32 nsid, __u32 anagrpid, void *ana_log,
return -ANA_ERR_GETANAS_NOTFOUND;
}
+int get_ana_info_sysfs(struct path *pp)
+static int get_ana_info_sysfs(struct path *pp)
+{
+ char state[32];
+
@ -65,19 +65,19 @@ index 2673d9d9..f34ade28 100644
+ return -ANA_ERR_INVALID_STATE;
+}
+
int get_ana_info(struct path * pp, unsigned int timeout)
static int get_ana_info(struct path * pp)
{
int rc;
@@ -208,8 +232,11 @@ int getprio(struct path *pp, char *args, unsigned int timeout)
@@ -210,8 +234,11 @@ int getprio(struct path *pp, __attribute__((unused)) char *args,
if (pp->fd < 0)
rc = -ANA_ERR_NO_INFORMATION;
- else
- rc = get_ana_info(pp, timeout);
- rc = get_ana_info(pp);
+ else {
+ rc = get_ana_info_sysfs(pp);
+ if (rc < 0)
+ rc = get_ana_info(pp, timeout);
+ rc = get_ana_info(pp);
+ }
switch (rc) {

View File

@ -0,0 +1,139 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 8 Jun 2020 14:27:51 -0500
Subject: [PATCH] libmultipath: remove _blacklist_exceptions functions
_blacklist_exceptions() and _blacklist_exceptions_device() are exactly
the same as _blacklist() and _blacklist_device(), so remove them, and
give the remaining functions to a more general name.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/blacklist.c | 62 ++++++++++------------------------------
1 file changed, 15 insertions(+), 47 deletions(-)
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
index d9691b17..04d3adb9 100644
--- a/libmultipath/blacklist.c
+++ b/libmultipath/blacklist.c
@@ -101,21 +101,8 @@ int set_ble_device(vector blist, char * vendor, char * product, int origin)
return 0;
}
-int
-_blacklist_exceptions (vector elist, const char * str)
-{
- int i;
- struct blentry * ele;
-
- vector_foreach_slot (elist, ele, i) {
- if (!regexec(&ele->regex, str, 0, NULL, 0))
- return 1;
- }
- return 0;
-}
-
-int
-_blacklist (vector blist, const char * str)
+static int
+match_reglist (vector blist, const char * str)
{
int i;
struct blentry * ble;
@@ -127,28 +114,9 @@ _blacklist (vector blist, const char * str)
return 0;
}
-int
-_blacklist_exceptions_device(const struct _vector *elist, const char * vendor,
- const char * product)
-{
- int i;
- struct blentry_device * ble;
-
- vector_foreach_slot (elist, ble, i) {
- if (!ble->vendor && !ble->product)
- continue;
- if ((!ble->vendor ||
- !regexec(&ble->vendor_reg, vendor, 0, NULL, 0)) &&
- (!ble->product ||
- !regexec(&ble->product_reg, product, 0, NULL, 0)))
- return 1;
- }
- return 0;
-}
-
-int
-_blacklist_device (const struct _vector *blist, const char * vendor,
- const char * product)
+static int
+match_reglist_device (const struct _vector *blist, const char * vendor,
+ const char * product)
{
int i;
struct blentry_device * ble;
@@ -294,9 +262,9 @@ filter_device (vector blist, vector elist, char * vendor, char * product,
int r = MATCH_NOTHING;
if (vendor && product) {
- if (_blacklist_exceptions_device(elist, vendor, product))
+ if (match_reglist_device(elist, vendor, product))
r = MATCH_DEVICE_BLIST_EXCEPT;
- else if (_blacklist_device(blist, vendor, product))
+ else if (match_reglist_device(blist, vendor, product))
r = MATCH_DEVICE_BLIST;
}
@@ -310,9 +278,9 @@ filter_devnode (vector blist, vector elist, char * dev)
int r = MATCH_NOTHING;
if (dev) {
- if (_blacklist_exceptions(elist, dev))
+ if (match_reglist(elist, dev))
r = MATCH_DEVNODE_BLIST_EXCEPT;
- else if (_blacklist(blist, dev))
+ else if (match_reglist(blist, dev))
r = MATCH_DEVNODE_BLIST;
}
@@ -326,9 +294,9 @@ filter_wwid (vector blist, vector elist, char * wwid, char * dev)
int r = MATCH_NOTHING;
if (wwid) {
- if (_blacklist_exceptions(elist, wwid))
+ if (match_reglist(elist, wwid))
r = MATCH_WWID_BLIST_EXCEPT;
- else if (_blacklist(blist, wwid))
+ else if (match_reglist(blist, wwid))
r = MATCH_WWID_BLIST;
}
@@ -345,9 +313,9 @@ filter_protocol(vector blist, vector elist, struct path * pp)
if (pp) {
snprint_path_protocol(buf, sizeof(buf), pp);
- if (_blacklist_exceptions(elist, buf))
+ if (match_reglist(elist, buf))
r = MATCH_PROTOCOL_BLIST_EXCEPT;
- else if (_blacklist(blist, buf))
+ else if (match_reglist(blist, buf))
r = MATCH_PROTOCOL_BLIST;
}
@@ -417,11 +385,11 @@ filter_property(struct config *conf, struct udev_device *udev, int lvl,
if (check_missing_prop && !strcmp(env, uid_attribute))
uid_attr_seen = true;
- if (_blacklist_exceptions(conf->elist_property, env)) {
+ if (match_reglist(conf->elist_property, env)) {
r = MATCH_PROPERTY_BLIST_EXCEPT;
break;
}
- if (_blacklist(conf->blist_property, env)) {
+ if (match_reglist(conf->blist_property, env)) {
r = MATCH_PROPERTY_BLIST;
break;
}
--
2.17.2

View File

@ -1,41 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Enzo Matsumiya <ematsumiya@suse.de>
Date: Fri, 7 Feb 2020 11:45:25 -0300
Subject: [PATCH] libmultipath: fix files read from config_dir
If config_dir contains a file named, for example, "some.conf.backup", this file
will still be loaded by multipath because process_config_dir()
(libmultipath/config.c) uses strstr() to check for the ".conf" extension, but
that doesn't guarantee that ".conf" is at the end of the filename.
This patch will make sure that only files ending in ".conf" are loaded from
config_dir.
This is to comply with config_dir entry description in man 5 multipath.conf.
Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 2c32acf7..791d16a1 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -684,8 +684,11 @@ process_config_dir(struct config *conf, vector keywords, char *dir)
sr.n = n;
pthread_cleanup_push_cast(free_scandir_result, &sr);
for (i = 0; i < n; i++) {
- if (!strstr(namelist[i]->d_name, ".conf"))
+ char *ext = strrchr(namelist[i]->d_name, '.');
+
+ if (!ext || strcmp(ext, ".conf"))
continue;
+
old_hwtable_size = VECTOR_SIZE(conf->hwtable);
snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
path[LINE_MAX-1] = '\0';
--
2.17.2

View File

@ -0,0 +1,95 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 8 Jun 2020 20:23:56 -0500
Subject: [PATCH] libmultipath: fix parser issue with comments in strings
If a quoted string starts with '#' or '!', the parser will stop
parsing the line, thinking that it's a comment. It should only
be checking for comments outside of quoted strings. Fixed this and
added unit tests to verify it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/parser.c | 4 +++-
tests/parser.c | 42 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index a184511b..a7285a35 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -300,8 +300,10 @@ alloc_strvec(char *string)
(isspace((int) *cp) || !isascii((int) *cp)))
&& *cp != '\0')
cp++;
- if (*cp == '\0' || *cp == '!' || *cp == '#')
+ if (*cp == '\0' ||
+ (!in_string && (*cp == '!' || *cp == '#'))) {
return strvec;
+ }
}
out:
vector_free(strvec);
diff --git a/tests/parser.c b/tests/parser.c
index 29859dac..5772391e 100644
--- a/tests/parser.c
+++ b/tests/parser.c
@@ -440,6 +440,46 @@ static void test18(void **state)
free_strvec(v);
}
+static void test19(void **state)
+{
+#define QUOTED19 "!value"
+ vector v = alloc_strvec("key \"" QUOTED19 "\"");
+ char *val;
+
+ assert_int_equal(VECTOR_SIZE(v), 4);
+ assert_string_equal(VECTOR_SLOT(v, 0), "key");
+ assert_true(is_quote(VECTOR_SLOT(v, 1)));
+ assert_string_equal(VECTOR_SLOT(v, 2), QUOTED19);
+ assert_true(is_quote(VECTOR_SLOT(v, 3)));
+ assert_int_equal(validate_config_strvec(v, test_file), 0);
+
+ val = set_value(v);
+ assert_string_equal(val, QUOTED19);
+
+ free(val);
+ free_strvec(v);
+}
+
+static void test20(void **state)
+{
+#define QUOTED20 "#value"
+ vector v = alloc_strvec("key \"" QUOTED20 "\"");
+ char *val;
+
+ assert_int_equal(VECTOR_SIZE(v), 4);
+ assert_string_equal(VECTOR_SLOT(v, 0), "key");
+ assert_true(is_quote(VECTOR_SLOT(v, 1)));
+ assert_string_equal(VECTOR_SLOT(v, 2), QUOTED20);
+ assert_true(is_quote(VECTOR_SLOT(v, 3)));
+ assert_int_equal(validate_config_strvec(v, test_file), 0);
+
+ val = set_value(v);
+ assert_string_equal(val, QUOTED20);
+
+ free(val);
+ free_strvec(v);
+}
+
int test_config_parser(void)
{
const struct CMUnitTest tests[] = {
@@ -461,6 +501,8 @@ int test_config_parser(void)
cmocka_unit_test(test16),
cmocka_unit_test(test17),
cmocka_unit_test(test18),
+ cmocka_unit_test(test19),
+ cmocka_unit_test(test20),
};
return cmocka_run_group_tests(tests, setup, teardown);
}
--
2.17.2

View File

@ -0,0 +1,435 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 8 Jun 2020 13:40:16 -0500
Subject: [PATCH] libmultipath: invert regexes that start with exclamation
point
The number of devices that multipath needs to blacklist keeps growing,
and the udev rules already have
KERNEL!="sd*|dasd*|nvme*", GOTO="end_mpath"
so they only work correctly with these device types. Instead of
individually blacklisting every type of device that can't be
multipathed, multipath's default blacklist should work like the udev
rule, and blacklist all devices that aren't scsi, dasd, or nvme.
Unfortunately, the c regex library doesn't support negative lookahead.
Instead, multipath should treat "!" at the beginning of
blacklist/exceptions regexes as inverse matching the rest of the regex.
If users need to match a literal '!' as the first character of their
regex, they can use "\!" instead. This allows multipath to change the
default devnode blacklist regex to "!^(sd[a-z]|dasd[a-z]|nvme[0-9])".
Extra tests have been added to the blacklist unit tests to verify the
inverse matching code and the new default blacklist.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/blacklist.c | 41 +++++++++-----
libmultipath/blacklist.h | 3 +
multipath/multipath.conf.5 | 17 ++++--
tests/blacklist.c | 110 +++++++++++++++++++++++++++++++++++++
tests/test-lib.c | 2 +-
5 files changed, 155 insertions(+), 18 deletions(-)
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
index 04d3adb9..0c58aa32 100644
--- a/libmultipath/blacklist.c
+++ b/libmultipath/blacklist.c
@@ -15,9 +15,24 @@
#include "structs_vec.h"
#include "print.h"
+char *check_invert(char *str, bool *invert)
+{
+ if (str[0] == '!') {
+ *invert = true;
+ return str + 1;
+ }
+ if (str[0] == '\\' && str[1] == '!') {
+ *invert = false;
+ return str + 1;
+ }
+ *invert = false;
+ return str;
+}
+
int store_ble(vector blist, char * str, int origin)
{
struct blentry * ble;
+ char *regex_str;
if (!str)
return 0;
@@ -30,7 +45,8 @@ int store_ble(vector blist, char * str, int origin)
if (!ble)
goto out;
- if (regcomp(&ble->regex, str, REG_EXTENDED|REG_NOSUB))
+ regex_str = check_invert(str, &ble->invert);
+ if (regcomp(&ble->regex, regex_str, REG_EXTENDED|REG_NOSUB))
goto out1;
if (!vector_alloc_slot(blist))
@@ -66,6 +82,7 @@ int alloc_ble_device(vector blist)
int set_ble_device(vector blist, char * vendor, char * product, int origin)
{
struct blentry_device * ble;
+ char *regex_str;
if (!blist)
return 1;
@@ -76,7 +93,8 @@ int set_ble_device(vector blist, char * vendor, char * product, int origin)
return 1;
if (vendor) {
- if (regcomp(&ble->vendor_reg, vendor,
+ regex_str = check_invert(vendor, &ble->vendor_invert);
+ if (regcomp(&ble->vendor_reg, regex_str,
REG_EXTENDED|REG_NOSUB)) {
FREE(vendor);
if (product)
@@ -86,7 +104,8 @@ int set_ble_device(vector blist, char * vendor, char * product, int origin)
ble->vendor = vendor;
}
if (product) {
- if (regcomp(&ble->product_reg, product,
+ regex_str = check_invert(product, &ble->product_invert);
+ if (regcomp(&ble->product_reg, regex_str,
REG_EXTENDED|REG_NOSUB)) {
FREE(product);
if (vendor) {
@@ -108,7 +127,7 @@ match_reglist (vector blist, const char * str)
struct blentry * ble;
vector_foreach_slot (blist, ble, i) {
- if (!regexec(&ble->regex, str, 0, NULL, 0))
+ if (!!regexec(&ble->regex, str, 0, NULL, 0) == ble->invert)
return 1;
}
return 0;
@@ -125,9 +144,11 @@ match_reglist_device (const struct _vector *blist, const char * vendor,
if (!ble->vendor && !ble->product)
continue;
if ((!ble->vendor ||
- !regexec(&ble->vendor_reg, vendor, 0, NULL, 0)) &&
+ !!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) ==
+ ble->vendor_invert) &&
(!ble->product ||
- !regexec(&ble->product_reg, product, 0, NULL, 0)))
+ !!regexec(&ble->product_reg, product, 0, NULL, 0) ==
+ ble->product_invert))
return 1;
}
return 0;
@@ -160,13 +181,7 @@ setup_default_blist (struct config * conf)
char * str;
int i;
- str = STRDUP("^(ram|zram|raw|loop|fd|md|dm-|sr|scd|st|dcssblk)[0-9]");
- if (!str)
- return 1;
- if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
- return 1;
-
- str = STRDUP("^(td|hd|vd)[a-z]");
+ str = STRDUP("!^(sd[a-z]|dasd[a-z]|nvme[0-9])");
if (!str)
return 1;
if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
diff --git a/libmultipath/blacklist.h b/libmultipath/blacklist.h
index 2d721f60..4305857d 100644
--- a/libmultipath/blacklist.h
+++ b/libmultipath/blacklist.h
@@ -20,6 +20,7 @@
struct blentry {
char * str;
regex_t regex;
+ bool invert;
int origin;
};
@@ -28,6 +29,8 @@ struct blentry_device {
char * product;
regex_t vendor_reg;
regex_t product_reg;
+ bool vendor_invert;
+ bool product_invert;
int origin;
};
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 3455b1cc..6dc26f10 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -1248,6 +1248,16 @@ being handled by multipath-tools.
.LP
.
.
+In the \fIblacklist\fR and \fIblacklist_exceptions\fR sections, starting a
+quoted value with an exclamation mark \fB"!"\fR will invert the matching
+of the rest of the regular expression. For instance, \fB"!^sd[a-z]"\fR will
+match all values that do not start with \fB"sd[a-z]"\fR. The exclamation mark
+can be escaped \fB"\\!"\fR to match a literal \fB!\fR at the start of a
+regular expression. \fBNote:\fR The exclamation mark must be inside quotes,
+otherwise it will be treated as starting a comment.
+.LP
+.
+.
The \fIblacklist_exceptions\fR section is used to revert the actions of the
\fIblacklist\fR section. This allows one to selectively include ("whitelist") devices which
would normally be excluded via the \fIblacklist\fR section. A common usage is
@@ -1264,10 +1274,9 @@ unless explicitly stated.
Regular expression matching the device nodes to be excluded/included.
.RS
.PP
-The default \fIblacklist\fR consists of the regular expressions
-"^(ram|zram|raw|loop|fd|md|dm-|sr|scd|st|dcssblk)[0-9]" and
-"^(td|hd|vd)[a-z]". This causes virtual devices, non-disk devices, and some other
-device types to be excluded from multipath handling by default.
+The default \fIblacklist\fR consists of the regular expression
+\fB"!^(sd[a-z]|dasd[a-z]|nvme[0-9])"\fR. This causes all device types other
+than scsi, dasd, and nvme to be excluded from multipath handling by default.
.RE
.TP
.B wwid
diff --git a/tests/blacklist.c b/tests/blacklist.c
index cc8a9a4a..d20e97af 100644
--- a/tests/blacklist.c
+++ b/tests/blacklist.c
@@ -60,20 +60,46 @@ __wrap_udev_list_entry_get_name(struct udev_list_entry *list_entry)
return *(const char **)list_entry;
}
+vector elist_property_default;
+vector blist_devnode_default;
vector blist_devnode_sdb;
+vector blist_devnode_sdb_inv;
vector blist_all;
vector blist_device_foo_bar;
+vector blist_device_foo_inv_bar;
+vector blist_device_foo_bar_inv;
vector blist_device_all;
vector blist_wwid_xyzzy;
+vector blist_wwid_xyzzy_inv;
vector blist_protocol_fcp;
+vector blist_protocol_fcp_inv;
vector blist_property_wwn;
+vector blist_property_wwn_inv;
static int setup(void **state)
{
+ struct config conf;
+
+ memset(&conf, 0, sizeof(conf));
+ conf.blist_devnode = vector_alloc();
+ if (!conf.blist_devnode)
+ return -1;
+ conf.elist_property = vector_alloc();
+ if (!conf.elist_property)
+ return -1;
+ if (setup_default_blist(&conf) != 0)
+ return -1;
+ elist_property_default = conf.elist_property;
+ blist_devnode_default = conf.blist_devnode;
+
blist_devnode_sdb = vector_alloc();
if (!blist_devnode_sdb ||
store_ble(blist_devnode_sdb, strdup("sdb"), ORIGIN_CONFIG))
return -1;
+ blist_devnode_sdb_inv = vector_alloc();
+ if (!blist_devnode_sdb_inv ||
+ store_ble(blist_devnode_sdb_inv, strdup("!sdb"), ORIGIN_CONFIG))
+ return -1;
blist_all = vector_alloc();
if (!blist_all || store_ble(blist_all, strdup(".*"), ORIGIN_CONFIG))
@@ -84,6 +110,18 @@ static int setup(void **state)
set_ble_device(blist_device_foo_bar, strdup("foo"), strdup("bar"),
ORIGIN_CONFIG))
return -1;
+ blist_device_foo_inv_bar = vector_alloc();
+ if (!blist_device_foo_inv_bar ||
+ alloc_ble_device(blist_device_foo_inv_bar) ||
+ set_ble_device(blist_device_foo_inv_bar, strdup("!foo"),
+ strdup("bar"), ORIGIN_CONFIG))
+ return -1;
+ blist_device_foo_bar_inv = vector_alloc();
+ if (!blist_device_foo_bar_inv ||
+ alloc_ble_device(blist_device_foo_bar_inv) ||
+ set_ble_device(blist_device_foo_bar_inv, strdup("foo"),
+ strdup("!bar"), ORIGIN_CONFIG))
+ return -1;
blist_device_all = vector_alloc();
if (!blist_device_all || alloc_ble_device(blist_device_all) ||
@@ -95,29 +133,50 @@ static int setup(void **state)
if (!blist_wwid_xyzzy ||
store_ble(blist_wwid_xyzzy, strdup("xyzzy"), ORIGIN_CONFIG))
return -1;
+ blist_wwid_xyzzy_inv = vector_alloc();
+ if (!blist_wwid_xyzzy_inv ||
+ store_ble(blist_wwid_xyzzy_inv, strdup("!xyzzy"), ORIGIN_CONFIG))
+ return -1;
blist_protocol_fcp = vector_alloc();
if (!blist_protocol_fcp ||
store_ble(blist_protocol_fcp, strdup("scsi:fcp"), ORIGIN_CONFIG))
return -1;
+ blist_protocol_fcp_inv = vector_alloc();
+ if (!blist_protocol_fcp_inv ||
+ store_ble(blist_protocol_fcp_inv, strdup("!scsi:fcp"),
+ ORIGIN_CONFIG))
+ return -1;
blist_property_wwn = vector_alloc();
if (!blist_property_wwn ||
store_ble(blist_property_wwn, strdup("ID_WWN"), ORIGIN_CONFIG))
return -1;
+ blist_property_wwn_inv = vector_alloc();
+ if (!blist_property_wwn_inv ||
+ store_ble(blist_property_wwn_inv, strdup("!ID_WWN"), ORIGIN_CONFIG))
+ return -1;
return 0;
}
static int teardown(void **state)
{
+ free_blacklist(elist_property_default);
+ free_blacklist(blist_devnode_default);
free_blacklist(blist_devnode_sdb);
+ free_blacklist(blist_devnode_sdb_inv);
free_blacklist(blist_all);
free_blacklist_device(blist_device_foo_bar);
+ free_blacklist_device(blist_device_foo_inv_bar);
+ free_blacklist_device(blist_device_foo_bar_inv);
free_blacklist_device(blist_device_all);
free_blacklist(blist_wwid_xyzzy);
+ free_blacklist(blist_wwid_xyzzy_inv);
free_blacklist(blist_protocol_fcp);
+ free_blacklist(blist_protocol_fcp_inv);
free_blacklist(blist_property_wwn);
+ free_blacklist(blist_property_wwn_inv);
return 0;
}
@@ -141,6 +200,11 @@ static void test_devnode_blacklist(void **state)
expect_condlog(3, "sdb: device node name blacklisted\n");
assert_int_equal(filter_devnode(blist_devnode_sdb, NULL, "sdb"),
MATCH_DEVNODE_BLIST);
+ assert_int_equal(filter_devnode(blist_devnode_sdb_inv, NULL, "sdb"),
+ MATCH_NOTHING);
+ expect_condlog(3, "sdc: device node name blacklisted\n");
+ assert_int_equal(filter_devnode(blist_devnode_sdb_inv, NULL, "sdc"),
+ MATCH_DEVNODE_BLIST);
}
static void test_devnode_whitelist(void **state)
@@ -159,12 +223,39 @@ static void test_devnode_missing(void **state)
MATCH_NOTHING);
}
+static void test_devnode_default(void **state)
+{
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "sdaa"),
+ MATCH_NOTHING);
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "nvme0n1"),
+ MATCH_NOTHING);
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "dasda"),
+ MATCH_NOTHING);
+ expect_condlog(3, "hda: device node name blacklisted\n");
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "hda"),
+ MATCH_DEVNODE_BLIST);
+}
+
static void test_device_blacklist(void **state)
{
expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n");
assert_int_equal(filter_device(blist_device_foo_bar, NULL, "foo",
"bar", "sdb"),
MATCH_DEVICE_BLIST);
+ assert_int_equal(filter_device(blist_device_foo_inv_bar, NULL, "foo",
+ "bar", "sdb"),
+ MATCH_NOTHING);
+ assert_int_equal(filter_device(blist_device_foo_bar_inv, NULL, "foo",
+ "bar", "sdb"),
+ MATCH_NOTHING);
+ expect_condlog(3, "sdb: (baz:bar) vendor/product blacklisted\n");
+ assert_int_equal(filter_device(blist_device_foo_inv_bar, NULL, "baz",
+ "bar", "sdb"),
+ MATCH_DEVICE_BLIST);
+ expect_condlog(3, "sdb: (foo:baz) vendor/product blacklisted\n");
+ assert_int_equal(filter_device(blist_device_foo_bar_inv, NULL, "foo",
+ "baz", "sdb"),
+ MATCH_DEVICE_BLIST);
}
static void test_device_whitelist(void **state)
@@ -191,6 +282,11 @@ static void test_wwid_blacklist(void **state)
expect_condlog(3, "sdb: wwid xyzzy blacklisted\n");
assert_int_equal(filter_wwid(blist_wwid_xyzzy, NULL, "xyzzy", "sdb"),
MATCH_WWID_BLIST);
+ assert_int_equal(filter_wwid(blist_wwid_xyzzy_inv, NULL, "xyzzy",
+ "sdb"), MATCH_NOTHING);
+ expect_condlog(3, "sdb: wwid plugh blacklisted\n");
+ assert_int_equal(filter_wwid(blist_wwid_xyzzy_inv, NULL, "plugh",
+ "sdb"), MATCH_WWID_BLIST);
}
static void test_wwid_whitelist(void **state)
@@ -218,6 +314,12 @@ static void test_protocol_blacklist(void **state)
expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n");
assert_int_equal(filter_protocol(blist_protocol_fcp, NULL, &pp),
MATCH_PROTOCOL_BLIST);
+ assert_int_equal(filter_protocol(blist_protocol_fcp_inv, NULL, &pp),
+ MATCH_NOTHING);
+ pp.sg_id.proto_id = SCSI_PROTOCOL_ATA;
+ expect_condlog(3, "sdb: protocol scsi:ata blacklisted\n");
+ assert_int_equal(filter_protocol(blist_protocol_fcp_inv, NULL, &pp),
+ MATCH_PROTOCOL_BLIST);
}
static void test_protocol_whitelist(void **state)
@@ -245,10 +347,17 @@ static void test_protocol_missing(void **state)
static void test_property_blacklist(void **state)
{
static struct udev_device udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } };
+ static struct udev_device udev_inv = { "sdb", { "ID_WWN", NULL } };
conf.blist_property = blist_property_wwn;
expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n");
assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
MATCH_PROPERTY_BLIST);
+ conf.blist_property = blist_property_wwn_inv;
+ expect_condlog(3, "sdb: udev property ID_FOO blacklisted\n");
+ assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
+ MATCH_PROPERTY_BLIST);
+ assert_int_equal(filter_property(&conf, &udev_inv, 3, "ID_SERIAL"),
+ MATCH_NOTHING);
}
/* the property check works different in that you check all the property
@@ -482,6 +591,7 @@ int test_blacklist(void)
cmocka_unit_test(test_devnode_blacklist),
cmocka_unit_test(test_devnode_whitelist),
cmocka_unit_test(test_devnode_missing),
+ cmocka_unit_test(test_devnode_default),
cmocka_unit_test(test_device_blacklist),
cmocka_unit_test(test_device_whitelist),
cmocka_unit_test(test_device_missing),
diff --git a/tests/test-lib.c b/tests/test-lib.c
index 59275163..08ff2d8d 100644
--- a/tests/test-lib.c
+++ b/tests/test-lib.c
@@ -15,7 +15,7 @@
#include "test-lib.h"
const int default_mask = (DI_SYSFS|DI_BLACKLIST|DI_WWID|DI_CHECKER|DI_PRIO);
-const char default_devnode[] = "sdTEST";
+const char default_devnode[] = "sdxTEST";
const char default_wwid[] = "TEST-WWID";
/* default_wwid should be a substring of default_wwid_1! */
const char default_wwid_1[] = "TEST-WWID-1";
--
2.17.2

View File

@ -17,10 +17,10 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
4 files changed, 72 insertions(+), 42 deletions(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 0f0c3a34..038ff82d 100644
index 13a1cf53..f6204e5f 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -520,36 +520,43 @@ int dm_map_present(const char * str)
@@ -525,36 +525,43 @@ int dm_map_present(const char * str)
int dm_get_map(const char *name, unsigned long long *size, char *outparams)
{
@ -71,7 +71,7 @@ index 0f0c3a34..038ff82d 100644
out:
dm_task_destroy(dmt);
return r;
@@ -623,35 +630,45 @@ is_mpath_part(const char *part_name, const char *map_name)
@@ -628,35 +635,45 @@ is_mpath_part(const char *part_name, const char *map_name)
int dm_get_status(const char *name, char *outstatus)
{
@ -124,7 +124,7 @@ index 0f0c3a34..038ff82d 100644
condlog(0, "%s: error getting map status string", name);
dm_task_destroy(dmt);
@@ -860,7 +877,7 @@ int _dm_flush_map (const char * mapname, int need_sync, int deferred_remove,
@@ -866,7 +883,7 @@ int _dm_flush_map (const char * mapname, int need_sync, int deferred_remove,
return 1;
if (need_suspend &&
@ -133,7 +133,7 @@ index 0f0c3a34..038ff82d 100644
strstr(params, "queue_if_no_path")) {
if (!dm_queue_if_no_path(mapname, 0))
queue_if_no_path = 1;
@@ -1069,7 +1086,7 @@ struct multipath *dm_get_multipath(const char *name)
@@ -1075,7 +1092,7 @@ struct multipath *dm_get_multipath(const char *name)
if (!mpp->alias)
goto out;
@ -142,7 +142,7 @@ index 0f0c3a34..038ff82d 100644
goto out;
dm_get_uuid(name, mpp->wwid, WWID_SIZE);
@@ -1253,7 +1270,7 @@ do_foreach_partmaps (const char * mapname,
@@ -1259,7 +1276,7 @@ do_foreach_partmaps (const char * mapname,
/*
* and we can fetch the map table from the kernel
*/
@ -169,7 +169,7 @@ index 7557a86b..adb55000 100644
void libmp_dm_init(void);
void libmp_udev_set_sync_support(int on);
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index c43b58fb..1342445b 100644
index 077f2e42..8137ea21 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -196,43 +196,47 @@ extract_hwe_from_path(struct multipath * mpp)
@ -271,12 +271,12 @@ index c43b58fb..1342445b 100644
+ return DMP_OK;
}
void enter_recovery_mode(struct multipath *mpp)
static void enter_recovery_mode(struct multipath *mpp)
diff --git a/multipathd/main.c b/multipathd/main.c
index 7b364cfe..13423d19 100644
index 6b7db2c0..e3427d3d 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -448,7 +448,7 @@ int __setup_multipath(struct vectors *vecs, struct multipath *mpp,
@@ -414,7 +414,7 @@ int __setup_multipath(struct vectors *vecs, struct multipath *mpp,
goto out;
}
@ -285,7 +285,7 @@ index 7b364cfe..13423d19 100644
condlog(0, "%s: failed to setup multipath", mpp->alias);
goto out;
}
@@ -587,9 +587,9 @@ add_map_without_path (struct vectors *vecs, const char *alias)
@@ -553,9 +553,9 @@ add_map_without_path (struct vectors *vecs, const char *alias)
mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
put_multipath_config(conf);
@ -297,7 +297,7 @@ index 7b364cfe..13423d19 100644
goto out;
if (!vector_alloc_slot(vecs->mpvec))
@@ -1380,8 +1380,8 @@ map_discovery (struct vectors * vecs)
@@ -1346,8 +1346,8 @@ map_discovery (struct vectors * vecs)
return 1;
vector_foreach_slot (vecs->mpvec, mpp, i)
@ -308,7 +308,7 @@ index 7b364cfe..13423d19 100644
remove_map(mpp, vecs, 1);
i--;
}
@@ -2121,7 +2121,7 @@ check_path (struct vectors * vecs, struct path * pp, int ticks)
@@ -2087,7 +2087,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
/*
* Synchronize with kernel state
*/

View File

@ -27,16 +27,16 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
1 file changed, 19 insertions(+), 25 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index 13423d19..d7ed9bf0 100644
index e3427d3d..1d9ce7f7 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -1645,23 +1645,19 @@ fail_path (struct path * pp, int del_active)
@@ -1611,22 +1611,18 @@ fail_path (struct path * pp, int del_active)
/*
* caller must have locked the path list before calling that function
*/
-static int
+static void
reinstate_path (struct path * pp, int add_active)
reinstate_path (struct path * pp)
{
- int ret = 0;
-
@ -51,14 +51,13 @@ index 13423d19..d7ed9bf0 100644
- } else {
+ else {
condlog(2, "%s: reinstated", pp->dev_t);
if (add_active)
update_queue_mode_add_path(pp->mpp);
update_queue_mode_add_path(pp->mpp);
}
- return ret;
}
static void
@@ -2121,9 +2117,16 @@ check_path (struct vectors * vecs, struct path * pp, int ticks)
@@ -2087,9 +2083,16 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
/*
* Synchronize with kernel state
*/
@ -78,36 +77,36 @@ index 13423d19..d7ed9bf0 100644
pp->dmstate = PSTATE_UNDEF;
}
/* if update_multipath_strings orphaned the path, quit early */
@@ -2218,12 +2221,8 @@ check_path (struct vectors * vecs, struct path * pp, int ticks)
add_active = 1;
else
add_active = 0;
- if (!disable_reinstate && reinstate_path(pp, add_active)) {
@@ -2179,12 +2182,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
/*
* reinstate this path
*/
- if (!disable_reinstate && reinstate_path(pp)) {
- condlog(3, "%s: reload map", pp->dev);
- ev_add_path(pp, vecs, 1);
- pp->tick = 1;
- return 0;
- }
+ if (!disable_reinstate)
+ reinstate_path(pp, add_active);
+ reinstate_path(pp);
new_path_up = 1;
if (oldchkrstate != PATH_UP && oldchkrstate != PATH_GHOST)
@@ -2239,15 +2238,10 @@ check_path (struct vectors * vecs, struct path * pp, int ticks)
@@ -2200,15 +2199,10 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
else if (newstate == PATH_UP || newstate == PATH_GHOST) {
if ((pp->dmstate == PSTATE_FAILED ||
pp->dmstate == PSTATE_UNDEF) &&
- !disable_reinstate) {
+ !disable_reinstate)
/* Clear IO errors */
- if (reinstate_path(pp, 0)) {
- if (reinstate_path(pp)) {
- condlog(3, "%s: reload map", pp->dev);
- ev_add_path(pp, vecs, 1);
- pp->tick = 1;
- return 0;
- }
- } else {
+ reinstate_path(pp, 0);
+ reinstate_path(pp);
+ else {
LOG_MSG(4, verbosity, pp);
if (pp->checkint != max_checkint) {

View File

@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 17 Jun 2020 13:31:37 -0500
Subject: [PATCH] libmultipath: make dm_flush_maps only return 0 on success
dm_flush_maps() returned both 0 and 1 on error, depending on which part
of the function it was in, but the caller was always treating 0 as a
success. Make dm_flush_maps() always return 1 on error and 0 on success.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/devmapper.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index f6204e5f..cda83ce4 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -953,13 +953,13 @@ dm_flush_map_nopaths(const char * mapname, int deferred_remove)
int dm_flush_maps (int retries)
{
- int r = 0;
+ int r = 1;
struct dm_task *dmt;
struct dm_names *names;
unsigned next = 0;
if (!(dmt = libmp_dm_task_create (DM_DEVICE_LIST)))
- return 0;
+ return r;
dm_task_no_open_count(dmt);
@@ -972,6 +972,7 @@ int dm_flush_maps (int retries)
if (!names->dev)
goto out;
+ r = 0;
do {
r |= dm_suspend_and_flush_map(names->name, retries);
next = names->next;
--
2.17.2

View File

@ -0,0 +1,160 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 15 Jun 2020 17:00:54 -0500
Subject: [PATCH] multipathd: add "del maps" multipathd command
This will flush all multipath devices.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/devmapper.c | 7 +++++--
libmultipath/devmapper.h | 2 +-
multipath/main.c | 2 +-
multipathd/cli.c | 1 +
multipathd/cli_handlers.c | 19 +++++++++++++++++++
multipathd/cli_handlers.h | 1 +
multipathd/main.c | 3 ++-
multipathd/main.h | 1 +
8 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index cda83ce4..7f98bf9d 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -951,7 +951,7 @@ dm_flush_map_nopaths(const char * mapname, int deferred_remove)
#endif
-int dm_flush_maps (int retries)
+int dm_flush_maps (int need_suspend, int retries)
{
int r = 1;
struct dm_task *dmt;
@@ -974,7 +974,10 @@ int dm_flush_maps (int retries)
r = 0;
do {
- r |= dm_suspend_and_flush_map(names->name, retries);
+ if (need_suspend)
+ r |= dm_suspend_and_flush_map(names->name, retries);
+ else
+ r |= dm_flush_map(names->name);
next = names->next;
names = (void *) names + next;
} while (next);
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index adb55000..7e8812ad 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -55,7 +55,7 @@ int dm_flush_map_nopaths(const char * mapname, int deferred_remove);
#define dm_suspend_and_flush_map(mapname, retries) \
_dm_flush_map(mapname, 1, 0, 1, retries)
int dm_cancel_deferred_remove(struct multipath *mpp);
-int dm_flush_maps (int retries);
+int dm_flush_maps (int need_suspend, int retries);
int dm_fail_path(const char * mapname, char * path);
int dm_reinstate_path(const char * mapname, char * path);
int dm_queue_if_no_path(const char *mapname, int enable);
diff --git a/multipath/main.c b/multipath/main.c
index 78822ee1..7ab3102f 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -1127,7 +1127,7 @@ main (int argc, char *argv[])
goto out;
}
else if (conf->remove == FLUSH_ALL) {
- r = dm_flush_maps(retries) ? RTVL_FAIL : RTVL_OK;
+ r = dm_flush_maps(1, retries) ? RTVL_FAIL : RTVL_OK;
goto out;
}
while ((r = configure(conf, cmd, dev_type, dev)) == RTVL_RETRY)
diff --git a/multipathd/cli.c b/multipathd/cli.c
index 800c0fbe..bdc9fb10 100644
--- a/multipathd/cli.c
+++ b/multipathd/cli.c
@@ -568,6 +568,7 @@ cli_init (void) {
add_handler(DEL+PATH, NULL);
add_handler(ADD+MAP, NULL);
add_handler(DEL+MAP, NULL);
+ add_handler(DEL+MAPS, NULL);
add_handler(SWITCH+MAP+GROUP, NULL);
add_handler(RECONFIGURE, NULL);
add_handler(SUSPEND+MAP, NULL);
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 31c3d9fd..782bb003 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -852,6 +852,25 @@ cli_del_map (void * v, char ** reply, int * len, void * data)
return rc;
}
+int
+cli_del_maps (void *v, char **reply, int *len, void *data)
+{
+ struct vectors * vecs = (struct vectors *)data;
+ struct multipath *mpp;
+ int i, ret = 0;
+
+ condlog(2, "remove maps (operator)");
+ vector_foreach_slot(vecs->mpvec, mpp, i) {
+ if (flush_map(mpp, vecs, 0))
+ ret++;
+ else
+ i--;
+ }
+ /* flush any multipath maps that aren't currently known by multipathd */
+ ret |= dm_flush_maps(0, 0);
+ return ret;
+}
+
int
cli_reload(void *v, char **reply, int *len, void *data)
{
diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h
index 0f451064..6f57b429 100644
--- a/multipathd/cli_handlers.h
+++ b/multipathd/cli_handlers.h
@@ -26,6 +26,7 @@ int cli_add_path (void * v, char ** reply, int * len, void * data);
int cli_del_path (void * v, char ** reply, int * len, void * data);
int cli_add_map (void * v, char ** reply, int * len, void * data);
int cli_del_map (void * v, char ** reply, int * len, void * data);
+int cli_del_maps (void * v, char ** reply, int * len, void * data);
int cli_switch_group(void * v, char ** reply, int * len, void * data);
int cli_reconfigure(void * v, char ** reply, int * len, void * data);
int cli_resize(void * v, char ** reply, int * len, void * data);
diff --git a/multipathd/main.c b/multipathd/main.c
index 1d9ce7f7..1d0579e9 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -631,7 +631,7 @@ sync_maps_state(vector mpvec)
sync_map_state(mpp);
}
-static int
+int
flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths)
{
int r;
@@ -1551,6 +1551,7 @@ uxlsnrloop (void * ap)
set_handler_callback(DEL+PATH, cli_del_path);
set_handler_callback(ADD+MAP, cli_add_map);
set_handler_callback(DEL+MAP, cli_del_map);
+ set_handler_callback(DEL+MAPS, cli_del_maps);
set_handler_callback(SWITCH+MAP+GROUP, cli_switch_group);
set_unlocked_handler_callback(RECONFIGURE, cli_reconfigure);
set_handler_callback(SUSPEND+MAP, cli_suspend);
diff --git a/multipathd/main.h b/multipathd/main.h
index 7bb8463f..5dff17e5 100644
--- a/multipathd/main.h
+++ b/multipathd/main.h
@@ -28,6 +28,7 @@ int ev_add_path (struct path *, struct vectors *, int);
int ev_remove_path (struct path *, struct vectors *, int);
int ev_add_map (char *, const char *, struct vectors *);
int ev_remove_map (char *, char *, int, struct vectors *);
+int flush_map(struct multipath *, struct vectors *, int);
int set_config_state(enum daemon_status);
void * mpath_alloc_prin_response(int prin_sa);
int prin_do_scsi_ioctl(char *, int rq_servact, struct prin_resp * resp,
--
2.17.2

View File

@ -0,0 +1,103 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 15 Jun 2020 23:54:29 -0500
Subject: [PATCH] multipath: make flushing maps work like other commands
The config structure doesn't need a special variable just for removes.
Multipath can just use the cmd variable, like it does for the other
commands.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.h | 3 ++-
libmultipath/configure.h | 3 ---
multipath/main.c | 20 ++++++++++----------
3 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 3368d8c9..4042eba6 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -39,6 +39,8 @@ enum mpath_cmds {
CMD_ADD_WWID,
CMD_USABLE_PATHS,
CMD_DUMP_CONFIG,
+ CMD_FLUSH_ONE,
+ CMD_FLUSH_ALL,
};
enum force_reload_types {
@@ -143,7 +145,6 @@ struct config {
unsigned int max_checkint;
bool use_watchdog;
int pgfailback;
- int remove;
int rr_weight;
int no_path_retry;
int user_friendly_names;
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
index d7509000..0e33bf40 100644
--- a/libmultipath/configure.h
+++ b/libmultipath/configure.h
@@ -45,9 +45,6 @@ enum {
CP_RETRY,
};
-#define FLUSH_ONE 1
-#define FLUSH_ALL 2
-
struct vectors;
int setup_map (struct multipath * mpp, char * params, int params_size,
diff --git a/multipath/main.c b/multipath/main.c
index 7ab3102f..a2080029 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -942,10 +942,10 @@ main (int argc, char *argv[])
cmd = CMD_DRY_RUN;
break;
case 'f':
- conf->remove = FLUSH_ONE;
+ cmd = CMD_FLUSH_ONE;
break;
case 'F':
- conf->remove = FLUSH_ALL;
+ cmd = CMD_FLUSH_ALL;
break;
case 'l':
if (optarg && !strncmp(optarg, "l", 1))
@@ -1084,6 +1084,10 @@ main (int argc, char *argv[])
condlog(0, "the -w option requires a device");
goto out;
}
+ if (cmd == CMD_FLUSH_ONE && dev_type != DEV_DEVMAP) {
+ condlog(0, "the -f option requires a map name to remove");
+ goto out;
+ }
switch(delegate_to_multipathd(cmd, dev, dev_type, conf)) {
case DELEGATE_OK:
@@ -1117,16 +1121,12 @@ main (int argc, char *argv[])
}
if (retries < 0)
retries = conf->remove_retries;
- if (conf->remove == FLUSH_ONE) {
- if (dev_type == DEV_DEVMAP) {
- r = dm_suspend_and_flush_map(dev, retries) ?
- RTVL_FAIL : RTVL_OK;
- } else
- condlog(0, "must provide a map name to remove");
-
+ if (cmd == CMD_FLUSH_ONE) {
+ r = dm_suspend_and_flush_map(dev, retries) ?
+ RTVL_FAIL : RTVL_OK;
goto out;
}
- else if (conf->remove == FLUSH_ALL) {
+ else if (cmd == CMD_FLUSH_ALL) {
r = dm_flush_maps(1, retries) ? RTVL_FAIL : RTVL_OK;
goto out;
}
--
2.17.2

View File

@ -0,0 +1,63 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 16 Jun 2020 16:25:34 -0500
Subject: [PATCH] multipath: delegate flushing maps to multipathd
Since there can be problems with removing maps outside of multipathd,
multipath should attempt to delegate this command to multipathd.
However, multipathd doesn't attempt to suspend the device, in order
to avoid potential hangs. If delegating to multipathd fails, multipath
should try the remove itself.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/main.c | 14 ++++++++++++++
multipath/multipath.8 | 4 ++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/multipath/main.c b/multipath/main.c
index a2080029..612c6815 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -828,6 +828,20 @@ int delegate_to_multipathd(enum mpath_cmds cmd,
if (cmd == CMD_CREATE && conf->force_reload == FORCE_RELOAD_YES) {
p += snprintf(p, n, "reconfigure");
}
+ else if (cmd == CMD_FLUSH_ONE && dev && dev_type == DEV_DEVMAP) {
+ p += snprintf(p, n, "del map %s", dev);
+ /* multipathd doesn't try as hard, to avoid potentially
+ * hanging. If it fails, retry with the regular multipath
+ * command */
+ r = NOT_DELEGATED;
+ }
+ else if (cmd == CMD_FLUSH_ALL) {
+ p += snprintf(p, n, "del maps");
+ /* multipathd doesn't try as hard, to avoid potentially
+ * hanging. If it fails, retry with the regular multipath
+ * command */
+ r = NOT_DELEGATED;
+ }
/* Add other translations here */
if (strlen(command) == 0)
diff --git a/multipath/multipath.8 b/multipath/multipath.8
index 8befc45a..47a33f9b 100644
--- a/multipath/multipath.8
+++ b/multipath/multipath.8
@@ -125,11 +125,11 @@ the system.
Other operation modes are chosen by using one of the following command line switches:
.TP
.B \-f
-Flush (remove) a multipath device map specified as parameter, if unused.
+Flush (remove) a multipath device map specified as parameter, if unused. This operation is delegated to the multipathd daemon if it's running.
.
.TP
.B \-F
-Flush (remove) all unused multipath device maps.
+Flush (remove) all unused multipath device maps. This operation is delegated to the multipathd daemon if it's running.
.
.TP
.B \-l
--
2.17.2

View File

@ -0,0 +1,62 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 16 Jun 2020 17:36:33 -0500
Subject: [PATCH] multipath: add option to skip multipathd delegation
Add the -D option to allow users to skip delegating commands to
multipathd.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.h | 1 +
multipath/main.c | 8 +++++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 4042eba6..160867cd 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -191,6 +191,7 @@ struct config {
int ghost_delay;
int find_multipaths_timeout;
int marginal_pathgroups;
+ int skip_delegate;
unsigned int version[3];
unsigned int sequence_nr;
diff --git a/multipath/main.c b/multipath/main.c
index 612c6815..3c3d2398 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -825,6 +825,9 @@ int delegate_to_multipathd(enum mpath_cmds cmd,
*p = '\0';
n = sizeof(command);
+ if (conf->skip_delegate)
+ return NOT_DELEGATED;
+
if (cmd == CMD_CREATE && conf->force_reload == FORCE_RELOAD_YES) {
p += snprintf(p, n, "reconfigure");
}
@@ -923,7 +926,7 @@ main (int argc, char *argv[])
multipath_conf = conf;
conf->retrigger_tries = 0;
conf->force_sync = 1;
- while ((arg = getopt(argc, argv, ":aAdcChl::FfM:v:p:b:BrR:itTquUwW")) != EOF ) {
+ while ((arg = getopt(argc, argv, ":aAdDcChl::FfM:v:p:b:BrR:itTquUwW")) != EOF ) {
switch(arg) {
case 1: printf("optarg : %s\n",optarg);
break;
@@ -955,6 +958,9 @@ main (int argc, char *argv[])
if (cmd == CMD_CREATE)
cmd = CMD_DRY_RUN;
break;
+ case 'D':
+ conf->skip_delegate = 1;
+ break;
case 'f':
cmd = CMD_FLUSH_ONE;
break;
--
2.17.2

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 25 Jun 2020 20:46:08 -0500
Subject: [PATCH] libmultipath: fix sysfs dev_loss_tmo parsing
dev_loss_tmo is a u32 value. However the kernel sysfs code prints it as
a signed integer. This means that if dev_loss_tmo is above INT_MAX, the
sysfs value will be a negative number. Parsing this was causing
sysfs_set_rport_tmo() to fail.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index ffec5162..83a41a4a 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -583,7 +583,7 @@ sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
struct udev_device *rport_dev = NULL;
char value[16], *eptr;
char rport_id[32];
- unsigned long long tmo = 0;
+ unsigned int tmo;
int ret;
sprintf(rport_id, "rport-%d:%d-%d",
@@ -607,8 +607,8 @@ sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
"error %d", rport_id, -ret);
goto out;
}
- tmo = strtoull(value, &eptr, 0);
- if (value == eptr || tmo == ULLONG_MAX) {
+ tmo = strtoul(value, &eptr, 0);
+ if (value == eptr) {
condlog(0, "%s: Cannot parse dev_loss_tmo "
"attribute '%s'", rport_id, value);
goto out;
--
2.17.2

View File

@ -0,0 +1,267 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 26 Jun 2020 20:06:24 -0500
Subject: [PATCH] kpartx: read devices with direct IO
If kpartx is used on top of shared storage, and a device has its
partition table changed on one machine, and then kpartx is run on
another, it may not see the new data, because the cache still contains
the old data, and there is nothing to tell the machine running kpartx to
invalidate it. To solve this, kpartx should read the devices using
direct io.
One issue with how this code has been updated is that the original code
for getblock() always read 1024 bytes. The new code reads a logical
sector size chunk of the device, and returns a pointer to the 512 byte
sector that the caller asked for, within that (possibly larger) chunk.
This means that if the logical sector size is 512, then the code is now
only reading 512 bytes. Looking through the code for the various
partition types, I can't see a case where more than 512 bytes is needed
and getblock() is used. If anyone has a reason why this code should be
reading 1024 bytes at minmum, I can certainly change this. But when I
looked, I couldn't find a case where reading 512 bytes would cause a
problem.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
kpartx/dasd.c | 7 ++++---
kpartx/gpt.c | 22 +++++++++----------
kpartx/kpartx.c | 56 +++++++++++++++++++++++++++++++++++++++----------
kpartx/kpartx.h | 2 ++
4 files changed, 61 insertions(+), 26 deletions(-)
diff --git a/kpartx/dasd.c b/kpartx/dasd.c
index 14b9d3aa..f0398645 100644
--- a/kpartx/dasd.c
+++ b/kpartx/dasd.c
@@ -22,6 +22,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -117,13 +118,13 @@ read_dasd_pt(int fd, __attribute__((unused)) struct slice all,
sprintf(pathname, "/dev/.kpartx-node-%u-%u",
(unsigned int)major(dev), (unsigned int)minor(dev));
- if ((fd_dasd = open(pathname, O_RDONLY)) == -1) {
+ if ((fd_dasd = open(pathname, O_RDONLY | O_DIRECT)) == -1) {
/* Devicenode does not exist. Try to create one */
if (mknod(pathname, 0600 | S_IFBLK, dev) == -1) {
/* Couldn't create a device node */
return -1;
}
- fd_dasd = open(pathname, O_RDONLY);
+ fd_dasd = open(pathname, O_RDONLY | O_DIRECT);
/*
* The file will vanish when the last process (we)
* has ceased to access it.
@@ -175,7 +176,7 @@ read_dasd_pt(int fd, __attribute__((unused)) struct slice all,
* Get volume label, extract name and type.
*/
- if (!(data = (unsigned char *)malloc(blocksize)))
+ if (aligned_malloc((void **)&data, blocksize, NULL))
goto out;
diff --git a/kpartx/gpt.c b/kpartx/gpt.c
index 785b34ea..f7fefb70 100644
--- a/kpartx/gpt.c
+++ b/kpartx/gpt.c
@@ -243,8 +243,7 @@ alloc_read_gpt_entries(int fd, gpt_header * gpt)
if (!count) return NULL;
- pte = (gpt_entry *)malloc(count);
- if (!pte)
+ if (aligned_malloc((void **)&pte, get_sector_size(fd), &count))
return NULL;
memset(pte, 0, count);
@@ -269,12 +268,11 @@ static gpt_header *
alloc_read_gpt_header(int fd, uint64_t lba)
{
gpt_header *gpt;
- gpt = (gpt_header *)
- malloc(sizeof (gpt_header));
- if (!gpt)
+ size_t size = sizeof (gpt_header);
+ if (aligned_malloc((void **)&gpt, get_sector_size(fd), &size))
return NULL;
- memset(gpt, 0, sizeof (*gpt));
- if (!read_lba(fd, lba, gpt, sizeof (gpt_header))) {
+ memset(gpt, 0, size);
+ if (!read_lba(fd, lba, gpt, size)) {
free(gpt);
return NULL;
}
@@ -498,6 +496,7 @@ find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
gpt_header *pgpt = NULL, *agpt = NULL;
gpt_entry *pptes = NULL, *aptes = NULL;
legacy_mbr *legacymbr = NULL;
+ size_t size = sizeof(legacy_mbr);
uint64_t lastlba;
if (!gpt || !ptes)
return 0;
@@ -526,11 +525,10 @@ find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
}
/* This will be added to the EFI Spec. per Intel after v1.02. */
- legacymbr = malloc(sizeof (*legacymbr));
- if (legacymbr) {
- memset(legacymbr, 0, sizeof (*legacymbr));
- read_lba(fd, 0, (uint8_t *) legacymbr,
- sizeof (*legacymbr));
+ if (aligned_malloc((void **)&legacymbr, get_sector_size(fd),
+ &size) == 0) {
+ memset(legacymbr, 0, size);
+ read_lba(fd, 0, (uint8_t *) legacymbr, size);
good_pmbr = is_pmbr_valid(legacymbr);
free(legacymbr);
legacymbr=NULL;
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
index d3620c5c..c24ad6d9 100644
--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -19,6 +19,7 @@
* cva, 2002-10-26
*/
+#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
@@ -41,7 +42,6 @@
#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
-#define READ_SIZE 1024
#define MAXTYPES 64
#define MAXSLICES 256
#define DM_TARGET "linear"
@@ -388,7 +388,7 @@ main(int argc, char **argv){
set_delimiter(mapname, delim);
}
- fd = open(device, O_RDONLY);
+ fd = open(device, O_RDONLY | O_DIRECT);
if (fd == -1) {
perror(device);
@@ -690,9 +690,9 @@ xmalloc (size_t size) {
*/
static int
-sseek(int fd, unsigned int secnr) {
+sseek(int fd, unsigned int secnr, int secsz) {
off64_t in, out;
- in = ((off64_t) secnr << 9);
+ in = ((off64_t) secnr * secsz);
out = 1;
if ((out = lseek64(fd, in, SEEK_SET)) != in)
@@ -703,6 +703,31 @@ sseek(int fd, unsigned int secnr) {
return 0;
}
+int
+aligned_malloc(void **mem_p, size_t align, size_t *size_p)
+{
+ static size_t pgsize = 0;
+ size_t size;
+ int err;
+
+ if (!mem_p || !align || (size_p && !*size_p))
+ return EINVAL;
+
+ if (!pgsize)
+ pgsize = getpagesize();
+
+ if (size_p)
+ size = ((*size_p + align - 1) / align) * align;
+ else
+ size = pgsize;
+
+ err = posix_memalign(mem_p, pgsize, size);
+ if (!err && size_p)
+ *size_p = size;
+ return err;
+}
+
+/* always in sector size blocks */
static
struct block {
unsigned int secnr;
@@ -710,30 +735,39 @@ struct block {
struct block *next;
} *blockhead;
+/* blknr is always in 512 byte blocks */
char *
-getblock (int fd, unsigned int secnr) {
+getblock (int fd, unsigned int blknr) {
+ unsigned int secsz = get_sector_size(fd);
+ unsigned int blks_per_sec = secsz / 512;
+ unsigned int secnr = blknr / blks_per_sec;
+ unsigned int blk_off = (blknr % blks_per_sec) * 512;
struct block *bp;
for (bp = blockhead; bp; bp = bp->next)
if (bp->secnr == secnr)
- return bp->block;
+ return bp->block + blk_off;
- if (sseek(fd, secnr))
+ if (sseek(fd, secnr, secsz))
return NULL;
bp = xmalloc(sizeof(struct block));
bp->secnr = secnr;
bp->next = blockhead;
blockhead = bp;
- bp->block = (char *) xmalloc(READ_SIZE);
+ if (aligned_malloc((void **)&bp->block, secsz, NULL)) {
+ fprintf(stderr, "aligned_malloc failed\n");
+ exit(1);
+ }
- if (read(fd, bp->block, READ_SIZE) != READ_SIZE) {
+ if (read(fd, bp->block, secsz) != secsz) {
fprintf(stderr, "read error, sector %d\n", secnr);
- bp->block = NULL;
+ blockhead = bp->next;
+ return NULL;
}
- return bp->block;
+ return bp->block + blk_off;
}
int
diff --git a/kpartx/kpartx.h b/kpartx/kpartx.h
index 67edeb82..727632c1 100644
--- a/kpartx/kpartx.h
+++ b/kpartx/kpartx.h
@@ -1,6 +1,7 @@
#ifndef _KPARTX_H
#define _KPARTX_H
+#include <stddef.h>
#include <stdint.h>
#include <sys/ioctl.h>
@@ -61,6 +62,7 @@ extern ptreader read_mac_pt;
extern ptreader read_sun_pt;
extern ptreader read_ps3_pt;
+int aligned_malloc(void **mem_p, size_t align, size_t *size_p);
char *getblock(int fd, unsigned int secnr);
static inline unsigned int
--
2.17.2

View File

@ -0,0 +1,52 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 30 Jun 2020 10:49:59 -0500
Subject: [PATCH] kpartx: handle alternate bsd disklabel location
bsd disk labels can either be at the start of the second sector, or 64
bytes into the first sector, but kpartx only handled the first case.
However the second case is what parted creates, and what the linux
kernel partition code expects. kpartx should handle both cases.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
kpartx/bsd.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/kpartx/bsd.c b/kpartx/bsd.c
index 0e661fbc..950b0f92 100644
--- a/kpartx/bsd.c
+++ b/kpartx/bsd.c
@@ -1,6 +1,7 @@
#include "kpartx.h"
#include <stdio.h>
+#define BSD_LABEL_OFFSET 64
#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
#define XBSD_MAXPARTITIONS 16
#define BSD_FS_UNUSED 0
@@ -60,8 +61,19 @@ read_bsd_pt(int fd, struct slice all, struct slice *sp, unsigned int ns) {
return -1;
l = (struct bsd_disklabel *) bp;
- if (l->d_magic != BSD_DISKMAGIC)
- return -1;
+ if (l->d_magic != BSD_DISKMAGIC) {
+ /*
+ * BSD disklabels can also start 64 bytes offset from the
+ * start of the first sector
+ */
+ bp = getblock(fd, offset);
+ if (bp == NULL)
+ return -1;
+
+ l = (struct bsd_disklabel *)(bp + 64);
+ if (l->d_magic != BSD_DISKMAGIC)
+ return -1;
+ }
max_partitions = 16;
if (l->d_npartitions < max_partitions)
--
2.17.2

View File

@ -0,0 +1,61 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 30 Jun 2020 13:59:13 -0500
Subject: [PATCH] libmultipath: fix checker detection for nvme devices
In order to fix hwhandler autodetection, commit 8794a776 made
detect_alua() differentiate between failures to detect whether alua was
supported, and successfully detecting that it was not supported.
However, this causes nvme devices to get the TUR checker assigned to
them. This is because there is nothing in detect_alua() to make it only
work on scsi devices, and select_checker wasn't updated to handle
detect_alua() failing without setting pp->tpgs to TPGS_NONE.
detect_alua() should automatically set pp->tpgs to TPGS_NONE and exit on
non-scsi devices. Also, select_checker() should not assume that a
devices is ALUA, simply because if failed to detect if alua was
supported.
Fixes: 8794a776 "libmultipath: fix ALUA autodetection when paths are
down"
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 6 ++++++
libmultipath/propsel.c | 4 +++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 83a41a4a..aa5942c3 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -887,6 +887,12 @@ detect_alua(struct path * pp)
int tpgs;
unsigned int timeout;
+
+ if (pp->bus != SYSFS_BUS_SCSI) {
+ pp->tpgs = TPGS_NONE;
+ return;
+ }
+
if (sysfs_get_timeout(pp, &timeout) <= 0)
timeout = DEF_TIMEOUT;
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index 897e48ca..d362beb4 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -521,7 +521,9 @@ int select_checker(struct config *conf, struct path *pp)
if (check_rdac(pp)) {
ckr_name = RDAC;
goto out;
- } else if (path_get_tpgs(pp) != TPGS_NONE) {
+ }
+ path_get_tpgs(pp);
+ if (pp->tpgs != TPGS_NONE && pp->tpgs != TPGS_UNDEF) {
ckr_name = TUR;
goto out;
}
--
2.17.2

View File

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 6 Jul 2020 13:21:12 -0500
Subject: [PATCH] Makefile.inc: trim extra information from systemd version
Some systemd versions print extra information in the
"pkg-config --modversion" output, which confuses make. Trim this
off.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.inc b/Makefile.inc
index c2abd301..220009e0 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -37,7 +37,7 @@ endif
ifndef SYSTEMD
ifeq ($(shell pkg-config --modversion libsystemd >/dev/null 2>&1 && echo 1), 1)
- SYSTEMD = $(shell pkg-config --modversion libsystemd)
+ SYSTEMD = $(shell pkg-config --modversion libsystemd | awk '{print $$1}')
else
ifeq ($(shell systemctl --version >/dev/null 2>&1 && echo 1), 1)
SYSTEMD = $(shell systemctl --version 2> /dev/null | \
--
2.17.2

View File

@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 6 Jul 2020 17:28:46 -0500
Subject: [PATCH] kpartx: fix -Wsign-compare error
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
kpartx/kpartx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
index c24ad6d9..653ce0c8 100644
--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -738,7 +738,7 @@ struct block {
/* blknr is always in 512 byte blocks */
char *
getblock (int fd, unsigned int blknr) {
- unsigned int secsz = get_sector_size(fd);
+ int secsz = get_sector_size(fd);
unsigned int blks_per_sec = secsz / 512;
unsigned int secnr = blknr / blks_per_sec;
unsigned int blk_off = (blknr % blks_per_sec) * 512;
--
2.17.2

View File

@ -0,0 +1,86 @@
From 7159242be31dbb3f25aa67920462107bc2bc5fe0 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 9 Jul 2020 18:20:18 -0500
Subject: [PATCH] libmultipath: count pending paths as active on loads
When multipath loads a table, it signals to udev if there are no active
paths. Multipath wasn't counting pending paths as active. This meant
that if all the paths were pending, udev would treat the device as not
ready, and not run kpartx on it. Even if the pending paths later
because active and were reinstated, the kernel would not send a new
uevent, because from its point of view, they were always up.
The alternative would be to continue to treat them as failed in the udev
rules, but then also tell the kernel that they were down, so that it
would trigger a uevent when they were reinstated. However, this could
lead to newly created multipath devices failing IO, simply because the
path checkers hadn't returned yet. Having udev assume that the the
device is up, like the kernel does, seems like the safer option.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/devmapper.c | 3 ++-
libmultipath/structs.c | 20 ++++++++++++++++++++
libmultipath/structs.h | 1 +
3 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 7f98bf9d..91ff0b3d 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -408,7 +408,8 @@ static uint16_t build_udev_flags(const struct multipath *mpp, int reload)
/* DM_UDEV_DISABLE_LIBRARY_FALLBACK is added in dm_addmap */
return (mpp->skip_kpartx == SKIP_KPARTX_ON ?
MPATH_UDEV_NO_KPARTX_FLAG : 0) |
- ((count_active_paths(mpp) == 0 || mpp->ghost_delay_tick > 0) ?
+ ((count_active_pending_paths(mpp) == 0 ||
+ mpp->ghost_delay_tick > 0) ?
MPATH_UDEV_NO_PATHS_FLAG : 0) |
(reload && !mpp->force_udev_reload ?
MPATH_UDEV_RELOAD_FLAG : 0);
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index 2dd378c4..dda9884c 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -500,6 +500,26 @@ int count_active_paths(const struct multipath *mpp)
return count;
}
+int count_active_pending_paths(const struct multipath *mpp)
+{
+ struct pathgroup *pgp;
+ struct path *pp;
+ int count = 0;
+ int i, j;
+
+ if (!mpp->pg)
+ return 0;
+
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ vector_foreach_slot (pgp->paths, pp, j) {
+ if (pp->state == PATH_UP || pp->state == PATH_GHOST ||
+ pp->state == PATH_PENDING)
+ count++;
+ }
+ }
+ return count;
+}
+
int pathcmp(const struct pathgroup *pgp, const struct pathgroup *cpgp)
{
int i, j;
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 9bd39eb1..8e78b8c0 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -465,6 +465,7 @@ struct path * first_path (const struct multipath *mpp);
int pathcountgr (const struct pathgroup *, int);
int pathcount (const struct multipath *, int);
int count_active_paths(const struct multipath *);
+int count_active_pending_paths(const struct multipath *);
int pathcmp (const struct pathgroup *, const struct pathgroup *);
int add_feature (char **, const char *);
int remove_feature (char **, const char *);
--
2.17.2

View File

@ -0,0 +1,58 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 13 Jul 2020 15:41:15 -0500
Subject: [PATCH] multipath: deal with failures flushing maps
dm_flush_maps() was failing if there were no device-mapper devices at
all, instead of returning success, since there is nothing to do.
delegate_to_multipathd() was returning success, even if the multipathd
command failed. Also, if the command was set to fail with NOT_DELEGATED,
it shouldn't print any errors, since multipath will try to issue to
command itself.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/devmapper.c | 2 +-
multipath/main.c | 9 ++++++---
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 91ff0b3d..3f70e576 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -970,10 +970,10 @@ int dm_flush_maps (int need_suspend, int retries)
if (!(names = dm_task_get_names (dmt)))
goto out;
+ r = 0;
if (!names->dev)
goto out;
- r = 0;
do {
if (need_suspend)
r |= dm_suspend_and_flush_map(names->name, retries);
diff --git a/multipath/main.c b/multipath/main.c
index 3c3d2398..607cada2 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -869,9 +869,12 @@ int delegate_to_multipathd(enum mpath_cmds cmd,
goto out;
}
- if (reply != NULL && *reply != '\0' && strcmp(reply, "ok\n"))
- printf("%s", reply);
- r = DELEGATE_OK;
+ if (reply != NULL && *reply != '\0') {
+ if (strcmp(reply, "fail\n"))
+ r = DELEGATE_OK;
+ if (r != NOT_DELEGATED && strcmp(reply, "ok\n"))
+ printf("%s", reply);
+ }
out:
FREE(reply);
--
2.17.2

View File

@ -0,0 +1,54 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 3 Nov 2020 14:27:58 -0600
Subject: [PATCH] libmultipath: factor out code to get vpd page data
A future patch will reuse the code to get the vpd page data, so factor
it out from get_vpd_sgio().
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index aa5942c3..eb1e735d 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1239,11 +1239,10 @@ get_vpd_sysfs (struct udev_device *parent, int pg, char * str, int maxlen)
return len;
}
-int
-get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen)
+static int
+fetch_vpd_page(int fd, int pg, unsigned char *buff)
{
- int len, buff_len;
- unsigned char buff[4096];
+ int buff_len;
memset(buff, 0x0, 4096);
if (sgio_get_vpd(buff, 4096, fd, pg) < 0) {
@@ -1264,6 +1263,18 @@ get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen)
condlog(3, "vpd pg%02x page truncated", pg);
buff_len = 4096;
}
+ return buff_len;
+}
+
+int
+get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen)
+{
+ int len, buff_len;
+ unsigned char buff[4096];
+
+ buff_len = fetch_vpd_page(fd, pg, buff);
+ if (buff_len < 0)
+ return buff_len;
if (pg == 0x80)
len = parse_vpd_pg80(buff, str, maxlen);
else if (pg == 0x83)
--
2.17.2

View File

@ -0,0 +1,98 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 7 Oct 2020 21:43:02 -0500
Subject: [PATCH] libmultipath: limit reading 0xc9 vpd page
Only rdac arrays support 0xC9 vpd page inquiries. All other arrays will
return a failure. Only do the rdac inquiry when detecting array
capabilities if the array's path checker is explicitly set to rdac, or
the path checker is not set, and the array reports that it supports vpd
page 0xC9 in the Supported VPD Pages (0x00) vpd page.
Multipath was doing the check if either the path checker was set to
rdac, or no path checker was set. This means that for almost all
non-rdac arrays, multipath was issuing a bad inquiry. This was annoying
users.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 25 +++++++++++++++++++++++++
libmultipath/discovery.h | 1 +
libmultipath/propsel.c | 10 ++++++----
3 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index eb1e735d..01aadba9 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1266,6 +1266,31 @@ fetch_vpd_page(int fd, int pg, unsigned char *buff)
return buff_len;
}
+/* heavily based on sg_inq.c from sg3_utils */
+bool
+is_vpd_page_supported(int fd, int pg)
+{
+ int i, len, buff_len;
+ unsigned char buff[4096];
+
+ buff_len = fetch_vpd_page(fd, 0x00, buff);
+ if (buff_len < 0)
+ return false;
+ if (buff_len < 4) {
+ condlog(3, "VPD page 00h too short");
+ return false;
+ }
+
+ len = buff[3] + 4;
+ if (len > buff_len)
+ condlog(3, "vpd page 00h trucated, expected %d, have %d",
+ len, buff_len);
+ for (i = 4; i < len; ++i)
+ if (buff[i] == pg)
+ return true;
+ return false;
+}
+
int
get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen)
{
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
index 6444887d..d3193daf 100644
--- a/libmultipath/discovery.h
+++ b/libmultipath/discovery.h
@@ -56,6 +56,7 @@ int sysfs_get_asymmetric_access_state(struct path *pp,
char *buff, int buflen);
int get_uid(struct path * pp, int path_state, struct udev_device *udev,
int allow_fallback);
+bool is_vpd_page_supported(int fd, int pg);
/*
* discovery bitmask
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index d362beb4..d7febec6 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -496,13 +496,15 @@ check_rdac(struct path * pp)
{
int len;
char buff[44];
- const char *checker_name;
+ const char *checker_name = NULL;
if (pp->bus != SYSFS_BUS_SCSI)
return 0;
- /* Avoid ioctl if this is likely not an RDAC array */
- if (__do_set_from_hwe(checker_name, pp, checker_name) &&
- strcmp(checker_name, RDAC))
+ /* Avoid checking 0xc9 if this is likely not an RDAC array */
+ if (!__do_set_from_hwe(checker_name, pp, checker_name) &&
+ !is_vpd_page_supported(pp->fd, 0xC9))
+ return 0;
+ if (checker_name && strcmp(checker_name, RDAC))
return 0;
len = get_vpd_sgio(pp->fd, 0xC9, 0, buff, 44);
if (len <= 0)
--
2.17.2

View File

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Steve Schremmer <steve.schremmer@netapp.com>
Date: Mon, 6 Jul 2020 20:22:35 +0000
Subject: [PATCH] libmultipath: add device to hwtable.c
Add FUJITSU ETERNUS_AHB defaults.
Signed-off-by: Steve Schremmer <steve.schremmer@netapp.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/hwtable.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
index d1fcfdb3..d680bdfc 100644
--- a/libmultipath/hwtable.c
+++ b/libmultipath/hwtable.c
@@ -428,6 +428,22 @@ static struct hwentry default_hw[] = {
.pgpolicy = MULTIBUS,
.no_path_retry = 10,
},
+ {
+ /*
+ * ETERNUS AB/HB
+ * Maintainer: NetApp RDAC team <ng-eseries-upstream-maintainers@netapp.com>
+ */
+ .vendor = "FUJITSU",
+ .product = "ETERNUS_AHB",
+ .bl_product = "Universal Xport",
+ .pgpolicy = GROUP_BY_PRIO,
+ .checker_name = RDAC,
+ .features = "2 pg_init_retries 50",
+ .hwhandler = "1 rdac",
+ .prio_name = PRIO_RDAC,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .no_path_retry = 30,
+ },
/*
* Hitachi Vantara
*
--
2.17.2

View File

@ -0,0 +1,159 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 12 Oct 2020 16:06:11 -0500
Subject: [PATCH] libmultipath: move fast_io_fail defines to structs.h
Since fast_io_fail is part of the multipath struct, its symbolic values
belong in structs.h. Also, make it an instance of a general enum, which
will be used again in future patches, and change the set/print functions
which use it to use the general enum instead.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.h | 8 --------
libmultipath/dict.c | 30 +++++++++++++++---------------
libmultipath/dict.h | 2 +-
libmultipath/propsel.c | 2 +-
libmultipath/structs.h | 17 +++++++++++++++++
5 files changed, 34 insertions(+), 25 deletions(-)
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 160867cd..f38c7639 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -11,14 +11,6 @@
#define ORIGIN_CONFIG 1
#define ORIGIN_NO_CONFIG 2
-/*
- * In kernel, fast_io_fail == 0 means immediate failure on rport delete.
- * OTOH '0' means not-configured in various places in multipath-tools.
- */
-#define MP_FAST_IO_FAIL_UNSET (0)
-#define MP_FAST_IO_FAIL_OFF (-1)
-#define MP_FAST_IO_FAIL_ZERO (-2)
-
enum devtypes {
DEV_NONE,
DEV_DEVT,
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 184d4b22..ce8e1cda 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -834,7 +834,7 @@ declare_mp_attr_handler(gid, set_gid)
declare_mp_attr_snprint(gid, print_gid)
static int
-set_fast_io_fail(vector strvec, void *ptr)
+set_undef_off_zero(vector strvec, void *ptr)
{
char * buff;
int *int_ptr = (int *)ptr;
@@ -844,36 +844,36 @@ set_fast_io_fail(vector strvec, void *ptr)
return 1;
if (strcmp(buff, "off") == 0)
- *int_ptr = MP_FAST_IO_FAIL_OFF;
+ *int_ptr = UOZ_OFF;
else if (sscanf(buff, "%d", int_ptr) != 1 ||
- *int_ptr < MP_FAST_IO_FAIL_ZERO)
- *int_ptr = MP_FAST_IO_FAIL_UNSET;
+ *int_ptr < UOZ_ZERO)
+ *int_ptr = UOZ_UNDEF;
else if (*int_ptr == 0)
- *int_ptr = MP_FAST_IO_FAIL_ZERO;
+ *int_ptr = UOZ_ZERO;
FREE(buff);
return 0;
}
int
-print_fast_io_fail(char * buff, int len, long v)
+print_undef_off_zero(char * buff, int len, long v)
{
- if (v == MP_FAST_IO_FAIL_UNSET)
+ if (v == UOZ_UNDEF)
return 0;
- if (v == MP_FAST_IO_FAIL_OFF)
+ if (v == UOZ_OFF)
return snprintf(buff, len, "\"off\"");
- if (v == MP_FAST_IO_FAIL_ZERO)
+ if (v == UOZ_ZERO)
return snprintf(buff, len, "0");
return snprintf(buff, len, "%ld", v);
}
-declare_def_handler(fast_io_fail, set_fast_io_fail)
-declare_def_snprint_defint(fast_io_fail, print_fast_io_fail,
+declare_def_handler(fast_io_fail, set_undef_off_zero)
+declare_def_snprint_defint(fast_io_fail, print_undef_off_zero,
DEFAULT_FAST_IO_FAIL)
-declare_ovr_handler(fast_io_fail, set_fast_io_fail)
-declare_ovr_snprint(fast_io_fail, print_fast_io_fail)
-declare_hw_handler(fast_io_fail, set_fast_io_fail)
-declare_hw_snprint(fast_io_fail, print_fast_io_fail)
+declare_ovr_handler(fast_io_fail, set_undef_off_zero)
+declare_ovr_snprint(fast_io_fail, print_undef_off_zero)
+declare_hw_handler(fast_io_fail, set_undef_off_zero)
+declare_hw_snprint(fast_io_fail, print_undef_off_zero)
static int
set_dev_loss(vector strvec, void *ptr)
diff --git a/libmultipath/dict.h b/libmultipath/dict.h
index a40ac66f..a917e1ca 100644
--- a/libmultipath/dict.h
+++ b/libmultipath/dict.h
@@ -13,7 +13,7 @@ int print_rr_weight(char *buff, int len, long v);
int print_pgfailback(char *buff, int len, long v);
int print_pgpolicy(char *buff, int len, long v);
int print_no_path_retry(char *buff, int len, long v);
-int print_fast_io_fail(char *buff, int len, long v);
+int print_undef_off_zero(char *buff, int len, long v);
int print_dev_loss(char *buff, int len, unsigned long v);
int print_reservation_key(char * buff, int len, struct be64 key, uint8_t
flags, int source);
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index d7febec6..725db2b1 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -755,7 +755,7 @@ int select_fast_io_fail(struct config *conf, struct multipath *mp)
mp_set_conf(fast_io_fail);
mp_set_default(fast_io_fail, DEFAULT_FAST_IO_FAIL);
out:
- print_fast_io_fail(buff, 12, mp->fast_io_fail);
+ print_undef_off_zero(buff, 12, mp->fast_io_fail);
condlog(3, "%s: fast_io_fail_tmo = %s %s", mp->alias, buff, origin);
return 0;
}
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 8e78b8c0..29209984 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -229,6 +229,23 @@ enum vpd_vendor_ids {
VPD_VP_ARRAY_SIZE, /* This must remain the last entry */
};
+/*
+ * Multipath treats 0 as undefined for optional config parameters.
+ * Use this for cases where 0 is a valid option for systems multipath
+ * is communicating with
+ */
+enum undefined_off_zero {
+ UOZ_UNDEF = 0,
+ UOZ_OFF = -1,
+ UOZ_ZERO = -2,
+};
+
+enum fast_io_fail_states {
+ MP_FAST_IO_FAIL_UNSET = UOZ_UNDEF,
+ MP_FAST_IO_FAIL_OFF = UOZ_OFF,
+ MP_FAST_IO_FAIL_ZERO = UOZ_ZERO,
+};
+
struct vpd_vendor_page {
int pg;
const char *name;
--
2.17.2

View File

@ -0,0 +1,295 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 14 Oct 2020 18:38:20 -0500
Subject: [PATCH] libmultipath: add eh_deadline multipath.conf parameter
There are times a fc rport is never lost, meaning that fast_io_fail_tmo
and dev_loss_tmo never trigger, but scsi commands still hang. This can
cause problems in cases where users have string timing requirements, and
the easiest way to solve these issues is to set eh_deadline. Since it's
already possible to set fast_io_fail_tmo and dev_loss_tmo from
multipath.conf, and have multipath take care of setting it correctly for
the scsi devices in sysfs, it makes sense to allow users to set
eh_deadline here as well.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 2 ++
libmultipath/config.h | 2 ++
libmultipath/configure.c | 1 +
libmultipath/dict.c | 10 +++++++
libmultipath/discovery.c | 58 +++++++++++++++++++++++++++++++++-----
libmultipath/propsel.c | 17 +++++++++++
libmultipath/propsel.h | 1 +
libmultipath/structs.h | 7 +++++
multipath/multipath.conf.5 | 16 +++++++++++
9 files changed, 107 insertions(+), 7 deletions(-)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 26f8e050..a71db2d0 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -359,6 +359,7 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
merge_num(flush_on_last_del);
merge_num(fast_io_fail);
merge_num(dev_loss);
+ merge_num(eh_deadline);
merge_num(user_friendly_names);
merge_num(retain_hwhandler);
merge_num(detect_prio);
@@ -514,6 +515,7 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
hwe->flush_on_last_del = dhwe->flush_on_last_del;
hwe->fast_io_fail = dhwe->fast_io_fail;
hwe->dev_loss = dhwe->dev_loss;
+ hwe->eh_deadline = dhwe->eh_deadline;
hwe->user_friendly_names = dhwe->user_friendly_names;
hwe->retain_hwhandler = dhwe->retain_hwhandler;
hwe->detect_prio = dhwe->detect_prio;
diff --git a/libmultipath/config.h b/libmultipath/config.h
index f38c7639..a22c1b4e 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -64,6 +64,7 @@ struct hwentry {
int flush_on_last_del;
int fast_io_fail;
unsigned int dev_loss;
+ int eh_deadline;
int user_friendly_names;
int retain_hwhandler;
int detect_prio;
@@ -149,6 +150,7 @@ struct config {
int attribute_flags;
int fast_io_fail;
unsigned int dev_loss;
+ int eh_deadline;
int log_checker_err;
int allow_queueing;
int find_multipaths;
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 96c79610..b7113291 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -340,6 +340,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size,
select_gid(conf, mpp);
select_fast_io_fail(conf, mpp);
select_dev_loss(conf, mpp);
+ select_eh_deadline(conf, mpp);
select_reservation_key(conf, mpp);
select_deferred_remove(conf, mpp);
select_marginal_path_err_sample_time(conf, mpp);
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index ce8e1cda..8fd91d8c 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -911,6 +911,13 @@ declare_ovr_snprint(dev_loss, print_dev_loss)
declare_hw_handler(dev_loss, set_dev_loss)
declare_hw_snprint(dev_loss, print_dev_loss)
+declare_def_handler(eh_deadline, set_undef_off_zero)
+declare_def_snprint(eh_deadline, print_undef_off_zero)
+declare_ovr_handler(eh_deadline, set_undef_off_zero)
+declare_ovr_snprint(eh_deadline, print_undef_off_zero)
+declare_hw_handler(eh_deadline, set_undef_off_zero)
+declare_hw_snprint(eh_deadline, print_undef_off_zero)
+
static int
set_pgpolicy(vector strvec, void *ptr)
{
@@ -1776,6 +1783,7 @@ init_keywords(vector keywords)
install_keyword("gid", &def_gid_handler, &snprint_def_gid);
install_keyword("fast_io_fail_tmo", &def_fast_io_fail_handler, &snprint_def_fast_io_fail);
install_keyword("dev_loss_tmo", &def_dev_loss_handler, &snprint_def_dev_loss);
+ install_keyword("eh_deadline", &def_eh_deadline_handler, &snprint_def_eh_deadline);
install_keyword("bindings_file", &def_bindings_file_handler, &snprint_def_bindings_file);
install_keyword("wwids_file", &def_wwids_file_handler, &snprint_def_wwids_file);
install_keyword("prkeys_file", &def_prkeys_file_handler, &snprint_def_prkeys_file);
@@ -1885,6 +1893,7 @@ init_keywords(vector keywords)
install_keyword("flush_on_last_del", &hw_flush_on_last_del_handler, &snprint_hw_flush_on_last_del);
install_keyword("fast_io_fail_tmo", &hw_fast_io_fail_handler, &snprint_hw_fast_io_fail);
install_keyword("dev_loss_tmo", &hw_dev_loss_handler, &snprint_hw_dev_loss);
+ install_keyword("eh_deadline", &hw_eh_deadline_handler, &snprint_hw_eh_deadline);
install_keyword("user_friendly_names", &hw_user_friendly_names_handler, &snprint_hw_user_friendly_names);
install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler);
install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_hw_detect_prio);
@@ -1925,6 +1934,7 @@ init_keywords(vector keywords)
install_keyword("flush_on_last_del", &ovr_flush_on_last_del_handler, &snprint_ovr_flush_on_last_del);
install_keyword("fast_io_fail_tmo", &ovr_fast_io_fail_handler, &snprint_ovr_fast_io_fail);
install_keyword("dev_loss_tmo", &ovr_dev_loss_handler, &snprint_ovr_dev_loss);
+ install_keyword("eh_deadline", &ovr_eh_deadline_handler, &snprint_ovr_eh_deadline);
install_keyword("user_friendly_names", &ovr_user_friendly_names_handler, &snprint_ovr_user_friendly_names);
install_keyword("retain_attached_hw_handler", &ovr_retain_hwhandler_handler, &snprint_ovr_retain_hwhandler);
install_keyword("detect_prio", &ovr_detect_prio_handler, &snprint_ovr_detect_prio);
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 01aadba9..a328aafa 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -577,6 +577,42 @@ sysfs_get_asymmetric_access_state(struct path *pp, char *buff, int buflen)
return !!preferred;
}
+static int
+sysfs_set_eh_deadline(struct multipath *mpp, struct path *pp)
+{
+ struct udev_device *hostdev;
+ char host_name[HOST_NAME_LEN], value[16];
+ int ret;
+
+ if (mpp->eh_deadline == EH_DEADLINE_UNSET)
+ return 0;
+
+ sprintf(host_name, "host%d", pp->sg_id.host_no);
+ hostdev = udev_device_new_from_subsystem_sysname(udev,
+ "scsi_host", host_name);
+ if (!hostdev)
+ return 1;
+
+ if (mpp->eh_deadline == EH_DEADLINE_OFF)
+ sprintf(value, "off");
+ else if (mpp->eh_deadline == EH_DEADLINE_ZERO)
+ sprintf(value, "0");
+ else
+ snprintf(value, 16, "%u", mpp->eh_deadline);
+
+ ret = sysfs_attr_set_value(hostdev, "eh_deadline",
+ value, strlen(value));
+ /*
+ * not all scsi drivers support setting eh_deadline, so failing
+ * is totally reasonable
+ */
+ if (ret <= 0)
+ condlog(4, "%s: failed to set eh_deadline to %s, error %d", udev_device_get_sysname(hostdev), value, -ret);
+
+ udev_device_unref(hostdev);
+ return (ret <= 0);
+}
+
static void
sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
{
@@ -787,16 +823,24 @@ sysfs_set_scsi_tmo (struct multipath *mpp, unsigned int checkint)
mpp->alias, mpp->fast_io_fail);
mpp->fast_io_fail = MP_FAST_IO_FAIL_OFF;
}
- if (!mpp->dev_loss && mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET)
+ if (!mpp->dev_loss && mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET &&
+ mpp->eh_deadline == EH_DEADLINE_UNSET)
return 0;
vector_foreach_slot(mpp->paths, pp, i) {
- if (pp->sg_id.proto_id == SCSI_PROTOCOL_FCP)
- sysfs_set_rport_tmo(mpp, pp);
- if (pp->sg_id.proto_id == SCSI_PROTOCOL_ISCSI)
- sysfs_set_session_tmo(mpp, pp);
- if (pp->sg_id.proto_id == SCSI_PROTOCOL_SAS)
- sysfs_set_nexus_loss_tmo(mpp, pp);
+ if (pp->bus != SYSFS_BUS_SCSI)
+ continue;
+
+ if (mpp->dev_loss ||
+ mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) {
+ if (pp->sg_id.proto_id == SCSI_PROTOCOL_FCP)
+ sysfs_set_rport_tmo(mpp, pp);
+ else if (pp->sg_id.proto_id == SCSI_PROTOCOL_ISCSI)
+ sysfs_set_session_tmo(mpp, pp);
+ else if (pp->sg_id.proto_id == SCSI_PROTOCOL_SAS)
+ sysfs_set_nexus_loss_tmo(mpp, pp);
+ }
+ sysfs_set_eh_deadline(mpp, pp);
}
return 0;
}
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index 725db2b1..1150cfe8 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -776,6 +776,23 @@ out:
return 0;
}
+int select_eh_deadline(struct config *conf, struct multipath *mp)
+{
+ const char *origin;
+ char buff[12];
+
+ mp_set_ovr(eh_deadline);
+ mp_set_hwe(eh_deadline);
+ mp_set_conf(eh_deadline);
+ mp->eh_deadline = EH_DEADLINE_UNSET;
+ /* not changing sysfs in default cause, so don't print anything */
+ return 0;
+out:
+ print_undef_off_zero(buff, 12, mp->eh_deadline);
+ condlog(3, "%s: eh_deadline = %s %s", mp->alias, buff, origin);
+ return 0;
+}
+
int select_flush_on_last_del(struct config *conf, struct multipath *mp)
{
const char *origin;
diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h
index 3d6edd8a..a68bacf0 100644
--- a/libmultipath/propsel.h
+++ b/libmultipath/propsel.h
@@ -17,6 +17,7 @@ int select_uid(struct config *conf, struct multipath *mp);
int select_gid(struct config *conf, struct multipath *mp);
int select_fast_io_fail(struct config *conf, struct multipath *mp);
int select_dev_loss(struct config *conf, struct multipath *mp);
+int select_eh_deadline(struct config *conf, struct multipath *mp);
int select_reservation_key(struct config *conf, struct multipath *mp);
int select_retain_hwhandler (struct config *conf, struct multipath * mp);
int select_detect_prio(struct config *conf, struct path * pp);
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 29209984..65542dea 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -246,6 +246,12 @@ enum fast_io_fail_states {
MP_FAST_IO_FAIL_ZERO = UOZ_ZERO,
};
+enum eh_deadline_states {
+ EH_DEADLINE_UNSET = UOZ_UNDEF,
+ EH_DEADLINE_OFF = UOZ_OFF,
+ EH_DEADLINE_ZERO = UOZ_ZERO,
+};
+
struct vpd_vendor_page {
int pg;
const char *name;
@@ -366,6 +372,7 @@ struct multipath {
int ghost_delay;
int ghost_delay_tick;
unsigned int dev_loss;
+ int eh_deadline;
uid_t uid;
gid_t gid;
mode_t mode;
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 6dc26f10..60954574 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -700,6 +700,22 @@ The default is: \fB600\fR
.
.
.TP
+.B eh_deadline
+Specify the maximum number of seconds the SCSI layer will spend doing error
+handling when scsi devices fail. After this timeout the scsi layer will perform
+a full HBA reset. Setting this may be necessary in cases where the rport is
+never lost, so \fIfast_io_fail_tmo\fR and \fIdev_loss_tmo\fR will never
+trigger, but (frequently do to load) scsi commands still hang. \fBNote:\fR when
+the scsi error handler performs the HBA reset, all target paths on that HBA
+will be affected. eh_deadline should only be set in cases where all targets on
+the affected HBAs are multipathed.
+.RS
+.TP
+The default is: \fB<unset>\fR
+.RE
+.
+.
+.TP
.B bindings_file
The full pathname of the binding file to be used when the user_friendly_names
option is set.
--
2.17.2

View File

@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 23 Oct 2020 11:38:24 -0500
Subject: [PATCH] libmultipath: don't dlclose tur checker DSO
The multipathd tur checker thread is designed to be able to finish at
any time, even after the tur checker itself has been freed. The
multipathd shutdown code makes sure all the checkers have been freed
before freeing the checker_class and calling dlclose() to unload the
DSO, but this doesn't guarantee that the checker threads have finished.
If one hasn't, the DSO will get unloaded while the thread still running
code from it, causing a segfault. Unfortunately, it's not possible to be
sure that all tur checker threads have ended during shutdown, without
making them joinable.
However, since libmultipath will never be reinitialized after it has
been uninitialzed, not dlclosing the tur checker DSO once a thread is
started has minimal cost (keeping the DSO code around until the program
exits, which usually happens right after freeing the checkers).
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/checkers.c | 10 +++++++++-
libmultipath/checkers.h | 1 +
libmultipath/checkers/tur.c | 1 +
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c
index 8d2be8a9..6359e5d8 100644
--- a/libmultipath/checkers.c
+++ b/libmultipath/checkers.c
@@ -21,6 +21,7 @@ struct checker_class {
void (*reset)(void); /* to reset the global variables */
const char **msgtable;
short msgtable_size;
+ int keep_dso;
};
char *checker_state_names[] = {
@@ -69,7 +70,7 @@ void free_checker_class(struct checker_class *c)
list_del(&c->node);
if (c->reset)
c->reset();
- if (c->handle) {
+ if (c->handle && !c->keep_dso) {
if (dlclose(c->handle) != 0) {
condlog(0, "Cannot unload checker %s: %s",
c->name, dlerror());
@@ -192,6 +193,13 @@ out:
return NULL;
}
+void checker_keep_dso(struct checker * c)
+{
+ if (!c || !c->cls)
+ return;
+ c->cls->keep_dso = 1;
+}
+
void checker_set_fd (struct checker * c, int fd)
{
if (!c)
diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h
index b458118d..f183cff9 100644
--- a/libmultipath/checkers.h
+++ b/libmultipath/checkers.h
@@ -145,6 +145,7 @@ void checker_reset (struct checker *);
void checker_set_sync (struct checker *);
void checker_set_async (struct checker *);
void checker_set_fd (struct checker *, int);
+void checker_keep_dso(struct checker *c);
void checker_enable (struct checker *);
void checker_disable (struct checker *);
int checker_check (struct checker *, int);
diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c
index e886fcf8..fd58d62a 100644
--- a/libmultipath/checkers/tur.c
+++ b/libmultipath/checkers/tur.c
@@ -394,6 +394,7 @@ int libcheck_check(struct checker * c)
uatomic_set(&ct->running, 1);
tur_set_async_timeout(c);
setup_thread_attr(&attr, 32 * 1024, 1);
+ checker_keep_dso(c);
r = pthread_create(&ct->thread, &attr, tur_thread, ct);
pthread_attr_destroy(&attr);
if (r) {
--
2.17.2

View File

@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 16 Nov 2020 13:52:09 -0600
Subject: [PATCH] libmultipath: warn about missing braces at end of
multipath.conf
Multipath doesn't warn when multipath.conf is missing closing braces at
the end of the file. This has confused people about the correct config
file syntax, so add a warning.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/parser.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index a7285a35..48b54e87 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -544,7 +544,7 @@ process_stream(struct config *conf, FILE *stream, vector keywords, char *file)
if (!strcmp(str, EOB)) {
if (kw_level > 0) {
free_strvec(strvec);
- break;
+ goto out;
}
condlog(0, "unmatched '%s' at line %d of %s",
EOB, line_nr, file);
@@ -583,7 +583,8 @@ process_stream(struct config *conf, FILE *stream, vector keywords, char *file)
free_strvec(strvec);
}
-
+ if (kw_level == 1)
+ condlog(1, "missing '%s' at end of %s", EOB, file);
out:
FREE(buf);
free_uniques(uniques);
--
2.17.2

View File

@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 16 Nov 2020 16:38:21 -0600
Subject: [PATCH] libmultipath: ignore multipaths sections without wwid option
"multipathd show config local" was crashing in find_mp_by_wwid() if
the multipath configuration included a multipaths section that did
not set a wwid option. There is no reason to keep a mpentry that
didn't set its wwid. Remove it in merge_mptable().
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index a71db2d0..dc81c994 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -444,6 +444,13 @@ void merge_mptable(vector mptable)
int i, j;
vector_foreach_slot(mptable, mp1, i) {
+ /* drop invalid multipath configs */
+ if (!mp1->wwid) {
+ condlog(0, "multipaths config section missing wwid");
+ vector_del_slot(mptable, i--);
+ free_mpe(mp1);
+ continue;
+ }
j = i + 1;
vector_foreach_slot_after(mptable, mp2, j) {
if (strcmp(mp1->wwid, mp2->wwid))
--
2.17.2

View File

@ -0,0 +1,25 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 16 Nov 2020 23:21:41 -0600
Subject: [PATCH] tests: fix missing priority blacklist test
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
tests/blacklist.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/blacklist.c b/tests/blacklist.c
index d20e97af..401600d9 100644
--- a/tests/blacklist.c
+++ b/tests/blacklist.c
@@ -378,7 +378,6 @@ static void test_property_missing(void **state)
{
static struct udev_device udev = { "sdb", { "ID_FOO", "ID_BAZ", "ID_BAR", "ID_SERIAL", NULL } };
conf.blist_property = blist_property_wwn;
- expect_condlog(3, "sdb: blacklisted, udev property missing\n");
assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
MATCH_NOTHING);
assert_int_equal(filter_property(&conf, &udev, 3, "ID_BLAH"),
--
2.17.2

View File

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 5 Nov 2020 09:15:43 -0600
Subject: [PATCH] mpathpersist: Fix Register and Ignore with 0x00 SARK
When the Register and Ignore command is run with sg_persist, if a 0x00
Service Action Reservation Key is given or the --param-sark option is
not used at all, sg_persist will clear the registration. mpathpersist
will fail with an error. This patch fixes mpathpersist to work like
sg_persist in this case.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathpersist/mpath_persist.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index 3da7a6cf..aa196008 100644
--- a/libmpathpersist/mpath_persist.c
+++ b/libmpathpersist/mpath_persist.c
@@ -321,7 +321,8 @@ int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
}
if (memcmp(paramp->key, &mpp->reservation_key, 8) &&
- memcmp(paramp->sa_key, &mpp->reservation_key, 8)) {
+ memcmp(paramp->sa_key, &mpp->reservation_key, 8) &&
+ (prkey || rq_servact != MPATH_PROUT_REG_IGN_SA)) {
condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64, alias, get_be64(mpp->reservation_key));
ret = MPATH_PR_SYNTAX_ERROR;
goto out1;
--
2.17.2

View File

@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 23 Nov 2020 20:45:50 -0600
Subject: [PATCH] mpathpersist: update prkeys file on changing registrations
When the "reservation_key" option is set to "file" and Register command
is run with both the current Reservation Key and a new Service Action
Reservation Key, mpathpersist will change the registration, but will not
update the prkeys file. This means that future paths that come online
will not be able to register, since multipathd is still using the old
reservation key. Fix this.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathpersist/mpath_persist.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index aa196008..a01dfb0b 100644
--- a/libmpathpersist/mpath_persist.c
+++ b/libmpathpersist/mpath_persist.c
@@ -307,9 +307,10 @@ int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
memcpy(&prkey, paramp->sa_key, 8);
if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey &&
- ((!get_be64(mpp->reservation_key) &&
- rq_servact == MPATH_PROUT_REG_SA) ||
- rq_servact == MPATH_PROUT_REG_IGN_SA)) {
+ (rq_servact == MPATH_PROUT_REG_IGN_SA ||
+ (rq_servact == MPATH_PROUT_REG_SA &&
+ (!get_be64(mpp->reservation_key) ||
+ memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) {
memcpy(&mpp->reservation_key, paramp->sa_key, 8);
if (update_prkey_flags(alias, get_be64(mpp->reservation_key),
paramp->sa_flags)) {
--
2.17.2

View File

@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 14 Dec 2020 14:16:29 -0600
Subject: [PATCH] multipathd: Fix multipathd stopping on shutdown
According to man "systemd.special"
"shutdown.target: ... Services that shall be terminated on system
shutdown shall add Conflicts= and Before= dependencies to this unit for
their service unit, which is implicitly done when
DefaultDependencies=yes is set (the default)."
multipathd.service sets DefaultDependencies=no and includes the
Conflits= dependency, but not the Before= one. This can cause multipathd
to continue running past when it is supposed to during shutdown.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/multipathd.service | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service
index 0fbcc46b..bc8fa07a 100644
--- a/multipathd/multipathd.service
+++ b/multipathd/multipathd.service
@@ -2,7 +2,7 @@
Description=Device-Mapper Multipath Device Controller
Wants=systemd-udev-trigger.service systemd-udev-settle.service
Before=iscsi.service iscsid.service lvm2-activation-early.service
-Before=local-fs-pre.target blk-availability.service
+Before=local-fs-pre.target blk-availability.service shutdown.target
After=multipathd.socket systemd-udev-trigger.service systemd-udev-settle.service
ConditionPathExists=/etc/multipath.conf
DefaultDependencies=no
--
2.17.2

View File

@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 15 Dec 2020 12:47:14 -0600
Subject: [PATCH] multipath.conf.5: Improve checker_timeout description
I was asked to explain how checker_timeout works for checkers like
directio, that don't issue scsi commands with an explicit timeout
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/multipath.conf.5 | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 60954574..a5686090 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -634,8 +634,13 @@ The default is: \fBno\fR
.
.TP
.B checker_timeout
-Specify the timeout to use for path checkers and prioritizers that issue SCSI
-commands with an explicit timeout, in seconds.
+Specify the timeout to use for path checkers and prioritizers, in seconds.
+Only prioritizers that issue scsi commands use checker_timeout. Checkers
+that support an asynchronous mode (\fItur\fR and \fIdirectio\fR), will
+return shortly after being called by multipathd, regardless of whether the
+storage array responds. If the storage array hasn't responded, mulitpathd will
+check for a response every second, until \fIchecker_timeout\fR seconds have
+elapsed.
.RS
.TP
The default is: in \fB/sys/block/sd<x>/device/timeout\fR
--
2.17.2

View File

@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 4 Jan 2021 21:59:54 -0600
Subject: [PATCH] libmultipath: check for null wwid before strcmp
Commit 749aabd0 (libmultipath: ignore multipaths sections without wwid
option) removed all mpentries with a NULL wwid, but didn't stop strcmp()
from being run on them in merge_mptable(). The result of strcmp() with
a NULL parameter is undefined, so fix that.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index dc81c994..dd645f17 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -453,7 +453,7 @@ void merge_mptable(vector mptable)
}
j = i + 1;
vector_foreach_slot_after(mptable, mp2, j) {
- if (strcmp(mp1->wwid, mp2->wwid))
+ if (!mp2->wwid || strcmp(mp1->wwid, mp2->wwid))
continue;
condlog(1, "%s: duplicate multipath config section for %s",
__func__, mp1->wwid);
--
2.17.2

View File

@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 14 Jan 2021 20:20:22 -0600
Subject: [PATCH] libmultipath: make find_err_path_by_dev() static
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/io_err_stat.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c
index 1b9cd6c0..449760a0 100644
--- a/libmultipath/io_err_stat.c
+++ b/libmultipath/io_err_stat.c
@@ -89,7 +89,7 @@ static void rcu_unregister(__attribute__((unused)) void *param)
rcu_unregister_thread();
}
-struct io_err_stat_path *find_err_path_by_dev(vector pathvec, char *dev)
+static struct io_err_stat_path *find_err_path_by_dev(vector pathvec, char *dev)
{
int i;
struct io_err_stat_path *pp;
--
2.17.2

View File

@ -0,0 +1,291 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 14 Jan 2021 20:20:23 -0600
Subject: [PATCH] multipathd: avoid io_err_stat crash during shutdown
The checker thread is reponsible for enqueueing paths for the
io_err_stat thread to check. During shutdown, the io_err_stat thread is
shut down and cleaned up before the checker thread. There is no code
to make sure that the checker thread isn't accessing the io_err_stat
pathvec or its mutex while they are being freed, which can lead to
memory corruption crashes.
To solve this, get rid of the io_err_stat_pathvec structure, and
statically define the mutex. This means that the mutex is always valid
to access, and the io_err_stat pathvec can only be accessed while
holding it. If the io_err_stat thread has already been cleaned up
when the checker tries to access the pathvec, it will be NULL, and the
checker will simply fail to enqueue the path.
This change also fixes a bug in free_io_err_pathvec(), which previously
only attempted to free the pathvec if it was not set, instead of when it
was set.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/io_err_stat.c | 112 +++++++++++++++----------------------
libmultipath/util.c | 5 ++
libmultipath/util.h | 1 +
3 files changed, 50 insertions(+), 68 deletions(-)
diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c
index 449760a0..f6c564f0 100644
--- a/libmultipath/io_err_stat.c
+++ b/libmultipath/io_err_stat.c
@@ -34,6 +34,7 @@
#include "lock.h"
#include "time-util.h"
#include "io_err_stat.h"
+#include "util.h"
#define IOTIMEOUT_SEC 60
#define TIMEOUT_NO_IO_NSEC 10000000 /*10ms = 10000000ns*/
@@ -46,12 +47,6 @@
#define io_err_stat_log(prio, fmt, args...) \
condlog(prio, "io error statistic: " fmt, ##args)
-
-struct io_err_stat_pathvec {
- pthread_mutex_t mutex;
- vector pathvec;
-};
-
struct dio_ctx {
struct timespec io_starttime;
unsigned int blksize;
@@ -76,9 +71,10 @@ pthread_attr_t io_err_stat_attr;
static pthread_mutex_t io_err_thread_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t io_err_thread_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t io_err_pathvec_lock = PTHREAD_MUTEX_INITIALIZER;
static int io_err_thread_running = 0;
-static struct io_err_stat_pathvec *paths;
+static vector io_err_pathvec;
struct vectors *vecs;
io_context_t ioctx;
@@ -208,46 +204,23 @@ static void free_io_err_stat_path(struct io_err_stat_path *p)
FREE(p);
}
-static struct io_err_stat_pathvec *alloc_pathvec(void)
-{
- struct io_err_stat_pathvec *p;
- int r;
-
- p = (struct io_err_stat_pathvec *)MALLOC(sizeof(*p));
- if (!p)
- return NULL;
- p->pathvec = vector_alloc();
- if (!p->pathvec)
- goto out_free_struct_pathvec;
- r = pthread_mutex_init(&p->mutex, NULL);
- if (r)
- goto out_free_member_pathvec;
-
- return p;
-
-out_free_member_pathvec:
- vector_free(p->pathvec);
-out_free_struct_pathvec:
- FREE(p);
- return NULL;
-}
-
-static void free_io_err_pathvec(struct io_err_stat_pathvec *p)
+static void free_io_err_pathvec(void)
{
struct io_err_stat_path *path;
int i;
- if (!p)
- return;
- pthread_mutex_destroy(&p->mutex);
- if (!p->pathvec) {
- vector_foreach_slot(p->pathvec, path, i) {
- destroy_directio_ctx(path);
- free_io_err_stat_path(path);
- }
- vector_free(p->pathvec);
+ pthread_mutex_lock(&io_err_pathvec_lock);
+ pthread_cleanup_push(cleanup_mutex, &io_err_pathvec_lock);
+ if (!io_err_pathvec)
+ goto out;
+ vector_foreach_slot(io_err_pathvec, path, i) {
+ destroy_directio_ctx(path);
+ free_io_err_stat_path(path);
}
- FREE(p);
+ vector_free(io_err_pathvec);
+ io_err_pathvec = NULL;
+out:
+ pthread_cleanup_pop(1);
}
/*
@@ -259,13 +232,13 @@ static int enqueue_io_err_stat_by_path(struct path *path)
{
struct io_err_stat_path *p;
- pthread_mutex_lock(&paths->mutex);
- p = find_err_path_by_dev(paths->pathvec, path->dev);
+ pthread_mutex_lock(&io_err_pathvec_lock);
+ p = find_err_path_by_dev(io_err_pathvec, path->dev);
if (p) {
- pthread_mutex_unlock(&paths->mutex);
+ pthread_mutex_unlock(&io_err_pathvec_lock);
return 0;
}
- pthread_mutex_unlock(&paths->mutex);
+ pthread_mutex_unlock(&io_err_pathvec_lock);
p = alloc_io_err_stat_path();
if (!p)
@@ -277,18 +250,18 @@ static int enqueue_io_err_stat_by_path(struct path *path)
if (setup_directio_ctx(p))
goto free_ioerr_path;
- pthread_mutex_lock(&paths->mutex);
- if (!vector_alloc_slot(paths->pathvec))
+ pthread_mutex_lock(&io_err_pathvec_lock);
+ if (!vector_alloc_slot(io_err_pathvec))
goto unlock_destroy;
- vector_set_slot(paths->pathvec, p);
- pthread_mutex_unlock(&paths->mutex);
+ vector_set_slot(io_err_pathvec, p);
+ pthread_mutex_unlock(&io_err_pathvec_lock);
io_err_stat_log(2, "%s: enqueue path %s to check",
path->mpp->alias, path->dev);
return 0;
unlock_destroy:
- pthread_mutex_unlock(&paths->mutex);
+ pthread_mutex_unlock(&io_err_pathvec_lock);
destroy_directio_ctx(p);
free_ioerr_path:
free_io_err_stat_path(p);
@@ -421,9 +394,9 @@ static int delete_io_err_stat_by_addr(struct io_err_stat_path *p)
{
int i;
- i = find_slot(paths->pathvec, p);
+ i = find_slot(io_err_pathvec, p);
if (i != -1)
- vector_del_slot(paths->pathvec, i);
+ vector_del_slot(io_err_pathvec, i);
destroy_directio_ctx(p);
free_io_err_stat_path(p);
@@ -594,7 +567,7 @@ static void poll_async_io_timeout(void)
if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0)
return;
- vector_foreach_slot(paths->pathvec, pp, i) {
+ vector_foreach_slot(io_err_pathvec, pp, i) {
for (j = 0; j < CONCUR_NR_EVENT; j++) {
rc = try_to_cancel_timeout_io(pp->dio_ctx_array + j,
&curr_time, pp->devname);
@@ -640,7 +613,7 @@ static void handle_async_io_done_event(struct io_event *io_evt)
int rc = PATH_UNCHECKED;
int i, j;
- vector_foreach_slot(paths->pathvec, pp, i) {
+ vector_foreach_slot(io_err_pathvec, pp, i) {
for (j = 0; j < CONCUR_NR_EVENT; j++) {
ct = pp->dio_ctx_array + j;
if (&ct->io == io_evt->obj) {
@@ -674,19 +647,14 @@ static void service_paths(void)
struct io_err_stat_path *pp;
int i;
- pthread_mutex_lock(&paths->mutex);
- vector_foreach_slot(paths->pathvec, pp, i) {
+ pthread_mutex_lock(&io_err_pathvec_lock);
+ vector_foreach_slot(io_err_pathvec, pp, i) {
send_batch_async_ios(pp);
process_async_ios_event(TIMEOUT_NO_IO_NSEC, pp->devname);
poll_async_io_timeout();
poll_io_err_stat(vecs, pp);
}
- pthread_mutex_unlock(&paths->mutex);
-}
-
-static void cleanup_unlock(void *arg)
-{
- pthread_mutex_unlock((pthread_mutex_t*) arg);
+ pthread_mutex_unlock(&io_err_pathvec_lock);
}
static void cleanup_exited(__attribute__((unused)) void *arg)
@@ -744,12 +712,17 @@ int start_io_err_stat_thread(void *data)
io_err_stat_log(4, "io_setup failed");
return 1;
}
- paths = alloc_pathvec();
- if (!paths)
+
+ pthread_mutex_lock(&io_err_pathvec_lock);
+ io_err_pathvec = vector_alloc();
+ if (!io_err_pathvec) {
+ pthread_mutex_unlock(&io_err_pathvec_lock);
goto destroy_ctx;
+ }
+ pthread_mutex_unlock(&io_err_pathvec_lock);
pthread_mutex_lock(&io_err_thread_lock);
- pthread_cleanup_push(cleanup_unlock, &io_err_thread_lock);
+ pthread_cleanup_push(cleanup_mutex, &io_err_thread_lock);
ret = pthread_create(&io_err_stat_thr, &io_err_stat_attr,
io_err_stat_loop, data);
@@ -769,7 +742,10 @@ int start_io_err_stat_thread(void *data)
return 0;
out_free:
- free_io_err_pathvec(paths);
+ pthread_mutex_lock(&io_err_pathvec_lock);
+ vector_free(io_err_pathvec);
+ io_err_pathvec = NULL;
+ pthread_mutex_unlock(&io_err_pathvec_lock);
destroy_ctx:
io_destroy(ioctx);
io_err_stat_log(0, "failed to start io_error statistic thread");
@@ -785,6 +761,6 @@ void stop_io_err_stat_thread(void)
pthread_cancel(io_err_stat_thr);
pthread_join(io_err_stat_thr, NULL);
- free_io_err_pathvec(paths);
+ free_io_err_pathvec();
io_destroy(ioctx);
}
diff --git a/libmultipath/util.c b/libmultipath/util.c
index 51c38c87..dd30a46e 100644
--- a/libmultipath/util.c
+++ b/libmultipath/util.c
@@ -469,3 +469,8 @@ void close_fd(void *arg)
{
close((long)arg);
}
+
+void cleanup_mutex(void *arg)
+{
+ pthread_mutex_unlock(arg);
+}
diff --git a/libmultipath/util.h b/libmultipath/util.h
index 56bd78c7..ce277680 100644
--- a/libmultipath/util.h
+++ b/libmultipath/util.h
@@ -44,6 +44,7 @@ void set_max_fds(rlim_t max_fds);
pthread_cleanup_push(((void (*)(void *))&f), (arg))
void close_fd(void *arg);
+void cleanup_mutex(void *arg);
struct scandir_result {
struct dirent **di;
--
2.17.2

View File

@ -0,0 +1,146 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 14 Jan 2021 20:20:24 -0600
Subject: [PATCH] multipathd: avoid io_err_stat ABBA deadlock
When the checker thread enqueues paths for the io_err_stat thread to
check, it calls enqueue_io_err_stat_by_path() with the vecs lock held.
start_io_err_stat_thread() is also called with the vecs lock held.
These two functions both lock io_err_pathvec_lock. When the io_err_stat
thread updates the paths in vecs->pathvec in poll_io_err_stat(), it has
the io_err_pathvec_lock held, and then locks the vecs lock. This can
cause an ABBA deadlock.
To solve this, service_paths() no longer updates the paths in
vecs->pathvec with the io_err_pathvec_lock held. It does this by moving
the io_err_stat_path from io_err_pathvec to a local vector when it needs
to update the path. After releasing the io_err_pathvec_lock, it goes
through this temporary vector, updates the paths with the vecs lock
held, and then frees everything.
This change fixes a bug in service_paths() where elements were being
deleted from io_err_pathvec, without the index being decremented,
causing the loop to skip elements. Also, service_paths() could be
cancelled while holding the io_err_pathvec_lock, so it should have a
cleanup handler.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/io_err_stat.c | 56 ++++++++++++++++++++++----------------
1 file changed, 32 insertions(+), 24 deletions(-)
diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c
index f6c564f0..63ee2e07 100644
--- a/libmultipath/io_err_stat.c
+++ b/libmultipath/io_err_stat.c
@@ -390,20 +390,6 @@ recover:
return 0;
}
-static int delete_io_err_stat_by_addr(struct io_err_stat_path *p)
-{
- int i;
-
- i = find_slot(io_err_pathvec, p);
- if (i != -1)
- vector_del_slot(io_err_pathvec, i);
-
- destroy_directio_ctx(p);
- free_io_err_stat_path(p);
-
- return 0;
-}
-
static void account_async_io_state(struct io_err_stat_path *pp, int rc)
{
switch (rc) {
@@ -420,17 +406,26 @@ static void account_async_io_state(struct io_err_stat_path *pp, int rc)
}
}
-static int poll_io_err_stat(struct vectors *vecs, struct io_err_stat_path *pp)
+static int io_err_stat_time_up(struct io_err_stat_path *pp)
{
struct timespec currtime, difftime;
- struct path *path;
- double err_rate;
if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0)
- return 1;
+ return 0;
timespecsub(&currtime, &pp->start_time, &difftime);
if (difftime.tv_sec < pp->total_time)
return 0;
+ return 1;
+}
+
+static void end_io_err_stat(struct io_err_stat_path *pp)
+{
+ struct timespec currtime;
+ struct path *path;
+ double err_rate;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0)
+ currtime = pp->start_time;
io_err_stat_log(4, "%s: check end", pp->devname);
@@ -469,10 +464,6 @@ static int poll_io_err_stat(struct vectors *vecs, struct io_err_stat_path *pp)
pp->devname);
}
lock_cleanup_pop(vecs->lock);
-
- delete_io_err_stat_by_addr(pp);
-
- return 0;
}
static int send_each_async_io(struct dio_ctx *ct, int fd, char *dev)
@@ -632,6 +623,7 @@ static void process_async_ios_event(int timeout_nsecs, char *dev)
struct timespec timeout = { .tv_nsec = timeout_nsecs };
errno = 0;
+ pthread_testcancel();
n = io_getevents(ioctx, 1L, CONCUR_NR_EVENT, events, &timeout);
if (n < 0) {
io_err_stat_log(3, "%s: async io events returned %d (errno=%s)",
@@ -644,17 +636,33 @@ static void process_async_ios_event(int timeout_nsecs, char *dev)
static void service_paths(void)
{
+ struct _vector _pathvec = {0};
+ /* avoid gcc warnings that &_pathvec will never be NULL in vector ops */
+ struct _vector * const tmp_pathvec = &_pathvec;
struct io_err_stat_path *pp;
int i;
pthread_mutex_lock(&io_err_pathvec_lock);
+ pthread_cleanup_push(cleanup_mutex, &io_err_pathvec_lock);
vector_foreach_slot(io_err_pathvec, pp, i) {
send_batch_async_ios(pp);
process_async_ios_event(TIMEOUT_NO_IO_NSEC, pp->devname);
poll_async_io_timeout();
- poll_io_err_stat(vecs, pp);
+ if (io_err_stat_time_up(pp)) {
+ if (!vector_alloc_slot(tmp_pathvec))
+ continue;
+ vector_del_slot(io_err_pathvec, i--);
+ vector_set_slot(tmp_pathvec, pp);
+ }
}
- pthread_mutex_unlock(&io_err_pathvec_lock);
+ pthread_cleanup_pop(1);
+ vector_foreach_slot_backwards(tmp_pathvec, pp, i) {
+ end_io_err_stat(pp);
+ vector_del_slot(tmp_pathvec, i);
+ destroy_directio_ctx(pp);
+ free_io_err_stat_path(pp);
+ }
+ vector_reset(tmp_pathvec);
}
static void cleanup_exited(__attribute__((unused)) void *arg)
--
2.17.2

View File

@ -0,0 +1,111 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 14 Jan 2021 20:20:25 -0600
Subject: [PATCH] multipathd: use get_monotonic_time() in io_err_stat code
Instead of calling clock_gettime(), and dealing with failure
conditions, just call get_monotonic_time().
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/io_err_stat.c | 34 +++++++++++-----------------------
1 file changed, 11 insertions(+), 23 deletions(-)
diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c
index 63ee2e07..3389d693 100644
--- a/libmultipath/io_err_stat.c
+++ b/libmultipath/io_err_stat.c
@@ -305,8 +305,7 @@ int io_err_stat_handle_pathfail(struct path *path)
* the repeated count threshold and time frame, we assume a path
* which fails at least twice within 60 seconds is flaky.
*/
- if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0)
- return 1;
+ get_monotonic_time(&curr_time);
if (path->io_err_pathfail_cnt == 0) {
path->io_err_pathfail_cnt++;
path->io_err_pathfail_starttime = curr_time.tv_sec;
@@ -362,9 +361,9 @@ int need_io_err_check(struct path *pp)
}
if (pp->io_err_pathfail_cnt != PATH_IO_ERR_WAITING_TO_CHECK)
return 1;
- if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0 ||
- (curr_time.tv_sec - pp->io_err_dis_reinstate_time) >
- pp->mpp->marginal_path_err_recheck_gap_time) {
+ get_monotonic_time(&curr_time);
+ if ((curr_time.tv_sec - pp->io_err_dis_reinstate_time) >
+ pp->mpp->marginal_path_err_recheck_gap_time) {
io_err_stat_log(4, "%s: reschedule checking after %d seconds",
pp->dev,
pp->mpp->marginal_path_err_recheck_gap_time);
@@ -410,8 +409,7 @@ static int io_err_stat_time_up(struct io_err_stat_path *pp)
{
struct timespec currtime, difftime;
- if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0)
- return 0;
+ get_monotonic_time(&currtime);
timespecsub(&currtime, &pp->start_time, &difftime);
if (difftime.tv_sec < pp->total_time)
return 0;
@@ -424,8 +422,7 @@ static void end_io_err_stat(struct io_err_stat_path *pp)
struct path *path;
double err_rate;
- if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0)
- currtime = pp->start_time;
+ get_monotonic_time(&currtime);
io_err_stat_log(4, "%s: check end", pp->devname);
@@ -474,11 +471,7 @@ static int send_each_async_io(struct dio_ctx *ct, int fd, char *dev)
ct->io_starttime.tv_sec == 0) {
struct iocb *ios[1] = { &ct->io };
- if (clock_gettime(CLOCK_MONOTONIC, &ct->io_starttime) != 0) {
- ct->io_starttime.tv_sec = 0;
- ct->io_starttime.tv_nsec = 0;
- return rc;
- }
+ get_monotonic_time(&ct->io_starttime);
io_prep_pread(&ct->io, fd, ct->buf, ct->blksize, 0);
if (io_submit(ioctx, 1, ios) != 1) {
io_err_stat_log(5, "%s: io_submit error %i",
@@ -497,8 +490,7 @@ static void send_batch_async_ios(struct io_err_stat_path *pp)
struct dio_ctx *ct;
struct timespec currtime, difftime;
- if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0)
- return;
+ get_monotonic_time(&currtime);
/*
* Give a free time for all IO to complete or timeout
*/
@@ -513,11 +505,8 @@ static void send_batch_async_ios(struct io_err_stat_path *pp)
if (!send_each_async_io(ct, pp->fd, pp->devname))
pp->io_nr++;
}
- if (pp->start_time.tv_sec == 0 && pp->start_time.tv_nsec == 0 &&
- clock_gettime(CLOCK_MONOTONIC, &pp->start_time)) {
- pp->start_time.tv_sec = 0;
- pp->start_time.tv_nsec = 0;
- }
+ if (pp->start_time.tv_sec == 0 && pp->start_time.tv_nsec == 0)
+ get_monotonic_time(&pp->start_time);
}
static int try_to_cancel_timeout_io(struct dio_ctx *ct, struct timespec *t,
@@ -556,8 +545,7 @@ static void poll_async_io_timeout(void)
int rc = PATH_UNCHECKED;
int i, j;
- if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0)
- return;
+ get_monotonic_time(&curr_time);
vector_foreach_slot(io_err_pathvec, pp, i) {
for (j = 0; j < CONCUR_NR_EVENT; j++) {
rc = try_to_cancel_timeout_io(pp->dio_ctx_array + j,
--
2.17.2

View File

@ -0,0 +1,101 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 14 Jan 2021 20:20:26 -0600
Subject: [PATCH] multipathd: combine free_io_err_stat_path and
destroy_directio_ctx
destroy_directio_ctx() is only called from free_io_err_stat_path(), and
free_io_err_stat_path() is very short, so combine them.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/io_err_stat.c | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c
index 3389d693..bf1d3910 100644
--- a/libmultipath/io_err_stat.c
+++ b/libmultipath/io_err_stat.c
@@ -163,12 +163,15 @@ fail_close:
return 1;
}
-static void destroy_directio_ctx(struct io_err_stat_path *p)
+static void free_io_err_stat_path(struct io_err_stat_path *p)
{
int i;
- if (!p || !p->dio_ctx_array)
+ if (!p)
return;
+ if (!p->dio_ctx_array)
+ goto free_path;
+
cancel_inflight_io(p);
for (i = 0; i < CONCUR_NR_EVENT; i++)
@@ -177,6 +180,8 @@ static void destroy_directio_ctx(struct io_err_stat_path *p)
if (p->fd > 0)
close(p->fd);
+free_path:
+ FREE(p);
}
static struct io_err_stat_path *alloc_io_err_stat_path(void)
@@ -199,11 +204,6 @@ static struct io_err_stat_path *alloc_io_err_stat_path(void)
return p;
}
-static void free_io_err_stat_path(struct io_err_stat_path *p)
-{
- FREE(p);
-}
-
static void free_io_err_pathvec(void)
{
struct io_err_stat_path *path;
@@ -213,10 +213,8 @@ static void free_io_err_pathvec(void)
pthread_cleanup_push(cleanup_mutex, &io_err_pathvec_lock);
if (!io_err_pathvec)
goto out;
- vector_foreach_slot(io_err_pathvec, path, i) {
- destroy_directio_ctx(path);
+ vector_foreach_slot(io_err_pathvec, path, i)
free_io_err_stat_path(path);
- }
vector_free(io_err_pathvec);
io_err_pathvec = NULL;
out:
@@ -252,7 +250,7 @@ static int enqueue_io_err_stat_by_path(struct path *path)
goto free_ioerr_path;
pthread_mutex_lock(&io_err_pathvec_lock);
if (!vector_alloc_slot(io_err_pathvec))
- goto unlock_destroy;
+ goto unlock_pathvec;
vector_set_slot(io_err_pathvec, p);
pthread_mutex_unlock(&io_err_pathvec_lock);
@@ -260,9 +258,8 @@ static int enqueue_io_err_stat_by_path(struct path *path)
path->mpp->alias, path->dev);
return 0;
-unlock_destroy:
+unlock_pathvec:
pthread_mutex_unlock(&io_err_pathvec_lock);
- destroy_directio_ctx(p);
free_ioerr_path:
free_io_err_stat_path(p);
@@ -647,7 +644,6 @@ static void service_paths(void)
vector_foreach_slot_backwards(tmp_pathvec, pp, i) {
end_io_err_stat(pp);
vector_del_slot(tmp_pathvec, i);
- destroy_directio_ctx(pp);
free_io_err_stat_path(pp);
}
vector_reset(tmp_pathvec);
--
2.17.2

View File

@ -0,0 +1,110 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 18 Jan 2021 22:46:04 -0600
Subject: [PATCH] multipathd: cleanup logging for marginal paths
io_err_stat logged at level 2 whenever it enqueued a path to check,
which could happen multiple times while a path was marginal. On the
other hand if marginal_pathgroups wasn't set, multipathd didn't log when
paths were set to marginal. Now io_err_stat only logs at level 2 when
something unexpected happens, but multipathd will always log when a
path switches its marginal state.
This patch also fixes an issue where paths in the delayed state could
get set to the pending state if they could not be checked in time.
Aside from going against the idea the paths should not be set to pending
if they already have a valid state, this caused multipathd to log a
message whenever the path state switched to from delayed to pending and
then back.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/io_err_stat.c | 7 +++----
multipathd/main.c | 20 +++++++++++++-------
2 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c
index bf1d3910..ee711f7f 100644
--- a/libmultipath/io_err_stat.c
+++ b/libmultipath/io_err_stat.c
@@ -254,7 +254,7 @@ static int enqueue_io_err_stat_by_path(struct path *path)
vector_set_slot(io_err_pathvec, p);
pthread_mutex_unlock(&io_err_pathvec_lock);
- io_err_stat_log(2, "%s: enqueue path %s to check",
+ io_err_stat_log(3, "%s: enqueue path %s to check",
path->mpp->alias, path->dev);
return 0;
@@ -353,7 +353,7 @@ int need_io_err_check(struct path *pp)
if (uatomic_read(&io_err_thread_running) == 0)
return 0;
if (count_active_paths(pp->mpp) <= 0) {
- io_err_stat_log(2, "%s: recover path early", pp->dev);
+ io_err_stat_log(2, "%s: no paths. recovering early", pp->dev);
goto recover;
}
if (pp->io_err_pathfail_cnt != PATH_IO_ERR_WAITING_TO_CHECK)
@@ -371,8 +371,7 @@ int need_io_err_check(struct path *pp)
* Or else, return 1 to set path state to PATH_SHAKY
*/
if (r == 1) {
- io_err_stat_log(3, "%s: enqueue fails, to recover",
- pp->dev);
+ io_err_stat_log(2, "%s: enqueue failed. recovering early", pp->dev);
goto recover;
} else
pp->io_err_pathfail_cnt = PATH_IO_ERR_IN_CHECKING;
diff --git a/multipathd/main.c b/multipathd/main.c
index 1d0579e9..cc1aeea2 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -2041,8 +2041,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
pathinfo(pp, conf, 0);
pthread_cleanup_pop(1);
return 1;
- } else if ((newstate != PATH_UP && newstate != PATH_GHOST) &&
- (pp->state == PATH_DELAYED)) {
+ } else if ((newstate != PATH_UP && newstate != PATH_GHOST &&
+ newstate != PATH_PENDING) && (pp->state == PATH_DELAYED)) {
/* If path state become failed again cancel path delay state */
pp->state = newstate;
return 1;
@@ -2104,8 +2104,9 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
if ((newstate == PATH_UP || newstate == PATH_GHOST) &&
(san_path_check_enabled(pp->mpp) ||
marginal_path_check_enabled(pp->mpp))) {
- int was_marginal = pp->marginal;
if (should_skip_path(pp)) {
+ if (!pp->marginal && pp->state != PATH_DELAYED)
+ condlog(2, "%s: path is now marginal", pp->dev);
if (!marginal_pathgroups) {
if (marginal_path_check_enabled(pp->mpp))
/* to reschedule as soon as possible,
@@ -2115,13 +2116,18 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
pp->state = PATH_DELAYED;
return 1;
}
- if (!was_marginal) {
+ if (!pp->marginal) {
pp->marginal = 1;
marginal_changed = 1;
}
- } else if (marginal_pathgroups && was_marginal) {
- pp->marginal = 0;
- marginal_changed = 1;
+ } else {
+ if (pp->marginal || pp->state == PATH_DELAYED)
+ condlog(2, "%s: path is no longer marginal",
+ pp->dev);
+ if (marginal_pathgroups && pp->marginal) {
+ pp->marginal = 0;
+ marginal_changed = 1;
+ }
}
}
--
2.17.2

View File

@ -0,0 +1,277 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 25 Jan 2021 23:31:04 -0600
Subject: [PATCH] libmpathpersist: fix thread safety of default functions
commit a839e39e ("libmpathpersist: factor out initialization and
teardown") made mpath_presistent_reserve_{in,out} use share variables
for curmp and pathvec. There are users of this library that call these
functions in a multi-threaded process, and this change causes their
application to crash. config and udev are also shared variables, but
libmpathpersist doesn't write to the config in
mpath_presistent_reserve_{in,out}, and looking into the libudev code, I
don't see any place where libmpathpersist uses the udev object in a way
that isn't thread-safe.
This patch makes mpath_presistent_reserve_{in,out} go back to using
local variables for curmp and pathvec, so that multiple threads won't
be operating on these variables at the same time.
Fixes: a839e39e ("libmpathpersist: factor out initialization and teardown")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmpathpersist/mpath_persist.c | 116 +++++++++++++++++++++-----------
libmpathpersist/mpath_persist.h | 24 +++++--
2 files changed, 94 insertions(+), 46 deletions(-)
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index a01dfb0b..07a5f17f 100644
--- a/libmpathpersist/mpath_persist.c
+++ b/libmpathpersist/mpath_persist.c
@@ -147,72 +147,60 @@ mpath_prin_activepath (struct multipath *mpp, int rq_servact,
return ret;
}
-int mpath_persistent_reserve_in (int fd, int rq_servact,
- struct prin_resp *resp, int noisy, int verbose)
-{
- int ret = mpath_persistent_reserve_init_vecs(verbose);
-
- if (ret != MPATH_PR_SUCCESS)
- return ret;
- ret = __mpath_persistent_reserve_in(fd, rq_servact, resp, noisy);
- mpath_persistent_reserve_free_vecs();
- return ret;
-}
-
-int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
- unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose)
-{
- int ret = mpath_persistent_reserve_init_vecs(verbose);
-
- if (ret != MPATH_PR_SUCCESS)
- return ret;
- ret = __mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type,
- paramp, noisy);
- mpath_persistent_reserve_free_vecs();
- return ret;
-}
-
static vector curmp;
static vector pathvec;
-void mpath_persistent_reserve_free_vecs(void)
+static void __mpath_persistent_reserve_free_vecs(vector curmp, vector pathvec)
{
free_multipathvec(curmp, KEEP_PATHS);
free_pathvec(pathvec, FREE_PATHS);
+}
+
+void mpath_persistent_reserve_free_vecs(void)
+{
+ __mpath_persistent_reserve_free_vecs(curmp, pathvec);
curmp = pathvec = NULL;
}
-int mpath_persistent_reserve_init_vecs(int verbose)
+static int __mpath_persistent_reserve_init_vecs(vector *curmp_p,
+ vector *pathvec_p, int verbose)
{
struct config *conf = get_multipath_config();
conf->verbosity = verbose;
put_multipath_config(conf);
- if (curmp)
+ if (*curmp_p)
return MPATH_PR_SUCCESS;
/*
* allocate core vectors to store paths and multipaths
*/
- curmp = vector_alloc ();
- pathvec = vector_alloc ();
+ *curmp_p = vector_alloc ();
+ *pathvec_p = vector_alloc ();
- if (!curmp || !pathvec){
+ if (!*curmp_p || !*pathvec_p){
condlog (0, "vector allocation failed.");
goto err;
}
- if (dm_get_maps(curmp))
+ if (dm_get_maps(*curmp_p))
goto err;
return MPATH_PR_SUCCESS;
err:
- mpath_persistent_reserve_free_vecs();
+ __mpath_persistent_reserve_free_vecs(*curmp_p, *pathvec_p);
+ *curmp_p = *pathvec_p = NULL;
return MPATH_PR_DMMP_ERROR;
}
-static int mpath_get_map(int fd, char **palias, struct multipath **pmpp)
+int mpath_persistent_reserve_init_vecs(int verbose)
+{
+ return __mpath_persistent_reserve_init_vecs(&curmp, &pathvec, verbose);
+}
+
+static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
+ struct multipath **pmpp)
{
int ret = MPATH_PR_DMMP_ERROR;
struct stat info;
@@ -272,13 +260,13 @@ out:
return ret;
}
-int __mpath_persistent_reserve_in (int fd, int rq_servact,
- struct prin_resp *resp, int noisy)
+static int do_mpath_persistent_reserve_in (vector curmp, vector pathvec,
+ int fd, int rq_servact, struct prin_resp *resp, int noisy)
{
struct multipath *mpp;
int ret;
- ret = mpath_get_map(fd, NULL, &mpp);
+ ret = mpath_get_map(curmp, pathvec, fd, NULL, &mpp);
if (ret != MPATH_PR_SUCCESS)
return ret;
@@ -287,8 +275,17 @@ int __mpath_persistent_reserve_in (int fd, int rq_servact,
return ret;
}
-int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
- unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy)
+
+int __mpath_persistent_reserve_in (int fd, int rq_servact,
+ struct prin_resp *resp, int noisy)
+{
+ return do_mpath_persistent_reserve_in(curmp, pathvec, fd, rq_servact,
+ resp, noisy);
+}
+
+static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
+ int rq_servact, int rq_scope, unsigned int rq_type,
+ struct prout_param_descriptor *paramp, int noisy)
{
struct multipath *mpp;
char *alias;
@@ -296,7 +293,7 @@ int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
uint64_t prkey;
struct config *conf;
- ret = mpath_get_map(fd, &alias, &mpp);
+ ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
if (ret != MPATH_PR_SUCCESS)
return ret;
@@ -366,6 +363,45 @@ out1:
return ret;
}
+
+int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
+ unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy)
+{
+ return do_mpath_persistent_reserve_out(curmp, pathvec, fd, rq_servact,
+ rq_scope, rq_type, paramp,
+ noisy);
+}
+
+int mpath_persistent_reserve_in (int fd, int rq_servact,
+ struct prin_resp *resp, int noisy, int verbose)
+{
+ vector curmp = NULL, pathvec;
+ int ret = __mpath_persistent_reserve_init_vecs(&curmp, &pathvec,
+ verbose);
+
+ if (ret != MPATH_PR_SUCCESS)
+ return ret;
+ ret = do_mpath_persistent_reserve_in(curmp, pathvec, fd, rq_servact,
+ resp, noisy);
+ __mpath_persistent_reserve_free_vecs(curmp, pathvec);
+ return ret;
+}
+
+int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
+ unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose)
+{
+ vector curmp = NULL, pathvec;
+ int ret = __mpath_persistent_reserve_init_vecs(&curmp, &pathvec,
+ verbose);
+
+ if (ret != MPATH_PR_SUCCESS)
+ return ret;
+ ret = do_mpath_persistent_reserve_out(curmp, pathvec, fd, rq_servact,
+ rq_scope, rq_type, paramp, noisy);
+ __mpath_persistent_reserve_free_vecs(curmp, pathvec);
+ return ret;
+}
+
int
get_mpvec (vector curmp, vector pathvec, char * refwwid)
{
diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h
index 7cf4faf9..0e4e0e53 100644
--- a/libmpathpersist/mpath_persist.h
+++ b/libmpathpersist/mpath_persist.h
@@ -215,9 +215,13 @@ extern int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp
/*
* DESCRIPTION :
- * This function is like mpath_persistent_reserve_in(), except that it doesn't call
- * mpath_persistent_reserve_init_vecs() and mpath_persistent_reserve_free_vecs()
- * before and after the actual PR call.
+ * This function is like mpath_persistent_reserve_in(), except that it
+ * requires mpath_persistent_reserve_init_vecs() to be called before the
+ * PR call to set up internal variables. These must later be cleanup up
+ * by calling mpath_persistent_reserve_free_vecs().
+ *
+ * RESTRICTIONS:
+ * This function uses static internal variables, and is not thread-safe.
*/
extern int __mpath_persistent_reserve_in(int fd, int rq_servact,
struct prin_resp *resp, int noisy);
@@ -249,9 +253,13 @@ extern int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
int verbose);
/*
* DESCRIPTION :
- * This function is like mpath_persistent_reserve_out(), except that it doesn't call
- * mpath_persistent_reserve_init_vecs() and mpath_persistent_reserve_free_vecs()
- * before and after the actual PR call.
+ * This function is like mpath_persistent_reserve_out(), except that it
+ * requires mpath_persistent_reserve_init_vecs() to be called before the
+ * PR call to set up internal variables. These must later be cleanup up
+ * by calling mpath_persistent_reserve_free_vecs().
+ *
+ * RESTRICTIONS:
+ * This function uses static internal variables, and is not thread-safe.
*/
extern int __mpath_persistent_reserve_out( int fd, int rq_servact, int rq_scope,
unsigned int rq_type, struct prout_param_descriptor *paramp,
@@ -265,6 +273,7 @@ extern int __mpath_persistent_reserve_out( int fd, int rq_servact, int rq_scope,
* @verbose: Set verbosity level. Input argument. value:0 to 3. 0->disabled, 3->Max verbose
*
* RESTRICTIONS:
+ * This function uses static internal variables, and is not thread-safe.
*
* RETURNS: MPATH_PR_SUCCESS if successful else returns any of the status specified
* above in RETURN_STATUS.
@@ -275,6 +284,9 @@ int mpath_persistent_reserve_init_vecs(int verbose);
* DESCRIPTION :
* This function frees data structures allocated by
* mpath_persistent_reserve_init_vecs().
+ *
+ * RESTRICTIONS:
+ * This function uses static internal variables, and is not thread-safe.
*/
void mpath_persistent_reserve_free_vecs(void);
--
2.17.2

View File

@ -0,0 +1,61 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 9 Feb 2021 17:16:04 -0600
Subject: [PATCH] kpartx: free loop device after listing partitions
If "kpartx -l" is run on a file that doesn't already have a loop device
associated with it, it will create a loop device to run the command.
Starting with da59d15c6 ("Fix loopback file with kpartx -av"), it will
not free the loop device when exitting. This is because it checks if the
the file it stat()ed is a regular file, before freeing the loop device.
However, after da59d15c6, stat() is rerun on the loop device itself, so
the check fails. There is no need to check this, if loopcreated is
true, then the file will be a kpartx created loop device, and should be
freed.
Also, keep kpartx from printing that the loop device has been removed
at normal verbosity.
Fixes: da59d15c6 ("Fix loopback file with kpartx -av")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
kpartx/kpartx.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
index 653ce0c8..a337a07b 100644
--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -407,7 +407,7 @@ main(int argc, char **argv){
fprintf(stderr, "can't del loop : %s\n",
loopdev);
r = 1;
- } else
+ } else if (verbose)
fprintf(stderr, "loop deleted : %s\n", loopdev);
}
goto end;
@@ -649,16 +649,17 @@ main(int argc, char **argv){
if (n > 0)
break;
}
- if (what == LIST && loopcreated && S_ISREG (buf.st_mode)) {
+ if (what == LIST && loopcreated) {
if (fd != -1)
close(fd);
if (del_loop(device)) {
if (verbose)
- printf("can't del loop : %s\n",
+ fprintf(stderr, "can't del loop : %s\n",
device);
exit(1);
}
- printf("loop deleted : %s\n", device);
+ if (verbose)
+ fprintf(stderr, "loop deleted : %s\n", device);
}
end:
--
2.17.2

View File

@ -0,0 +1,134 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 10 Feb 2021 15:42:42 -0600
Subject: [PATCH] RH: fix find_multipaths in mpathconf
mpathconf wasn't correctly dealing with the new rhel-8 values for
find_multipaths
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/mpathconf | 38 +++++++++++++++++++-------------------
multipath/mpathconf.8 | 14 +++++++-------
2 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/multipath/mpathconf b/multipath/mpathconf
index f34003c9..2f4f3eaf 100644
--- a/multipath/mpathconf
+++ b/multipath/mpathconf
@@ -54,7 +54,7 @@ function usage
echo "Disable: --disable"
echo "Only allow certain wwids (instead of enable): --allow <WWID>"
echo "Set user_friendly_names (Default y): --user_friendly_names <y|n>"
- echo "Set find_multipaths (Default y): --find_multipaths <y|n>"
+ echo "Set find_multipaths (Default y): --find_multipaths <yes|no|strict|greedy|smart>"
echo "Set default property blacklist (Default y): --property_blacklist <y|n>"
echo "Set enable_foreign to show foreign devices (Default n): --enable_foreign <y|n>"
echo "Load the dm-multipath modules on enable (Default y): --with_module <y|n>"
@@ -224,8 +224,12 @@ function validate_args
echo "--user_friendly_names must be either 'y' or 'n'"
exit 1
fi
- if [ -n "$FIND" ] && [ "$FIND" != "y" -a "$FIND" != "n" ]; then
- echo "--find_multipaths must be either 'y' or 'n'"
+ if [ "$FIND" = "y" ]; then
+ FIND="yes"
+ elif [ "$FIND" = "n" ]; then
+ FIND="no"
+ elif [ -n "$FIND" ] && [ "$FIND" != "yes" -a "$FIND" != "no" -a "$FIND" != "strict" -a "$FIND" != "greedy" -a "$FIND" != "smart" ]; then
+ echo "--find_multipaths must be one of 'yes' 'no' 'strict' 'greedy' or 'smart'"
exit 1
fi
if [ -n "$PROPERTY" ] && [ "$PROPERTY" != "y" -a "$PROPERTY" != "n" ]; then
@@ -327,10 +331,11 @@ if [ "$HAVE_BLACKLIST" = "1" ]; then
fi
if [ "$HAVE_DEFAULTS" = "1" ]; then
- if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*find_multipaths[[:space:]]*\(yes\|1\)" ; then
- HAVE_FIND=1
- elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*find_multipaths[[:space:]]*\(no\|0\)" ; then
- HAVE_FIND=0
+ HAVE_FIND=`sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | sed -n 's/^[[:blank:]]*find_multipaths[[:blank:]]*\([^[:blank:]]*\).*$/\1/p' | sed -n 1p`
+ if [ "$HAVE_FIND" = "1" ]; then
+ HAVE_FIND="yes"
+ elif [ "$HAVE_FIND" = "0" ]; then
+ HAVE_FIND="no"
fi
if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]]*\(yes\|1\)" ; then
HAVE_FRIENDLY=1
@@ -360,10 +365,10 @@ if [ -n "$SHOW_STATUS" ]; then
else
echo "multipath is disabled"
fi
- if [ -z "$HAVE_FIND" -o "$HAVE_FIND" = 0 ]; then
- echo "find_multipaths is disabled"
+ if [ -z "$HAVE_FIND" ]; then
+ echo "find_multipaths is no"
else
- echo "find_multipaths is enabled"
+ echo "find_multipaths is $HAVE_FIND"
fi
if [ -z "$HAVE_FRIENDLY" -o "$HAVE_FRIENDLY" = 0 ]; then
echo "user_friendly_names is disabled"
@@ -455,19 +460,14 @@ elif [ "$ENABLE" = 0 ]; then
fi
fi
-if [ "$FIND" = "n" ]; then
- if [ "$HAVE_FIND" = 1 ]; then
- sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*find_multipaths[[:space:]]*\(yes\|1\)/ find_multipaths no/' $TMPFILE
- CHANGED_CONFIG=1
- fi
-elif [ "$FIND" = "y" ]; then
+if [ -n "$FIND" ]; then
if [ -z "$HAVE_FIND" ]; then
sed -i '/^defaults[[:space:]]*{/ a\
- find_multipaths yes
+ find_multipaths '"$FIND"'
' $TMPFILE
CHANGED_CONFIG=1
- elif [ "$HAVE_FIND" = 0 ]; then
- sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*find_multipaths[[:space:]]*\(no\|0\)/ find_multipaths yes/' $TMPFILE
+ elif [ "$FIND" != "$HAVE_FIND" ]; then
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:blank:]]*find_multipaths[[:blank:]]*[^[:blank:]]*/ find_multipaths '"$FIND"'/' $TMPFILE
CHANGED_CONFIG=1
fi
fi
diff --git a/multipath/mpathconf.8 b/multipath/mpathconf.8
index b82961d6..83515eb4 100644
--- a/multipath/mpathconf.8
+++ b/multipath/mpathconf.8
@@ -38,9 +38,9 @@ If
already exists, mpathconf will edit it. If it does not exist, mpathconf will
create a default file with
.B user_friendly_names
-and
+set and
.B find_multipaths
-set. To disable these, use the
+set to \fByes\fP. To disable these, use the
.B --user_friendly_names n
and
.B --find_multipaths n
@@ -77,13 +77,13 @@ to the
defaults section. If set to \fBn\fP, this removes the line, if present. This
command can be used along with any other command.
.TP
-.B --find_multipaths\fP { \fBy\fP | \fBn\fP }
-If set to \fBy\fP, this adds the line
-.B find_multipaths yes
+.B --find_multipaths\fP { \fByes\fP | \fBno\fP | \fBstrict\fP | \fBgreedy\fP | \fBsmart\fP }
+If set to \fB<value>\fP, this adds the line
+.B find_multipaths <value>
to the
.B /etc/multipath.conf
-defaults section. If set to \fBn\fP, this removes the line, if present. This
-command can be used along with any other command.
+defaults section. This command can be used along with any other command.
+\fBy\fP and \fBn\fP can be used instead of \fByes\fP and \fBno\fP.
.TP
.B --property_blacklist \fP { \fBy\fP | \fBn\fP }
If set to \fBy\fP, this adds the line
--
2.17.2

View File

@ -0,0 +1,45 @@
From 7a7b96246b84ccf533a6f4dc0424830792fdb96a Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Fri, 3 Jul 2020 15:17:09 +0200
Subject: [PATCH] libmultipath: select_action(): don't drop map if alias
clashes
If for a given map, if we find that the requested alias is already
used by a map with different WWID, while the map's own WWID is
not used yet, give up the alias and use the WWID instead. This
is safer than trying to destroy the existing map, which is likely
to fail.
This allows us to make use const for the "curmp" parameter.
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/configure.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index b7113291..2e8f34f9 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -690,12 +690,13 @@ select_action (struct multipath * mpp, vector curmp, int force_reload)
}
if (!cmpp) {
- condlog(2, "%s: remove (wwid changed)", mpp->alias);
- dm_flush_map(mpp->alias);
- strlcpy(cmpp_by_name->wwid, mpp->wwid, WWID_SIZE);
- drop_multipath(curmp, cmpp_by_name->wwid, KEEP_PATHS);
+ condlog(1, "%s: can't use alias \"%s\" used by %s, falling back to WWID",
+ mpp->wwid, mpp->alias, cmpp_by_name->wwid);
+ /* We can do this because wwid wasn't found */
+ free(mpp->alias);
+ mpp->alias = strdup(mpp->wwid);
mpp->action = ACT_CREATE;
- condlog(3, "%s: set ACT_CREATE (map wwid change)",
+ condlog(3, "%s: set ACT_CREATE (map does not exist, name changed)",
mpp->alias);
return;
}
--
2.17.2

View File

@ -0,0 +1,231 @@
From e714eb26fddc8768a8de279d1de3ffedab35929e Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 5 Mar 2021 21:40:57 -0600
Subject: [PATCH] libmultipath: check if user_friendly_name is in use
If there are multipath devices that have user_friendly_names but do not
have their bindings in the bindings_file, get_user_friendly_alias() can
currently give out those names again. This can result in an incorrect
entry in the bindings file, and a device that gets created with a WWID
alias instead of a user_friendly_name. This situation can happen after
the pivot root, if a multipath device is created in the initramfs. If
this device doesn't have a binding in the regular filesystem
bindings_file and a new multipath device is created before it can add
its binding, the new device can steal that user_friendly_name during
multipathd's initial configure.
To solve this, get_user_friendly_alias() now calls lookup_binding() with
a new paramter, telling it to check if the id it found is already in use
by a diffent device. If so, lookup_binding() will continue to check open
ids, until it finds one that it not currently in use by a dm device.
---
libmultipath/alias.c | 48 +++++++++++++++++++++++++++++++++++++++++---
tests/alias.c | 22 ++++++++++----------
2 files changed, 56 insertions(+), 14 deletions(-)
diff --git a/libmultipath/alias.c b/libmultipath/alias.c
index 14401cae..01f737f4 100644
--- a/libmultipath/alias.c
+++ b/libmultipath/alias.c
@@ -17,6 +17,7 @@
#include "vector.h"
#include "checkers.h"
#include "structs.h"
+#include "devmapper.h"
/*
@@ -104,6 +105,28 @@ scan_devname(const char *alias, const char *prefix)
return n;
}
+static int
+id_already_taken(int id, const char *prefix, const char *map_wwid)
+{
+ char alias[LINE_MAX];
+
+ if (format_devname(alias, id, LINE_MAX, prefix) < 0)
+ return 0;
+
+ if (dm_map_present(alias)) {
+ char wwid[WWID_SIZE];
+
+ /* If both the name and the wwid match, then it's fine.*/
+ if (dm_get_uuid(alias, wwid, sizeof(wwid)) == 0 &&
+ strncmp(map_wwid, wwid, sizeof(wwid)) == 0)
+ return 0;
+ condlog(3, "%s: alias '%s' already taken, but not in bindings file. reselecting alias", map_wwid, alias);
+ return 1;
+ }
+ return 0;
+}
+
+
/*
* Returns: 0 if matching entry in WWIDs file found
* -1 if an error occurs
@@ -113,7 +136,7 @@ scan_devname(const char *alias, const char *prefix)
*/
static int
lookup_binding(FILE *f, const char *map_wwid, char **map_alias,
- const char *prefix)
+ const char *prefix, int check_if_taken)
{
char buf[LINE_MAX];
unsigned int line_nr = 0;
@@ -168,12 +191,31 @@ lookup_binding(FILE *f, const char *map_wwid, char **map_alias,
return 0;
}
}
+ if (!prefix && check_if_taken)
+ id = -1;
if (id >= smallest_bigger_id) {
if (biggest_id < INT_MAX)
id = biggest_id + 1;
else
id = -1;
}
+ if (id > 0 && check_if_taken) {
+ while(id_already_taken(id, prefix, map_wwid)) {
+ if (id == INT_MAX) {
+ id = -1;
+ break;
+ }
+ id++;
+ if (id == smallest_bigger_id) {
+ if (biggest_id == INT_MAX) {
+ id = -1;
+ break;
+ }
+ if (biggest_id >= smallest_bigger_id)
+ id = biggest_id + 1;
+ }
+ }
+ }
if (id < 0) {
condlog(0, "no more available user_friendly_names");
return -1;
@@ -316,7 +358,7 @@ use_existing_alias (const char *wwid, const char *file, const char *alias_old,
goto out;
}
- id = lookup_binding(f, wwid, &alias, NULL);
+ id = lookup_binding(f, wwid, &alias, NULL, 0);
if (alias) {
condlog(3, "Use existing binding [%s] for WWID [%s]",
alias, wwid);
@@ -373,7 +415,7 @@ get_user_friendly_alias(const char *wwid, const char *file, const char *prefix,
return NULL;
}
- id = lookup_binding(f, wwid, &alias, prefix);
+ id = lookup_binding(f, wwid, &alias, prefix, 1);
if (id < 0) {
fclose(f);
return NULL;
diff --git a/tests/alias.c b/tests/alias.c
index 30414db0..ab1a9325 100644
--- a/tests/alias.c
+++ b/tests/alias.c
@@ -356,7 +356,7 @@ static void lb_empty(void **state)
will_return(__wrap_fgets, NULL);
expect_condlog(3, "No matching wwid [WWID0] in bindings file.\n");
- rc = lookup_binding(NULL, "WWID0", &alias, NULL);
+ rc = lookup_binding(NULL, "WWID0", &alias, NULL, 0);
assert_int_equal(rc, 1);
assert_ptr_equal(alias, NULL);
}
@@ -369,7 +369,7 @@ static void lb_match_a(void **state)
will_return(__wrap_fgets, "MPATHa WWID0\n");
expect_condlog(3, "Found matching wwid [WWID0] in bindings file."
" Setting alias to MPATHa\n");
- rc = lookup_binding(NULL, "WWID0", &alias, "MPATH");
+ rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 0);
assert_int_equal(rc, 0);
assert_ptr_not_equal(alias, NULL);
assert_string_equal(alias, "MPATHa");
@@ -384,7 +384,7 @@ static void lb_nomatch_a(void **state)
will_return(__wrap_fgets, "MPATHa WWID0\n");
will_return(__wrap_fgets, NULL);
expect_condlog(3, "No matching wwid [WWID1] in bindings file.\n");
- rc = lookup_binding(NULL, "WWID1", &alias, "MPATH");
+ rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 0);
assert_int_equal(rc, 2);
assert_ptr_equal(alias, NULL);
}
@@ -398,7 +398,7 @@ static void lb_match_c(void **state)
will_return(__wrap_fgets, "MPATHc WWID1\n");
expect_condlog(3, "Found matching wwid [WWID1] in bindings file."
" Setting alias to MPATHc\n");
- rc = lookup_binding(NULL, "WWID1", &alias, "MPATH");
+ rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 0);
assert_int_equal(rc, 0);
assert_ptr_not_equal(alias, NULL);
assert_string_equal(alias, "MPATHc");
@@ -414,7 +414,7 @@ static void lb_nomatch_a_c(void **state)
will_return(__wrap_fgets, "MPATHc WWID1\n");
will_return(__wrap_fgets, NULL);
expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
+ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0);
assert_int_equal(rc, 2);
assert_ptr_equal(alias, NULL);
}
@@ -428,7 +428,7 @@ static void lb_nomatch_c_a(void **state)
will_return(__wrap_fgets, "MPATHa WWID0\n");
will_return(__wrap_fgets, NULL);
expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
+ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0);
assert_int_equal(rc, 2);
assert_ptr_equal(alias, NULL);
}
@@ -443,7 +443,7 @@ static void lb_nomatch_a_b(void **state)
will_return(__wrap_fgets, "MPATHb WWID1\n");
will_return(__wrap_fgets, NULL);
expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
+ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0);
assert_int_equal(rc, 3);
assert_ptr_equal(alias, NULL);
}
@@ -459,7 +459,7 @@ static void lb_nomatch_a_b_bad(void **state)
will_return(__wrap_fgets, NULL);
expect_condlog(3, "Ignoring malformed line 3 in bindings file\n");
expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
+ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0);
assert_int_equal(rc, 3);
assert_ptr_equal(alias, NULL);
}
@@ -474,7 +474,7 @@ static void lb_nomatch_b_a(void **state)
will_return(__wrap_fgets, "MPATHa WWID0\n");
will_return(__wrap_fgets, NULL);
expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
+ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0);
assert_int_equal(rc, 27);
assert_ptr_equal(alias, NULL);
}
@@ -490,7 +490,7 @@ static void lb_nomatch_int_max(void **state)
will_return(__wrap_fgets, "MPATHa WWID0\n");
will_return(__wrap_fgets, NULL);
expect_condlog(0, "no more available user_friendly_names\n");
- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
+ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0);
assert_int_equal(rc, -1);
assert_ptr_equal(alias, NULL);
}
@@ -505,7 +505,7 @@ static void lb_nomatch_int_max_m1(void **state)
will_return(__wrap_fgets, "MPATHa WWID0\n");
will_return(__wrap_fgets, NULL);
expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
+ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0);
assert_int_equal(rc, INT_MAX);
assert_ptr_equal(alias, NULL);
}
--
2.17.2

View File

@ -0,0 +1,129 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: lixiaokeng <lixiaokeng@huawei.com>
Date: Mon, 21 Sep 2020 12:00:39 +0800
Subject: [PATCH] libmultipath: check udev_device_get_* return value to avoid
segfault
The udev_device_get_* function may return NULL, and it will be
deregerenced in str* and sscanf func. We check the return value
to avoid segfault. Fix all.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by:Lixiaokeng<lixiaokeng@huawei.com>
Signed-off-by: Zhiqiang Liu <liuzhiqiang26@huawei.com>
Signed-off-by: Linfeilong <linfeilong@huawei.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/configure.c | 4 +++-
libmultipath/discovery.c | 9 +++++++--
libmultipath/foreign/nvme.c | 10 +++++++---
3 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 2e8f34f9..a6893d8d 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -511,6 +511,7 @@ static void trigger_partitions_udev_change(struct udev_device *dev,
{
struct udev_enumerate *part_enum;
struct udev_list_entry *item;
+ const char *devtype;
part_enum = udev_enumerate_new(udev);
if (!part_enum)
@@ -531,7 +532,8 @@ static void trigger_partitions_udev_change(struct udev_device *dev,
if (!part)
continue;
- if (!strcmp("partition", udev_device_get_devtype(part))) {
+ devtype = udev_device_get_devtype(part);
+ if (devtype && !strcmp("partition", devtype)) {
condlog(4, "%s: triggering %s event for %s", __func__,
action, syspath);
sysfs_attr_set_value(part, "uevent", action, len);
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index a328aafa..74abf34d 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -353,7 +353,7 @@ sysfs_get_tgt_nodename(struct path *pp, char *node)
tgtdev = udev_device_get_parent(parent);
while (tgtdev) {
tgtname = udev_device_get_sysname(tgtdev);
- if (sscanf(tgtname, "end_device-%d:%d",
+ if (tgtname && sscanf(tgtname, "end_device-%d:%d",
&host, &tgtid) == 2)
break;
tgtdev = udev_device_get_parent(tgtdev);
@@ -386,7 +386,7 @@ sysfs_get_tgt_nodename(struct path *pp, char *node)
/* Check for FibreChannel */
tgtdev = udev_device_get_parent(parent);
value = udev_device_get_sysname(tgtdev);
- if (sscanf(value, "rport-%d:%d-%d",
+ if (value && sscanf(value, "rport-%d:%d-%d",
&host, &channel, &tgtid) == 3) {
tgtdev = udev_device_new_from_subsystem_sysname(udev,
"fc_remote_ports", value);
@@ -516,6 +516,9 @@ int sysfs_get_host_pci_name(const struct path *pp, char *pci_name)
*/
value = udev_device_get_sysname(parent);
+ if (!value)
+ return 1;
+
strncpy(pci_name, value, SLOT_NAME_SIZE);
udev_device_unref(hostdev);
return 0;
@@ -1518,6 +1521,8 @@ ccw_sysfs_pathinfo (struct path * pp, vector hwtable)
* host / bus / target / lun
*/
attr_path = udev_device_get_sysname(parent);
+ if (!attr_path)
+ return PATHINFO_FAILED;
pp->sg_id.lun = 0;
if (sscanf(attr_path, "%i.%i.%x",
&pp->sg_id.host_no,
diff --git a/libmultipath/foreign/nvme.c b/libmultipath/foreign/nvme.c
index 09cdddf0..5feb1e95 100644
--- a/libmultipath/foreign/nvme.c
+++ b/libmultipath/foreign/nvme.c
@@ -482,6 +482,7 @@ _find_path_by_syspath(struct nvme_map *map, const char *syspath)
struct nvme_pathgroup *pg;
char real[PATH_MAX];
const char *ppath;
+ const char *psyspath;
int i;
ppath = realpath(syspath, real);
@@ -493,8 +494,8 @@ _find_path_by_syspath(struct nvme_map *map, const char *syspath)
vector_foreach_slot(&map->pgvec, pg, i) {
struct nvme_path *path = nvme_pg_to_path(pg);
- if (!strcmp(ppath,
- udev_device_get_syspath(path->udev)))
+ psyspath = udev_device_get_syspath(path->udev);
+ if (psyspath && !strcmp(ppath, psyspath))
return path;
}
condlog(4, "%s: %s: %s not found", __func__, THIS, ppath);
@@ -538,6 +539,7 @@ struct udev_device *get_ctrl_blkdev(const struct context *ctx,
struct udev_list_entry *item;
struct udev_device *blkdev = NULL;
struct udev_enumerate *enm = udev_enumerate_new(ctx->udev);
+ const char *devtype;
if (enm == NULL)
return NULL;
@@ -562,7 +564,9 @@ struct udev_device *get_ctrl_blkdev(const struct context *ctx,
udev_list_entry_get_name(item));
if (tmp == NULL)
continue;
- if (!strcmp(udev_device_get_devtype(tmp), "disk")) {
+
+ devtype = udev_device_get_devtype(tmp);
+ if (devtype && !strcmp(devtype, "disk")) {
blkdev = tmp;
break;
} else
--
2.17.2

View File

@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 24 Feb 2021 00:33:20 -0600
Subject: [PATCH] libmultipath: cleanup code to strip wwid trailing spaces
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/discovery.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 74abf34d..126a70b3 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -2062,11 +2062,11 @@ int
get_uid (struct path * pp, int path_state, struct udev_device *udev,
int allow_fallback)
{
- char *c;
const char *origin = "unknown";
ssize_t len = 0;
struct config *conf;
int used_fallback = 0;
+ size_t i;
if (!pp->uid_attribute && !pp->getuid) {
conf = get_multipath_config();
@@ -2119,12 +2119,9 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev,
return 1;
} else {
/* Strip any trailing blanks */
- c = strchr(pp->wwid, '\0');
- c--;
- while (c && c >= pp->wwid && *c == ' ') {
- *c = '\0';
- c--;
- }
+ for (i = strlen(pp->wwid); i > 0 && pp->wwid[i-1] == ' '; i--);
+ /* no-op */
+ pp->wwid[i] = '\0';
}
condlog((used_fallback)? 1 : 3, "%s: uid = %s (%s)", pp->dev,
*pp->wwid == '\0' ? "<empty>" : pp->wwid, origin);
--
2.17.2

View File

@ -0,0 +1,429 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 24 Feb 2021 00:33:22 -0600
Subject: [PATCH] multipathd: add recheck_wwid option to verify the path wwid
There are cases where the wwid of a path changes due to LUN remapping
without triggering uevent for the changed path. Multipathd has no method
for trying to catch these cases, and corruption has resulted because of
it.
In order to have a better chance at catching these cases, multipath now
has a recheck_wwid option. If this is set to "yes", when a failed path
has become active again, multipathd will recheck its wwid. If multipathd
notices that a path's wwid has changed, it will remove and re-add the
path, just like the existing wwid checking code for change events does.
In cases where the no uevent occurs, both the udev database entry and
sysfs will have the old wwid, so the only way to get a current wwid is
to ask the device directly. Currently multipath only has code to
directly get the wwid for scsi devices, so this option only effects scsi
devices, and they must be configured to be able to use the uid_fallback
methods. To make sure both the sysfs and udev database values are
updated, multipathd triggers a both a rescan of the device and a udev
add event.
Co-developed-by: Chongyun Wu <wucy11@chinatelecom.cn>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/config.c | 2 +
libmultipath/config.h | 2 +
libmultipath/configure.c | 4 +-
libmultipath/configure.h | 2 +
libmultipath/defaults.h | 1 +
libmultipath/dict.c | 11 ++++++
libmultipath/discovery.c | 3 +-
libmultipath/discovery.h | 1 +
libmultipath/propsel.c | 21 ++++++++++
libmultipath/propsel.h | 1 +
libmultipath/structs.h | 7 ++++
multipath/multipath.conf.5 | 14 +++++++
multipathd/cli_handlers.c | 9 +++++
multipathd/main.c | 78 ++++++++++++++++++++++++++++++++++++++
multipathd/main.h | 2 +
15 files changed, 155 insertions(+), 3 deletions(-)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index dd645f17..abbddaf1 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -371,6 +371,7 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
merge_num(max_sectors_kb);
merge_num(ghost_delay);
merge_num(all_tg_pt);
+ merge_num(recheck_wwid);
merge_num(vpd_vendor_id);
merge_num(san_path_err_threshold);
merge_num(san_path_err_forget_rate);
@@ -762,6 +763,7 @@ load_config (char * file)
conf->remove_retries = 0;
conf->ghost_delay = DEFAULT_GHOST_DELAY;
conf->all_tg_pt = DEFAULT_ALL_TG_PT;
+ conf->recheck_wwid = DEFAULT_RECHECK_WWID;
/*
* preload default hwtable
*/
diff --git a/libmultipath/config.h b/libmultipath/config.h
index a22c1b4e..e2e3f143 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -84,6 +84,7 @@ struct hwentry {
int ghost_delay;
int all_tg_pt;
int vpd_vendor_id;
+ int recheck_wwid;
char * bl_product;
};
@@ -188,6 +189,7 @@ struct config {
int skip_delegate;
unsigned int version[3];
unsigned int sequence_nr;
+ int recheck_wwid;
char * multipath_dir;
char * selector;
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index a6893d8d..f24d9283 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -506,8 +506,8 @@ trigger_udev_change(const struct multipath *mpp)
udev_device_unref(udd);
}
-static void trigger_partitions_udev_change(struct udev_device *dev,
- const char *action, int len)
+void trigger_partitions_udev_change(struct udev_device *dev,
+ const char *action, int len)
{
struct udev_enumerate *part_enum;
struct udev_list_entry *item;
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
index 0e33bf40..81090dd4 100644
--- a/libmultipath/configure.h
+++ b/libmultipath/configure.h
@@ -57,3 +57,5 @@ int get_refwwid (enum mpath_cmds cmd, char * dev, enum devtypes dev_type,
int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh, int is_daemon);
struct udev_device *get_udev_device(const char *dev, enum devtypes dev_type);
void trigger_paths_udev_change(struct multipath *mpp, bool is_mpath);
+void trigger_partitions_udev_change(struct udev_device *dev, const char *action,
+ int len);
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
index 52fe05b9..f1cb000d 100644
--- a/libmultipath/defaults.h
+++ b/libmultipath/defaults.h
@@ -50,6 +50,7 @@
#define DEFAULT_FIND_MULTIPATHS_TIMEOUT -10
#define DEFAULT_UNKNOWN_FIND_MULTIPATHS_TIMEOUT 1
#define DEFAULT_ALL_TG_PT ALL_TG_PT_OFF
+#define DEFAULT_RECHECK_WWID RECHECK_WWID_OFF
/* Enable all foreign libraries by default */
#define DEFAULT_ENABLE_FOREIGN ""
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 8fd91d8c..13698b76 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -1413,6 +1413,14 @@ declare_hw_snprint(all_tg_pt, print_yes_no_undef)
declare_def_handler(marginal_pathgroups, set_yes_no)
declare_def_snprint(marginal_pathgroups, print_yes_no)
+declare_def_handler(recheck_wwid, set_yes_no_undef)
+declare_def_snprint_defint(recheck_wwid, print_yes_no_undef, DEFAULT_RECHECK_WWID)
+declare_ovr_handler(recheck_wwid, set_yes_no_undef)
+declare_ovr_snprint(recheck_wwid, print_yes_no_undef)
+declare_hw_handler(recheck_wwid, set_yes_no_undef)
+declare_hw_snprint(recheck_wwid, print_yes_no_undef)
+
+
static int
def_uxsock_timeout_handler(struct config *conf, vector strvec)
{
@@ -1824,6 +1832,7 @@ init_keywords(vector keywords)
install_keyword("enable_foreign", &def_enable_foreign_handler,
&snprint_def_enable_foreign);
install_keyword("marginal_pathgroups", &def_marginal_pathgroups_handler, &snprint_def_marginal_pathgroups);
+ install_keyword("recheck_wwid", &def_recheck_wwid_handler, &snprint_def_recheck_wwid);
__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
__deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
@@ -1913,6 +1922,7 @@ init_keywords(vector keywords)
install_keyword("ghost_delay", &hw_ghost_delay_handler, &snprint_hw_ghost_delay);
install_keyword("all_tg_pt", &hw_all_tg_pt_handler, &snprint_hw_all_tg_pt);
install_keyword("vpd_vendor", &hw_vpd_vendor_handler, &snprint_hw_vpd_vendor);
+ install_keyword("recheck_wwid", &hw_recheck_wwid_handler, &snprint_hw_recheck_wwid);
install_sublevel_end();
install_keyword_root("overrides", &overrides_handler);
@@ -1954,6 +1964,7 @@ init_keywords(vector keywords)
install_keyword("max_sectors_kb", &ovr_max_sectors_kb_handler, &snprint_ovr_max_sectors_kb);
install_keyword("ghost_delay", &ovr_ghost_delay_handler, &snprint_ovr_ghost_delay);
install_keyword("all_tg_pt", &ovr_all_tg_pt_handler, &snprint_ovr_all_tg_pt);
+ install_keyword("recheck_wwid", &ovr_recheck_wwid_handler, &snprint_ovr_recheck_wwid);
install_keyword_root("multipaths", &multipaths_handler);
install_keyword_multi("multipath", &multipath_handler, NULL);
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 126a70b3..bc267609 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -2040,7 +2040,7 @@ static ssize_t uid_fallback(struct path *pp, int path_state,
return len;
}
-static bool has_uid_fallback(struct path *pp)
+bool has_uid_fallback(struct path *pp)
{
/*
* Falling back to direct WWID determination is dangerous
@@ -2072,6 +2072,7 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev,
conf = get_multipath_config();
pthread_cleanup_push(put_multipath_config, conf);
select_getuid(conf, pp);
+ select_recheck_wwid(conf, pp);
pthread_cleanup_pop(1);
}
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
index d3193daf..a5446b4d 100644
--- a/libmultipath/discovery.h
+++ b/libmultipath/discovery.h
@@ -54,6 +54,7 @@ ssize_t sysfs_get_inquiry(struct udev_device *udev,
unsigned char *buff, size_t len);
int sysfs_get_asymmetric_access_state(struct path *pp,
char *buff, int buflen);
+bool has_uid_fallback(struct path *pp);
int get_uid(struct path * pp, int path_state, struct udev_device *udev,
int allow_fallback);
bool is_vpd_page_supported(int fd, int pg);
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index 1150cfe8..127b3370 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -581,6 +581,27 @@ out:
return 0;
}
+/* must be called after select_getuid */
+int select_recheck_wwid(struct config *conf, struct path * pp)
+{
+ const char *origin;
+
+ pp_set_ovr(recheck_wwid);
+ pp_set_hwe(recheck_wwid);
+ pp_set_conf(recheck_wwid);
+ pp_set_default(recheck_wwid, DEFAULT_RECHECK_WWID);
+out:
+ if (pp->recheck_wwid == RECHECK_WWID_ON &&
+ (pp->bus != SYSFS_BUS_SCSI || pp->getuid != NULL ||
+ !has_uid_fallback(pp))) {
+ pp->recheck_wwid = RECHECK_WWID_OFF;
+ origin = "(setting: unsupported by device type/config)";
+ }
+ condlog(3, "%s: recheck_wwid = %i %s", pp->dev, pp->recheck_wwid,
+ origin);
+ return 0;
+}
+
void
detect_prio(struct config *conf, struct path * pp)
{
diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h
index a68bacf0..72a7e33c 100644
--- a/libmultipath/propsel.h
+++ b/libmultipath/propsel.h
@@ -7,6 +7,7 @@ int select_features (struct config *conf, struct multipath * mp);
int select_hwhandler (struct config *conf, struct multipath * mp);
int select_checker(struct config *conf, struct path *pp);
int select_getuid (struct config *conf, struct path * pp);
+int select_recheck_wwid(struct config *conf, struct path * pp);
int select_prio (struct config *conf, struct path * pp);
int select_find_multipaths_timeout(struct config *conf, struct path *pp);
int select_no_path_retry(struct config *conf, struct multipath *mp);
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 65542dea..a5dbad5b 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -252,6 +252,12 @@ enum eh_deadline_states {
EH_DEADLINE_ZERO = UOZ_ZERO,
};
+enum recheck_wwid_states {
+ RECHECK_WWID_UNDEF = YNU_UNDEF,
+ RECHECK_WWID_OFF = YNU_NO,
+ RECHECK_WWID_ON = YNU_YES,
+};
+
struct vpd_vendor_page {
int pg;
const char *name;
@@ -326,6 +332,7 @@ struct path {
int find_multipaths_timeout;
int marginal;
int vpd_vendor_id;
+ int recheck_wwid;
/* configlet pointers */
vector hwe;
struct gen_path generic_path;
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index a5686090..6da15aad 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -1256,6 +1256,20 @@ The default is: \fB\(dq\(dq\fR (the empty regular expression)
.RE
.
.
+.TP
+.B recheck_wwid
+If set to \fIyes\fR, when a failed path is restored, its wwid is rechecked. If
+the wwid has changed, the path is removed from the current multipath device,
+and re-added as a new path. Multipathd will also recheck a path's wwid if it is
+manually re-added. This option only works for SCSI devices that are configured
+to use the default uid_attribute, \fIID_SERIAL\fR, or sysfs for getting their
+wwid.
+.RS
+.TP
+The default is \fBno\fR
+.RE
+.
+.
.
.\" ----------------------------------------------------------------------------
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 782bb003..8b4bd187 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -715,6 +715,15 @@ cli_add_path (void * v, char ** reply, int * len, void * data)
pp = find_path_by_dev(vecs->pathvec, param);
if (pp) {
condlog(2, "%s: path already in pathvec", param);
+
+ if (pp->recheck_wwid == RECHECK_WWID_ON &&
+ check_path_wwid_change(pp)) {
+ condlog(0, "%s: wwid changed. Removing device",
+ pp->dev);
+ handle_path_wwid_change(pp, vecs);
+ return 1;
+ }
+
if (pp->mpp)
return 0;
} else {
diff --git a/multipathd/main.c b/multipathd/main.c
index cc1aeea2..1fbc31eb 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -822,6 +822,73 @@ ev_remove_map (char * devname, char * alias, int minor, struct vectors * vecs)
return flush_map(mpp, vecs, 0);
}
+static void
+rescan_path(struct udev_device *parent)
+{
+ while(parent) {
+ const char *subsys = udev_device_get_subsystem(parent);
+ if (subsys && !strncmp(subsys, "scsi", 4))
+ break;
+ parent = udev_device_get_parent(parent);
+ }
+ if (parent)
+ sysfs_attr_set_value(parent, "rescan", "1", strlen("1"));
+}
+
+void
+handle_path_wwid_change(struct path *pp, struct vectors *vecs)
+{
+ struct udev_device *udd;
+
+ if (!pp || !pp->udev)
+ return;
+
+ udd = udev_device_ref(pp->udev);
+ if (ev_remove_path(pp, vecs, 1) != 0 && pp->mpp) {
+ pp->dmstate = PSTATE_FAILED;
+ dm_fail_path(pp->mpp->alias, pp->dev_t);
+ }
+ rescan_path(udd);
+ sysfs_attr_set_value(udd, "uevent", "add", strlen("add"));
+ trigger_partitions_udev_change(udd, "add", strlen("add"));
+ udev_device_unref(udd);
+}
+
+bool
+check_path_wwid_change(struct path *pp)
+{
+ char wwid[WWID_SIZE];
+ int len = 0;
+ size_t i;
+
+ if (!strlen(pp->wwid))
+ return false;
+
+ /* Get the real fresh device wwid by sgio. sysfs still has old
+ * data, so only get_vpd_sgio will work to get the new wwid */
+ len = get_vpd_sgio(pp->fd, 0x83, 0, wwid, WWID_SIZE);
+
+ if (len <= 0) {
+ condlog(2, "%s: failed to check wwid by sgio: len = %d",
+ pp->dev, len);
+ return false;
+ }
+
+ /*Strip any trailing blanks */
+ for (i = strlen(pp->wwid); i > 0 && pp->wwid[i-1] == ' '; i--);
+ /* no-op */
+ pp->wwid[i] = '\0';
+ condlog(4, "%s: Got wwid %s by sgio", pp->dev, wwid);
+
+ if (strncmp(wwid, pp->wwid, WWID_SIZE)) {
+ condlog(0, "%s: wwid '%s' doesn't match wwid '%s' from device",
+ pp->dev, pp->wwid, wwid);
+ return true;
+ }
+
+ return false;
+}
+
static int
uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map)
{
@@ -1241,6 +1308,7 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
condlog(0, "%s: path wwid changed from '%s' to '%s'",
uev->kernel, wwid, pp->wwid);
ev_remove_path(pp, vecs, 1);
+ rescan_path(uev->udev);
needs_reinit = 1;
goto out;
} else {
@@ -2101,6 +2169,16 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
return 0;
set_no_path_retry(pp->mpp);
+ if (pp->recheck_wwid == RECHECK_WWID_ON &&
+ (newstate == PATH_UP || newstate == PATH_GHOST) &&
+ ((pp->state != PATH_UP && pp->state != PATH_GHOST) ||
+ pp->dmstate == PSTATE_FAILED) &&
+ check_path_wwid_change(pp)) {
+ condlog(0, "%s: path wwid change detected. Removing", pp->dev);
+ handle_path_wwid_change(pp, vecs);
+ return 0;
+ }
+
if ((newstate == PATH_UP || newstate == PATH_GHOST) &&
(san_path_check_enabled(pp->mpp) ||
marginal_path_check_enabled(pp->mpp))) {
diff --git a/multipathd/main.h b/multipathd/main.h
index 5dff17e5..8f0028a9 100644
--- a/multipathd/main.h
+++ b/multipathd/main.h
@@ -49,4 +49,6 @@ int update_multipath (struct vectors *vecs, char *mapname, int reset);
int update_path_groups(struct multipath *mpp, struct vectors *vecs,
int refresh);
+void handle_path_wwid_change(struct path *pp, struct vectors *vecs);
+bool check_path_wwid_change(struct path *pp);
#endif /* MAIN_H */
--
2.17.2

View File

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 25 Mar 2021 19:52:43 -0500
Subject: [PATCH] libmultipath: avoid infinite loop with bad vpd page 83
identifier
If a device with a scsi name identifier has an unknown prefix,
parse_vpd_pg83() needs to advance to the next identifier, instead of
simply trying the same one again in an infinite loop.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/discovery.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index bc267609..8c2ab073 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1101,7 +1101,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
if (memcmp(d + 4, "eui.", 4) &&
memcmp(d + 4, "naa.", 4) &&
memcmp(d + 4, "iqn.", 4))
- continue;
+ break;
if (prio < 4) {
prio = 4;
vpd = d;
--
2.17.2

View File

@ -0,0 +1,50 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 25 Mar 2021 19:52:44 -0500
Subject: [PATCH] libmultipath: fix priorities in parse_vpd_pg83
The priorities for the EUI-64 (0x02) and NAME (0x08) scsi identifiers in
parse_vpd_pg83() don't match their priorities in 55-scsi-sg3_id.rules.
Switch them so that they match.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/discovery.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 8c2ab073..5e988631 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1096,19 +1096,19 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
vpd = d;
}
break;
- case 0x8:
- /* SCSI Name: Prio 4 */
- if (memcmp(d + 4, "eui.", 4) &&
- memcmp(d + 4, "naa.", 4) &&
- memcmp(d + 4, "iqn.", 4))
- break;
+ case 0x2:
+ /* EUI-64: Prio 4 */
if (prio < 4) {
prio = 4;
vpd = d;
}
break;
- case 0x2:
- /* EUI-64: Prio 3 */
+ case 0x8:
+ /* SCSI Name: Prio 3 */
+ if (memcmp(d + 4, "eui.", 4) &&
+ memcmp(d + 4, "naa.", 4) &&
+ memcmp(d + 4, "iqn.", 4))
+ break;
if (prio < 3) {
prio = 3;
vpd = d;
--
2.17.2

View File

@ -0,0 +1,54 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 25 Mar 2021 13:05:10 -0500
Subject: [PATCH] RH: make parse_vpd_pg83 match scsi_id output
Red Hat sets ID_SERIAL based on the result of scsi_id, instead of using
the result of sg_inq and 55-scsi-sg3_id.rules. Make parse_vpd_pg83 match
that.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 18 ++----------------
1 file changed, 2 insertions(+), 16 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 5e988631..2404cb87 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1079,12 +1079,9 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
naa_prio = 7;
break;
case 2:
- /* IEEE Extended: Prio 6 */
- naa_prio = 6;
- break;
case 3:
- /* IEEE Locally assigned: Prio 1 */
- naa_prio = 1;
+ /* IEEE Extended or Locally assigned: Prio 6 */
+ naa_prio = 6;
break;
default:
/* Default: no priority */
@@ -1103,17 +1100,6 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
vpd = d;
}
break;
- case 0x8:
- /* SCSI Name: Prio 3 */
- if (memcmp(d + 4, "eui.", 4) &&
- memcmp(d + 4, "naa.", 4) &&
- memcmp(d + 4, "iqn.", 4))
- break;
- if (prio < 3) {
- prio = 3;
- vpd = d;
- }
- break;
case 0x1:
/* T-10 Vendor ID: Prio 2 */
if (prio < 2) {
--
2.17.2

View File

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 25 Mar 2021 19:52:45 -0500
Subject: [PATCH] multipathd: improve getting parent udevice in rescan_path
Instead of looping through parents and checking, just call
udev_device_get_parent_with_subsystem_devtype() to get the
right one.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
multipathd/main.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index 1fbc31eb..4598d354 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -823,16 +823,12 @@ ev_remove_map (char * devname, char * alias, int minor, struct vectors * vecs)
}
static void
-rescan_path(struct udev_device *parent)
+rescan_path(struct udev_device *ud)
{
- while(parent) {
- const char *subsys = udev_device_get_subsystem(parent);
- if (subsys && !strncmp(subsys, "scsi", 4))
- break;
- parent = udev_device_get_parent(parent);
- }
- if (parent)
- sysfs_attr_set_value(parent, "rescan", "1", strlen("1"));
+ ud = udev_device_get_parent_with_subsystem_devtype(ud, "scsi",
+ "scsi_device");
+ if (ud)
+ sysfs_attr_set_value(ud, "rescan", "1", strlen("1"));
}
void
--
2.17.2

View File

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 25 Mar 2021 19:52:46 -0500
Subject: [PATCH] multipathd: don't trigger uevent for partitions on wwid
change
If the wwid changed, the device is no longer the same, so sending add
events to the devices partitions doesn't make any sense.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
multipathd/main.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index 4598d354..e6c19ab2 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -846,7 +846,6 @@ handle_path_wwid_change(struct path *pp, struct vectors *vecs)
}
rescan_path(udd);
sysfs_attr_set_value(udd, "uevent", "add", strlen("add"));
- trigger_partitions_udev_change(udd, "add", strlen("add"));
udev_device_unref(udd);
}
--
2.17.2

View File

@ -0,0 +1,165 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 9 Jul 2021 14:30:10 -0500
Subject: [PATCH] RH: mpathconf: correctly handle spaces after option names
mpathconf was either accepting any number of spaces, including zero,
after option names, or it was only accepting one space. It should
accept one or more spaces.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/mpathconf | 40 ++++++++++++++++++++--------------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/multipath/mpathconf b/multipath/mpathconf
index 2f4f3eaf..5f2285ab 100644
--- a/multipath/mpathconf
+++ b/multipath/mpathconf
@@ -240,7 +240,7 @@ function validate_args
echo "--enable_foreign must be either 'y' or 'n'"
exit 1
fi
- if [ -z "$ENABLE" -a -z "$FIND" -a -z "$FRIENDLY" -a -z "$PROPERTY" ]; then
+ if [ -z "$ENABLE" -a -z "$FIND" -a -z "$FRIENDLY" -a -z "$PROPERTY" -a -z "$FOREIGN" ]; then
SHOW_STATUS=1
fi
if [ -n "$MODULE" ] && [ "$MODULE" != "y" -a "$MODULE" != "n" ]; then
@@ -315,36 +315,36 @@ if [ "$MULTIPATHD" = "y" ]; then
fi
if [ "$HAVE_BLACKLIST" = "1" ]; then
- if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*devnode \"\.\?\*\"" ; then
+ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"" ; then
HAVE_DISABLE=1
- elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*devnode \"\.\?\*\"" ; then
+ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"" ; then
HAVE_DISABLE=0
fi
fi
if [ "$HAVE_BLACKLIST" = "1" ]; then
- if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*wwid \"\.\?\*\"" ; then
+ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*wwid[[:space:]][[:space:]]*\"\.\?\*\"" ; then
HAVE_WWID_DISABLE=1
- elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*wwid \"\.\?\*\"" ; then
+ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*wwid[[:space:]][[:space:]]*\"\.\?\*\"" ; then
HAVE_WWID_DISABLE=0
fi
fi
if [ "$HAVE_DEFAULTS" = "1" ]; then
- HAVE_FIND=`sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | sed -n 's/^[[:blank:]]*find_multipaths[[:blank:]]*\([^[:blank:]]*\).*$/\1/p' | sed -n 1p`
+ HAVE_FIND=`sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | sed -n 's/^[[:blank:]]*find_multipaths[[:blank:]][[:blank:]]*\([^[:blank:]]*\).*$/\1/p' | sed -n 1p`
if [ "$HAVE_FIND" = "1" ]; then
HAVE_FIND="yes"
elif [ "$HAVE_FIND" = "0" ]; then
HAVE_FIND="no"
fi
- if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]]*\(yes\|1\)" ; then
+ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]][[:space:]]*\(yes\|1\)" ; then
HAVE_FRIENDLY=1
- elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]]*\(no\|0\)" ; then
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]][[:space:]]*\(no\|0\)" ; then
HAVE_FRIENDLY=0
fi
if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*enable_foreign" ; then
HAVE_FOREIGN=0
- elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign[[:space:]]*\"\^\$\"" ; then
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign[[:space:]][[:space:]]*\"\^\$\"" ; then
HAVE_FOREIGN=1
elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign" ; then
HAVE_FOREIGN=2
@@ -352,9 +352,9 @@ if [ "$HAVE_DEFAULTS" = "1" ]; then
fi
if [ "$HAVE_EXCEPTIONS" = "1" ]; then
- if sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then
+ if sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*property[[:space:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then
HAVE_PROPERTY=1
- elif sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then
+ elif sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*property[[:space:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then
HAVE_PROPERTY=0
fi
fi
@@ -427,14 +427,14 @@ fi
if [ "$ENABLE" = 2 ]; then
if [ "$HAVE_DISABLE" = 1 ]; then
- sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode \"\.\?\*\"/# devnode ".*"/' $TMPFILE
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"/# devnode ".*"/' $TMPFILE
fi
if [ -z "$HAVE_WWID_DISABLE" ]; then
sed -i '/^blacklist[[:space:]]*{/ a\
wwid ".*"
' $TMPFILE
elif [ "$HAVE_WWID_DISABLE" = 0 ]; then
- sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*wwid \"\.\?\*\"/ wwid ".*"/' $TMPFILE
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*wwid[[:space:]][[:space:]]*\"\.\?\*\"/ wwid ".*"/' $TMPFILE
fi
if [ "$HAVE_EXCEPTIONS" = 1 ]; then
sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ {/^[[:space:]]*wwid/ d}' $TMPFILE
@@ -448,7 +448,7 @@ _EOF_
add_blacklist_exceptions
elif [ "$ENABLE" = 1 ]; then
if [ "$HAVE_DISABLE" = 1 ]; then
- sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode \"\.\?\*\"/# devnode ".*"/' $TMPFILE
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"/# devnode ".*"/' $TMPFILE
fi
elif [ "$ENABLE" = 0 ]; then
if [ -z "$HAVE_DISABLE" ]; then
@@ -456,7 +456,7 @@ elif [ "$ENABLE" = 0 ]; then
devnode ".*"
' $TMPFILE
elif [ "$HAVE_DISABLE" = 0 ]; then
- sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*devnode \"\.\?\*\"/ devnode ".*"/' $TMPFILE
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"/ devnode ".*"/' $TMPFILE
fi
fi
@@ -467,14 +467,14 @@ if [ -n "$FIND" ]; then
' $TMPFILE
CHANGED_CONFIG=1
elif [ "$FIND" != "$HAVE_FIND" ]; then
- sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:blank:]]*find_multipaths[[:blank:]]*[^[:blank:]]*/ find_multipaths '"$FIND"'/' $TMPFILE
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:blank:]]*find_multipaths[[:blank:]][[:blank:]]*[^[:blank:]]*/ find_multipaths '"$FIND"'/' $TMPFILE
CHANGED_CONFIG=1
fi
fi
if [ "$FRIENDLY" = "n" ]; then
if [ "$HAVE_FRIENDLY" = 1 ]; then
- sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]]*\(yes\|1\)/ user_friendly_names no/' $TMPFILE
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]][[:space:]]*\(yes\|1\)/ user_friendly_names no/' $TMPFILE
CHANGED_CONFIG=1
fi
elif [ "$FRIENDLY" = "y" ]; then
@@ -484,14 +484,14 @@ elif [ "$FRIENDLY" = "y" ]; then
' $TMPFILE
CHANGED_CONFIG=1
elif [ "$HAVE_FRIENDLY" = 0 ]; then
- sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]]*\(no\|0\)/ user_friendly_names yes/' $TMPFILE
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]][[:space:]]*\(no\|0\)/ user_friendly_names yes/' $TMPFILE
CHANGED_CONFIG=1
fi
fi
if [ "$PROPERTY" = "n" ]; then
if [ "$HAVE_PROPERTY" = 1 ]; then
- sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/# property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE
+ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*property[[:space:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/# property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE
CHANGED_CONFIG=1
fi
elif [ "$PROPERTY" = "y" ]; then
@@ -501,7 +501,7 @@ elif [ "$PROPERTY" = "y" ]; then
' $TMPFILE
CHANGED_CONFIG=1
elif [ "$HAVE_PROPERTY" = 0 ]; then
- sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/ property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE
+ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*property[[:space:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/ property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE
CHANGED_CONFIG=1
fi
fi
--
2.30.2

View File

@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 15 Jul 2021 14:48:15 -0500
Subject: [PATCH] multipath.conf: fix typo in checker_timeout description
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/multipath.conf.5 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 6da15aad..0c04c7e4 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -638,7 +638,7 @@ Specify the timeout to use for path checkers and prioritizers, in seconds.
Only prioritizers that issue scsi commands use checker_timeout. Checkers
that support an asynchronous mode (\fItur\fR and \fIdirectio\fR), will
return shortly after being called by multipathd, regardless of whether the
-storage array responds. If the storage array hasn't responded, mulitpathd will
+storage array responds. If the storage array hasn't responded, multipathd will
check for a response every second, until \fIchecker_timeout\fR seconds have
elapsed.
.RS

View File

@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 22 Jul 2021 17:48:06 -0500
Subject: [PATCH] mpathpersist: fail commands when no usable paths exist
"mpathpersist -oCK <reservation_key> <device>" will return success if it
is run on devices with no usable paths, but nothing is actually done.
The -L command will fail, but it should give up sooner, and with a more
helpful error message.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathpersist/mpath_persist.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index 07a5f17f..d0744773 100644
--- a/libmpathpersist/mpath_persist.c
+++ b/libmpathpersist/mpath_persist.c
@@ -629,7 +629,8 @@ int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
return ret ;
}
}
- return MPATH_PR_SUCCESS;
+ condlog (0, "%s: no path available", mpp->wwid);
+ return MPATH_PR_DMMP_ERROR;
}
int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
@@ -688,6 +689,11 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
active_pathcount = pathcount (mpp, PATH_UP) + pathcount (mpp, PATH_GHOST);
+ if (active_pathcount == 0) {
+ condlog (0, "%s: no path available", mpp->wwid);
+ return MPATH_PR_DMMP_ERROR;
+ }
+
struct threadinfo thread[active_pathcount];
memset(thread, 0, sizeof(thread));
for (i = 0; i < active_pathcount; i++){

View File

@ -0,0 +1,107 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 16 Jul 2021 12:39:17 -0500
Subject: [PATCH] multipath: print warning if multipathd is not running.
If multipath notices that multipath devices exist or were created, and
multipathd is not running, it now prints a warning message, so users are
notified of the issue.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/configure.c | 13 +++++++++++--
libmultipath/configure.h | 1 +
multipath/main.c | 5 +++++
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index f24d9283..9c8d3e34 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -1043,7 +1043,8 @@ deadmap (struct multipath * mpp)
return 1; /* dead */
}
-int check_daemon(void)
+extern int
+check_daemon(void)
{
int fd;
char *reply;
@@ -1097,6 +1098,8 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
struct config *conf;
int allow_queueing;
uint64_t *size_mismatch_seen;
+ bool map_processed = false;
+ bool no_daemon = false;
/* ignore refwwid if it's empty */
if (refwwid && !strlen(refwwid))
@@ -1239,7 +1242,9 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
conf = get_multipath_config();
allow_queueing = conf->allow_queueing;
put_multipath_config(conf);
- if (!is_daemon && !allow_queueing && !check_daemon()) {
+ if (!is_daemon && !allow_queueing &&
+ (no_daemon || !check_daemon())) {
+ no_daemon = true;
if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
mpp->no_path_retry != NO_PATH_RETRY_FAIL)
condlog(3, "%s: multipathd not running, unset "
@@ -1267,6 +1272,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
else
remove_map(mpp, vecs, 0);
}
+ map_processed = true;
}
/*
* Flush maps with only dead paths (ie not in sysfs)
@@ -1292,6 +1298,9 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
condlog(2, "%s: remove (dead)", alias);
}
}
+ if (map_processed && !is_daemon && (no_daemon || !check_daemon()))
+ condlog(2, "multipath devices exist, but multipathd service is not running");
+
ret = CP_OK;
out:
free(size_mismatch_seen);
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
index 81090dd4..8a266d31 100644
--- a/libmultipath/configure.h
+++ b/libmultipath/configure.h
@@ -59,3 +59,4 @@ struct udev_device *get_udev_device(const char *dev, enum devtypes dev_type);
void trigger_paths_udev_change(struct multipath *mpp, bool is_mpath);
void trigger_partitions_udev_change(struct udev_device *dev, const char *action,
int len);
+int check_daemon(void);
diff --git a/multipath/main.c b/multipath/main.c
index 607cada2..14d045c9 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -254,6 +254,7 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
int i;
struct multipath * mpp;
char params[PARAMS_SIZE], status[PARAMS_SIZE];
+ bool maps_present = false;
if (dm_get_maps(curmp))
return 1;
@@ -302,6 +303,8 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
if (cmd == CMD_CREATE)
reinstate_paths(mpp);
+
+ maps_present = true;
}
if (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG) {
@@ -311,6 +314,8 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
put_multipath_config(conf);
}
+ if (maps_present && !check_daemon())
+ condlog(2, "multipath devices exist, but multipathd service is not running");
return 0;
}

View File

@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 23 Jul 2021 14:10:06 -0500
Subject: [PATCH] multipathd: don't access path if it was deleted
ev_remove_path() could fail and still delete the path. This could cause
problems for handle_path_wwid_change(), which expected that a failure
meant that the path still existed. ev_remove_path now returns a
different error code for failure to reload the multipath device, so that
it can be differentiated from cases where the path was no removed.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/main.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index e6c19ab2..823b53a2 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -86,6 +86,9 @@
#define FILE_NAME_SIZE 256
#define CMDSIZE 160
+#define PATH_REMOVE_FAILED 1
+#define MAP_RELOAD_FAILED 2
+
#define LOG_MSG(lvl, verb, pp) \
do { \
if (pp->mpp && checker_selected(&pp->checker) && \
@@ -840,7 +843,7 @@ handle_path_wwid_change(struct path *pp, struct vectors *vecs)
return;
udd = udev_device_ref(pp->udev);
- if (ev_remove_path(pp, vecs, 1) != 0 && pp->mpp) {
+ if (ev_remove_path(pp, vecs, 1) == PATH_REMOVE_FAILED && pp->mpp) {
pp->dmstate = PSTATE_FAILED;
dm_fail_path(pp->mpp->alias, pp->dev_t);
}
@@ -1226,13 +1229,13 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map)
condlog(0, "%s: failed in domap for "
"removal of path %s",
mpp->alias, pp->dev);
- retval = 1;
+ retval = MAP_RELOAD_FAILED;
} else {
/*
* update our state from kernel
*/
if (setup_multipath(vecs, mpp))
- return 1;
+ return PATH_REMOVE_FAILED;
sync_map_state(mpp);
condlog(2, "%s [%s]: path removed from map %s",
@@ -1250,7 +1253,7 @@ out:
fail:
remove_map_and_stop_waiter(mpp, vecs);
- return 1;
+ return PATH_REMOVE_FAILED;
}
static int

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Luca BRUNO <luca.bruno@coreos.com>
Date: Fri, 24 Sep 2021 09:34:01 +0000
Subject: [PATCH] multipathd.socket: add missing conditions from service unit
Upstream Status: https://github.com/openSUSE/multipath-tools.git
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2008101
Conflicts: Match the conditions with RHEL-8 multipathd.service unit
commit 345ccf564ce7d904641bd32baf4fc53c2283d95c
Author: Luca BRUNO <luca.bruno@coreos.com>
Date: Fri Sep 24 09:34:01 2021 +0000
multipathd.socket: add missing conditions from service unit
This aligns 'multipathd' socket and service units, by adding the
start conditions that are set on the service but not on the socket.
It should help avoiding situations where the socket unit ends up
marked as failed after hitting its retry-limit.
Fixes: https://github.com/opensvc/multipath-tools/issues/15
Signed-off-by: Luca BRUNO <luca.bruno@coreos.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/multipathd.socket | 3 +++
1 file changed, 3 insertions(+)
diff --git a/multipathd/multipathd.socket b/multipathd/multipathd.socket
index 0ed4a1f7..c62c0fc8 100644
--- a/multipathd/multipathd.socket
+++ b/multipathd/multipathd.socket
@@ -1,6 +1,9 @@
[Unit]
Description=multipathd control socket
DefaultDependencies=no
+ConditionPathExists=/etc/multipath.conf
+ConditionKernelCommandLine=!nompath
+ConditionKernelCommandLine=!multipath=off
Before=sockets.target
[Socket]

View File

@ -0,0 +1,70 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 23 Sep 2021 14:16:51 -0500
Subject: [PATCH] libmulitpath: add section name to invalid keyword output
If users forget the closing brace for a section in multipath.conf,
multipath has no way to detect that. When it sees the keyword at the
start of the next section, it will complain that there is an invalid
keyword, because that keyword doesn't belong in previous section (which
was never ended with a closing brace). This can confuse users. To make
this easier to understand, when multipath prints and invalid keyword
message, it now also prints the current section name, which can give
users a hint that they didn't end the previous section.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/parser.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index 48b54e87..96b95936 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -507,7 +507,8 @@ validate_config_strvec(vector strvec, char *file)
}
static int
-process_stream(struct config *conf, FILE *stream, vector keywords, char *file)
+process_stream(struct config *conf, FILE *stream, vector keywords,
+ const char *section, char *file)
{
int i;
int r = 0, t;
@@ -571,16 +572,22 @@ process_stream(struct config *conf, FILE *stream, vector keywords, char *file)
if (keyword->sub) {
kw_level++;
r += process_stream(conf, stream,
- keyword->sub, file);
+ keyword->sub,
+ keyword->string,
+ file);
kw_level--;
}
break;
}
}
- if (i >= VECTOR_SIZE(keywords))
- condlog(1, "%s line %d, invalid keyword: %s",
- file, line_nr, str);
-
+ if (i >= VECTOR_SIZE(keywords)) {
+ if (section)
+ condlog(1, "%s line %d, invalid keyword in the %s section: %s",
+ file, line_nr, section, str);
+ else
+ condlog(1, "%s line %d, invalid keyword: %s",
+ file, line_nr, str);
+ }
free_strvec(strvec);
}
if (kw_level == 1)
@@ -611,7 +618,7 @@ process_file(struct config *conf, char *file)
/* Stream handling */
line_nr = 0;
- r = process_stream(conf, stream, conf->keywords, file);
+ r = process_stream(conf, stream, conf->keywords, NULL, file);
fclose(stream);
//free_keywords(keywords);

View File

@ -0,0 +1,97 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 23 Sep 2021 21:39:36 -0500
Subject: [PATCH] libmultipath: use typedef for keyword handler and print
functions
Don't keep writing out the function type.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/parser.c | 10 +++++-----
libmultipath/parser.h | 25 ++++++++++++-------------
2 files changed, 17 insertions(+), 18 deletions(-)
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index 96b95936..e511acf9 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -32,8 +32,8 @@ static int line_nr;
int
keyword_alloc(vector keywords, char *string,
- int (*handler) (struct config *, vector),
- int (*print) (struct config *, char *, int, const void*),
+ handler_fn *handler,
+ print_fn *print,
int unique)
{
struct keyword *keyword;
@@ -71,8 +71,8 @@ install_sublevel_end(void)
int
_install_keyword(vector keywords, char *string,
- int (*handler) (struct config *, vector),
- int (*print) (struct config *, char *, int, const void*),
+ handler_fn *handler,
+ print_fn *print,
int unique)
{
int i = 0;
@@ -562,7 +562,7 @@ process_stream(struct config *conf, FILE *stream, vector keywords,
goto out;
}
if (keyword->handler) {
- t = (*keyword->handler) (conf, strvec);
+ t = keyword->handler(conf, strvec);
r += t;
if (t)
condlog(1, "multipath.conf +%d, parsing failed: %s",
diff --git a/libmultipath/parser.h b/libmultipath/parser.h
index b7917052..e8d89607 100644
--- a/libmultipath/parser.h
+++ b/libmultipath/parser.h
@@ -39,11 +39,15 @@
#define EOB "}"
#define MAXBUF 1024
-/* ketword definition */
+
+/* keyword definition */
+typedef int print_fn(struct config *, char *, int, const void *);
+typedef int handler_fn(struct config *, vector);
+
struct keyword {
char *string;
- int (*handler) (struct config *, vector);
- int (*print) (struct config *, char *, int, const void *);
+ handler_fn *handler;
+ print_fn *print;
vector sub;
int unique;
};
@@ -58,19 +62,14 @@ struct keyword {
for (i = 0; i < (k)->sub->allocated && ((p) = (k)->sub->slot[i]); i++)
/* Prototypes */
-extern int keyword_alloc(vector keywords, char *string,
- int (*handler) (struct config *, vector),
- int (*print) (struct config *, char *, int,
- const void *),
- int unique);
+extern int keyword_alloc(vector keywords, char *string, handler_fn *handler,
+ print_fn *print, int unique);
#define install_keyword_root(str, h) keyword_alloc(keywords, str, h, NULL, 1)
extern void install_sublevel(void);
extern void install_sublevel_end(void);
-extern int _install_keyword(vector keywords, char *string,
- int (*handler) (struct config *, vector),
- int (*print) (struct config *, char *, int,
- const void *),
- int unique);
+
+extern int _install_keyword(vector keywords, char *string, handler_fn *handler,
+ print_fn *print, int unique);
#define install_keyword(str, vec, pri) _install_keyword(keywords, str, vec, pri, 1)
#define install_keyword_multi(str, vec, pri) _install_keyword(keywords, str, vec, pri, 0)
extern void dump_keywords(vector keydump, int level);

View File

@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 24 Sep 2021 13:13:31 -0500
Subject: [PATCH] libmultipath: print the correct file when parsing fails
Don't assume that parsing failed on multipath.conf
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/parser.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index e511acf9..341f2b80 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -565,8 +565,8 @@ process_stream(struct config *conf, FILE *stream, vector keywords,
t = keyword->handler(conf, strvec);
r += t;
if (t)
- condlog(1, "multipath.conf +%d, parsing failed: %s",
- line_nr, buf);
+ condlog(1, "%s line %d, parsing failed: %s",
+ file, line_nr, buf);
}
if (keyword->sub) {

View File

@ -0,0 +1,536 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 24 Sep 2021 17:59:12 -0500
Subject: [PATCH] libmultipath: pass file and line number to keyword handlers
This will make it possible for the keyword handlers to print more useful
warning messages. It will be used by future patches.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/dict.c | 145 +++++++++++++++++++++++++-----------------
libmultipath/parser.c | 3 +-
libmultipath/parser.h | 2 +-
3 files changed, 91 insertions(+), 59 deletions(-)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 13698b76..a8872da7 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -28,7 +28,7 @@
#include "dict.h"
static int
-set_int(vector strvec, void *ptr)
+set_int(vector strvec, void *ptr, const char *file, int line_nr)
{
int *int_ptr = (int *)ptr;
char *buff, *eptr;
@@ -57,7 +57,7 @@ set_int(vector strvec, void *ptr)
}
static int
-set_uint(vector strvec, void *ptr)
+set_uint(vector strvec, void *ptr, const char *file, int line_nr)
{
unsigned int *uint_ptr = (unsigned int *)ptr;
char *buff, *eptr, *p;
@@ -89,7 +89,7 @@ set_uint(vector strvec, void *ptr)
}
static int
-set_str(vector strvec, void *ptr)
+set_str(vector strvec, void *ptr, const char *file, int line_nr)
{
char **str_ptr = (char **)ptr;
@@ -104,7 +104,7 @@ set_str(vector strvec, void *ptr)
}
static int
-set_regex(vector strvec, void *ptr)
+set_regex(vector strvec, void *ptr, const char *file, int line_nr)
{
char **str_ptr = (char **)ptr;
@@ -119,7 +119,7 @@ set_regex(vector strvec, void *ptr)
}
static int
-set_yes_no(vector strvec, void *ptr)
+set_yes_no(vector strvec, void *ptr, const char *file, int line_nr)
{
char * buff;
int *int_ptr = (int *)ptr;
@@ -138,7 +138,7 @@ set_yes_no(vector strvec, void *ptr)
}
static int
-set_yes_no_undef(vector strvec, void *ptr)
+set_yes_no_undef(vector strvec, void *ptr, const char *file, int line_nr)
{
char * buff;
int *int_ptr = (int *)ptr;
@@ -240,9 +240,10 @@ print_yes_no_undef (char *buff, int len, long v)
#define declare_def_handler(option, function) \
static int \
-def_ ## option ## _handler (struct config *conf, vector strvec) \
+def_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
- return function (strvec, &conf->option); \
+ return function (strvec, &conf->option, file, line_nr); \
}
#define declare_def_snprint(option, function) \
@@ -277,12 +278,13 @@ snprint_def_ ## option (struct config *conf, char * buff, int len, \
#define declare_hw_handler(option, function) \
static int \
-hw_ ## option ## _handler (struct config *conf, vector strvec) \
+hw_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable); \
if (!hwe) \
return 1; \
- return function (strvec, &hwe->option); \
+ return function (strvec, &hwe->option, file, line_nr); \
}
#define declare_hw_snprint(option, function) \
@@ -296,11 +298,12 @@ snprint_hw_ ## option (struct config *conf, char * buff, int len, \
#define declare_ovr_handler(option, function) \
static int \
-ovr_ ## option ## _handler (struct config *conf, vector strvec) \
+ovr_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
if (!conf->overrides) \
return 1; \
- return function (strvec, &conf->overrides->option); \
+ return function (strvec, &conf->overrides->option, file, line_nr); \
}
#define declare_ovr_snprint(option, function) \
@@ -313,12 +316,13 @@ snprint_ovr_ ## option (struct config *conf, char * buff, int len, \
#define declare_mp_handler(option, function) \
static int \
-mp_ ## option ## _handler (struct config *conf, vector strvec) \
+mp_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable); \
if (!mpe) \
return 1; \
- return function (strvec, &mpe->option); \
+ return function (strvec, &mpe->option, file, line_nr); \
}
#define declare_mp_snprint(option, function) \
@@ -330,9 +334,10 @@ snprint_mp_ ## option (struct config *conf, char * buff, int len, \
return function (buff, len, mpe->option); \
}
-static int checkint_handler(struct config *conf, vector strvec)
+static int checkint_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
- int rc = set_uint(strvec, &conf->checkint);
+ int rc = set_uint(strvec, &conf->checkint, file, line_nr);
if (rc)
return rc;
@@ -355,9 +360,10 @@ declare_def_snprint(reassign_maps, print_yes_no)
declare_def_handler(multipath_dir, set_str)
declare_def_snprint(multipath_dir, print_str)
-static int def_partition_delim_handler(struct config *conf, vector strvec)
+static int def_partition_delim_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
- int rc = set_str(strvec, &conf->partition_delim);
+ int rc = set_str(strvec, &conf->partition_delim, file, line_nr);
if (rc != 0)
return rc;
@@ -387,13 +393,13 @@ static const char * const find_multipaths_optvals[] = {
};
static int
-def_find_multipaths_handler(struct config *conf, vector strvec)
+def_find_multipaths_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
char *buff;
int i;
- if (set_yes_no_undef(strvec, &conf->find_multipaths) == 0 &&
- conf->find_multipaths != FIND_MULTIPATHS_UNDEF)
+ if (set_yes_no_undef(strvec, &conf->find_multipaths, file, line_nr) == 0 && conf->find_multipaths != FIND_MULTIPATHS_UNDEF)
return 0;
buff = set_value(strvec);
@@ -451,7 +457,8 @@ static int snprint_uid_attrs(struct config *conf, char *buff, int len,
return p - buff;
}
-static int uid_attrs_handler(struct config *conf, vector strvec)
+static int uid_attrs_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
char *val;
@@ -644,7 +651,8 @@ declare_hw_handler(skip_kpartx, set_yes_no_undef)
declare_hw_snprint(skip_kpartx, print_yes_no_undef)
declare_mp_handler(skip_kpartx, set_yes_no_undef)
declare_mp_snprint(skip_kpartx, print_yes_no_undef)
-static int def_disable_changed_wwids_handler(struct config *conf, vector strvec)
+static int def_disable_changed_wwids_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
return 0;
}
@@ -675,20 +683,23 @@ declare_def_snprint_defstr(enable_foreign, print_str,
DEFAULT_ENABLE_FOREIGN)
static int
-def_config_dir_handler(struct config *conf, vector strvec)
+def_config_dir_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
/* this is only valid in the main config file */
if (conf->processed_main_config)
return 0;
- return set_str(strvec, &conf->config_dir);
+ return set_str(strvec, &conf->config_dir, file, line_nr);
}
declare_def_snprint(config_dir, print_str)
#define declare_def_attr_handler(option, function) \
static int \
-def_ ## option ## _handler (struct config *conf, vector strvec) \
+def_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
- return function (strvec, &conf->option, &conf->attribute_flags);\
+ return function (strvec, &conf->option, &conf->attribute_flags, \
+ file, line_nr); \
}
#define declare_def_attr_snprint(option, function) \
@@ -702,12 +713,14 @@ snprint_def_ ## option (struct config *conf, char * buff, int len, \
#define declare_mp_attr_handler(option, function) \
static int \
-mp_ ## option ## _handler (struct config *conf, vector strvec) \
+mp_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable); \
if (!mpe) \
return 1; \
- return function (strvec, &mpe->option, &mpe->attribute_flags); \
+ return function (strvec, &mpe->option, &mpe->attribute_flags, \
+ file, line_nr); \
}
#define declare_mp_attr_snprint(option, function) \
@@ -721,7 +734,7 @@ snprint_mp_ ## option (struct config *conf, char * buff, int len, \
}
static int
-set_mode(vector strvec, void *ptr, int *flags)
+set_mode(vector strvec, void *ptr, int *flags, const char *file, int line_nr)
{
mode_t mode;
mode_t *mode_ptr = (mode_t *)ptr;
@@ -742,7 +755,7 @@ set_mode(vector strvec, void *ptr, int *flags)
}
static int
-set_uid(vector strvec, void *ptr, int *flags)
+set_uid(vector strvec, void *ptr, int *flags, const char *file, int line_nr)
{
uid_t uid;
uid_t *uid_ptr = (uid_t *)ptr;
@@ -767,7 +780,7 @@ set_uid(vector strvec, void *ptr, int *flags)
}
static int
-set_gid(vector strvec, void *ptr, int *flags)
+set_gid(vector strvec, void *ptr, int *flags, const char *file, int line_nr)
{
gid_t gid;
gid_t *gid_ptr = (gid_t *)ptr;
@@ -834,7 +847,7 @@ declare_mp_attr_handler(gid, set_gid)
declare_mp_attr_snprint(gid, print_gid)
static int
-set_undef_off_zero(vector strvec, void *ptr)
+set_undef_off_zero(vector strvec, void *ptr, const char *file, int line_nr)
{
char * buff;
int *int_ptr = (int *)ptr;
@@ -876,7 +889,7 @@ declare_hw_handler(fast_io_fail, set_undef_off_zero)
declare_hw_snprint(fast_io_fail, print_undef_off_zero)
static int
-set_dev_loss(vector strvec, void *ptr)
+set_dev_loss(vector strvec, void *ptr, const char *file, int line_nr)
{
char * buff;
unsigned int *uint_ptr = (unsigned int *)ptr;
@@ -919,7 +932,7 @@ declare_hw_handler(eh_deadline, set_undef_off_zero)
declare_hw_snprint(eh_deadline, print_undef_off_zero)
static int
-set_pgpolicy(vector strvec, void *ptr)
+set_pgpolicy(vector strvec, void *ptr, const char *file, int line_nr)
{
char * buff;
int *int_ptr = (int *)ptr;
@@ -985,7 +998,8 @@ get_sys_max_fds(int *max_fds)
static int
-max_fds_handler(struct config *conf, vector strvec)
+max_fds_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
char * buff;
int r = 0, max_fds;
@@ -1030,7 +1044,7 @@ snprint_max_fds (struct config *conf, char * buff, int len, const void * data)
}
static int
-set_rr_weight(vector strvec, void *ptr)
+set_rr_weight(vector strvec, void *ptr, const char *file, int line_nr)
{
int *int_ptr = (int *)ptr;
char * buff;
@@ -1074,7 +1088,7 @@ declare_mp_handler(rr_weight, set_rr_weight)
declare_mp_snprint(rr_weight, print_rr_weight)
static int
-set_pgfailback(vector strvec, void *ptr)
+set_pgfailback(vector strvec, void *ptr, const char *file, int line_nr)
{
int *int_ptr = (int *)ptr;
char * buff;
@@ -1124,7 +1138,7 @@ declare_mp_handler(pgfailback, set_pgfailback)
declare_mp_snprint(pgfailback, print_pgfailback)
static int
-no_path_retry_helper(vector strvec, void *ptr)
+no_path_retry_helper(vector strvec, void *ptr, const char *file, int line_nr)
{
int *int_ptr = (int *)ptr;
char * buff;
@@ -1169,7 +1183,8 @@ declare_mp_handler(no_path_retry, no_path_retry_helper)
declare_mp_snprint(no_path_retry, print_no_path_retry)
static int
-def_log_checker_err_handler(struct config *conf, vector strvec)
+def_log_checker_err_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
char * buff;
@@ -1243,7 +1258,8 @@ print_reservation_key(char * buff, int len, struct be64 key, uint8_t flags,
}
static int
-def_reservation_key_handler(struct config *conf, vector strvec)
+def_reservation_key_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
return set_reservation_key(strvec, &conf->reservation_key,
&conf->sa_flags,
@@ -1260,7 +1276,8 @@ snprint_def_reservation_key (struct config *conf, char * buff, int len,
}
static int
-mp_reservation_key_handler(struct config *conf, vector strvec)
+mp_reservation_key_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
if (!mpe)
@@ -1281,7 +1298,7 @@ snprint_mp_reservation_key (struct config *conf, char * buff, int len,
}
static int
-set_off_int_undef(vector strvec, void *ptr)
+set_off_int_undef(vector strvec, void *ptr, const char *file, int line_nr)
{
int *int_ptr = (int *)ptr;
char * buff;
@@ -1422,7 +1439,8 @@ declare_hw_snprint(recheck_wwid, print_yes_no_undef)
static int
-def_uxsock_timeout_handler(struct config *conf, vector strvec)
+def_uxsock_timeout_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
unsigned int uxsock_timeout;
char *buff;
@@ -1442,7 +1460,8 @@ def_uxsock_timeout_handler(struct config *conf, vector strvec)
}
static int
-hw_vpd_vendor_handler(struct config *conf, vector strvec)
+hw_vpd_vendor_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
int i;
char *buff;
@@ -1482,7 +1501,8 @@ snprint_hw_vpd_vendor(struct config *conf, char * buff, int len,
* blacklist block handlers
*/
static int
-blacklist_handler(struct config *conf, vector strvec)
+blacklist_handler(struct config *conf, vector strvec, const char*file,
+ int line_nr)
{
if (!conf->blist_devnode)
conf->blist_devnode = vector_alloc();
@@ -1504,7 +1524,8 @@ blacklist_handler(struct config *conf, vector strvec)
}
static int
-blacklist_exceptions_handler(struct config *conf, vector strvec)
+blacklist_exceptions_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
if (!conf->elist_devnode)
conf->elist_devnode = vector_alloc();
@@ -1527,7 +1548,8 @@ blacklist_exceptions_handler(struct config *conf, vector strvec)
#define declare_ble_handler(option) \
static int \
-ble_ ## option ## _handler (struct config *conf, vector strvec) \
+ble_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
char * buff; \
\
@@ -1543,7 +1565,8 @@ ble_ ## option ## _handler (struct config *conf, vector strvec) \
#define declare_ble_device_handler(name, option, vend, prod) \
static int \
-ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \
+ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
char * buff; \
\
@@ -1583,13 +1606,15 @@ snprint_ble_simple (struct config *conf, char * buff, int len,
}
static int
-ble_device_handler(struct config *conf, vector strvec)
+ble_device_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
return alloc_ble_device(conf->blist_device);
}
static int
-ble_except_device_handler(struct config *conf, vector strvec)
+ble_except_device_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
return alloc_ble_device(conf->elist_device);
}
@@ -1623,7 +1648,8 @@ snprint_bled_product (struct config *conf, char * buff, int len,
* devices block handlers
*/
static int
-devices_handler(struct config *conf, vector strvec)
+devices_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
if (!conf->hwtable)
conf->hwtable = vector_alloc();
@@ -1635,7 +1661,8 @@ devices_handler(struct config *conf, vector strvec)
}
static int
-device_handler(struct config *conf, vector strvec)
+device_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
struct hwentry * hwe;
@@ -1672,7 +1699,8 @@ declare_hw_snprint(hwhandler, print_str)
* overrides handlers
*/
static int
-overrides_handler(struct config *conf, vector strvec)
+overrides_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
if (!conf->overrides)
conf->overrides = alloc_hwe();
@@ -1689,7 +1717,8 @@ overrides_handler(struct config *conf, vector strvec)
* multipaths block handlers
*/
static int
-multipaths_handler(struct config *conf, vector strvec)
+multipaths_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
if (!conf->mptable)
conf->mptable = vector_alloc();
@@ -1701,7 +1730,8 @@ multipaths_handler(struct config *conf, vector strvec)
}
static int
-multipath_handler(struct config *conf, vector strvec)
+multipath_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
struct mpentry * mpe;
@@ -1730,7 +1760,8 @@ declare_mp_snprint(alias, print_str)
*/
static int
-deprecated_handler(struct config *conf, vector strvec)
+deprecated_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
char * buff;
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index 341f2b80..29e8cee0 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -562,7 +562,8 @@ process_stream(struct config *conf, FILE *stream, vector keywords,
goto out;
}
if (keyword->handler) {
- t = keyword->handler(conf, strvec);
+ t = keyword->handler(conf, strvec, file,
+ line_nr);
r += t;
if (t)
condlog(1, "%s line %d, parsing failed: %s",
diff --git a/libmultipath/parser.h b/libmultipath/parser.h
index e8d89607..8b424b7a 100644
--- a/libmultipath/parser.h
+++ b/libmultipath/parser.h
@@ -42,7 +42,7 @@
/* keyword definition */
typedef int print_fn(struct config *, char *, int, const void *);
-typedef int handler_fn(struct config *, vector);
+typedef int handler_fn(struct config *, vector, const char *file, int line_nr);
struct keyword {
char *string;

View File

@ -0,0 +1,250 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 28 Sep 2021 15:59:19 -0500
Subject: [PATCH] libmultipath: make set_int take a range for valid values
If a value outside of the valid range is passed to set_int, it caps the
value at appropriate limit, and issues a warning.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/dict.c | 121 +++++++++++++++++++++++++++-----------------
1 file changed, 75 insertions(+), 46 deletions(-)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index a8872da7..686f4d5c 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -28,7 +28,8 @@
#include "dict.h"
static int
-set_int(vector strvec, void *ptr, const char *file, int line_nr)
+set_int(vector strvec, void *ptr, int min, int max, const char *file,
+ int line_nr)
{
int *int_ptr = (int *)ptr;
char *buff, *eptr;
@@ -43,11 +44,17 @@ set_int(vector strvec, void *ptr, const char *file, int line_nr)
if (eptr > buff)
while (isspace(*eptr))
eptr++;
- if (*buff == '\0' || *eptr != '\0' || res > INT_MAX || res < INT_MIN) {
- condlog(1, "%s: invalid value for %s: \"%s\"",
- __func__, (char*)VECTOR_SLOT(strvec, 0), buff);
+ if (*buff == '\0' || *eptr != '\0') {
+ condlog(1, "%s line %d, invalid value for %s: \"%s\"",
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff);
rc = 1;
} else {
+ if (res > max || res < min) {
+ res = (res > max) ? max : min;
+ condlog(1, "%s line %d, value for %s too %s, capping at %ld",
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0),
+ (res == max)? "large" : "small", res);
+ }
rc = 0;
*int_ptr = res;
}
@@ -76,8 +83,8 @@ set_uint(vector strvec, void *ptr, const char *file, int line_nr)
while (isspace(*eptr))
eptr++;
if (*buff == '\0' || *eptr != '\0' || !isdigit(*p) || res > UINT_MAX) {
- condlog(1, "%s: invalid value for %s: \"%s\"",
- __func__, (char*)VECTOR_SLOT(strvec, 0), buff);
+ condlog(1, "%s line %d, invalid value for %s: \"%s\"",
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff);
rc = 1;
} else {
rc = 0;
@@ -246,6 +253,14 @@ def_ ## option ## _handler (struct config *conf, vector strvec, \
return function (strvec, &conf->option, file, line_nr); \
}
+#define declare_def_range_handler(option, minval, maxval) \
+static int \
+def_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
+{ \
+ return set_int(strvec, &conf->option, minval, maxval, file, line_nr); \
+}
+
#define declare_def_snprint(option, function) \
static int \
snprint_def_ ## option (struct config *conf, char * buff, int len, \
@@ -287,6 +302,18 @@ hw_ ## option ## _handler (struct config *conf, vector strvec, \
return function (strvec, &hwe->option, file, line_nr); \
}
+#define declare_hw_range_handler(option, minval, maxval) \
+static int \
+hw_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
+{ \
+ struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable); \
+ if (!hwe) \
+ return 1; \
+ return set_int(strvec, &hwe->option, minval, maxval, file, line_nr); \
+}
+
+
#define declare_hw_snprint(option, function) \
static int \
snprint_hw_ ## option (struct config *conf, char * buff, int len, \
@@ -306,6 +333,17 @@ ovr_ ## option ## _handler (struct config *conf, vector strvec, \
return function (strvec, &conf->overrides->option, file, line_nr); \
}
+#define declare_ovr_range_handler(option, minval, maxval) \
+static int \
+ovr_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
+{ \
+ if (!conf->overrides) \
+ return 1; \
+ return set_int(strvec, &conf->overrides->option, minval, maxval, \
+ file, line_nr); \
+}
+
#define declare_ovr_snprint(option, function) \
static int \
snprint_ovr_ ## option (struct config *conf, char * buff, int len, \
@@ -325,6 +363,17 @@ mp_ ## option ## _handler (struct config *conf, vector strvec, \
return function (strvec, &mpe->option, file, line_nr); \
}
+#define declare_mp_range_handler(option, minval, maxval) \
+static int \
+mp_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
+{ \
+ struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable); \
+ if (!mpe) \
+ return 1; \
+ return set_int(strvec, &mpe->option, minval, maxval, file, line_nr); \
+}
+
#define declare_mp_snprint(option, function) \
static int \
snprint_mp_ ## option (struct config *conf, char * buff, int len, \
@@ -351,7 +400,7 @@ declare_def_snprint(checkint, print_int)
declare_def_handler(max_checkint, set_uint)
declare_def_snprint(max_checkint, print_int)
-declare_def_handler(verbosity, set_int)
+declare_def_range_handler(verbosity, 0, MAX_VERBOSITY)
declare_def_snprint(verbosity, print_int)
declare_def_handler(reassign_maps, set_yes_no)
@@ -528,22 +577,22 @@ declare_ovr_snprint(checker_name, print_str)
declare_hw_handler(checker_name, set_str)
declare_hw_snprint(checker_name, print_str)
-declare_def_handler(minio, set_int)
+declare_def_range_handler(minio, 0, INT_MAX)
declare_def_snprint_defint(minio, print_int, DEFAULT_MINIO)
-declare_ovr_handler(minio, set_int)
+declare_ovr_range_handler(minio, 0, INT_MAX)
declare_ovr_snprint(minio, print_nonzero)
-declare_hw_handler(minio, set_int)
+declare_hw_range_handler(minio, 0, INT_MAX)
declare_hw_snprint(minio, print_nonzero)
-declare_mp_handler(minio, set_int)
+declare_mp_range_handler(minio, 0, INT_MAX)
declare_mp_snprint(minio, print_nonzero)
-declare_def_handler(minio_rq, set_int)
+declare_def_range_handler(minio_rq, 0, INT_MAX)
declare_def_snprint_defint(minio_rq, print_int, DEFAULT_MINIO_RQ)
-declare_ovr_handler(minio_rq, set_int)
+declare_ovr_range_handler(minio_rq, 0, INT_MAX)
declare_ovr_snprint(minio_rq, print_nonzero)
-declare_hw_handler(minio_rq, set_int)
+declare_hw_range_handler(minio_rq, 0, INT_MAX)
declare_hw_snprint(minio_rq, print_nonzero)
-declare_mp_handler(minio_rq, set_int)
+declare_mp_range_handler(minio_rq, 0, INT_MAX)
declare_mp_snprint(minio_rq, print_nonzero)
declare_def_handler(queue_without_daemon, set_yes_no)
@@ -562,7 +611,7 @@ snprint_def_queue_without_daemon (struct config *conf,
return 0;
}
-declare_def_handler(checker_timeout, set_int)
+declare_def_range_handler(checker_timeout, 0, INT_MAX)
declare_def_snprint(checker_timeout, print_nonzero)
declare_def_handler(flush_on_last_del, set_yes_no_undef)
@@ -630,13 +679,13 @@ declare_hw_snprint(deferred_remove, print_yes_no_undef)
declare_mp_handler(deferred_remove, set_yes_no_undef)
declare_mp_snprint(deferred_remove, print_yes_no_undef)
-declare_def_handler(retrigger_tries, set_int)
+declare_def_range_handler(retrigger_tries, 0, INT_MAX)
declare_def_snprint(retrigger_tries, print_int)
-declare_def_handler(retrigger_delay, set_int)
+declare_def_range_handler(retrigger_delay, 0, INT_MAX)
declare_def_snprint(retrigger_delay, print_int)
-declare_def_handler(uev_wait_timeout, set_int)
+declare_def_range_handler(uev_wait_timeout, 0, INT_MAX)
declare_def_snprint(uev_wait_timeout, print_int)
declare_def_handler(strict_timing, set_yes_no)
@@ -662,19 +711,19 @@ static int snprint_def_disable_changed_wwids(struct config *conf, char *buff,
return print_ignored(buff, len);
}
-declare_def_handler(remove_retries, set_int)
+declare_def_range_handler(remove_retries, 0, INT_MAX)
declare_def_snprint(remove_retries, print_int)
-declare_def_handler(max_sectors_kb, set_int)
+declare_def_range_handler(max_sectors_kb, 0, INT_MAX)
declare_def_snprint(max_sectors_kb, print_nonzero)
-declare_ovr_handler(max_sectors_kb, set_int)
+declare_ovr_range_handler(max_sectors_kb, 0, INT_MAX)
declare_ovr_snprint(max_sectors_kb, print_nonzero)
-declare_hw_handler(max_sectors_kb, set_int)
+declare_hw_range_handler(max_sectors_kb, 0, INT_MAX)
declare_hw_snprint(max_sectors_kb, print_nonzero)
-declare_mp_handler(max_sectors_kb, set_int)
+declare_mp_range_handler(max_sectors_kb, 0, INT_MAX)
declare_mp_snprint(max_sectors_kb, print_nonzero)
-declare_def_handler(find_multipaths_timeout, set_int)
+declare_def_range_handler(find_multipaths_timeout, INT_MIN, INT_MAX)
declare_def_snprint_defint(find_multipaths_timeout, print_int,
DEFAULT_FIND_MULTIPATHS_TIMEOUT)
@@ -1437,27 +1486,7 @@ declare_ovr_snprint(recheck_wwid, print_yes_no_undef)
declare_hw_handler(recheck_wwid, set_yes_no_undef)
declare_hw_snprint(recheck_wwid, print_yes_no_undef)
-
-static int
-def_uxsock_timeout_handler(struct config *conf, vector strvec, const char *file,
- int line_nr)
-{
- unsigned int uxsock_timeout;
- char *buff;
-
- buff = set_value(strvec);
- if (!buff)
- return 1;
-
- if (sscanf(buff, "%u", &uxsock_timeout) == 1 &&
- uxsock_timeout > DEFAULT_REPLY_TIMEOUT)
- conf->uxsock_timeout = uxsock_timeout;
- else
- conf->uxsock_timeout = DEFAULT_REPLY_TIMEOUT;
-
- free(buff);
- return 0;
-}
+declare_def_range_handler(uxsock_timeout, DEFAULT_REPLY_TIMEOUT, INT_MAX)
static int
hw_vpd_vendor_handler(struct config *conf, vector strvec, const char *file,

View File

@ -0,0 +1,177 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 29 Sep 2021 12:56:04 -0500
Subject: [PATCH] libmultipath: improve checks for set_str
multipath always requires absolute pathnames, so make sure all file and
directory names start with a slash. Also check that the directories
exist. Finally, some strings, like the alias, will be used in paths.
These must not contain the slash character '/', since it is a forbidden
character in file/directory names. This patch adds seperate handlers for
these three cases. If a config line is invalid, these handlers retain
the existing config string, if any.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/dict.c | 89 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 78 insertions(+), 11 deletions(-)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 686f4d5c..d547d898 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -5,6 +5,8 @@
* Copyright (c) 2005 Kiyoshi Ueda, NEC
*/
#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include <pwd.h>
#include <string.h>
#include "checkers.h"
@@ -121,7 +123,72 @@ set_regex(vector strvec, void *ptr, const char *file, int line_nr)
if (!*str_ptr)
return 1;
+ return 0;
+}
+static int
+set_dir(vector strvec, void *ptr, const char *file, int line_nr)
+{
+ char **str_ptr = (char **)ptr;
+ char *old_str = *str_ptr;
+ struct stat sb;
+
+ *str_ptr = set_value(strvec);
+ if (!*str_ptr) {
+ free(old_str);
+ return 1;
+ }
+ if ((*str_ptr)[0] != '/'){
+ condlog(1, "%s line %d, %s is not an absolute directory path. Ignoring", file, line_nr, *str_ptr);
+ *str_ptr = old_str;
+ } else {
+ if (stat(*str_ptr, &sb) == 0 && S_ISDIR(sb.st_mode))
+ free(old_str);
+ else {
+ condlog(1, "%s line %d, %s is not an existing directory. Ignoring", file, line_nr, *str_ptr);
+ *str_ptr = old_str;
+ }
+ }
+ return 0;
+}
+
+static int
+set_path(vector strvec, void *ptr, const char *file, int line_nr)
+{
+ char **str_ptr = (char **)ptr;
+ char *old_str = *str_ptr;
+
+ *str_ptr = set_value(strvec);
+ if (!*str_ptr) {
+ free(old_str);
+ return 1;
+ }
+ if ((*str_ptr)[0] != '/'){
+ condlog(1, "%s line %d, %s is not an absolute path. Ignoring",
+ file, line_nr, *str_ptr);
+ *str_ptr = old_str;
+ } else
+ free(old_str);
+ return 0;
+}
+
+static int
+set_str_noslash(vector strvec, void *ptr, const char *file, int line_nr)
+{
+ char **str_ptr = (char **)ptr;
+ char *old_str = *str_ptr;
+
+ *str_ptr = set_value(strvec);
+ if (!*str_ptr) {
+ free(old_str);
+ return 1;
+ }
+ if (strchr(*str_ptr, '/')) {
+ condlog(1, "%s line %d, %s cannot contain a slash. Ignoring",
+ file, line_nr, *str_ptr);
+ *str_ptr = old_str;
+ } else
+ free(old_str);
return 0;
}
@@ -400,19 +467,19 @@ declare_def_snprint(checkint, print_int)
declare_def_handler(max_checkint, set_uint)
declare_def_snprint(max_checkint, print_int)
-declare_def_range_handler(verbosity, 0, MAX_VERBOSITY)
+declare_def_range_handler(verbosity, 0, 4)
declare_def_snprint(verbosity, print_int)
declare_def_handler(reassign_maps, set_yes_no)
declare_def_snprint(reassign_maps, print_yes_no)
-declare_def_handler(multipath_dir, set_str)
+declare_def_handler(multipath_dir, set_dir)
declare_def_snprint(multipath_dir, print_str)
static int def_partition_delim_handler(struct config *conf, vector strvec,
const char *file, int line_nr)
{
- int rc = set_str(strvec, &conf->partition_delim, file, line_nr);
+ int rc = set_str_noslash(strvec, &conf->partition_delim, file, line_nr);
if (rc != 0)
return rc;
@@ -545,11 +612,11 @@ declare_hw_snprint(prio_name, print_str)
declare_mp_handler(prio_name, set_str)
declare_mp_snprint(prio_name, print_str)
-declare_def_handler(alias_prefix, set_str)
+declare_def_handler(alias_prefix, set_str_noslash)
declare_def_snprint_defstr(alias_prefix, print_str, DEFAULT_ALIAS_PREFIX)
-declare_ovr_handler(alias_prefix, set_str)
+declare_ovr_handler(alias_prefix, set_str_noslash)
declare_ovr_snprint(alias_prefix, print_str)
-declare_hw_handler(alias_prefix, set_str)
+declare_hw_handler(alias_prefix, set_str_noslash)
declare_hw_snprint(alias_prefix, print_str)
declare_def_handler(prio_args, set_str)
@@ -633,13 +700,13 @@ declare_hw_snprint(user_friendly_names, print_yes_no_undef)
declare_mp_handler(user_friendly_names, set_yes_no_undef)
declare_mp_snprint(user_friendly_names, print_yes_no_undef)
-declare_def_handler(bindings_file, set_str)
+declare_def_handler(bindings_file, set_path)
declare_def_snprint(bindings_file, print_str)
-declare_def_handler(wwids_file, set_str)
+declare_def_handler(wwids_file, set_path)
declare_def_snprint(wwids_file, print_str)
-declare_def_handler(prkeys_file, set_str)
+declare_def_handler(prkeys_file, set_path)
declare_def_snprint(prkeys_file, print_str)
declare_def_handler(retain_hwhandler, set_yes_no_undef)
@@ -738,7 +805,7 @@ def_config_dir_handler(struct config *conf, vector strvec, const char *file,
/* this is only valid in the main config file */
if (conf->processed_main_config)
return 0;
- return set_str(strvec, &conf->config_dir, file, line_nr);
+ return set_path(strvec, &conf->config_dir, file, line_nr);
}
declare_def_snprint(config_dir, print_str)
@@ -1781,7 +1848,7 @@ multipath_handler(struct config *conf, vector strvec, const char *file,
declare_mp_handler(wwid, set_str)
declare_mp_snprint(wwid, print_str)
-declare_mp_handler(alias, set_str)
+declare_mp_handler(alias, set_str_noslash)
declare_mp_snprint(alias, print_str)
/*

View File

@ -0,0 +1,191 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 4 Oct 2021 15:27:36 -0500
Subject: [PATCH] libmultipath: split set_int to enable reuse
Split the code that does the actual value parsing out of set_int(), into
a helper function, do_set_int(), so that it can be used by other
handlers. These functions no longer set the config value at all, when
they have invalid input.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/dict.c | 82 +++++++++++++++++++++++++--------------------
1 file changed, 46 insertions(+), 36 deletions(-)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index d547d898..6330836a 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -30,17 +30,12 @@
#include "dict.h"
static int
-set_int(vector strvec, void *ptr, int min, int max, const char *file,
- int line_nr)
+do_set_int(vector strvec, void *ptr, int min, int max, const char *file,
+ int line_nr, char *buff)
{
int *int_ptr = (int *)ptr;
- char *buff, *eptr;
+ char *eptr;
long res;
- int rc;
-
- buff = set_value(strvec);
- if (!buff)
- return 1;
res = strtol(buff, &eptr, 10);
if (eptr > buff)
@@ -49,17 +44,30 @@ set_int(vector strvec, void *ptr, int min, int max, const char *file,
if (*buff == '\0' || *eptr != '\0') {
condlog(1, "%s line %d, invalid value for %s: \"%s\"",
file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff);
- rc = 1;
- } else {
- if (res > max || res < min) {
- res = (res > max) ? max : min;
- condlog(1, "%s line %d, value for %s too %s, capping at %ld",
+ return 1;
+ }
+ if (res > max || res < min) {
+ res = (res > max) ? max : min;
+ condlog(1, "%s line %d, value for %s too %s, capping at %ld",
file, line_nr, (char*)VECTOR_SLOT(strvec, 0),
- (res == max)? "large" : "small", res);
- }
- rc = 0;
- *int_ptr = res;
+ (res == max)? "large" : "small", res);
}
+ *int_ptr = res;
+ return 0;
+}
+
+static int
+set_int(vector strvec, void *ptr, int min, int max, const char *file,
+ int line_nr)
+{
+ char *buff;
+ int rc;
+
+ buff = set_value(strvec);
+ if (!buff)
+ return 1;
+
+ rc = do_set_int(strvec, ptr, min, max, file, line_nr, buff);
FREE(buff);
return rc;
@@ -965,6 +973,7 @@ declare_mp_attr_snprint(gid, print_gid)
static int
set_undef_off_zero(vector strvec, void *ptr, const char *file, int line_nr)
{
+ int rc = 0;
char * buff;
int *int_ptr = (int *)ptr;
@@ -974,10 +983,10 @@ set_undef_off_zero(vector strvec, void *ptr, const char *file, int line_nr)
if (strcmp(buff, "off") == 0)
*int_ptr = UOZ_OFF;
- else if (sscanf(buff, "%d", int_ptr) != 1 ||
- *int_ptr < UOZ_ZERO)
- *int_ptr = UOZ_UNDEF;
- else if (*int_ptr == 0)
+ else
+ rc = do_set_int(strvec, int_ptr, 0, INT_MAX, file, line_nr,
+ buff);
+ if (rc == 0 && *int_ptr == 0)
*int_ptr = UOZ_ZERO;
FREE(buff);
@@ -1130,14 +1139,12 @@ max_fds_handler(struct config *conf, vector strvec, const char *file,
/* Assume safe limit */
max_fds = 4096;
}
- if (strlen(buff) == 3 &&
- !strcmp(buff, "max"))
- conf->max_fds = max_fds;
- else
- conf->max_fds = atoi(buff);
-
- if (conf->max_fds > max_fds)
+ if (!strcmp(buff, "max")) {
conf->max_fds = max_fds;
+ r = 0;
+ } else
+ r = do_set_int(strvec, &conf->max_fds, 0, max_fds, file,
+ line_nr, buff);
FREE(buff);
@@ -1206,6 +1213,7 @@ declare_mp_snprint(rr_weight, print_rr_weight)
static int
set_pgfailback(vector strvec, void *ptr, const char *file, int line_nr)
{
+ int rc = 0;
int *int_ptr = (int *)ptr;
char * buff;
@@ -1220,11 +1228,11 @@ set_pgfailback(vector strvec, void *ptr, const char *file, int line_nr)
else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
*int_ptr = -FAILBACK_FOLLOWOVER;
else
- *int_ptr = atoi(buff);
+ rc = do_set_int(strvec, ptr, 0, INT_MAX, file, line_nr, buff);
FREE(buff);
- return 0;
+ return rc;
}
int
@@ -1256,6 +1264,7 @@ declare_mp_snprint(pgfailback, print_pgfailback)
static int
no_path_retry_helper(vector strvec, void *ptr, const char *file, int line_nr)
{
+ int rc = 0;
int *int_ptr = (int *)ptr;
char * buff;
@@ -1267,11 +1276,11 @@ no_path_retry_helper(vector strvec, void *ptr, const char *file, int line_nr)
*int_ptr = NO_PATH_RETRY_FAIL;
else if (!strcmp(buff, "queue"))
*int_ptr = NO_PATH_RETRY_QUEUE;
- else if ((*int_ptr = atoi(buff)) < 1)
- *int_ptr = NO_PATH_RETRY_UNDEF;
+ else
+ rc = do_set_int(strvec, ptr, 1, INT_MAX, file, line_nr, buff);
FREE(buff);
- return 0;
+ return rc;
}
int
@@ -1416,6 +1425,7 @@ snprint_mp_reservation_key (struct config *conf, char * buff, int len,
static int
set_off_int_undef(vector strvec, void *ptr, const char *file, int line_nr)
{
+ int rc =0;
int *int_ptr = (int *)ptr;
char * buff;
@@ -1425,11 +1435,11 @@ set_off_int_undef(vector strvec, void *ptr, const char *file, int line_nr)
if (!strcmp(buff, "no") || !strcmp(buff, "0"))
*int_ptr = NU_NO;
- else if ((*int_ptr = atoi(buff)) < 1)
- *int_ptr = NU_UNDEF;
+ else
+ rc = do_set_int(strvec, ptr, 1, INT_MAX, file, line_nr, buff);
FREE(buff);
- return 0;
+ return rc;
}
int

View File

@ -0,0 +1,201 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 4 Oct 2021 16:52:55 -0500
Subject: [PATCH] libmultipath: cleanup invalid config handling
Add error reporting to the remaining config handlers. If the value is
invalid, do not change the existing config option's value. Also print
an error whenever 0 is returned for an invalid value. When the handler
returns 1, config processing already fails with an error message.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/dict.c | 73 +++++++++++++++++++++++++++++++--------------
1 file changed, 51 insertions(+), 22 deletions(-)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 6330836a..b255322e 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -212,8 +212,11 @@ set_yes_no(vector strvec, void *ptr, const char *file, int line_nr)
if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
*int_ptr = YN_YES;
- else
+ else if (strcmp(buff, "no") == 0 || strcmp(buff, "0") == 0)
*int_ptr = YN_NO;
+ else
+ condlog(1, "%s line %d, invalid value for %s: \"%s\"",
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff);
FREE(buff);
return 0;
@@ -234,7 +237,8 @@ set_yes_no_undef(vector strvec, void *ptr, const char *file, int line_nr)
else if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
*int_ptr = YNU_YES;
else
- *int_ptr = YNU_UNDEF;
+ condlog(1, "%s line %d, invalid value for %s: \"%s\"",
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff);
FREE(buff);
return 0;
@@ -523,9 +527,6 @@ def_find_multipaths_handler(struct config *conf, vector strvec,
char *buff;
int i;
- if (set_yes_no_undef(strvec, &conf->find_multipaths, file, line_nr) == 0 && conf->find_multipaths != FIND_MULTIPATHS_UNDEF)
- return 0;
-
buff = set_value(strvec);
if (!buff)
return 1;
@@ -538,9 +539,14 @@ def_find_multipaths_handler(struct config *conf, vector strvec,
}
}
- if (conf->find_multipaths == YNU_UNDEF) {
- condlog(0, "illegal value for find_multipaths: %s", buff);
- conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
+ if (i >= __FIND_MULTIPATHS_LAST) {
+ if (strcmp(buff, "no") == 0 || strcmp(buff, "0") == 0)
+ conf->find_multipaths = FIND_MULTIPATHS_OFF;
+ else if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
+ conf->find_multipaths = FIND_MULTIPATHS_ON;
+ else
+ condlog(1, "%s line %d, invalid value for find_multipaths: \"%s\"",
+ file, line_nr, buff);
}
FREE(buff);
@@ -591,8 +597,10 @@ static int uid_attrs_handler(struct config *conf, vector strvec,
if (!val)
return 1;
if (parse_uid_attrs(val, conf))
- condlog(1, "error parsing uid_attrs: \"%s\"", val);
- condlog(3, "parsed %d uid_attrs", VECTOR_SIZE(&conf->uid_attrs));
+ condlog(1, "%s line %d,error parsing uid_attrs: \"%s\"", file,
+ line_nr, val);
+ else
+ condlog(4, "parsed %d uid_attrs", VECTOR_SIZE(&conf->uid_attrs));
FREE(val);
return 0;
}
@@ -811,8 +819,11 @@ def_config_dir_handler(struct config *conf, vector strvec, const char *file,
int line_nr)
{
/* this is only valid in the main config file */
- if (conf->processed_main_config)
+ if (conf->processed_main_config) {
+ condlog(1, "%s line %d, config_dir option only valid in /etc/multipath.conf",
+ file, line_nr);
return 0;
+ }
return set_path(strvec, &conf->config_dir, file, line_nr);
}
declare_def_snprint(config_dir, print_str)
@@ -872,7 +883,9 @@ set_mode(vector strvec, void *ptr, int *flags, const char *file, int line_nr)
if (sscanf(buff, "%o", &mode) == 1 && mode <= 0777) {
*flags |= (1 << ATTR_MODE);
*mode_ptr = mode;
- }
+ } else
+ condlog(1, "%s line %d, invalid value for mode: \"%s\"",
+ file, line_nr, buff);
FREE(buff);
return 0;
@@ -897,7 +910,9 @@ set_uid(vector strvec, void *ptr, int *flags, const char *file, int line_nr)
else if (sscanf(buff, "%u", &uid) == 1){
*flags |= (1 << ATTR_UID);
*uid_ptr = uid;
- }
+ } else
+ condlog(1, "%s line %d, invalid value for uid: \"%s\"",
+ file, line_nr, buff);
FREE(buff);
return 0;
@@ -923,7 +938,9 @@ set_gid(vector strvec, void *ptr, int *flags, const char *file, int line_nr)
else if (sscanf(buff, "%u", &gid) == 1){
*flags |= (1 << ATTR_GID);
*gid_ptr = gid;
- }
+ } else
+ condlog(1, "%s line %d, invalid value for gid: \"%s\"",
+ file, line_nr, buff);
FREE(buff);
return 0;
}
@@ -1026,7 +1043,8 @@ set_dev_loss(vector strvec, void *ptr, const char *file, int line_nr)
if (!strcmp(buff, "infinity"))
*uint_ptr = MAX_DEV_LOSS_TMO;
else if (sscanf(buff, "%u", uint_ptr) != 1)
- *uint_ptr = 0;
+ condlog(1, "%s line %d, invalid value for dev_loss_tmo: \"%s\"",
+ file, line_nr, buff);
FREE(buff);
return 0;
@@ -1060,13 +1078,19 @@ static int
set_pgpolicy(vector strvec, void *ptr, const char *file, int line_nr)
{
char * buff;
+ int policy;
int *int_ptr = (int *)ptr;
buff = set_value(strvec);
if (!buff)
return 1;
- *int_ptr = get_pgpolicy_id(buff);
+ policy = get_pgpolicy_id(buff);
+ if (policy != IOPOLICY_UNDEF)
+ *int_ptr = policy;
+ else
+ condlog(1, "%s line %d, invalid value for path_grouping_policy: \"%s\"",
+ file, line_nr, buff);
FREE(buff);
return 0;
@@ -1179,10 +1203,11 @@ set_rr_weight(vector strvec, void *ptr, const char *file, int line_nr)
if (!strcmp(buff, "priorities"))
*int_ptr = RR_WEIGHT_PRIO;
-
- if (!strcmp(buff, "uniform"))
+ else if (!strcmp(buff, "uniform"))
*int_ptr = RR_WEIGHT_NONE;
-
+ else
+ condlog(1, "%s line %d, invalid value for rr_weight: \"%s\"",
+ file, line_nr, buff);
FREE(buff);
return 0;
@@ -1318,10 +1343,13 @@ def_log_checker_err_handler(struct config *conf, vector strvec,
if (!buff)
return 1;
- if (strlen(buff) == 4 && !strcmp(buff, "once"))
+ if (!strcmp(buff, "once"))
conf->log_checker_err = LOG_CHKR_ERR_ONCE;
- else if (strlen(buff) == 6 && !strcmp(buff, "always"))
+ else if (!strcmp(buff, "always"))
conf->log_checker_err = LOG_CHKR_ERR_ALWAYS;
+ else
+ condlog(1, "%s line %d, invalid value for log_checker_err: \"%s\"",
+ file, line_nr, buff);
free(buff);
return 0;
@@ -1585,7 +1613,8 @@ hw_vpd_vendor_handler(struct config *conf, vector strvec, const char *file,
goto out;
}
}
- hwe->vpd_vendor_id = 0;
+ condlog(1, "%s line %d, invalid value for vpd_vendor: \"%s\"",
+ file, line_nr, buff);
out:
FREE(buff);
return 0;

View File

@ -0,0 +1,218 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 11 Nov 2021 17:37:05 -0600
Subject: [PATCH] libmultipath: don't return error on invalid values
do_set_int and set_uint return 1 for invalid values. This can cause
multipath to fail completely, while reading the config. The config
handlers should only return a non-zero value if there is an internal
error, not if there is just an invalid value.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/dict.c | 64 ++++++++++++++++++---------------------------
1 file changed, 25 insertions(+), 39 deletions(-)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index b255322e..5a0255b0 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -29,7 +29,7 @@
#include "mpath_cmd.h"
#include "dict.h"
-static int
+static void
do_set_int(vector strvec, void *ptr, int min, int max, const char *file,
int line_nr, char *buff)
{
@@ -44,7 +44,7 @@ do_set_int(vector strvec, void *ptr, int min, int max, const char *file,
if (*buff == '\0' || *eptr != '\0') {
condlog(1, "%s line %d, invalid value for %s: \"%s\"",
file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff);
- return 1;
+ return;
}
if (res > max || res < min) {
res = (res > max) ? max : min;
@@ -53,7 +53,7 @@ do_set_int(vector strvec, void *ptr, int min, int max, const char *file,
(res == max)? "large" : "small", res);
}
*int_ptr = res;
- return 0;
+ return;
}
static int
@@ -61,16 +61,15 @@ set_int(vector strvec, void *ptr, int min, int max, const char *file,
int line_nr)
{
char *buff;
- int rc;
buff = set_value(strvec);
if (!buff)
return 1;
- rc = do_set_int(strvec, ptr, min, max, file, line_nr, buff);
+ do_set_int(strvec, ptr, min, max, file, line_nr, buff);
FREE(buff);
- return rc;
+ return 0;
}
static int
@@ -79,7 +78,6 @@ set_uint(vector strvec, void *ptr, const char *file, int line_nr)
unsigned int *uint_ptr = (unsigned int *)ptr;
char *buff, *eptr, *p;
unsigned long res;
- int rc;
buff = set_value(strvec);
if (!buff)
@@ -92,17 +90,14 @@ set_uint(vector strvec, void *ptr, const char *file, int line_nr)
if (eptr > buff)
while (isspace(*eptr))
eptr++;
- if (*buff == '\0' || *eptr != '\0' || !isdigit(*p) || res > UINT_MAX) {
+ if (*buff == '\0' || *eptr != '\0' || !isdigit(*p) || res > UINT_MAX)
condlog(1, "%s line %d, invalid value for %s: \"%s\"",
file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff);
- rc = 1;
- } else {
- rc = 0;
+ else
*uint_ptr = res;
- }
FREE(buff);
- return rc;
+ return 0;
}
static int
@@ -990,7 +985,6 @@ declare_mp_attr_snprint(gid, print_gid)
static int
set_undef_off_zero(vector strvec, void *ptr, const char *file, int line_nr)
{
- int rc = 0;
char * buff;
int *int_ptr = (int *)ptr;
@@ -1000,11 +994,10 @@ set_undef_off_zero(vector strvec, void *ptr, const char *file, int line_nr)
if (strcmp(buff, "off") == 0)
*int_ptr = UOZ_OFF;
- else
- rc = do_set_int(strvec, int_ptr, 0, INT_MAX, file, line_nr,
- buff);
- if (rc == 0 && *int_ptr == 0)
+ else if (strcmp(buff, "0") == 0)
*int_ptr = UOZ_ZERO;
+ else
+ do_set_int(strvec, int_ptr, 1, INT_MAX, file, line_nr, buff);
FREE(buff);
return 0;
@@ -1151,28 +1144,24 @@ max_fds_handler(struct config *conf, vector strvec, const char *file,
int line_nr)
{
char * buff;
- int r = 0, max_fds;
+ int max_fds;
buff = set_value(strvec);
if (!buff)
return 1;
- r = get_sys_max_fds(&max_fds);
- if (r) {
- /* Assume safe limit */
- max_fds = 4096;
- }
- if (!strcmp(buff, "max")) {
+ if (get_sys_max_fds(&max_fds) != 0)
+ max_fds = 4096; /* Assume safe limit */
+ if (!strcmp(buff, "max"))
conf->max_fds = max_fds;
- r = 0;
- } else
- r = do_set_int(strvec, &conf->max_fds, 0, max_fds, file,
- line_nr, buff);
+ else
+ do_set_int(strvec, &conf->max_fds, 0, max_fds, file, line_nr,
+ buff);
FREE(buff);
- return r;
+ return 0;
}
static int
@@ -1238,7 +1227,6 @@ declare_mp_snprint(rr_weight, print_rr_weight)
static int
set_pgfailback(vector strvec, void *ptr, const char *file, int line_nr)
{
- int rc = 0;
int *int_ptr = (int *)ptr;
char * buff;
@@ -1253,11 +1241,11 @@ set_pgfailback(vector strvec, void *ptr, const char *file, int line_nr)
else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
*int_ptr = -FAILBACK_FOLLOWOVER;
else
- rc = do_set_int(strvec, ptr, 0, INT_MAX, file, line_nr, buff);
+ do_set_int(strvec, ptr, 0, INT_MAX, file, line_nr, buff);
FREE(buff);
- return rc;
+ return 0;
}
int
@@ -1289,7 +1277,6 @@ declare_mp_snprint(pgfailback, print_pgfailback)
static int
no_path_retry_helper(vector strvec, void *ptr, const char *file, int line_nr)
{
- int rc = 0;
int *int_ptr = (int *)ptr;
char * buff;
@@ -1302,10 +1289,10 @@ no_path_retry_helper(vector strvec, void *ptr, const char *file, int line_nr)
else if (!strcmp(buff, "queue"))
*int_ptr = NO_PATH_RETRY_QUEUE;
else
- rc = do_set_int(strvec, ptr, 1, INT_MAX, file, line_nr, buff);
+ do_set_int(strvec, ptr, 1, INT_MAX, file, line_nr, buff);
FREE(buff);
- return rc;
+ return 0;
}
int
@@ -1453,7 +1440,6 @@ snprint_mp_reservation_key (struct config *conf, char * buff, int len,
static int
set_off_int_undef(vector strvec, void *ptr, const char *file, int line_nr)
{
- int rc =0;
int *int_ptr = (int *)ptr;
char * buff;
@@ -1464,10 +1450,10 @@ set_off_int_undef(vector strvec, void *ptr, const char *file, int line_nr)
if (!strcmp(buff, "no") || !strcmp(buff, "0"))
*int_ptr = NU_NO;
else
- rc = do_set_int(strvec, ptr, 1, INT_MAX, file, line_nr, buff);
+ do_set_int(strvec, ptr, 1, INT_MAX, file, line_nr, buff);
FREE(buff);
- return rc;
+ return 0;
}
int

View File

@ -0,0 +1,115 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 15 Nov 2021 10:54:35 -0600
Subject: [PATCH] multipathd: avoid unnecessary path read-only reloads
A mulitpath device can only be reloaded read/write when all paths are
read/write. Also, whenever a read-only device is rescanned, the scsi
subsystem will first unconditionally issue a uevent with DISK_RO=0
before checking the read-only status, and if it the device is still
read-only, issuing another uevent with DISK_RO=1. These uevents cause
pointless reloads when read-only paths are rescanned. To avoid this,
check to see if all paths are read/write before changing a multipath
device from read-only to read/write.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/sysfs.c | 22 ++++++++++++++++++++++
libmultipath/sysfs.h | 1 +
multipathd/main.c | 31 ++++++++++++++++++++++++++++++-
3 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c
index 62ec2ed7..a57bd60e 100644
--- a/libmultipath/sysfs.c
+++ b/libmultipath/sysfs.c
@@ -236,6 +236,28 @@ sysfs_get_size (struct path *pp, unsigned long long * size)
return 0;
}
+int
+sysfs_get_ro (struct path *pp)
+{
+ int ro;
+ char buff[3]; /* Either "0\n\0" or "1\n\0" */
+
+ if (!pp->udev)
+ return -1;
+
+ if (sysfs_attr_get_value(pp->udev, "ro", buff, sizeof(buff)) <= 0) {
+ condlog(3, "%s: Cannot read ro attribute in sysfs", pp->dev);
+ return -1;
+ }
+
+ if (sscanf(buff, "%d\n", &ro) != 1 || ro < 0 || ro > 1) {
+ condlog(3, "%s: Cannot parse ro attribute", pp->dev);
+ return -1;
+ }
+
+ return ro;
+}
+
int sysfs_check_holders(char * check_devt, char * new_devt)
{
unsigned int major, new_minor, table_minor;
diff --git a/libmultipath/sysfs.h b/libmultipath/sysfs.h
index 9ae30b39..91092e44 100644
--- a/libmultipath/sysfs.h
+++ b/libmultipath/sysfs.h
@@ -13,6 +13,7 @@ ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name,
ssize_t sysfs_bin_attr_get_value(struct udev_device *dev, const char *attr_name,
unsigned char * value, size_t value_len);
int sysfs_get_size (struct path *pp, unsigned long long * size);
+int sysfs_get_ro(struct path *pp);
int sysfs_check_holders(char * check_devt, char * new_devt);
bool sysfs_is_multipathed(const struct path *pp);
#endif
diff --git a/multipathd/main.c b/multipathd/main.c
index 823b53a2..e2b9d546 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -1256,6 +1256,35 @@ fail:
return PATH_REMOVE_FAILED;
}
+static bool
+needs_ro_update(struct multipath *mpp, int ro)
+{
+ struct pathgroup * pgp;
+ struct path * pp;
+ unsigned int i, j;
+ struct dm_info *dmi = NULL;
+
+ if (!mpp || ro < 0)
+ return false;
+ dm_get_info(mpp->alias, &dmi);
+ if (!dmi) /* assume we do need to reload the device */
+ return true;
+ if (dmi->read_only == ro) {
+ free(dmi);
+ return false;
+ }
+ free(dmi);
+ if (ro == 1)
+ return true;
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ vector_foreach_slot (pgp->paths, pp, j) {
+ if (sysfs_get_ro(pp) == 1)
+ return false;
+ }
+ }
+ return true;
+}
+
static int
uev_update_path (struct uevent *uev, struct vectors * vecs)
{
@@ -1321,7 +1350,7 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
}
ro = uevent_get_disk_ro(uev);
- if (mpp && ro >= 0) {
+ if (needs_ro_update(mpp, ro)) {
condlog(2, "%s: update path write_protect to '%d' (uevent)", uev->kernel, ro);
if (mpp->wait_for_udev)

View File

@ -0,0 +1,133 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 17 Jan 2022 14:45:38 -0600
Subject: [PATCH] libmultipath: make helper function to trigger path uevents
Pull the code that checks if a path needs to trigger a uevent, and
triggers, out of trigger_paths_udev_change() and into a new function,
trigger_path_udev_change(). This function will be used separately by
a future patch. No functional changes.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/configure.c | 79 +++++++++++++++++++++-------------------
libmultipath/configure.h | 1 +
2 files changed, 43 insertions(+), 37 deletions(-)
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 9c8d3e34..9a9890f5 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -545,11 +545,8 @@ unref:
}
void
-trigger_paths_udev_change(struct multipath *mpp, bool is_mpath)
+trigger_path_udev_change(struct path *pp, bool is_mpath)
{
- struct pathgroup *pgp;
- struct path *pp;
- int i, j;
/*
* If a path changes from multipath to non-multipath, we must
* synthesize an artificial "add" event, otherwise the LVM2 rules
@@ -557,6 +554,45 @@ trigger_paths_udev_change(struct multipath *mpp, bool is_mpath)
* irritate ourselves with an "add", so use "change".
*/
const char *action = is_mpath ? "change" : "add";
+ const char *env;
+
+ if (!pp->udev)
+ return;
+ /*
+ * Paths that are already classified as multipath
+ * members don't need another uevent.
+ */
+ env = udev_device_get_property_value(
+ pp->udev, "DM_MULTIPATH_DEVICE_PATH");
+
+ if (is_mpath && env != NULL && !strcmp(env, "1")) {
+ /*
+ * If FIND_MULTIPATHS_WAIT_UNTIL is not "0",
+ * path is in "maybe" state and timer is running
+ * Send uevent now (see multipath.rules).
+ */
+ env = udev_device_get_property_value(
+ pp->udev, "FIND_MULTIPATHS_WAIT_UNTIL");
+ if (env == NULL || !strcmp(env, "0"))
+ return;
+ } else if (!is_mpath &&
+ (env == NULL || !strcmp(env, "0")))
+ return;
+
+ condlog(3, "triggering %s uevent for %s (is %smultipath member)",
+ action, pp->dev, is_mpath ? "" : "no ");
+ sysfs_attr_set_value(pp->udev, "uevent",
+ action, strlen(action));
+ trigger_partitions_udev_change(pp->udev, action,
+ strlen(action));
+}
+
+void
+trigger_paths_udev_change(struct multipath *mpp, bool is_mpath)
+{
+ struct pathgroup *pgp;
+ struct path *pp;
+ int i, j;
if (!mpp || !mpp->pg)
return;
@@ -564,39 +600,8 @@ trigger_paths_udev_change(struct multipath *mpp, bool is_mpath)
vector_foreach_slot (mpp->pg, pgp, i) {
if (!pgp->paths)
continue;
- vector_foreach_slot(pgp->paths, pp, j) {
- const char *env;
-
- if (!pp->udev)
- continue;
- /*
- * Paths that are already classified as multipath
- * members don't need another uevent.
- */
- env = udev_device_get_property_value(
- pp->udev, "DM_MULTIPATH_DEVICE_PATH");
-
- if (is_mpath && env != NULL && !strcmp(env, "1")) {
- /*
- * If FIND_MULTIPATHS_WAIT_UNTIL is not "0",
- * path is in "maybe" state and timer is running
- * Send uevent now (see multipath.rules).
- */
- env = udev_device_get_property_value(
- pp->udev, "FIND_MULTIPATHS_WAIT_UNTIL");
- if (env == NULL || !strcmp(env, "0"))
- continue;
- } else if (!is_mpath &&
- (env == NULL || !strcmp(env, "0")))
- continue;
-
- condlog(3, "triggering %s uevent for %s (is %smultipath member)",
- action, pp->dev, is_mpath ? "" : "no ");
- sysfs_attr_set_value(pp->udev, "uevent",
- action, strlen(action));
- trigger_partitions_udev_change(pp->udev, action,
- strlen(action));
- }
+ vector_foreach_slot(pgp->paths, pp, j)
+ trigger_path_udev_change(pp, is_mpath);
}
mpp->needs_paths_uevent = 0;
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
index 8a266d31..5cf08d45 100644
--- a/libmultipath/configure.h
+++ b/libmultipath/configure.h
@@ -56,6 +56,7 @@ 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);
struct udev_device *get_udev_device(const char *dev, enum devtypes dev_type);
+void trigger_path_udev_change(struct path *pp, bool is_mpath);
void trigger_paths_udev_change(struct multipath *mpp, bool is_mpath);
void trigger_partitions_udev_change(struct udev_device *dev, const char *action,
int len);

Some files were not shown because too many files have changed in this diff Show More