import device-mapper-multipath-0.8.7-20.el9
This commit is contained in:
parent
a617125e1e
commit
952c4628fa
@ -0,0 +1,35 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Fri, 5 Aug 2022 18:16:03 -0500
|
||||||
|
Subject: [PATCH] multipath: fix systemd timers in the initramfs
|
||||||
|
|
||||||
|
The systemd timers created for "find_multipaths smart" conflict with
|
||||||
|
shutdown.target, but not with initrd-cleanup.service. This can make
|
||||||
|
these timers trigger after the inirtd has started shutting down,
|
||||||
|
restarting multipathd (which then stops initrd-cleanup.service, since it
|
||||||
|
conflicts). To avoid this, make sure the timers and the unit they
|
||||||
|
trigger conflict with inird-cleanup.service. Also don't make them start
|
||||||
|
multipathd. "multipath -u" will not return "maybe" if multipathd isn't
|
||||||
|
running or set to run, and since we no longer wait for udev-settle,
|
||||||
|
multipathd starts up pretty quickly, so it shouldn't be a problem to
|
||||||
|
not trigger it here.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
multipath/multipath.rules | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/multipath/multipath.rules b/multipath/multipath.rules
|
||||||
|
index 0486bf70..68c30644 100644
|
||||||
|
--- a/multipath/multipath.rules
|
||||||
|
+++ b/multipath/multipath.rules
|
||||||
|
@@ -72,7 +72,7 @@ ENV{.SAVED_FM_WAIT_UNTIL}=="?*", GOTO="pretend_mpath"
|
||||||
|
#
|
||||||
|
# We must trigger an "add" event because LVM2 will only act on those.
|
||||||
|
|
||||||
|
-RUN+="/usr/bin/systemd-run --unit=cancel-multipath-wait-$kernel --description 'cancel waiting for multipath siblings of $kernel' --no-block --timer-property DefaultDependencies=no --timer-property Conflicts=shutdown.target --timer-property Before=shutdown.target --timer-property AccuracySec=500ms --property DefaultDependencies=no --property Conflicts=shutdown.target --property Before=shutdown.target --property Wants=multipathd.service --property After=multipathd.service --on-active=$env{FIND_MULTIPATHS_WAIT_UNTIL} /usr/bin/udevadm trigger --action=add $sys$devpath"
|
||||||
|
+RUN+="/usr/bin/systemd-run --unit=cancel-multipath-wait-$kernel --description 'cancel waiting for multipath siblings of $kernel' --no-block --timer-property DefaultDependencies=no --timer-property Conflicts=shutdown.target --timer-property Before=shutdown.target --timer-property Conflicts=initrd-cleanup.service --timer-property Before=initrd-cleanup.service --timer-property AccuracySec=500ms --property DefaultDependencies=no --property Conflicts=shutdown.target --property Before=shutdown.target --property Conflicts=initrd-cleanup.service --property Before=initrd-cleanup.service --on-active=$env{FIND_MULTIPATHS_WAIT_UNTIL} /usr/bin/udevadm trigger --action=add $sys$devpath"
|
||||||
|
|
||||||
|
LABEL="pretend_mpath"
|
||||||
|
ENV{DM_MULTIPATH_DEVICE_PATH}="1"
|
@ -0,0 +1,90 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Tue, 9 Aug 2022 16:46:26 -0500
|
||||||
|
Subject: [PATCH] multipathd: factor out the code to flush a map with no paths
|
||||||
|
|
||||||
|
The code to flush a multipath device because all of its paths have
|
||||||
|
been removed will be used by another caller, so factor it out of
|
||||||
|
ev_remove_path().
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
multipathd/main.c | 56 ++++++++++++++++++++++++-----------------------
|
||||||
|
1 file changed, 29 insertions(+), 27 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||||
|
index ed2515e5..b00eae3f 100644
|
||||||
|
--- a/multipathd/main.c
|
||||||
|
+++ b/multipathd/main.c
|
||||||
|
@@ -488,6 +488,30 @@ int update_multipath (struct vectors *vecs, char *mapname, int reset)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static bool
|
||||||
|
+flush_map_nopaths(struct multipath *mpp, struct vectors *vecs) {
|
||||||
|
+ char alias[WWID_SIZE];
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * flush_map will fail if the device is open
|
||||||
|
+ */
|
||||||
|
+ strlcpy(alias, mpp->alias, WWID_SIZE);
|
||||||
|
+ if (mpp->flush_on_last_del == FLUSH_ENABLED) {
|
||||||
|
+ condlog(2, "%s Last path deleted, disabling queueing",
|
||||||
|
+ mpp->alias);
|
||||||
|
+ mpp->retry_tick = 0;
|
||||||
|
+ mpp->no_path_retry = NO_PATH_RETRY_FAIL;
|
||||||
|
+ mpp->disable_queueing = 1;
|
||||||
|
+ mpp->stat_map_failures++;
|
||||||
|
+ dm_queue_if_no_path(mpp->alias, 0);
|
||||||
|
+ }
|
||||||
|
+ if (!flush_map(mpp, vecs, 1)) {
|
||||||
|
+ condlog(2, "%s: removed map after removing all paths", alias);
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+ return false;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int
|
||||||
|
update_map (struct multipath *mpp, struct vectors *vecs, int new_map)
|
||||||
|
{
|
||||||
|
@@ -1247,34 +1271,12 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map)
|
||||||
|
vector_del_slot(mpp->paths, i);
|
||||||
|
|
||||||
|
/*
|
||||||
|
- * remove the map IF removing the last path
|
||||||
|
+ * remove the map IF removing the last path. If
|
||||||
|
+ * flush_map_nopaths succeeds, the path has been removed.
|
||||||
|
*/
|
||||||
|
- if (VECTOR_SIZE(mpp->paths) == 0) {
|
||||||
|
- char alias[WWID_SIZE];
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * flush_map will fail if the device is open
|
||||||
|
- */
|
||||||
|
- strlcpy(alias, mpp->alias, WWID_SIZE);
|
||||||
|
- if (mpp->flush_on_last_del == FLUSH_ENABLED) {
|
||||||
|
- condlog(2, "%s Last path deleted, disabling queueing", mpp->alias);
|
||||||
|
- mpp->retry_tick = 0;
|
||||||
|
- mpp->no_path_retry = NO_PATH_RETRY_FAIL;
|
||||||
|
- mpp->disable_queueing = 1;
|
||||||
|
- mpp->stat_map_failures++;
|
||||||
|
- dm_queue_if_no_path(mpp->alias, 0);
|
||||||
|
- }
|
||||||
|
- if (!flush_map(mpp, vecs, 1)) {
|
||||||
|
- condlog(2, "%s: removed map after"
|
||||||
|
- " removing all paths",
|
||||||
|
- alias);
|
||||||
|
- /* flush_map() has freed the path */
|
||||||
|
- goto out;
|
||||||
|
- }
|
||||||
|
- /*
|
||||||
|
- * Not an error, continue
|
||||||
|
- */
|
||||||
|
- }
|
||||||
|
+ if (VECTOR_SIZE(mpp->paths) == 0 &&
|
||||||
|
+ flush_map_nopaths(mpp, vecs))
|
||||||
|
+ goto out;
|
||||||
|
|
||||||
|
if (setup_map(mpp, ¶ms, vecs)) {
|
||||||
|
condlog(0, "%s: failed to setup map for"
|
@ -0,0 +1,47 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Tue, 9 Aug 2022 16:46:27 -0500
|
||||||
|
Subject: [PATCH] libmultipath: return success if we raced to remove a map and
|
||||||
|
lost
|
||||||
|
|
||||||
|
_dm_flush_map() was returning failure if it failed to remove a map,
|
||||||
|
even if that was because the map had already been removed. Return
|
||||||
|
success in this case.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
libmultipath/devmapper.c | 4 ++++
|
||||||
|
multipathd/main.c | 4 ----
|
||||||
|
2 files changed, 4 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
|
||||||
|
index 1ff75c81..4b2e8a15 100644
|
||||||
|
--- a/libmultipath/devmapper.c
|
||||||
|
+++ b/libmultipath/devmapper.c
|
||||||
|
@@ -1104,6 +1104,10 @@ int _dm_flush_map (const char * mapname, int need_sync, int deferred_remove,
|
||||||
|
}
|
||||||
|
condlog(4, "multipath map %s removed", mapname);
|
||||||
|
return 0;
|
||||||
|
+ } else if (dm_is_mpath(mapname) != 1) {
|
||||||
|
+ condlog(4, "multipath map %s removed externally",
|
||||||
|
+ mapname);
|
||||||
|
+ return 0; /*we raced with someone else removing it */
|
||||||
|
} else {
|
||||||
|
condlog(2, "failed to remove multipath map %s",
|
||||||
|
mapname);
|
||||||
|
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||||
|
index b00eae3f..68ee067b 100644
|
||||||
|
--- a/multipathd/main.c
|
||||||
|
+++ b/multipathd/main.c
|
||||||
|
@@ -685,10 +685,6 @@ flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths)
|
||||||
|
* the spurious uevent we may generate with the dm_flush_map call below
|
||||||
|
*/
|
||||||
|
if (r) {
|
||||||
|
- /*
|
||||||
|
- * May not really be an error -- if the map was already flushed
|
||||||
|
- * from the device mapper by dmsetup(8) for instance.
|
||||||
|
- */
|
||||||
|
if (r == 1)
|
||||||
|
condlog(0, "%s: can't flush", mpp->alias);
|
||||||
|
else {
|
@ -0,0 +1,36 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Tue, 9 Aug 2022 16:46:28 -0500
|
||||||
|
Subject: [PATCH] multipathd: Handle losing all path in update_map
|
||||||
|
|
||||||
|
Its possible that when a multipath device is being updated, it will end
|
||||||
|
up that all the paths for it are gone. This can happen if paths are
|
||||||
|
added and then removed again before multipathd processes the uevent for
|
||||||
|
the newly created multipath device. In this case multipathd wasn't
|
||||||
|
taking the proper action for the case where all the paths had been
|
||||||
|
removed. If flush_on_last_del was set, multipathd wasn't disabling
|
||||||
|
flushing and if deferred_remove was set, it wasn't doing a deferred
|
||||||
|
remove. Multipathd should call flush_map_nopaths(), just like
|
||||||
|
ev_remove_path() does when the last path is removed.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
multipathd/main.c | 4 ++++
|
||||||
|
1 file changed, 4 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||||
|
index 68ee067b..d2c48d3b 100644
|
||||||
|
--- a/multipathd/main.c
|
||||||
|
+++ b/multipathd/main.c
|
||||||
|
@@ -529,6 +529,10 @@ retry:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
verify_paths(mpp);
|
||||||
|
+ if (VECTOR_SIZE(mpp->paths) == 0 &&
|
||||||
|
+ flush_map_nopaths(mpp, vecs))
|
||||||
|
+ return 1;
|
||||||
|
+
|
||||||
|
mpp->action = ACT_RELOAD;
|
||||||
|
|
||||||
|
if (mpp->prflag) {
|
@ -0,0 +1,153 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Thu, 8 Sep 2022 11:54:49 -0500
|
||||||
|
Subject: [PATCH] multipathd: ignore duplicated multipathd command keys
|
||||||
|
|
||||||
|
multipath adds rather than or-s the values of command keys. Fix this.
|
||||||
|
Also, return an invalid fingerprint if a key is used more than once.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
---
|
||||||
|
multipathd/cli.c | 8 ++--
|
||||||
|
multipathd/main.c | 106 +++++++++++++++++++++++-----------------------
|
||||||
|
2 files changed, 58 insertions(+), 56 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/multipathd/cli.c b/multipathd/cli.c
|
||||||
|
index cc547e67..eb2e8c1d 100644
|
||||||
|
--- a/multipathd/cli.c
|
||||||
|
+++ b/multipathd/cli.c
|
||||||
|
@@ -342,9 +342,11 @@ fingerprint(vector vec)
|
||||||
|
if (!vec)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
- vector_foreach_slot(vec, kw, i)
|
||||||
|
- fp += kw->code;
|
||||||
|
-
|
||||||
|
+ vector_foreach_slot(vec, kw, i) {
|
||||||
|
+ if (fp & kw->code)
|
||||||
|
+ return (uint64_t)-1;
|
||||||
|
+ fp |= kw->code;
|
||||||
|
+ }
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||||
|
index d2c48d3b..a098f3c2 100644
|
||||||
|
--- a/multipathd/main.c
|
||||||
|
+++ b/multipathd/main.c
|
||||||
|
@@ -1696,62 +1696,62 @@ uxlsnrloop (void * ap)
|
||||||
|
/* Tell main thread that thread has started */
|
||||||
|
post_config_state(DAEMON_CONFIGURE);
|
||||||
|
|
||||||
|
- set_handler_callback(LIST+PATHS, cli_list_paths);
|
||||||
|
- set_handler_callback(LIST+PATHS+FMT, cli_list_paths_fmt);
|
||||||
|
- set_handler_callback(LIST+PATHS+RAW+FMT, cli_list_paths_raw);
|
||||||
|
- set_handler_callback(LIST+PATH, cli_list_path);
|
||||||
|
- set_handler_callback(LIST+MAPS, cli_list_maps);
|
||||||
|
- set_handler_callback(LIST+STATUS, cli_list_status);
|
||||||
|
- set_unlocked_handler_callback(LIST+DAEMON, cli_list_daemon);
|
||||||
|
- set_handler_callback(LIST+MAPS+STATUS, cli_list_maps_status);
|
||||||
|
- set_handler_callback(LIST+MAPS+STATS, cli_list_maps_stats);
|
||||||
|
- set_handler_callback(LIST+MAPS+FMT, cli_list_maps_fmt);
|
||||||
|
- set_handler_callback(LIST+MAPS+RAW+FMT, cli_list_maps_raw);
|
||||||
|
- set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology);
|
||||||
|
- set_handler_callback(LIST+TOPOLOGY, cli_list_maps_topology);
|
||||||
|
- set_handler_callback(LIST+MAPS+JSON, cli_list_maps_json);
|
||||||
|
- set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology);
|
||||||
|
- set_handler_callback(LIST+MAP+FMT, cli_list_map_fmt);
|
||||||
|
- set_handler_callback(LIST+MAP+RAW+FMT, cli_list_map_fmt);
|
||||||
|
- set_handler_callback(LIST+MAP+JSON, cli_list_map_json);
|
||||||
|
- set_handler_callback(LIST+CONFIG+LOCAL, cli_list_config_local);
|
||||||
|
- set_handler_callback(LIST+CONFIG, cli_list_config);
|
||||||
|
- set_handler_callback(LIST+BLACKLIST, cli_list_blacklist);
|
||||||
|
- set_handler_callback(LIST+DEVICES, cli_list_devices);
|
||||||
|
- set_handler_callback(LIST+WILDCARDS, cli_list_wildcards);
|
||||||
|
- set_handler_callback(RESET+MAPS+STATS, cli_reset_maps_stats);
|
||||||
|
- set_handler_callback(RESET+MAP+STATS, cli_reset_map_stats);
|
||||||
|
- set_handler_callback(ADD+PATH, cli_add_path);
|
||||||
|
- 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_handler_callback(LIST|PATHS, cli_list_paths);
|
||||||
|
+ set_handler_callback(LIST|PATHS|FMT, cli_list_paths_fmt);
|
||||||
|
+ set_handler_callback(LIST|PATHS|RAW|FMT, cli_list_paths_raw);
|
||||||
|
+ set_handler_callback(LIST|PATH, cli_list_path);
|
||||||
|
+ set_handler_callback(LIST|MAPS, cli_list_maps);
|
||||||
|
+ set_handler_callback(LIST|STATUS, cli_list_status);
|
||||||
|
+ set_unlocked_handler_callback(LIST|DAEMON, cli_list_daemon);
|
||||||
|
+ set_handler_callback(LIST|MAPS|STATUS, cli_list_maps_status);
|
||||||
|
+ set_handler_callback(LIST|MAPS|STATS, cli_list_maps_stats);
|
||||||
|
+ set_handler_callback(LIST|MAPS|FMT, cli_list_maps_fmt);
|
||||||
|
+ set_handler_callback(LIST|MAPS|RAW|FMT, cli_list_maps_raw);
|
||||||
|
+ set_handler_callback(LIST|MAPS|TOPOLOGY, cli_list_maps_topology);
|
||||||
|
+ set_handler_callback(LIST|TOPOLOGY, cli_list_maps_topology);
|
||||||
|
+ set_handler_callback(LIST|MAPS|JSON, cli_list_maps_json);
|
||||||
|
+ set_handler_callback(LIST|MAP|TOPOLOGY, cli_list_map_topology);
|
||||||
|
+ set_handler_callback(LIST|MAP|FMT, cli_list_map_fmt);
|
||||||
|
+ set_handler_callback(LIST|MAP|RAW|FMT, cli_list_map_fmt);
|
||||||
|
+ set_handler_callback(LIST|MAP|JSON, cli_list_map_json);
|
||||||
|
+ set_handler_callback(LIST|CONFIG|LOCAL, cli_list_config_local);
|
||||||
|
+ set_handler_callback(LIST|CONFIG, cli_list_config);
|
||||||
|
+ set_handler_callback(LIST|BLACKLIST, cli_list_blacklist);
|
||||||
|
+ set_handler_callback(LIST|DEVICES, cli_list_devices);
|
||||||
|
+ set_handler_callback(LIST|WILDCARDS, cli_list_wildcards);
|
||||||
|
+ set_handler_callback(RESET|MAPS|STATS, cli_reset_maps_stats);
|
||||||
|
+ set_handler_callback(RESET|MAP|STATS, cli_reset_map_stats);
|
||||||
|
+ set_handler_callback(ADD|PATH, cli_add_path);
|
||||||
|
+ 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);
|
||||||
|
- set_handler_callback(RESUME+MAP, cli_resume);
|
||||||
|
- set_handler_callback(RESIZE+MAP, cli_resize);
|
||||||
|
- set_handler_callback(RELOAD+MAP, cli_reload);
|
||||||
|
- set_handler_callback(RESET+MAP, cli_reassign);
|
||||||
|
- set_handler_callback(REINSTATE+PATH, cli_reinstate);
|
||||||
|
- set_handler_callback(FAIL+PATH, cli_fail);
|
||||||
|
- set_handler_callback(DISABLEQ+MAP, cli_disable_queueing);
|
||||||
|
- set_handler_callback(RESTOREQ+MAP, cli_restore_queueing);
|
||||||
|
- set_handler_callback(DISABLEQ+MAPS, cli_disable_all_queueing);
|
||||||
|
- set_handler_callback(RESTOREQ+MAPS, cli_restore_all_queueing);
|
||||||
|
+ set_handler_callback(SUSPEND|MAP, cli_suspend);
|
||||||
|
+ set_handler_callback(RESUME|MAP, cli_resume);
|
||||||
|
+ set_handler_callback(RESIZE|MAP, cli_resize);
|
||||||
|
+ set_handler_callback(RELOAD|MAP, cli_reload);
|
||||||
|
+ set_handler_callback(RESET|MAP, cli_reassign);
|
||||||
|
+ set_handler_callback(REINSTATE|PATH, cli_reinstate);
|
||||||
|
+ set_handler_callback(FAIL|PATH, cli_fail);
|
||||||
|
+ set_handler_callback(DISABLEQ|MAP, cli_disable_queueing);
|
||||||
|
+ set_handler_callback(RESTOREQ|MAP, cli_restore_queueing);
|
||||||
|
+ set_handler_callback(DISABLEQ|MAPS, cli_disable_all_queueing);
|
||||||
|
+ set_handler_callback(RESTOREQ|MAPS, cli_restore_all_queueing);
|
||||||
|
set_unlocked_handler_callback(QUIT, cli_quit);
|
||||||
|
set_unlocked_handler_callback(SHUTDOWN, cli_shutdown);
|
||||||
|
- set_handler_callback(GETPRSTATUS+MAP, cli_getprstatus);
|
||||||
|
- set_handler_callback(SETPRSTATUS+MAP, cli_setprstatus);
|
||||||
|
- set_handler_callback(UNSETPRSTATUS+MAP, cli_unsetprstatus);
|
||||||
|
- set_handler_callback(FORCEQ+DAEMON, cli_force_no_daemon_q);
|
||||||
|
- set_handler_callback(RESTOREQ+DAEMON, cli_restore_no_daemon_q);
|
||||||
|
- set_handler_callback(GETPRKEY+MAP, cli_getprkey);
|
||||||
|
- set_handler_callback(SETPRKEY+MAP+KEY, cli_setprkey);
|
||||||
|
- set_handler_callback(UNSETPRKEY+MAP, cli_unsetprkey);
|
||||||
|
- set_handler_callback(SETMARGINAL+PATH, cli_set_marginal);
|
||||||
|
- set_handler_callback(UNSETMARGINAL+PATH, cli_unset_marginal);
|
||||||
|
- set_handler_callback(UNSETMARGINAL+MAP, cli_unset_all_marginal);
|
||||||
|
+ set_handler_callback(GETPRSTATUS|MAP, cli_getprstatus);
|
||||||
|
+ set_handler_callback(SETPRSTATUS|MAP, cli_setprstatus);
|
||||||
|
+ set_handler_callback(UNSETPRSTATUS|MAP, cli_unsetprstatus);
|
||||||
|
+ set_handler_callback(FORCEQ|DAEMON, cli_force_no_daemon_q);
|
||||||
|
+ set_handler_callback(RESTOREQ|DAEMON, cli_restore_no_daemon_q);
|
||||||
|
+ set_handler_callback(GETPRKEY|MAP, cli_getprkey);
|
||||||
|
+ set_handler_callback(SETPRKEY|MAP|KEY, cli_setprkey);
|
||||||
|
+ set_handler_callback(UNSETPRKEY|MAP, cli_unsetprkey);
|
||||||
|
+ set_handler_callback(SETMARGINAL|PATH, cli_set_marginal);
|
||||||
|
+ set_handler_callback(UNSETMARGINAL|PATH, cli_unset_marginal);
|
||||||
|
+ set_handler_callback(UNSETMARGINAL|MAP, cli_unset_all_marginal);
|
||||||
|
|
||||||
|
umask(077);
|
||||||
|
uxsock_listen(&uxsock_trigger, ux_sock, ap);
|
141
SOURCES/0066-multipath-tools-use-run-instead-of-dev-shm.patch
Normal file
141
SOURCES/0066-multipath-tools-use-run-instead-of-dev-shm.patch
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Martin Wilck <mwilck@suse.com>
|
||||||
|
Date: Thu, 1 Sep 2022 19:21:30 +0200
|
||||||
|
Subject: [PATCH] multipath-tools: use /run instead of /dev/shm
|
||||||
|
|
||||||
|
/dev/shm may have unsafe permissions. Use /run instead.
|
||||||
|
Use systemd's tmpfiles.d mechanism to create /run/multipath
|
||||||
|
early during boot.
|
||||||
|
|
||||||
|
For backward compatibilty, make the runtime directory configurable
|
||||||
|
via the "runtimedir" make variable.
|
||||||
|
|
||||||
|
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
---
|
||||||
|
.gitignore | 2 ++
|
||||||
|
Makefile.inc | 4 +++-
|
||||||
|
libmultipath/defaults.h | 2 +-
|
||||||
|
multipath/Makefile | 9 +++++++--
|
||||||
|
multipath/{multipath.rules => multipath.rules.in} | 4 ++--
|
||||||
|
multipath/tmpfiles.conf.in | 1 +
|
||||||
|
6 files changed, 16 insertions(+), 6 deletions(-)
|
||||||
|
rename multipath/{multipath.rules => multipath.rules.in} (96%)
|
||||||
|
create mode 100644 multipath/tmpfiles.conf.in
|
||||||
|
|
||||||
|
diff --git a/.gitignore b/.gitignore
|
||||||
|
index 087dffc2..6ee4fa09 100644
|
||||||
|
--- a/.gitignore
|
||||||
|
+++ b/.gitignore
|
||||||
|
@@ -11,6 +11,8 @@ cscope.files
|
||||||
|
cscope.out
|
||||||
|
kpartx/kpartx
|
||||||
|
multipath/multipath
|
||||||
|
+multipath/multipath.rules
|
||||||
|
+multipath/tmpfiles.conf
|
||||||
|
multipathd/multipathd
|
||||||
|
mpathpersist/mpathpersist
|
||||||
|
.nfs*
|
||||||
|
diff --git a/Makefile.inc b/Makefile.inc
|
||||||
|
index 05027703..4c452159 100644
|
||||||
|
--- a/Makefile.inc
|
||||||
|
+++ b/Makefile.inc
|
||||||
|
@@ -62,6 +62,7 @@ exec_prefix = $(prefix)
|
||||||
|
usr_prefix = $(prefix)
|
||||||
|
bindir = $(exec_prefix)/usr/sbin
|
||||||
|
libudevdir = $(prefix)/$(SYSTEMDPATH)/udev
|
||||||
|
+tmpfilesdir = $(prefix)/$(SYSTEMDPATH)/tmpfiles.d
|
||||||
|
udevrulesdir = $(libudevdir)/rules.d
|
||||||
|
multipathdir = $(TOPDIR)/libmultipath
|
||||||
|
man8dir = $(prefix)/usr/share/man/man8
|
||||||
|
@@ -79,6 +80,7 @@ libdmmpdir = $(TOPDIR)/libdmmp
|
||||||
|
nvmedir = $(TOPDIR)/libmultipath/nvme
|
||||||
|
includedir = $(prefix)/usr/include
|
||||||
|
pkgconfdir = $(usrlibdir)/pkgconfig
|
||||||
|
+runtimedir = /$(RUN)
|
||||||
|
|
||||||
|
GZIP = gzip -9 -c
|
||||||
|
RM = rm -f
|
||||||
|
@@ -120,7 +122,7 @@ WARNFLAGS := -Werror -Wextra -Wformat=2 $(WFORMATOVERFLOW) -Werror=implicit-int
|
||||||
|
$(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) \
|
||||||
|
-Wstrict-prototypes
|
||||||
|
CFLAGS := --std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \
|
||||||
|
- -DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
|
||||||
|
+ -DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" -DRUNTIME_DIR=\"$(runtimedir)\" \
|
||||||
|
-MMD -MP
|
||||||
|
BIN_CFLAGS = -fPIE -DPIE
|
||||||
|
LIB_CFLAGS = -fPIC
|
||||||
|
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
|
||||||
|
index e0dd32ad..cec82f07 100644
|
||||||
|
--- a/libmultipath/defaults.h
|
||||||
|
+++ b/libmultipath/defaults.h
|
||||||
|
@@ -69,7 +69,7 @@
|
||||||
|
#define DEFAULT_WWIDS_FILE "/etc/multipath/wwids"
|
||||||
|
#define DEFAULT_PRKEYS_FILE "/etc/multipath/prkeys"
|
||||||
|
#define DEFAULT_CONFIG_DIR "/etc/multipath/conf.d"
|
||||||
|
-#define MULTIPATH_SHM_BASE "/dev/shm/multipath/"
|
||||||
|
+#define MULTIPATH_SHM_BASE RUNTIME_DIR "/multipath/"
|
||||||
|
|
||||||
|
|
||||||
|
static inline char *set_default(char *str)
|
||||||
|
diff --git a/multipath/Makefile b/multipath/Makefile
|
||||||
|
index e720c7f6..f3d98012 100644
|
||||||
|
--- a/multipath/Makefile
|
||||||
|
+++ b/multipath/Makefile
|
||||||
|
@@ -12,7 +12,7 @@ EXEC = multipath
|
||||||
|
|
||||||
|
OBJS = main.o
|
||||||
|
|
||||||
|
-all: $(EXEC)
|
||||||
|
+all: $(EXEC) multipath.rules tmpfiles.conf
|
||||||
|
|
||||||
|
$(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
|
||||||
|
$(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS)
|
||||||
|
@@ -27,6 +27,8 @@ install:
|
||||||
|
$(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir)
|
||||||
|
$(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir)
|
||||||
|
$(INSTALL_PROGRAM) -m 644 $(EXEC).rules $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules
|
||||||
|
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(tmpfilesdir)
|
||||||
|
+ $(INSTALL_PROGRAM) -m 644 tmpfiles.conf $(DESTDIR)$(tmpfilesdir)/multipath.conf
|
||||||
|
$(INSTALL_PROGRAM) -d $(DESTDIR)$(man8dir)
|
||||||
|
$(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir)
|
||||||
|
$(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir)
|
||||||
|
@@ -43,9 +45,12 @@ uninstall:
|
||||||
|
$(RM) $(DESTDIR)$(man8dir)/mpathconf.8.gz
|
||||||
|
|
||||||
|
clean: dep_clean
|
||||||
|
- $(RM) core *.o $(EXEC) *.gz
|
||||||
|
+ $(RM) core *.o $(EXEC) *.gz multipath.rules tmpfiles.conf
|
||||||
|
|
||||||
|
include $(wildcard $(OBJS:.o=.d))
|
||||||
|
|
||||||
|
dep_clean:
|
||||||
|
$(RM) $(OBJS:.o=.d)
|
||||||
|
+
|
||||||
|
+%: %.in
|
||||||
|
+ sed 's,@RUNTIME_DIR@,$(runtimedir),' $< >$@
|
||||||
|
diff --git a/multipath/multipath.rules b/multipath/multipath.rules.in
|
||||||
|
similarity index 96%
|
||||||
|
rename from multipath/multipath.rules
|
||||||
|
rename to multipath/multipath.rules.in
|
||||||
|
index 68c30644..5c4447a2 100644
|
||||||
|
--- a/multipath/multipath.rules
|
||||||
|
+++ b/multipath/multipath.rules.in
|
||||||
|
@@ -1,8 +1,8 @@
|
||||||
|
# Set DM_MULTIPATH_DEVICE_PATH if the device should be handled by multipath
|
||||||
|
SUBSYSTEM!="block", GOTO="end_mpath"
|
||||||
|
KERNEL!="sd*|dasd*|nvme*", GOTO="end_mpath"
|
||||||
|
-ACTION=="remove", TEST=="/dev/shm/multipath/find_multipaths/$major:$minor", \
|
||||||
|
- RUN+="/usr/bin/rm -f /dev/shm/multipath/find_multipaths/$major:$minor"
|
||||||
|
+ACTION=="remove", TEST=="@RUNTIME_DIR@/multipath/find_multipaths/$major:$minor", \
|
||||||
|
+ RUN+="/usr/bin/rm -f @RUNTIME_DIR@/multipath/find_multipaths/$major:$minor"
|
||||||
|
ACTION!="add|change", GOTO="end_mpath"
|
||||||
|
|
||||||
|
IMPORT{cmdline}="nompath"
|
||||||
|
diff --git a/multipath/tmpfiles.conf.in b/multipath/tmpfiles.conf.in
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..21be438a
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/multipath/tmpfiles.conf.in
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+d @RUNTIME_DIR@/multipath 0700 root root -
|
@ -0,0 +1,47 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Wed, 19 Oct 2022 12:57:10 -0500
|
||||||
|
Subject: [PATCH] kpartx: hold device open until partitions have been created
|
||||||
|
|
||||||
|
kpartx was closing the whole device after it read the partition
|
||||||
|
information off it. This allowed a race, where the device could be
|
||||||
|
removed and another one created with the same major:minor, after kpartx
|
||||||
|
read the partition information but before it created the partition
|
||||||
|
devices.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
kpartx/kpartx.c | 11 +++--------
|
||||||
|
1 file changed, 3 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
|
||||||
|
index 7bc64543..e79fdd4a 100644
|
||||||
|
--- a/kpartx/kpartx.c
|
||||||
|
+++ b/kpartx/kpartx.c
|
||||||
|
@@ -443,12 +443,7 @@ main(int argc, char **argv){
|
||||||
|
if (n >= 0)
|
||||||
|
printf("%s: %d slices\n", ptp->type, n);
|
||||||
|
#endif
|
||||||
|
-
|
||||||
|
- if (n > 0) {
|
||||||
|
- close(fd);
|
||||||
|
- fd = -1;
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
+ if (n <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch(what) {
|
||||||
|
@@ -668,9 +663,9 @@ main(int argc, char **argv){
|
||||||
|
if (n > 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
+ if (fd != -1)
|
||||||
|
+ close(fd);
|
||||||
|
if (what == LIST && loopcreated) {
|
||||||
|
- if (fd != -1)
|
||||||
|
- close(fd);
|
||||||
|
if (del_loop(device)) {
|
||||||
|
if (verbose)
|
||||||
|
fprintf(stderr, "can't del loop : %s\n",
|
153
SOURCES/0068-libmultipath-cleanup-remove_feature.patch
Normal file
153
SOURCES/0068-libmultipath-cleanup-remove_feature.patch
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Fri, 7 Oct 2022 12:35:37 -0500
|
||||||
|
Subject: [PATCH] libmultipath: cleanup remove_feature
|
||||||
|
|
||||||
|
remove_feature() didn't correctly handle feature strings that used
|
||||||
|
whitespace other than spaces, which the kernel allows. It also didn't
|
||||||
|
check if the feature string to be removed was part of a larger feature
|
||||||
|
token. Finally, it did a lot of unnecessary work. By failing if the
|
||||||
|
feature string to be removed contains leading or trailing whitespace,
|
||||||
|
the function can be significanly simplified.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
libmultipath/structs.c | 82 +++++++++++++++---------------------------
|
||||||
|
1 file changed, 29 insertions(+), 53 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
|
||||||
|
index acd4cbeb..83906ffe 100644
|
||||||
|
--- a/libmultipath/structs.c
|
||||||
|
+++ b/libmultipath/structs.c
|
||||||
|
@@ -6,6 +6,7 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <libdevmapper.h>
|
||||||
|
#include <libudev.h>
|
||||||
|
+#include <ctype.h>
|
||||||
|
|
||||||
|
#include "checkers.h"
|
||||||
|
#include "memory.h"
|
||||||
|
@@ -669,7 +670,7 @@ int add_feature(char **f, const char *n)
|
||||||
|
|
||||||
|
int remove_feature(char **f, const char *o)
|
||||||
|
{
|
||||||
|
- int c = 0, d, l;
|
||||||
|
+ int c = 0, d;
|
||||||
|
char *e, *p, *n;
|
||||||
|
const char *q;
|
||||||
|
|
||||||
|
@@ -680,33 +681,35 @@ int remove_feature(char **f, const char *o)
|
||||||
|
if (!o || *o == '\0')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
- /* Check if not present */
|
||||||
|
- if (!strstr(*f, o))
|
||||||
|
+ d = strlen(o);
|
||||||
|
+ if (isspace(*o) || isspace(*(o + d - 1))) {
|
||||||
|
+ condlog(0, "internal error: feature \"%s\" has leading or trailing spaces", o);
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Check if present and not part of a larger feature token*/
|
||||||
|
+ p = *f + 1; /* the size must be at the start of the features string */
|
||||||
|
+ while ((p = strstr(p, o)) != NULL) {
|
||||||
|
+ if (isspace(*(p - 1)) &&
|
||||||
|
+ (isspace(*(p + d)) || *(p + d) == '\0'))
|
||||||
|
+ break;
|
||||||
|
+ p += d;
|
||||||
|
+ }
|
||||||
|
+ if (!p)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Get feature count */
|
||||||
|
c = strtoul(*f, &e, 10);
|
||||||
|
- if (*f == e)
|
||||||
|
- /* parse error */
|
||||||
|
+ if (*f == e || !isspace(*e)) {
|
||||||
|
+ condlog(0, "parse error in feature string \"%s\"", *f);
|
||||||
|
return 1;
|
||||||
|
-
|
||||||
|
- /* Normalize features */
|
||||||
|
- while (*o == ' ') {
|
||||||
|
- o++;
|
||||||
|
}
|
||||||
|
- /* Just spaces, return */
|
||||||
|
- if (*o == '\0')
|
||||||
|
- return 0;
|
||||||
|
- q = o + strlen(o);
|
||||||
|
- while (*q == ' ')
|
||||||
|
- q--;
|
||||||
|
- d = (int)(q - o);
|
||||||
|
|
||||||
|
/* Update feature count */
|
||||||
|
c--;
|
||||||
|
q = o;
|
||||||
|
- while (q[0] != '\0') {
|
||||||
|
- if (q[0] == ' ' && q[1] != ' ' && q[1] != '\0')
|
||||||
|
+ while (*q != '\0') {
|
||||||
|
+ if (isspace(*q) && !isspace(*(q + 1)) && *(q + 1) != '\0')
|
||||||
|
c--;
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
@@ -720,15 +723,8 @@ int remove_feature(char **f, const char *o)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* Search feature to be removed */
|
||||||
|
- e = strstr(*f, o);
|
||||||
|
- if (!e)
|
||||||
|
- /* Not found, return */
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
/* Update feature count space */
|
||||||
|
- l = strlen(*f) - d;
|
||||||
|
- n = MALLOC(l + 1);
|
||||||
|
+ n = MALLOC(strlen(*f) - d + 1);
|
||||||
|
if (!n)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
@@ -738,36 +734,16 @@ int remove_feature(char **f, const char *o)
|
||||||
|
* Copy existing features up to the feature
|
||||||
|
* about to be removed
|
||||||
|
*/
|
||||||
|
- p = strchr(*f, ' ');
|
||||||
|
- if (!p) {
|
||||||
|
- /* Internal error, feature string inconsistent */
|
||||||
|
- FREE(n);
|
||||||
|
- return 1;
|
||||||
|
- }
|
||||||
|
- while (*p == ' ')
|
||||||
|
- p++;
|
||||||
|
- p--;
|
||||||
|
- if (e != p) {
|
||||||
|
- do {
|
||||||
|
- e--;
|
||||||
|
- d++;
|
||||||
|
- } while (*e == ' ');
|
||||||
|
- e++; d--;
|
||||||
|
- strncat(n, p, (size_t)(e - p));
|
||||||
|
- p += (size_t)(e - p);
|
||||||
|
- }
|
||||||
|
+ strncat(n, e, (size_t)(p - e));
|
||||||
|
/* Skip feature to be removed */
|
||||||
|
p += d;
|
||||||
|
-
|
||||||
|
/* Copy remaining features */
|
||||||
|
- if (strlen(p)) {
|
||||||
|
- while (*p == ' ')
|
||||||
|
- p++;
|
||||||
|
- if (strlen(p)) {
|
||||||
|
- p--;
|
||||||
|
- strcat(n, p);
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
+ while (isspace(*p))
|
||||||
|
+ p++;
|
||||||
|
+ if (*p != '\0')
|
||||||
|
+ strcat(n, p);
|
||||||
|
+ else
|
||||||
|
+ strchop(n);
|
||||||
|
|
||||||
|
out:
|
||||||
|
FREE(*f);
|
107
SOURCES/0069-libmultipath-cleanup-add_feature.patch
Normal file
107
SOURCES/0069-libmultipath-cleanup-add_feature.patch
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Fri, 7 Oct 2022 12:35:38 -0500
|
||||||
|
Subject: [PATCH] libmultipath: cleanup add_feature
|
||||||
|
|
||||||
|
add_feature() didn't correctly handle feature strings that used
|
||||||
|
whitespace other than spaces, which the kernel allows. It also didn't
|
||||||
|
allow adding features with multiple tokens. When it looked to see if the
|
||||||
|
feature string to be added already existed, it didn't check if the match
|
||||||
|
was part of a larger token. Finally, it did unnecessary work. By using
|
||||||
|
asprintf() to create the string, the function can be signifcantly
|
||||||
|
simplified.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
libmultipath/structs.c | 49 +++++++++++++++++++++---------------------
|
||||||
|
1 file changed, 24 insertions(+), 25 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
|
||||||
|
index 83906ffe..5dfa86a8 100644
|
||||||
|
--- a/libmultipath/structs.c
|
||||||
|
+++ b/libmultipath/structs.c
|
||||||
|
@@ -608,23 +608,33 @@ int add_feature(char **f, const char *n)
|
||||||
|
{
|
||||||
|
int c = 0, d, l;
|
||||||
|
char *e, *t;
|
||||||
|
+ const char *p;
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Nothing to do */
|
||||||
|
- if (!n || *n == '0')
|
||||||
|
+ if (!n || *n == '\0')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
- if (strchr(n, ' ') != NULL) {
|
||||||
|
- condlog(0, "internal error: feature \"%s\" contains spaces", n);
|
||||||
|
+ l = strlen(n);
|
||||||
|
+ if (isspace(*n) || isspace(*(n + l - 1))) {
|
||||||
|
+ condlog(0, "internal error: feature \"%s\" has leading or trailing spaces", n);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ p = n;
|
||||||
|
+ d = 1;
|
||||||
|
+ while (*p != '\0') {
|
||||||
|
+ if (isspace(*p) && !isspace(*(p + 1)) && *(p + 1) != '\0')
|
||||||
|
+ d++;
|
||||||
|
+ p++;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* default feature is null */
|
||||||
|
if(!*f)
|
||||||
|
{
|
||||||
|
- l = asprintf(&t, "1 %s", n);
|
||||||
|
+ l = asprintf(&t, "%0d %s", d, n);
|
||||||
|
if(l == -1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
@@ -633,35 +643,24 @@ int add_feature(char **f, const char *n)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if feature is already present */
|
||||||
|
- if (strstr(*f, n))
|
||||||
|
- return 0;
|
||||||
|
+ e = *f;
|
||||||
|
+ while ((e = strstr(e, n)) != NULL) {
|
||||||
|
+ if (isspace(*(e - 1)) &&
|
||||||
|
+ (isspace(*(e + l)) || *(e + l) == '\0'))
|
||||||
|
+ return 0;
|
||||||
|
+ e += l;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
/* Get feature count */
|
||||||
|
c = strtoul(*f, &e, 10);
|
||||||
|
- if (*f == e || (*e != ' ' && *e != '\0')) {
|
||||||
|
+ if (*f == e || (!isspace(*e) && *e != '\0')) {
|
||||||
|
condlog(0, "parse error in feature string \"%s\"", *f);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- /* Add 1 digit and 1 space */
|
||||||
|
- l = strlen(e) + strlen(n) + 2;
|
||||||
|
-
|
||||||
|
- c++;
|
||||||
|
- /* Check if we need more digits for feature count */
|
||||||
|
- for (d = c; d >= 10; d /= 10)
|
||||||
|
- l++;
|
||||||
|
-
|
||||||
|
- t = MALLOC(l + 1);
|
||||||
|
- if (!t)
|
||||||
|
+ c += d;
|
||||||
|
+ if (asprintf(&t, "%0d%s %s", c, e, n) < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
- /* e: old feature string with leading space, or "" */
|
||||||
|
- if (*e == ' ')
|
||||||
|
- while (*(e + 1) == ' ')
|
||||||
|
- e++;
|
||||||
|
-
|
||||||
|
- snprintf(t, l + 1, "%0d%s %s", c, e, n);
|
||||||
|
-
|
||||||
|
FREE(*f);
|
||||||
|
*f = t;
|
||||||
|
|
@ -0,0 +1,351 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Fri, 7 Oct 2022 12:35:39 -0500
|
||||||
|
Subject: [PATCH] multipath tests: tests for adding and removing features
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
tests/Makefile | 2 +-
|
||||||
|
tests/features.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
2 files changed, 320 insertions(+), 1 deletion(-)
|
||||||
|
create mode 100644 tests/features.c
|
||||||
|
|
||||||
|
diff --git a/tests/Makefile b/tests/Makefile
|
||||||
|
index 8cbc4b73..972a5e04 100644
|
||||||
|
--- a/tests/Makefile
|
||||||
|
+++ b/tests/Makefile
|
||||||
|
@@ -13,7 +13,7 @@ CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) \
|
||||||
|
LIBDEPS += -L. -L$(mpathcmddir) -lmultipath -lmpathcmd -lcmocka
|
||||||
|
|
||||||
|
TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \
|
||||||
|
- alias directio valid devt mpathvalid strbuf
|
||||||
|
+ alias directio valid devt mpathvalid strbuf features
|
||||||
|
HELPERS := test-lib.o test-log.o
|
||||||
|
|
||||||
|
.SILENT: $(TESTS:%=%.o)
|
||||||
|
diff --git a/tests/features.c b/tests/features.c
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..4d8f0860
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/features.c
|
||||||
|
@@ -0,0 +1,319 @@
|
||||||
|
+#include <stddef.h>
|
||||||
|
+#include <stdarg.h>
|
||||||
|
+#include <setjmp.h>
|
||||||
|
+#include <cmocka.h>
|
||||||
|
+
|
||||||
|
+#include "structs.h"
|
||||||
|
+#include "globals.c"
|
||||||
|
+
|
||||||
|
+static void test_af_null_features_ptr(void **state)
|
||||||
|
+{
|
||||||
|
+ assert_int_equal(add_feature(NULL, "test"), 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void af_helper(const char *features_start, const char *addition,
|
||||||
|
+ const char *features_end, int result)
|
||||||
|
+{
|
||||||
|
+ char *f = NULL, *orig = NULL;
|
||||||
|
+
|
||||||
|
+ if (features_start) {
|
||||||
|
+ f = strdup(features_start);
|
||||||
|
+ assert_non_null(f);
|
||||||
|
+ orig = f;
|
||||||
|
+ }
|
||||||
|
+ assert_int_equal(add_feature(&f, addition), result);
|
||||||
|
+ if (result != 0 || features_end == NULL)
|
||||||
|
+ assert_ptr_equal(orig, f);
|
||||||
|
+ else
|
||||||
|
+ assert_string_equal(f, features_end);
|
||||||
|
+ free(f);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_null_addition1(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("0", NULL, NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_null_addition2(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("1 queue_if_no_path", NULL, NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_empty_addition(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("2 pg_init_retries 5", "", NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_invalid_addition1(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("2 pg_init_retries 5", " ", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_invalid_addition2(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("2 pg_init_retries 5", "\tbad", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_invalid_addition3(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("2 pg_init_retries 5", "bad ", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_invalid_addition4(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("2 pg_init_retries 5", " bad ", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_null_features1(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper(NULL, "test", "1 test", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_null_features2(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper(NULL, "test\t more", "2 test\t more", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_null_features3(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper(NULL, "test\neven\tmore", "3 test\neven\tmore", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_already_exists1(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("4 this is a test", "test", NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_already_exists2(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("5 contest testy intestine test retest", "test", NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_almost_exists(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("3 contest testy intestine", "test",
|
||||||
|
+ "4 contest testy intestine test", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_bad_features1(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("bad", "test", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_bad_features2(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("1bad", "test", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_add1(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("0", "test", "1 test", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_add2(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("0", "this is a test", "4 this is a test", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_add3(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("1 features", "more values", "3 features more values", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_af_add4(void **state)
|
||||||
|
+{
|
||||||
|
+ af_helper("2 one\ttwo", "three\t four", "4 one\ttwo three\t four", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int test_add_features(void)
|
||||||
|
+{
|
||||||
|
+ const struct CMUnitTest tests[] = {
|
||||||
|
+ cmocka_unit_test(test_af_null_features_ptr),
|
||||||
|
+ cmocka_unit_test(test_af_null_addition1),
|
||||||
|
+ cmocka_unit_test(test_af_null_addition2),
|
||||||
|
+ cmocka_unit_test(test_af_empty_addition),
|
||||||
|
+ cmocka_unit_test(test_af_invalid_addition1),
|
||||||
|
+ cmocka_unit_test(test_af_invalid_addition2),
|
||||||
|
+ cmocka_unit_test(test_af_invalid_addition3),
|
||||||
|
+ cmocka_unit_test(test_af_invalid_addition4),
|
||||||
|
+ cmocka_unit_test(test_af_null_features1),
|
||||||
|
+ cmocka_unit_test(test_af_null_features2),
|
||||||
|
+ cmocka_unit_test(test_af_null_features3),
|
||||||
|
+ cmocka_unit_test(test_af_already_exists1),
|
||||||
|
+ cmocka_unit_test(test_af_already_exists2),
|
||||||
|
+ cmocka_unit_test(test_af_almost_exists),
|
||||||
|
+ cmocka_unit_test(test_af_bad_features1),
|
||||||
|
+ cmocka_unit_test(test_af_bad_features2),
|
||||||
|
+ cmocka_unit_test(test_af_add1),
|
||||||
|
+ cmocka_unit_test(test_af_add2),
|
||||||
|
+ cmocka_unit_test(test_af_add3),
|
||||||
|
+ cmocka_unit_test(test_af_add4),
|
||||||
|
+ };
|
||||||
|
+ return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_null_features_ptr(void **state)
|
||||||
|
+{
|
||||||
|
+ assert_int_equal(remove_feature(NULL, "test"), 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_null_features(void **state)
|
||||||
|
+{
|
||||||
|
+ char *f = NULL;
|
||||||
|
+ assert_int_equal(remove_feature(&f, "test"), 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void rf_helper(const char *features_start, const char *removal,
|
||||||
|
+ const char *features_end, int result)
|
||||||
|
+{
|
||||||
|
+ char *f = strdup(features_start);
|
||||||
|
+ char *orig = f;
|
||||||
|
+
|
||||||
|
+ assert_non_null(f);
|
||||||
|
+ assert_int_equal(remove_feature(&f, removal), result);
|
||||||
|
+ if (result != 0 || features_end == NULL)
|
||||||
|
+ assert_ptr_equal(orig, f);
|
||||||
|
+ else
|
||||||
|
+ assert_string_equal(f, features_end);
|
||||||
|
+ free(f);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_null_removal(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("1 feature", NULL, NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_empty_removal(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("1 feature", "", NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_invalid_removal1(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("1 feature", " ", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_invalid_removal2(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("1 feature", " bad", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_invalid_removal3(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("1 feature", "bad\n", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_invalid_removal4(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("1 feature", "\tbad \n", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_bad_features1(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("invalid feature test string", "test", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_bad_features2(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("2no space test", "test", NULL, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_missing_removal1(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("0", "test", NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_missing_removal2(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("1 detest", "test", NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_missing_removal3(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("4 testing one two three", "test", NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_missing_removal4(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("1 contestant", "test", NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_missing_removal5(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("3 testament protest detestable", "test", NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_remove_all_features1(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("1 test", "test", "0", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_remove_all_features2(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("2 another\t test", "another\t test", "0", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_remove1(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("2 feature1 feature2", "feature2", "1 feature1", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_remove2(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("2 feature1 feature2", "feature1", "1 feature2", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_remove3(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("3 test1 test\ttest2", "test", "2 test1 test2", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_remove4(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("4 this\t is a test", "is a", "2 this\t test", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_rf_remove5(void **state)
|
||||||
|
+{
|
||||||
|
+ rf_helper("3 one more test", "more test", "1 one", 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int test_remove_features(void)
|
||||||
|
+{
|
||||||
|
+ const struct CMUnitTest tests[] = {
|
||||||
|
+ cmocka_unit_test(test_rf_null_features_ptr),
|
||||||
|
+ cmocka_unit_test(test_rf_null_features),
|
||||||
|
+ cmocka_unit_test(test_rf_null_removal),
|
||||||
|
+ cmocka_unit_test(test_rf_empty_removal),
|
||||||
|
+ cmocka_unit_test(test_rf_invalid_removal1),
|
||||||
|
+ cmocka_unit_test(test_rf_invalid_removal2),
|
||||||
|
+ cmocka_unit_test(test_rf_invalid_removal3),
|
||||||
|
+ cmocka_unit_test(test_rf_invalid_removal4),
|
||||||
|
+ cmocka_unit_test(test_rf_bad_features1),
|
||||||
|
+ cmocka_unit_test(test_rf_bad_features2),
|
||||||
|
+ cmocka_unit_test(test_rf_missing_removal1),
|
||||||
|
+ cmocka_unit_test(test_rf_missing_removal2),
|
||||||
|
+ cmocka_unit_test(test_rf_missing_removal3),
|
||||||
|
+ cmocka_unit_test(test_rf_missing_removal4),
|
||||||
|
+ cmocka_unit_test(test_rf_missing_removal5),
|
||||||
|
+ cmocka_unit_test(test_rf_remove_all_features1),
|
||||||
|
+ cmocka_unit_test(test_rf_remove_all_features2),
|
||||||
|
+ cmocka_unit_test(test_rf_remove1),
|
||||||
|
+ cmocka_unit_test(test_rf_remove2),
|
||||||
|
+ cmocka_unit_test(test_rf_remove3),
|
||||||
|
+ cmocka_unit_test(test_rf_remove4),
|
||||||
|
+ cmocka_unit_test(test_rf_remove5),
|
||||||
|
+ };
|
||||||
|
+ return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int main(void)
|
||||||
|
+{
|
||||||
|
+ int ret = 0;
|
||||||
|
+
|
||||||
|
+ init_test_verbosity(-1);
|
||||||
|
+ ret += test_add_features();
|
||||||
|
+ ret += test_remove_features();
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
177
SOURCES/0071-libmultipath-fix-queue_mode-feature-handling.patch
Normal file
177
SOURCES/0071-libmultipath-fix-queue_mode-feature-handling.patch
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Fri, 7 Oct 2022 12:35:40 -0500
|
||||||
|
Subject: [PATCH] libmultipath: fix queue_mode feature handling
|
||||||
|
|
||||||
|
device-mapper is not able to change the queue_mode on a table reload.
|
||||||
|
Make sure that when multipath sets up the map, both on regular reloads
|
||||||
|
and reconfigures, it keeps the queue_mode the same.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
libmultipath/configure.c | 4 +++
|
||||||
|
libmultipath/dmparser.c | 2 ++
|
||||||
|
libmultipath/propsel.c | 55 ++++++++++++++++++++++++++++++++++++++
|
||||||
|
libmultipath/structs.h | 7 +++++
|
||||||
|
multipath/multipath.conf.5 | 7 +++--
|
||||||
|
5 files changed, 73 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||||||
|
index 70049f47..cc778a22 100644
|
||||||
|
--- a/libmultipath/configure.c
|
||||||
|
+++ b/libmultipath/configure.c
|
||||||
|
@@ -1118,6 +1118,7 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid,
|
||||||
|
struct config *conf = NULL;
|
||||||
|
int allow_queueing;
|
||||||
|
struct bitfield *size_mismatch_seen;
|
||||||
|
+ struct multipath * cmpp;
|
||||||
|
|
||||||
|
/* ignore refwwid if it's empty */
|
||||||
|
if (refwwid && !strlen(refwwid))
|
||||||
|
@@ -1227,6 +1228,9 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid,
|
||||||
|
}
|
||||||
|
verify_paths(mpp);
|
||||||
|
|
||||||
|
+ cmpp = find_mp_by_wwid(curmp, mpp->wwid);
|
||||||
|
+ if (cmpp)
|
||||||
|
+ mpp->queue_mode = cmpp->queue_mode;
|
||||||
|
if (setup_map(mpp, ¶ms, vecs)) {
|
||||||
|
remove_map(mpp, vecs->pathvec, NULL);
|
||||||
|
continue;
|
||||||
|
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
|
||||||
|
index bc311421..16377c54 100644
|
||||||
|
--- a/libmultipath/dmparser.c
|
||||||
|
+++ b/libmultipath/dmparser.c
|
||||||
|
@@ -152,6 +152,8 @@ int disassemble_map(const struct _vector *pathvec,
|
||||||
|
|
||||||
|
FREE(word);
|
||||||
|
}
|
||||||
|
+ mpp->queue_mode = strstr(mpp->features, "queue_mode bio") ?
|
||||||
|
+ QUEUE_MODE_BIO : QUEUE_MODE_RQ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hwhandler
|
||||||
|
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
|
||||||
|
index 2b47f5f8..9dea6f92 100644
|
||||||
|
--- a/libmultipath/propsel.c
|
||||||
|
+++ b/libmultipath/propsel.c
|
||||||
|
@@ -27,6 +27,7 @@
|
||||||
|
#include "strbuf.h"
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <libudev.h>
|
||||||
|
+#include <ctype.h>
|
||||||
|
|
||||||
|
pgpolicyfn *pgpolicies[] = {
|
||||||
|
NULL,
|
||||||
|
@@ -414,6 +415,59 @@ void reconcile_features_with_options(const char *id, char **features, int* no_pa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void reconcile_features_with_queue_mode(struct multipath *mp)
|
||||||
|
+{
|
||||||
|
+ char *space = NULL, *val = NULL, *mode_str = NULL, *feat;
|
||||||
|
+ int features_mode = QUEUE_MODE_UNDEF;
|
||||||
|
+
|
||||||
|
+ if (!mp->features)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ pthread_cleanup_push(cleanup_free_ptr, &space);
|
||||||
|
+ pthread_cleanup_push(cleanup_free_ptr, &val);
|
||||||
|
+ pthread_cleanup_push(cleanup_free_ptr, &mode_str);
|
||||||
|
+
|
||||||
|
+ if (!(feat = strstr(mp->features, "queue_mode")) ||
|
||||||
|
+ feat == mp->features || !isspace(*(feat - 1)) ||
|
||||||
|
+ sscanf(feat, "queue_mode%m[ \f\n\r\t\v]%ms", &space, &val) != 2)
|
||||||
|
+ goto sync_mode;
|
||||||
|
+ if (asprintf(&mode_str, "queue_mode%s%s", space, val) < 0) {
|
||||||
|
+ condlog(1, "failed to allocate space for queue_mode feature string");
|
||||||
|
+ mode_str = NULL; /* value undefined on failure */
|
||||||
|
+ goto exit;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!strcmp(val, "rq") || !strcmp(val, "mq"))
|
||||||
|
+ features_mode = QUEUE_MODE_RQ;
|
||||||
|
+ else if (!strcmp(val, "bio"))
|
||||||
|
+ features_mode = QUEUE_MODE_BIO;
|
||||||
|
+ if (features_mode == QUEUE_MODE_UNDEF) {
|
||||||
|
+ condlog(2, "%s: ignoring invalid feature '%s'",
|
||||||
|
+ mp->alias, mode_str);
|
||||||
|
+ goto sync_mode;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (mp->queue_mode == QUEUE_MODE_UNDEF)
|
||||||
|
+ mp->queue_mode = features_mode;
|
||||||
|
+ if (mp->queue_mode == features_mode)
|
||||||
|
+ goto exit;
|
||||||
|
+
|
||||||
|
+ condlog(2,
|
||||||
|
+ "%s: ignoring feature '%s' because queue_mode is set to '%s'",
|
||||||
|
+ mp->alias, mode_str,
|
||||||
|
+ (mp->queue_mode == QUEUE_MODE_RQ)? "rq" : "bio");
|
||||||
|
+
|
||||||
|
+sync_mode:
|
||||||
|
+ if (mode_str)
|
||||||
|
+ remove_feature(&mp->features, mode_str);
|
||||||
|
+ if (mp->queue_mode == QUEUE_MODE_BIO)
|
||||||
|
+ add_feature(&mp->features, "queue_mode bio");
|
||||||
|
+exit:
|
||||||
|
+ pthread_cleanup_pop(1);
|
||||||
|
+ pthread_cleanup_pop(1);
|
||||||
|
+ pthread_cleanup_pop(1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int select_features(struct config *conf, struct multipath *mp)
|
||||||
|
{
|
||||||
|
const char *origin;
|
||||||
|
@@ -429,6 +483,7 @@ out:
|
||||||
|
reconcile_features_with_options(mp->alias, &mp->features,
|
||||||
|
&mp->no_path_retry,
|
||||||
|
&mp->retain_hwhandler);
|
||||||
|
+ reconcile_features_with_queue_mode(mp);
|
||||||
|
condlog(3, "%s: features = \"%s\" %s", mp->alias, mp->features, origin);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||||
|
index 8a07d470..b4f75de0 100644
|
||||||
|
--- a/libmultipath/structs.h
|
||||||
|
+++ b/libmultipath/structs.h
|
||||||
|
@@ -170,6 +170,12 @@ enum max_sectors_kb_states {
|
||||||
|
MAX_SECTORS_KB_MIN = 4, /* can't be smaller than page size */
|
||||||
|
};
|
||||||
|
|
||||||
|
+enum queue_mode_states {
|
||||||
|
+ QUEUE_MODE_UNDEF = 0,
|
||||||
|
+ QUEUE_MODE_BIO,
|
||||||
|
+ QUEUE_MODE_RQ,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
enum scsi_protocol {
|
||||||
|
SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */
|
||||||
|
SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */
|
||||||
|
@@ -387,6 +393,7 @@ struct multipath {
|
||||||
|
int needs_paths_uevent;
|
||||||
|
int ghost_delay;
|
||||||
|
int ghost_delay_tick;
|
||||||
|
+ int queue_mode;
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
mode_t mode;
|
||||||
|
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
||||||
|
index f7de5140..e1a787d4 100644
|
||||||
|
--- a/multipath/multipath.conf.5
|
||||||
|
+++ b/multipath/multipath.conf.5
|
||||||
|
@@ -468,8 +468,11 @@ precedence. See KNOWN ISSUES.
|
||||||
|
<mode> can be \fIbio\fR, \fIrq\fR or \fImq\fR, which corresponds to
|
||||||
|
bio-based, request-based, and block-multiqueue (blk-mq) request-based,
|
||||||
|
respectively.
|
||||||
|
-The default depends on the kernel parameter \fBdm_mod.use_blk_mq\fR. It is
|
||||||
|
-\fImq\fR if the latter is set, and \fIrq\fR otherwise.
|
||||||
|
+Before kernel 4.20 The default depends on the kernel parameter
|
||||||
|
+\fBdm_mod.use_blk_mq\fR. It is \fImq\fR if the latter is set, and \fIrq\fR
|
||||||
|
+otherwise. Since kernel 4.20, \fIrq\fR and \fImq\fR both correspond to
|
||||||
|
+block-multiqueue. Once a multipath device has been created, its queue_mode
|
||||||
|
+cannot be changed.
|
||||||
|
.TP
|
||||||
|
The default is: \fB<unset>\fR
|
||||||
|
.RE
|
@ -0,0 +1,291 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Fri, 7 Oct 2022 12:35:41 -0500
|
||||||
|
Subject: [PATCH] multipath tests: tests for reconcile_features_with_queue_mode
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
tests/Makefile | 2 +
|
||||||
|
tests/features.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++-
|
||||||
|
2 files changed, 233 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/tests/Makefile b/tests/Makefile
|
||||||
|
index 972a5e04..27e3ffa9 100644
|
||||||
|
--- a/tests/Makefile
|
||||||
|
+++ b/tests/Makefile
|
||||||
|
@@ -33,6 +33,7 @@ ifneq ($(DIO_TEST_DEV),)
|
||||||
|
directio-test_FLAGS := -DDIO_TEST_DEV=\"$(DIO_TEST_DEV)\"
|
||||||
|
endif
|
||||||
|
mpathvalid-test_FLAGS := -I$(mpathvaliddir)
|
||||||
|
+features-test_FLAGS := -I$(multipathdir)/nvme
|
||||||
|
|
||||||
|
# test-specific linker flags
|
||||||
|
# XYZ-test_TESTDEPS: test libraries containing __wrap_xyz functions
|
||||||
|
@@ -64,6 +65,7 @@ ifneq ($(DIO_TEST_DEV),)
|
||||||
|
directio-test_LIBDEPS := -laio
|
||||||
|
endif
|
||||||
|
strbuf-test_OBJDEPS := ../libmultipath/strbuf.o
|
||||||
|
+features-test_LIBDEPS := -ludev -lpthread
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) $($*-test_FLAGS) -c -o $@ $<
|
||||||
|
diff --git a/tests/features.c b/tests/features.c
|
||||||
|
index 4d8f0860..31f978fd 100644
|
||||||
|
--- a/tests/features.c
|
||||||
|
+++ b/tests/features.c
|
||||||
|
@@ -1,9 +1,10 @@
|
||||||
|
+#define _GNU_SOURCE
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <cmocka.h>
|
||||||
|
|
||||||
|
-#include "structs.h"
|
||||||
|
+#include "../libmultipath/propsel.c"
|
||||||
|
#include "globals.c"
|
||||||
|
|
||||||
|
static void test_af_null_features_ptr(void **state)
|
||||||
|
@@ -307,6 +308,234 @@ static int test_remove_features(void)
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void test_cf_null_features(void **state)
|
||||||
|
+{
|
||||||
|
+ struct multipath mp = {
|
||||||
|
+ .alias = "test",
|
||||||
|
+ };
|
||||||
|
+ reconcile_features_with_queue_mode(&mp);
|
||||||
|
+ assert_null(mp.features);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void cf_helper(const char *features_start, const char *features_end,
|
||||||
|
+ int queue_mode_start, int queue_mode_end)
|
||||||
|
+{
|
||||||
|
+ struct multipath mp = {
|
||||||
|
+ .alias = "test",
|
||||||
|
+ .features = strdup(features_start),
|
||||||
|
+ .queue_mode = queue_mode_start,
|
||||||
|
+ };
|
||||||
|
+ char *orig = mp.features;
|
||||||
|
+
|
||||||
|
+ assert_non_null(orig);
|
||||||
|
+ reconcile_features_with_queue_mode(&mp);
|
||||||
|
+ if (!features_end)
|
||||||
|
+ assert_ptr_equal(orig, mp.features);
|
||||||
|
+ else
|
||||||
|
+ assert_string_equal(mp.features, features_end);
|
||||||
|
+ free(mp.features);
|
||||||
|
+ assert_int_equal(mp.queue_mode, queue_mode_end);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_unset_unset1(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("0", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_UNDEF);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_unset_unset2(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("1 queue_mode", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_UNDEF);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_unset_unset3(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("queue_mode", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_UNDEF);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_unset_unset4(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 queue_model bio", NULL, QUEUE_MODE_UNDEF,
|
||||||
|
+ QUEUE_MODE_UNDEF);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_unset_unset5(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("1 queue_if_no_path", NULL, QUEUE_MODE_UNDEF,
|
||||||
|
+ QUEUE_MODE_UNDEF);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_invalid_unset1(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 queue_mode biop", "0", QUEUE_MODE_UNDEF, QUEUE_MODE_UNDEF);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_invalid_unset2(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("3 queue_mode rqs queue_if_no_path", "1 queue_if_no_path",
|
||||||
|
+ QUEUE_MODE_UNDEF, QUEUE_MODE_UNDEF);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_rq_unset1(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 queue_mode rq", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_RQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_rq_unset2(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 queue_mode mq", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_RQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_bio_unset(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 queue_mode bio", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_unset_bio1(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("1 queue_if_no_path", "3 queue_if_no_path queue_mode bio",
|
||||||
|
+ QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_unset_bio2(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("0", "2 queue_mode bio", QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_unset_bio3(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 pg_init_retries 50", "4 pg_init_retries 50 queue_mode bio",
|
||||||
|
+ QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_invalid_bio1(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 queue_mode bad", "2 queue_mode bio",
|
||||||
|
+ QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_invalid_bio2(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("3 queue_if_no_path queue_mode\tbad", "3 queue_if_no_path queue_mode bio",
|
||||||
|
+ QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_bio_bio1(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 queue_mode bio", NULL, QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_bio_bio2(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("3 queue_if_no_path queue_mode bio", NULL, QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_bio_bio3(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("3 queue_mode\nbio queue_if_no_path", NULL, QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_bio_rq1(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2\nqueue_mode\tbio", "0", QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_bio_rq2(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("3 queue_if_no_path\nqueue_mode bio", "1 queue_if_no_path",
|
||||||
|
+ QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_bio_rq3(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("4 queue_mode bio pg_init_retries 20", "2 pg_init_retries 20",
|
||||||
|
+ QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_unset_rq1(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("0", NULL, QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_unset_rq2(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 pg_init_retries 15", NULL, QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_invalid_rq1(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 queue_mode bionic", "0", QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_invalid_rq2(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("3 queue_mode b\nqueue_if_no_path", "1 queue_if_no_path",
|
||||||
|
+ QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_rq_rq1(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 queue_mode rq", NULL, QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_rq_rq2(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("3 queue_mode\t \trq\nqueue_if_no_path", NULL, QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_rq_bio1(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("2 queue_mode rq", "2 queue_mode bio", QUEUE_MODE_BIO,
|
||||||
|
+ QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_rq_bio2(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("3 queue_if_no_path\nqueue_mode rq", "3 queue_if_no_path queue_mode bio", QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void test_cf_rq_bio3(void **state)
|
||||||
|
+{
|
||||||
|
+ cf_helper("3 queue_mode rq\nqueue_if_no_path", "3 queue_if_no_path queue_mode bio", QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int test_reconcile_features(void)
|
||||||
|
+{
|
||||||
|
+ const struct CMUnitTest tests[] = {
|
||||||
|
+ cmocka_unit_test(test_cf_null_features),
|
||||||
|
+ cmocka_unit_test(test_cf_unset_unset1),
|
||||||
|
+ cmocka_unit_test(test_cf_unset_unset2),
|
||||||
|
+ cmocka_unit_test(test_cf_unset_unset3),
|
||||||
|
+ cmocka_unit_test(test_cf_unset_unset4),
|
||||||
|
+ cmocka_unit_test(test_cf_unset_unset5),
|
||||||
|
+ cmocka_unit_test(test_cf_invalid_unset1),
|
||||||
|
+ cmocka_unit_test(test_cf_invalid_unset2),
|
||||||
|
+ cmocka_unit_test(test_cf_rq_unset1),
|
||||||
|
+ cmocka_unit_test(test_cf_rq_unset2),
|
||||||
|
+ cmocka_unit_test(test_cf_bio_unset),
|
||||||
|
+ cmocka_unit_test(test_cf_unset_bio1),
|
||||||
|
+ cmocka_unit_test(test_cf_unset_bio2),
|
||||||
|
+ cmocka_unit_test(test_cf_unset_bio3),
|
||||||
|
+ cmocka_unit_test(test_cf_invalid_bio1),
|
||||||
|
+ cmocka_unit_test(test_cf_invalid_bio2),
|
||||||
|
+ cmocka_unit_test(test_cf_bio_bio1),
|
||||||
|
+ cmocka_unit_test(test_cf_bio_bio2),
|
||||||
|
+ cmocka_unit_test(test_cf_bio_bio3),
|
||||||
|
+ cmocka_unit_test(test_cf_bio_rq1),
|
||||||
|
+ cmocka_unit_test(test_cf_bio_rq2),
|
||||||
|
+ cmocka_unit_test(test_cf_bio_rq3),
|
||||||
|
+ cmocka_unit_test(test_cf_unset_rq1),
|
||||||
|
+ cmocka_unit_test(test_cf_unset_rq2),
|
||||||
|
+ cmocka_unit_test(test_cf_invalid_rq1),
|
||||||
|
+ cmocka_unit_test(test_cf_invalid_rq2),
|
||||||
|
+ cmocka_unit_test(test_cf_rq_rq1),
|
||||||
|
+ cmocka_unit_test(test_cf_rq_rq2),
|
||||||
|
+ cmocka_unit_test(test_cf_rq_bio1),
|
||||||
|
+ cmocka_unit_test(test_cf_rq_bio2),
|
||||||
|
+ cmocka_unit_test(test_cf_rq_bio3),
|
||||||
|
+ };
|
||||||
|
+ return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
@@ -314,6 +543,7 @@ int main(void)
|
||||||
|
init_test_verbosity(-1);
|
||||||
|
ret += test_add_features();
|
||||||
|
ret += test_remove_features();
|
||||||
|
+ ret += test_reconcile_features();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Fri, 7 Oct 2022 12:35:42 -0500
|
||||||
|
Subject: [PATCH] libmultipath: prepare proto_id for use by non-scsi devivces
|
||||||
|
|
||||||
|
Make sure that when we are checking for a scsi protocol, we are first
|
||||||
|
checking that we are working with a scsi path.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
libmultipath/configure.c | 9 +++++----
|
||||||
|
libmultipath/discovery.c | 13 ++++++++-----
|
||||||
|
libmultipath/print.c | 6 ++++--
|
||||||
|
libmultipath/structs.c | 2 +-
|
||||||
|
libmultipath/structs.h | 4 +++-
|
||||||
|
multipathd/fpin_handlers.c | 2 +-
|
||||||
|
6 files changed, 22 insertions(+), 14 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||||||
|
index cc778a22..c6803b40 100644
|
||||||
|
--- a/libmultipath/configure.c
|
||||||
|
+++ b/libmultipath/configure.c
|
||||||
|
@@ -223,10 +223,11 @@ int rr_optimize_path_order(struct pathgroup *pgp)
|
||||||
|
|
||||||
|
total_paths = VECTOR_SIZE(pgp->paths);
|
||||||
|
vector_foreach_slot(pgp->paths, pp, i) {
|
||||||
|
- if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP &&
|
||||||
|
- pp->sg_id.proto_id != SCSI_PROTOCOL_SAS &&
|
||||||
|
- pp->sg_id.proto_id != SCSI_PROTOCOL_ISCSI &&
|
||||||
|
- pp->sg_id.proto_id != SCSI_PROTOCOL_SRP) {
|
||||||
|
+ if (pp->bus != SYSFS_BUS_SCSI ||
|
||||||
|
+ (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP &&
|
||||||
|
+ pp->sg_id.proto_id != SCSI_PROTOCOL_SAS &&
|
||||||
|
+ pp->sg_id.proto_id != SCSI_PROTOCOL_ISCSI &&
|
||||||
|
+ pp->sg_id.proto_id != SCSI_PROTOCOL_SRP)) {
|
||||||
|
/* return success as default path order
|
||||||
|
* is maintained in path group
|
||||||
|
*/
|
||||||
|
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
||||||
|
index bcda8b09..7f2eb409 100644
|
||||||
|
--- a/libmultipath/discovery.c
|
||||||
|
+++ b/libmultipath/discovery.c
|
||||||
|
@@ -481,10 +481,11 @@ int sysfs_get_host_adapter_name(const struct path *pp, char *adapter_name)
|
||||||
|
|
||||||
|
proto_id = pp->sg_id.proto_id;
|
||||||
|
|
||||||
|
- if (proto_id != SCSI_PROTOCOL_FCP &&
|
||||||
|
- proto_id != SCSI_PROTOCOL_SAS &&
|
||||||
|
- proto_id != SCSI_PROTOCOL_ISCSI &&
|
||||||
|
- proto_id != SCSI_PROTOCOL_SRP) {
|
||||||
|
+ if (pp->bus != SYSFS_BUS_SCSI ||
|
||||||
|
+ (proto_id != SCSI_PROTOCOL_FCP &&
|
||||||
|
+ proto_id != SCSI_PROTOCOL_SAS &&
|
||||||
|
+ proto_id != SCSI_PROTOCOL_ISCSI &&
|
||||||
|
+ proto_id != SCSI_PROTOCOL_SRP)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* iscsi doesn't have adapter info in sysfs
|
||||||
|
@@ -1754,8 +1755,10 @@ sysfs_pathinfo(struct path *pp, const struct _vector *hwtable)
|
||||||
|
pp->bus = SYSFS_BUS_CCISS;
|
||||||
|
if (!strncmp(pp->dev,"dasd", 4))
|
||||||
|
pp->bus = SYSFS_BUS_CCW;
|
||||||
|
- if (!strncmp(pp->dev,"sd", 2))
|
||||||
|
+ if (!strncmp(pp->dev,"sd", 2)) {
|
||||||
|
pp->bus = SYSFS_BUS_SCSI;
|
||||||
|
+ pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
|
||||||
|
+ }
|
||||||
|
if (!strncmp(pp->dev,"nvme", 4))
|
||||||
|
pp->bus = SYSFS_BUS_NVME;
|
||||||
|
|
||||||
|
diff --git a/libmultipath/print.c b/libmultipath/print.c
|
||||||
|
index 46e3d32e..082e4e30 100644
|
||||||
|
--- a/libmultipath/print.c
|
||||||
|
+++ b/libmultipath/print.c
|
||||||
|
@@ -592,7 +592,8 @@ snprint_host_attr (struct strbuf *buff, const struct path * pp, char *attr)
|
||||||
|
const char *value = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
- if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
|
||||||
|
+ if (pp->bus != SYSFS_BUS_SCSI ||
|
||||||
|
+ pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
|
||||||
|
return append_strbuf_str(buff, "[undef]");
|
||||||
|
sprintf(host_id, "host%d", pp->sg_id.host_no);
|
||||||
|
host_dev = udev_device_new_from_subsystem_sysname(udev, "fc_host",
|
||||||
|
@@ -631,7 +632,8 @@ snprint_tgt_wwpn (struct strbuf *buff, const struct path * pp)
|
||||||
|
const char *value = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
- if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
|
||||||
|
+ if (pp->bus != SYSFS_BUS_SCSI ||
|
||||||
|
+ pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
|
||||||
|
return append_strbuf_str(buff, "[undef]");
|
||||||
|
sprintf(rport_id, "rport-%d:%d-%d",
|
||||||
|
pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
|
||||||
|
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
|
||||||
|
index 5dfa86a8..be81a83c 100644
|
||||||
|
--- a/libmultipath/structs.c
|
||||||
|
+++ b/libmultipath/structs.c
|
||||||
|
@@ -116,7 +116,7 @@ alloc_path (void)
|
||||||
|
pp->sg_id.channel = -1;
|
||||||
|
pp->sg_id.scsi_id = -1;
|
||||||
|
pp->sg_id.lun = SCSI_INVALID_LUN;
|
||||||
|
- pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
|
||||||
|
+ pp->sg_id.proto_id = PROTOCOL_UNSET;
|
||||||
|
pp->fd = -1;
|
||||||
|
pp->tpgs = TPGS_UNDEF;
|
||||||
|
pp->priority = PRIO_UNDEF;
|
||||||
|
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||||
|
index b4f75de0..2525af17 100644
|
||||||
|
--- a/libmultipath/structs.h
|
||||||
|
+++ b/libmultipath/structs.h
|
||||||
|
@@ -176,6 +176,8 @@ enum queue_mode_states {
|
||||||
|
QUEUE_MODE_RQ,
|
||||||
|
};
|
||||||
|
|
||||||
|
+#define PROTOCOL_UNSET -1
|
||||||
|
+
|
||||||
|
enum scsi_protocol {
|
||||||
|
SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */
|
||||||
|
SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */
|
||||||
|
@@ -284,7 +286,7 @@ struct sg_id {
|
||||||
|
uint64_t lun;
|
||||||
|
short h_cmd_per_lun;
|
||||||
|
short d_queue_depth;
|
||||||
|
- enum scsi_protocol proto_id;
|
||||||
|
+ int proto_id;
|
||||||
|
int transport_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/multipathd/fpin_handlers.c b/multipathd/fpin_handlers.c
|
||||||
|
index aaf5655d..571796e7 100644
|
||||||
|
--- a/multipathd/fpin_handlers.c
|
||||||
|
+++ b/multipathd/fpin_handlers.c
|
||||||
|
@@ -219,7 +219,7 @@ static int fpin_chk_wwn_setpath_marginal(uint16_t host_num, struct vectors *ve
|
||||||
|
|
||||||
|
vector_foreach_slot(vecs->pathvec, pp, k) {
|
||||||
|
/* Checks the host number and also for the SCSI FCP */
|
||||||
|
- if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP || host_num != pp->sg_id.host_no)
|
||||||
|
+ if (pp->bus != SYSFS_BUS_SCSI || pp->sg_id.proto_id != SCSI_PROTOCOL_FCP || host_num != pp->sg_id.host_no)
|
||||||
|
continue;
|
||||||
|
sprintf(rport_id, "rport-%d:%d-%d",
|
||||||
|
pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
|
194
SOURCES/0074-libmultipath-get-nvme-path-transport-protocol.patch
Normal file
194
SOURCES/0074-libmultipath-get-nvme-path-transport-protocol.patch
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Fri, 7 Oct 2022 12:35:43 -0500
|
||||||
|
Subject: [PATCH] libmultipath: get nvme path transport protocol
|
||||||
|
|
||||||
|
Read the transport protocol from /sys/block/nvmeXnY/device/transport.
|
||||||
|
Update protocol_name[] and bus_protocol_id() to store the nvme protocol
|
||||||
|
names after the scsi protocol names.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
libmultipath/discovery.c | 18 ++++++++++++++++--
|
||||||
|
libmultipath/structs.c | 22 +++++++++++++++++-----
|
||||||
|
libmultipath/structs.h | 33 +++++++++++++++++++++------------
|
||||||
|
multipath/multipath.conf.5 | 10 +++++++---
|
||||||
|
4 files changed, 61 insertions(+), 22 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
||||||
|
index 7f2eb409..f593a7bf 100644
|
||||||
|
--- a/libmultipath/discovery.c
|
||||||
|
+++ b/libmultipath/discovery.c
|
||||||
|
@@ -1483,6 +1483,7 @@ nvme_sysfs_pathinfo (struct path *pp, const struct _vector *hwtable)
|
||||||
|
struct udev_device *parent;
|
||||||
|
const char *attr_path = NULL;
|
||||||
|
const char *attr;
|
||||||
|
+ int i;
|
||||||
|
|
||||||
|
if (pp->udev)
|
||||||
|
attr_path = udev_device_get_sysname(pp->udev);
|
||||||
|
@@ -1505,6 +1506,18 @@ nvme_sysfs_pathinfo (struct path *pp, const struct _vector *hwtable)
|
||||||
|
attr = udev_device_get_sysattr_value(parent, "cntlid");
|
||||||
|
pp->sg_id.channel = attr ? atoi(attr) : 0;
|
||||||
|
|
||||||
|
+ attr = udev_device_get_sysattr_value(parent, "transport");
|
||||||
|
+ if (attr) {
|
||||||
|
+ for (i = 0; i < NVME_PROTOCOL_UNSPEC; i++){
|
||||||
|
+ if (protocol_name[SYSFS_BUS_NVME + i] &&
|
||||||
|
+ !strcmp(attr,
|
||||||
|
+ protocol_name[SYSFS_BUS_NVME + i] + 5)) {
|
||||||
|
+ pp->sg_id.proto_id = i;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
snprintf(pp->vendor_id, SCSI_VENDOR_SIZE, "NVME");
|
||||||
|
snprintf(pp->product_id, PATH_PRODUCT_SIZE, "%s",
|
||||||
|
udev_device_get_sysattr_value(parent, "model"));
|
||||||
|
@@ -1759,9 +1772,10 @@ sysfs_pathinfo(struct path *pp, const struct _vector *hwtable)
|
||||||
|
pp->bus = SYSFS_BUS_SCSI;
|
||||||
|
pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
|
||||||
|
}
|
||||||
|
- if (!strncmp(pp->dev,"nvme", 4))
|
||||||
|
+ if (!strncmp(pp->dev,"nvme", 4)) {
|
||||||
|
pp->bus = SYSFS_BUS_NVME;
|
||||||
|
-
|
||||||
|
+ pp->sg_id.proto_id = NVME_PROTOCOL_UNSPEC;
|
||||||
|
+ }
|
||||||
|
switch (pp->bus) {
|
||||||
|
case SYSFS_BUS_SCSI:
|
||||||
|
return scsi_sysfs_pathinfo(pp, hwtable);
|
||||||
|
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
|
||||||
|
index be81a83c..a2e56890 100644
|
||||||
|
--- a/libmultipath/structs.c
|
||||||
|
+++ b/libmultipath/structs.c
|
||||||
|
@@ -25,7 +25,6 @@ const char * const protocol_name[LAST_BUS_PROTOCOL_ID + 1] = {
|
||||||
|
[SYSFS_BUS_UNDEF] = "undef",
|
||||||
|
[SYSFS_BUS_CCW] = "ccw",
|
||||||
|
[SYSFS_BUS_CCISS] = "cciss",
|
||||||
|
- [SYSFS_BUS_NVME] = "nvme",
|
||||||
|
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_FCP] = "scsi:fcp",
|
||||||
|
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_SPI] = "scsi:spi",
|
||||||
|
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_SSA] = "scsi:ssa",
|
||||||
|
@@ -37,6 +36,13 @@ const char * const protocol_name[LAST_BUS_PROTOCOL_ID + 1] = {
|
||||||
|
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_ATA] = "scsi:ata",
|
||||||
|
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_USB] = "scsi:usb",
|
||||||
|
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_UNSPEC] = "scsi:unspec",
|
||||||
|
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_PCIE] = "nvme:pcie",
|
||||||
|
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_RDMA] = "nvme:rdma",
|
||||||
|
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_FC] = "nvme:fc",
|
||||||
|
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_TCP] = "nvme:tcp",
|
||||||
|
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_LOOP] = "nvme:loop",
|
||||||
|
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_APPLE_NVME] = "nvme:apple-nvme",
|
||||||
|
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_UNSPEC] = "nvme:unspec",
|
||||||
|
};
|
||||||
|
|
||||||
|
struct adapter_group *
|
||||||
|
@@ -752,11 +758,17 @@ out:
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int bus_protocol_id(const struct path *pp) {
|
||||||
|
- if (!pp || pp->bus < 0 || pp->bus > SYSFS_BUS_SCSI)
|
||||||
|
+ if (!pp || pp->bus < 0 || pp->bus > SYSFS_BUS_NVME)
|
||||||
|
return SYSFS_BUS_UNDEF;
|
||||||
|
- if (pp->bus != SYSFS_BUS_SCSI)
|
||||||
|
+ if (pp->bus != SYSFS_BUS_SCSI && pp->bus != SYSFS_BUS_NVME)
|
||||||
|
return pp->bus;
|
||||||
|
- if ((int)pp->sg_id.proto_id < 0 || pp->sg_id.proto_id > SCSI_PROTOCOL_UNSPEC)
|
||||||
|
+ if (pp->sg_id.proto_id < 0)
|
||||||
|
return SYSFS_BUS_UNDEF;
|
||||||
|
- return SYSFS_BUS_SCSI + pp->sg_id.proto_id;
|
||||||
|
+ if (pp->bus == SYSFS_BUS_SCSI &&
|
||||||
|
+ pp->sg_id.proto_id > SCSI_PROTOCOL_UNSPEC)
|
||||||
|
+ return SYSFS_BUS_UNDEF;
|
||||||
|
+ if (pp->bus == SYSFS_BUS_NVME &&
|
||||||
|
+ pp->sg_id.proto_id > NVME_PROTOCOL_UNSPEC)
|
||||||
|
+ return SYSFS_BUS_UNDEF;
|
||||||
|
+ return pp->bus + pp->sg_id.proto_id;
|
||||||
|
}
|
||||||
|
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||||
|
index 2525af17..0867b91d 100644
|
||||||
|
--- a/libmultipath/structs.h
|
||||||
|
+++ b/libmultipath/structs.h
|
||||||
|
@@ -56,15 +56,6 @@ enum failback_mode {
|
||||||
|
FAILBACK_FOLLOWOVER
|
||||||
|
};
|
||||||
|
|
||||||
|
-/* SYSFS_BUS_SCSI should be last, see bus_protocol_id() */
|
||||||
|
-enum sysfs_buses {
|
||||||
|
- SYSFS_BUS_UNDEF,
|
||||||
|
- SYSFS_BUS_CCW,
|
||||||
|
- SYSFS_BUS_CCISS,
|
||||||
|
- SYSFS_BUS_NVME,
|
||||||
|
- SYSFS_BUS_SCSI,
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
enum pathstates {
|
||||||
|
PSTATE_UNDEF,
|
||||||
|
PSTATE_FAILED,
|
||||||
|
@@ -190,14 +181,32 @@ enum scsi_protocol {
|
||||||
|
SCSI_PROTOCOL_ATA = 8,
|
||||||
|
SCSI_PROTOCOL_USB = 9, /* USB Attached SCSI (UAS), and others */
|
||||||
|
SCSI_PROTOCOL_UNSPEC = 0xa, /* No specific protocol */
|
||||||
|
+ SCSI_PROTOCOL_END = 0xb, /* offset of the next sysfs_buses entry */
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/* values from /sys/class/nvme/nvmeX */
|
||||||
|
+enum nvme_protocol {
|
||||||
|
+ NVME_PROTOCOL_PCIE = 0,
|
||||||
|
+ NVME_PROTOCOL_RDMA = 1,
|
||||||
|
+ NVME_PROTOCOL_FC = 2,
|
||||||
|
+ NVME_PROTOCOL_TCP = 3,
|
||||||
|
+ NVME_PROTOCOL_LOOP = 4,
|
||||||
|
+ NVME_PROTOCOL_APPLE_NVME = 5,
|
||||||
|
+ NVME_PROTOCOL_UNSPEC = 6, /* unknown protocol */
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+enum sysfs_buses {
|
||||||
|
+ SYSFS_BUS_UNDEF,
|
||||||
|
+ SYSFS_BUS_CCW,
|
||||||
|
+ SYSFS_BUS_CCISS,
|
||||||
|
+ SYSFS_BUS_SCSI,
|
||||||
|
+ SYSFS_BUS_NVME = SYSFS_BUS_SCSI + SCSI_PROTOCOL_END,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linear ordering of bus/protocol
|
||||||
|
- * This assumes that SYSFS_BUS_SCSI is last in enum sysfs_buses
|
||||||
|
- * SCSI is the only bus type for which we distinguish protocols.
|
||||||
|
*/
|
||||||
|
-#define LAST_BUS_PROTOCOL_ID (SYSFS_BUS_SCSI + SCSI_PROTOCOL_UNSPEC)
|
||||||
|
+#define LAST_BUS_PROTOCOL_ID (SYSFS_BUS_NVME + NVME_PROTOCOL_UNSPEC)
|
||||||
|
unsigned int bus_protocol_id(const struct path *pp);
|
||||||
|
extern const char * const protocol_name[];
|
||||||
|
|
||||||
|
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
||||||
|
index e1a787d4..7af53588 100644
|
||||||
|
--- a/multipath/multipath.conf.5
|
||||||
|
+++ b/multipath/multipath.conf.5
|
||||||
|
@@ -1395,7 +1395,9 @@ Regular expression for the protocol of a device to be excluded/included.
|
||||||
|
The protocol strings that multipath recognizes are \fIscsi:fcp\fR,
|
||||||
|
\fIscsi:spi\fR, \fIscsi:ssa\fR, \fIscsi:sbp\fR, \fIscsi:srp\fR,
|
||||||
|
\fIscsi:iscsi\fR, \fIscsi:sas\fR, \fIscsi:adt\fR, \fIscsi:ata\fR,
|
||||||
|
-\fIscsi:unspec\fR, \fIccw\fR, \fIcciss\fR, \fInvme\fR, and \fIundef\fR.
|
||||||
|
+\fIscsi:unspec\fR, \fInvme:pcie\fR, \fInvme:rdma\fR, \fInvme:fc\fR,
|
||||||
|
+\fInvme:tcp\fR, \fInvme:loop\fR, \fInvme:apple-nvme\fR, \fInvme:unspec\fR,
|
||||||
|
+\fIccw\fR, \fIcciss\fR, and \fIundef\fR.
|
||||||
|
The protocol that a path is using can be viewed by running
|
||||||
|
\fBmultipathd show paths format "%d %P"\fR
|
||||||
|
.RE
|
||||||
|
@@ -1783,8 +1785,10 @@ The protocol subsection recognizes the following mandatory attribute:
|
||||||
|
The protocol string of the path device. The possible values are \fIscsi:fcp\fR,
|
||||||
|
\fIscsi:spi\fR, \fIscsi:ssa\fR, \fIscsi:sbp\fR, \fIscsi:srp\fR,
|
||||||
|
\fIscsi:iscsi\fR, \fIscsi:sas\fR, \fIscsi:adt\fR, \fIscsi:ata\fR,
|
||||||
|
-\fIscsi:unspec\fR, \fIccw\fR, \fIcciss\fR, \fInvme\fR, and \fIundef\fR. This is
|
||||||
|
-\fBnot\fR a regular expression. the path device protcol string must match
|
||||||
|
+\fIscsi:unspec\fR, \fInvme:pcie\fR, \fInvme:rdma\fR, \fInvme:fc\fR,
|
||||||
|
+\fInvme:tcp\fR, \fInvme:loop\fR, \fInvme:apple-nvme\fR, \fInvme:unspec\fR,
|
||||||
|
+\fIccw\fR, \fIcciss\fR, and \fIundef\fR. This is
|
||||||
|
+\fBnot\fR a regular expression. the path device protocol string must match
|
||||||
|
exactly. The protocol that a path is using can be viewed by running
|
||||||
|
\fBmultipathd show paths format "%d %P"\fR
|
||||||
|
.LP
|
@ -0,0 +1,111 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Fri, 7 Oct 2022 12:35:44 -0500
|
||||||
|
Subject: [PATCH] libmultipath: enforce queue_mode bio for nmve:tcp paths
|
||||||
|
|
||||||
|
nvme:tcp devices set BLK_MQ_F_BLOCKING (they are the only block devices
|
||||||
|
which multipath supports that do so), meaning that block_mq expects that
|
||||||
|
they can block at certain points while servicing a request. However,
|
||||||
|
due to the way device-mapper sets up its queue, it is not able to set
|
||||||
|
BLK_MQ_F_BLOCKING when it includes paths that set this flag. Patches
|
||||||
|
were written to address this issue but they were rejected upstream
|
||||||
|
|
||||||
|
https://lore.kernel.org/linux-block/YcH%2FE4JNag0QYYAa@infradead.org/T/#t
|
||||||
|
|
||||||
|
The proposed solution was to have multipath use the bio queue_mode for
|
||||||
|
multipath devices that include nvme:tcp paths.
|
||||||
|
|
||||||
|
Multipath devices now automatically add the "queue_mode bio" feature if
|
||||||
|
they include nvme:tcp paths. If a multipath devices was created with
|
||||||
|
"queue_mode rq", it will disallow the addition of nvme:tcp paths.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
libmultipath/configure.c | 17 ++++++++++++++++-
|
||||||
|
libmultipath/structs_vec.c | 7 +++++++
|
||||||
|
multipath/multipath.conf.5 | 4 +++-
|
||||||
|
3 files changed, 26 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||||||
|
index c6803b40..193bf27d 100644
|
||||||
|
--- a/libmultipath/configure.c
|
||||||
|
+++ b/libmultipath/configure.c
|
||||||
|
@@ -296,6 +296,7 @@ static int wait_for_pending_paths(struct multipath *mpp,
|
||||||
|
int setup_map(struct multipath *mpp, char **params, struct vectors *vecs)
|
||||||
|
{
|
||||||
|
struct pathgroup * pgp;
|
||||||
|
+ struct path *pp;
|
||||||
|
struct config *conf;
|
||||||
|
int i, n_paths, marginal_pathgroups;
|
||||||
|
char *save_attr;
|
||||||
|
@@ -311,6 +312,14 @@ int setup_map(struct multipath *mpp, char **params, struct vectors *vecs)
|
||||||
|
if (mpp->disable_queueing && VECTOR_SIZE(mpp->paths) != 0)
|
||||||
|
mpp->disable_queueing = 0;
|
||||||
|
|
||||||
|
+ /* Force QUEUE_MODE_BIO for maps with nvme:tcp paths */
|
||||||
|
+ vector_foreach_slot(mpp->paths, pp, i) {
|
||||||
|
+ if (pp->bus == SYSFS_BUS_NVME &&
|
||||||
|
+ pp->sg_id.proto_id == NVME_PROTOCOL_TCP) {
|
||||||
|
+ mpp->queue_mode = QUEUE_MODE_BIO;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
/*
|
||||||
|
* If this map was created with add_map_without_path(),
|
||||||
|
* mpp->hwe might not be set yet.
|
||||||
|
@@ -1191,6 +1200,13 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid,
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ cmpp = find_mp_by_wwid(curmp, pp1->wwid);
|
||||||
|
+ if (cmpp && cmpp->queue_mode == QUEUE_MODE_RQ &&
|
||||||
|
+ pp1->bus == SYSFS_BUS_NVME && pp1->sg_id.proto_id ==
|
||||||
|
+ NVME_PROTOCOL_TCP) {
|
||||||
|
+ orphan_path(pp1, "nvme:tcp path not allowed with request queue_mode multipath device");
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
/*
|
||||||
|
* at this point, we know we really got a new mp
|
||||||
|
*/
|
||||||
|
@@ -1229,7 +1245,6 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid,
|
||||||
|
}
|
||||||
|
verify_paths(mpp);
|
||||||
|
|
||||||
|
- cmpp = find_mp_by_wwid(curmp, mpp->wwid);
|
||||||
|
if (cmpp)
|
||||||
|
mpp->queue_mode = cmpp->queue_mode;
|
||||||
|
if (setup_map(mpp, ¶ms, vecs)) {
|
||||||
|
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
|
||||||
|
index 85d97ac1..4a32b405 100644
|
||||||
|
--- a/libmultipath/structs_vec.c
|
||||||
|
+++ b/libmultipath/structs_vec.c
|
||||||
|
@@ -262,6 +262,13 @@ int adopt_paths(vector pathvec, struct multipath *mpp)
|
||||||
|
}
|
||||||
|
if (pp->initialized == INIT_REMOVED)
|
||||||
|
continue;
|
||||||
|
+ if (mpp->queue_mode == QUEUE_MODE_RQ &&
|
||||||
|
+ pp->bus == SYSFS_BUS_NVME &&
|
||||||
|
+ pp->sg_id.proto_id == NVME_PROTOCOL_TCP) {
|
||||||
|
+ condlog(2, "%s: mulitpath device %s created with request queue_mode. Unable to add nvme:tcp paths",
|
||||||
|
+ pp->dev, mpp->alias);
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
if (!mpp->paths && !(mpp->paths = vector_alloc()))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
||||||
|
index 7af53588..01904feb 100644
|
||||||
|
--- a/multipath/multipath.conf.5
|
||||||
|
+++ b/multipath/multipath.conf.5
|
||||||
|
@@ -472,7 +472,9 @@ Before kernel 4.20 The default depends on the kernel parameter
|
||||||
|
\fBdm_mod.use_blk_mq\fR. It is \fImq\fR if the latter is set, and \fIrq\fR
|
||||||
|
otherwise. Since kernel 4.20, \fIrq\fR and \fImq\fR both correspond to
|
||||||
|
block-multiqueue. Once a multipath device has been created, its queue_mode
|
||||||
|
-cannot be changed.
|
||||||
|
+cannot be changed. \fInvme:tcp\fR paths are only supported in multipath
|
||||||
|
+devices with queue_mode set to \fIbio\fR. multipath will automatically
|
||||||
|
+set this when creating a device with \fInvme:tcp\fR paths.
|
||||||
|
.TP
|
||||||
|
The default is: \fB<unset>\fR
|
||||||
|
.RE
|
@ -0,0 +1,33 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Tue, 29 Nov 2022 19:56:37 -0600
|
||||||
|
Subject: [PATCH] multipath.conf(5): remove io-affinity information
|
||||||
|
|
||||||
|
The multpath-tools do not support the io-affinity path selector. We
|
||||||
|
always add a repeat count as the path argument. The io-affinity selector
|
||||||
|
doesn't take one. Instead it takes a bit map of CPUs that a path can
|
||||||
|
run on. This isn't something that lends itself to the kind of
|
||||||
|
auto-assembling that multipathd does. But even if we did want to
|
||||||
|
try to support this path-selector, until we do, we shouldn't be listing
|
||||||
|
it in the multipath.conf documentation.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
---
|
||||||
|
multipath/multipath.conf.5 | 4 ----
|
||||||
|
1 file changed, 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
||||||
|
index 01904feb..5e447e67 100644
|
||||||
|
--- a/multipath/multipath.conf.5
|
||||||
|
+++ b/multipath/multipath.conf.5
|
||||||
|
@@ -211,10 +211,6 @@ of outstanding I/O to the path and its relative throughput.
|
||||||
|
estimation of future service time based on the history of previous I/O submitted
|
||||||
|
to each path.
|
||||||
|
.TP
|
||||||
|
-.I "io-affinity 0"
|
||||||
|
-(Since 5.11 kernel) Choose the path for the next bunch of I/O based on a CPU to
|
||||||
|
-path mapping the user passes in and what CPU we are executing on.
|
||||||
|
-.TP
|
||||||
|
The default is: \fBservice-time 0\fR
|
||||||
|
.RE
|
||||||
|
.
|
@ -0,0 +1,35 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Wed, 14 Dec 2022 15:38:19 -0600
|
||||||
|
Subject: [PATCH] libmultipath: don't leak memory on invalid strings
|
||||||
|
|
||||||
|
If set_path() or set_str_noslash() are called with a bad value, they
|
||||||
|
ignore it and continue to use the old value. But they weren't freeing
|
||||||
|
the bad value, causing a memory leak.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
libmultipath/dict.c | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
|
||||||
|
index 46b9f225..861d1d17 100644
|
||||||
|
--- a/libmultipath/dict.c
|
||||||
|
+++ b/libmultipath/dict.c
|
||||||
|
@@ -156,6 +156,7 @@ set_path(vector strvec, void *ptr, const char *file, int line_nr)
|
||||||
|
if ((*str_ptr)[0] != '/'){
|
||||||
|
condlog(1, "%s line %d, %s is not an absolute path. Ignoring",
|
||||||
|
file, line_nr, *str_ptr);
|
||||||
|
+ free(*str_ptr);
|
||||||
|
*str_ptr = old_str;
|
||||||
|
} else
|
||||||
|
free(old_str);
|
||||||
|
@@ -176,6 +177,7 @@ set_str_noslash(vector strvec, void *ptr, const char *file, int line_nr)
|
||||||
|
if (strchr(*str_ptr, '/')) {
|
||||||
|
condlog(1, "%s line %d, %s cannot contain a slash. Ignoring",
|
||||||
|
file, line_nr, *str_ptr);
|
||||||
|
+ free(*str_ptr);
|
||||||
|
*str_ptr = old_str;
|
||||||
|
} else
|
||||||
|
free(old_str);
|
@ -0,0 +1,195 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Wed, 14 Dec 2022 15:38:20 -0600
|
||||||
|
Subject: [PATCH] libmutipath: validate the argument count of config strings
|
||||||
|
|
||||||
|
The features, path_selector, and hardware_handler config options pass
|
||||||
|
their strings directly into the kernel. If users omit the argument
|
||||||
|
counts from these strings, or use the wrong value, the kernel's table
|
||||||
|
parsing gets completely messed up, and the error messages it prints
|
||||||
|
don't reflect what actully went wrong. To avoid messing up the
|
||||||
|
kernel table parsing, verify that these strings correctly set the
|
||||||
|
argument count to the number of arguments they have.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||||
|
---
|
||||||
|
libmultipath/dict.c | 110 ++++++++++++++++++++++++++++++++++++++++----
|
||||||
|
1 file changed, 101 insertions(+), 9 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
|
||||||
|
index 861d1d17..eb2f33a2 100644
|
||||||
|
--- a/libmultipath/dict.c
|
||||||
|
+++ b/libmultipath/dict.c
|
||||||
|
@@ -142,6 +142,58 @@ set_dir(vector strvec, void *ptr, const char *file, int line_nr)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int
|
||||||
|
+set_arg_str(vector strvec, void *ptr, int count_idx, const char *file,
|
||||||
|
+ int line_nr)
|
||||||
|
+{
|
||||||
|
+ char **str_ptr = (char **)ptr;
|
||||||
|
+ char *old_str = *str_ptr;
|
||||||
|
+ const char * const spaces = " \f\r\t\v";
|
||||||
|
+ char *p, *end;
|
||||||
|
+ int idx = -1;
|
||||||
|
+ long int count = -1;
|
||||||
|
+
|
||||||
|
+ *str_ptr = set_value(strvec);
|
||||||
|
+ if (!*str_ptr) {
|
||||||
|
+ free(old_str);
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+ p = *str_ptr;
|
||||||
|
+ while (*p != '\0') {
|
||||||
|
+ p += strspn(p, spaces);
|
||||||
|
+ if (*p == '\0')
|
||||||
|
+ break;
|
||||||
|
+ idx += 1;
|
||||||
|
+ if (idx == count_idx) {
|
||||||
|
+ errno = 0;
|
||||||
|
+ count = strtol(p, &end, 10);
|
||||||
|
+ if (errno == ERANGE || end == p ||
|
||||||
|
+ !(isspace(*end) || *end == '\0')) {
|
||||||
|
+ count = -1;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ p += strcspn(p, spaces);
|
||||||
|
+ }
|
||||||
|
+ if (count < 0) {
|
||||||
|
+ condlog(1, "%s line %d, missing argument count for %s",
|
||||||
|
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0));
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+ if (count != idx - count_idx) {
|
||||||
|
+ condlog(1, "%s line %d, invalid argument count for %s:, got '%ld' expected '%d'",
|
||||||
|
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0), count,
|
||||||
|
+ idx - count_idx);
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+ free(old_str);
|
||||||
|
+ return 0;
|
||||||
|
+fail:
|
||||||
|
+ free(*str_ptr);
|
||||||
|
+ *str_ptr = old_str;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int
|
||||||
|
set_path(vector strvec, void *ptr, const char *file, int line_nr)
|
||||||
|
{
|
||||||
|
@@ -294,6 +346,14 @@ def_ ## option ## _handler (struct config *conf, vector strvec, \
|
||||||
|
return set_int(strvec, &conf->option, minval, maxval, file, line_nr); \
|
||||||
|
}
|
||||||
|
|
||||||
|
+#define declare_def_arg_str_handler(option, count_idx) \
|
||||||
|
+static int \
|
||||||
|
+def_ ## option ## _handler (struct config *conf, vector strvec, \
|
||||||
|
+ const char *file, int line_nr) \
|
||||||
|
+{ \
|
||||||
|
+ return set_arg_str(strvec, &conf->option, count_idx, file, line_nr); \
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#define declare_def_snprint(option, function) \
|
||||||
|
static int \
|
||||||
|
snprint_def_ ## option (struct config *conf, struct strbuf *buff, \
|
||||||
|
@@ -346,6 +406,17 @@ hw_ ## option ## _handler (struct config *conf, vector strvec, \
|
||||||
|
return set_int(strvec, &hwe->option, minval, maxval, file, line_nr); \
|
||||||
|
}
|
||||||
|
|
||||||
|
+#define declare_hw_arg_str_handler(option, count_idx) \
|
||||||
|
+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_arg_str(strvec, &hwe->option, count_idx, file, line_nr); \
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
|
||||||
|
#define declare_hw_snprint(option, function) \
|
||||||
|
static int \
|
||||||
|
@@ -377,6 +448,16 @@ ovr_ ## option ## _handler (struct config *conf, vector strvec, \
|
||||||
|
file, line_nr); \
|
||||||
|
}
|
||||||
|
|
||||||
|
+#define declare_ovr_arg_str_handler(option, count_idx) \
|
||||||
|
+static int \
|
||||||
|
+ovr_ ## option ## _handler (struct config *conf, vector strvec, \
|
||||||
|
+ const char *file, int line_nr) \
|
||||||
|
+{ \
|
||||||
|
+ if (!conf->overrides) \
|
||||||
|
+ return 1; \
|
||||||
|
+ return set_arg_str(strvec, &conf->overrides->option, count_idx, file, line_nr); \
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#define declare_ovr_snprint(option, function) \
|
||||||
|
static int \
|
||||||
|
snprint_ovr_ ## option (struct config *conf, struct strbuf *buff, \
|
||||||
|
@@ -407,6 +488,17 @@ mp_ ## option ## _handler (struct config *conf, vector strvec, \
|
||||||
|
return set_int(strvec, &mpe->option, minval, maxval, file, line_nr); \
|
||||||
|
}
|
||||||
|
|
||||||
|
+#define declare_mp_arg_str_handler(option, count_idx) \
|
||||||
|
+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_arg_str(strvec, &mpe->option, count_idx, file, line_nr); \
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#define declare_mp_snprint(option, function) \
|
||||||
|
static int \
|
||||||
|
snprint_mp_ ## option (struct config *conf, struct strbuf *buff, \
|
||||||
|
@@ -591,13 +683,13 @@ snprint_def_marginal_pathgroups(struct config *conf, struct strbuf *buff,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-declare_def_handler(selector, set_str)
|
||||||
|
+declare_def_arg_str_handler(selector, 1)
|
||||||
|
declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
|
||||||
|
-declare_hw_handler(selector, set_str)
|
||||||
|
+declare_hw_arg_str_handler(selector, 1)
|
||||||
|
declare_hw_snprint(selector, print_str)
|
||||||
|
-declare_ovr_handler(selector, set_str)
|
||||||
|
+declare_ovr_arg_str_handler(selector, 1)
|
||||||
|
declare_ovr_snprint(selector, print_str)
|
||||||
|
-declare_mp_handler(selector, set_str)
|
||||||
|
+declare_mp_arg_str_handler(selector, 1)
|
||||||
|
declare_mp_snprint(selector, print_str)
|
||||||
|
|
||||||
|
static int snprint_uid_attrs(struct config *conf, struct strbuf *buff,
|
||||||
|
@@ -672,13 +764,13 @@ declare_hw_snprint(prio_args, print_str)
|
||||||
|
declare_mp_handler(prio_args, set_str)
|
||||||
|
declare_mp_snprint(prio_args, print_str)
|
||||||
|
|
||||||
|
-declare_def_handler(features, set_str)
|
||||||
|
+declare_def_arg_str_handler(features, 0)
|
||||||
|
declare_def_snprint_defstr(features, print_str, DEFAULT_FEATURES)
|
||||||
|
-declare_ovr_handler(features, set_str)
|
||||||
|
+declare_ovr_arg_str_handler(features, 0)
|
||||||
|
declare_ovr_snprint(features, print_str)
|
||||||
|
-declare_hw_handler(features, set_str)
|
||||||
|
+declare_hw_arg_str_handler(features, 0)
|
||||||
|
declare_hw_snprint(features, print_str)
|
||||||
|
-declare_mp_handler(features, set_str)
|
||||||
|
+declare_mp_arg_str_handler(features, 0)
|
||||||
|
declare_mp_snprint(features, print_str)
|
||||||
|
|
||||||
|
declare_def_handler(checker_name, set_str)
|
||||||
|
@@ -1857,7 +1949,7 @@ declare_hw_snprint(revision, print_str)
|
||||||
|
declare_hw_handler(bl_product, set_str)
|
||||||
|
declare_hw_snprint(bl_product, print_str)
|
||||||
|
|
||||||
|
-declare_hw_handler(hwhandler, set_str)
|
||||||
|
+declare_hw_arg_str_handler(hwhandler, 0)
|
||||||
|
declare_hw_snprint(hwhandler, print_str)
|
||||||
|
|
||||||
|
/*
|
@ -0,0 +1,38 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Mon, 30 Jan 2023 19:54:19 -0600
|
||||||
|
Subject: [PATCH] libmultipath: use select_reload_action in select_action
|
||||||
|
|
||||||
|
Since we have a function to set the action to reload, use it.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
---
|
||||||
|
libmultipath/configure.c | 8 ++------
|
||||||
|
1 file changed, 2 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||||||
|
index 193bf27d..09d7de0f 100644
|
||||||
|
--- a/libmultipath/configure.c
|
||||||
|
+++ b/libmultipath/configure.c
|
||||||
|
@@ -771,9 +771,7 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
|
||||||
|
|
||||||
|
if (force_reload) {
|
||||||
|
mpp->force_udev_reload = 1;
|
||||||
|
- mpp->action = ACT_RELOAD;
|
||||||
|
- condlog(3, "%s: set ACT_RELOAD (forced by user)",
|
||||||
|
- mpp->alias);
|
||||||
|
+ select_reload_action(mpp, "forced by user");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cmpp->size != mpp->size) {
|
||||||
|
@@ -786,9 +784,7 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
|
||||||
|
|
||||||
|
if (!is_udev_ready(cmpp) && count_active_paths(mpp) > 0) {
|
||||||
|
mpp->force_udev_reload = 1;
|
||||||
|
- mpp->action = ACT_RELOAD;
|
||||||
|
- condlog(3, "%s: set ACT_RELOAD (udev incomplete)",
|
||||||
|
- mpp->alias);
|
||||||
|
+ select_reload_action(mpp, "udev incomplete");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Tue, 31 Jan 2023 09:58:55 -0600
|
||||||
|
Subject: [PATCH] libmultipath: select resize action even if reload is forced
|
||||||
|
|
||||||
|
The ACT_RESIZE action is the same as the ACT_RELOAD action, except that
|
||||||
|
it flushes outstanding IO because the device size is changing and
|
||||||
|
the new size might be too small for some of the outstanding IO. If we've
|
||||||
|
detected a size change, and a forced reload is requested, we still need
|
||||||
|
to flush the IO because the reload will change the device size.
|
||||||
|
|
||||||
|
Signed-off-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 09d7de0f..c91a8139 100644
|
||||||
|
--- a/libmultipath/configure.c
|
||||||
|
+++ b/libmultipath/configure.c
|
||||||
|
@@ -769,11 +769,6 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (force_reload) {
|
||||||
|
- mpp->force_udev_reload = 1;
|
||||||
|
- select_reload_action(mpp, "forced by user");
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
if (cmpp->size != mpp->size) {
|
||||||
|
mpp->force_udev_reload = 1;
|
||||||
|
mpp->action = ACT_RESIZE;
|
||||||
|
@@ -782,6 +777,12 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (force_reload) {
|
||||||
|
+ mpp->force_udev_reload = 1;
|
||||||
|
+ select_reload_action(mpp, "forced by user");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (!is_udev_ready(cmpp) && count_active_paths(mpp) > 0) {
|
||||||
|
mpp->force_udev_reload = 1;
|
||||||
|
select_reload_action(mpp, "udev incomplete");
|
@ -0,0 +1,67 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Tue, 31 Jan 2023 10:35:10 -0600
|
||||||
|
Subject: [PATCH] libmultipath: cleanup ACT_CREATE code in select_action
|
||||||
|
|
||||||
|
Combine the two separate blocks that set ACT_CREATE into one.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
---
|
||||||
|
libmultipath/configure.c | 38 +++++++++++++++++---------------------
|
||||||
|
1 file changed, 17 insertions(+), 21 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||||||
|
index c91a8139..24d051dd 100644
|
||||||
|
--- a/libmultipath/configure.c
|
||||||
|
+++ b/libmultipath/configure.c
|
||||||
|
@@ -728,33 +728,29 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
|
||||||
|
cmpp = find_mp_by_wwid(curmp, mpp->wwid);
|
||||||
|
cmpp_by_name = find_mp_by_alias(curmp, mpp->alias);
|
||||||
|
|
||||||
|
- if (!cmpp_by_name) {
|
||||||
|
- if (cmpp) {
|
||||||
|
- condlog(2, "%s: rename %s to %s", mpp->wwid,
|
||||||
|
- cmpp->alias, mpp->alias);
|
||||||
|
- strlcpy(mpp->alias_old, cmpp->alias, WWID_SIZE);
|
||||||
|
- mpp->action = ACT_RENAME;
|
||||||
|
- if (force_reload) {
|
||||||
|
- mpp->force_udev_reload = 1;
|
||||||
|
- mpp->action = ACT_FORCERENAME;
|
||||||
|
- }
|
||||||
|
- return;
|
||||||
|
+ if (!cmpp) {
|
||||||
|
+ if (cmpp_by_name) {
|
||||||
|
+ 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 does not exist)",
|
||||||
|
- mpp->alias);
|
||||||
|
+ condlog(3, "%s: set ACT_CREATE (map does not exist%s)",
|
||||||
|
+ mpp->alias, cmpp_by_name ? ", name changed" : "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (!cmpp) {
|
||||||
|
- 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 does not exist, name changed)",
|
||||||
|
+ if (!cmpp_by_name) {
|
||||||
|
+ condlog(2, "%s: rename %s to %s", mpp->wwid, cmpp->alias,
|
||||||
|
mpp->alias);
|
||||||
|
+ strlcpy(mpp->alias_old, cmpp->alias, WWID_SIZE);
|
||||||
|
+ mpp->action = ACT_RENAME;
|
||||||
|
+ if (force_reload) {
|
||||||
|
+ mpp->force_udev_reload = 1;
|
||||||
|
+ mpp->action = ACT_FORCERENAME;
|
||||||
|
+ }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,185 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Tue, 31 Jan 2023 12:00:31 -0600
|
||||||
|
Subject: [PATCH] libmultipath: keep renames from stopping other multipath
|
||||||
|
actions
|
||||||
|
|
||||||
|
If select_action() is called and a multipath device needs to be renamed,
|
||||||
|
the code currently checks if force_reload is set, and if so, does the
|
||||||
|
reload after the rename. But if force_reload isn't set, only the rename
|
||||||
|
happens, regardless of what other actions are needed. This can happen if
|
||||||
|
multipathd starts up and a device needs both a reload and a rename.
|
||||||
|
|
||||||
|
Make multipath check for resize, reload, and switch pathgroup along with
|
||||||
|
rename, and do both if necessary.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
---
|
||||||
|
libmultipath/configure.c | 62 +++++++++++++++++-----------------------
|
||||||
|
libmultipath/configure.h | 4 ++-
|
||||||
|
2 files changed, 30 insertions(+), 36 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||||||
|
index 24d051dd..bbdbb8ca 100644
|
||||||
|
--- a/libmultipath/configure.c
|
||||||
|
+++ b/libmultipath/configure.c
|
||||||
|
@@ -714,7 +714,8 @@ static bool is_udev_ready(struct multipath *cmpp)
|
||||||
|
static void
|
||||||
|
select_reload_action(struct multipath *mpp, const char *reason)
|
||||||
|
{
|
||||||
|
- mpp->action = ACT_RELOAD;
|
||||||
|
+ mpp->action = mpp->action == ACT_RENAME ? ACT_RELOAD_RENAME :
|
||||||
|
+ ACT_RELOAD;
|
||||||
|
condlog(3, "%s: set ACT_RELOAD (%s)", mpp->alias, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -725,6 +726,7 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
|
||||||
|
struct multipath * cmpp_by_name;
|
||||||
|
char * mpp_feat, * cmpp_feat;
|
||||||
|
|
||||||
|
+ mpp->action = ACT_NOTHING;
|
||||||
|
cmpp = find_mp_by_wwid(curmp, mpp->wwid);
|
||||||
|
cmpp_by_name = find_mp_by_alias(curmp, mpp->alias);
|
||||||
|
|
||||||
|
@@ -747,14 +749,8 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
|
||||||
|
mpp->alias);
|
||||||
|
strlcpy(mpp->alias_old, cmpp->alias, WWID_SIZE);
|
||||||
|
mpp->action = ACT_RENAME;
|
||||||
|
- if (force_reload) {
|
||||||
|
- mpp->force_udev_reload = 1;
|
||||||
|
- mpp->action = ACT_FORCERENAME;
|
||||||
|
- }
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (cmpp != cmpp_by_name) {
|
||||||
|
+ /* don't return here. Check for other needed actions */
|
||||||
|
+ } else if (cmpp != cmpp_by_name) {
|
||||||
|
condlog(2, "%s: unable to rename %s to %s (%s is used by %s)",
|
||||||
|
mpp->wwid, cmpp->alias, mpp->alias,
|
||||||
|
mpp->alias, cmpp_by_name->wwid);
|
||||||
|
@@ -762,12 +758,13 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
|
||||||
|
FREE(mpp->alias);
|
||||||
|
mpp->alias = STRDUP(cmpp->alias);
|
||||||
|
mpp->action = ACT_IMPOSSIBLE;
|
||||||
|
- return;
|
||||||
|
+ /* don't return here. Check for other needed actions */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmpp->size != mpp->size) {
|
||||||
|
mpp->force_udev_reload = 1;
|
||||||
|
- mpp->action = ACT_RESIZE;
|
||||||
|
+ mpp->action = mpp->action == ACT_RENAME ? ACT_RESIZE_RENAME :
|
||||||
|
+ ACT_RESIZE;
|
||||||
|
condlog(3, "%s: set ACT_RESIZE (size change)",
|
||||||
|
mpp->alias);
|
||||||
|
return;
|
||||||
|
@@ -843,14 +840,14 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cmpp->nextpg != mpp->bestpg) {
|
||||||
|
- mpp->action = ACT_SWITCHPG;
|
||||||
|
+ mpp->action = mpp->action == ACT_RENAME ? ACT_SWITCHPG_RENAME :
|
||||||
|
+ ACT_SWITCHPG;
|
||||||
|
condlog(3, "%s: set ACT_SWITCHPG (next path group change)",
|
||||||
|
mpp->alias);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
- mpp->action = ACT_NOTHING;
|
||||||
|
- condlog(3, "%s: set ACT_NOTHING (map unchanged)",
|
||||||
|
- mpp->alias);
|
||||||
|
+ if (mpp->action == ACT_NOTHING)
|
||||||
|
+ condlog(3, "%s: set ACT_NOTHING (map unchanged)", mpp->alias);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -951,6 +948,17 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (mpp->action == ACT_RENAME || mpp->action == ACT_SWITCHPG_RENAME ||
|
||||||
|
+ mpp->action == ACT_RELOAD_RENAME ||
|
||||||
|
+ mpp->action == ACT_RESIZE_RENAME) {
|
||||||
|
+ conf = get_multipath_config();
|
||||||
|
+ pthread_cleanup_push(put_multipath_config, conf);
|
||||||
|
+ r = dm_rename(mpp->alias_old, mpp->alias,
|
||||||
|
+ conf->partition_delim, mpp->skip_kpartx);
|
||||||
|
+ pthread_cleanup_pop(1);
|
||||||
|
+ if (r == DOMAP_FAIL)
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
switch (mpp->action) {
|
||||||
|
case ACT_REJECT:
|
||||||
|
case ACT_NOTHING:
|
||||||
|
@@ -958,6 +966,7 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
|
||||||
|
return DOMAP_EXIST;
|
||||||
|
|
||||||
|
case ACT_SWITCHPG:
|
||||||
|
+ case ACT_SWITCHPG_RENAME:
|
||||||
|
dm_switchgroup(mpp->alias, mpp->bestpg);
|
||||||
|
/*
|
||||||
|
* we may have avoided reinstating paths because there where in
|
||||||
|
@@ -984,6 +993,7 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACT_RELOAD:
|
||||||
|
+ case ACT_RELOAD_RENAME:
|
||||||
|
sysfs_set_max_sectors_kb(mpp, 1);
|
||||||
|
if (mpp->ghost_delay_tick > 0 && pathcount(mpp, PATH_UP))
|
||||||
|
mpp->ghost_delay_tick = 0;
|
||||||
|
@@ -991,6 +1001,7 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACT_RESIZE:
|
||||||
|
+ case ACT_RESIZE_RENAME:
|
||||||
|
sysfs_set_max_sectors_kb(mpp, 1);
|
||||||
|
if (mpp->ghost_delay_tick > 0 && pathcount(mpp, PATH_UP))
|
||||||
|
mpp->ghost_delay_tick = 0;
|
||||||
|
@@ -998,29 +1009,10 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACT_RENAME:
|
||||||
|
- conf = get_multipath_config();
|
||||||
|
- pthread_cleanup_push(put_multipath_config, conf);
|
||||||
|
- r = dm_rename(mpp->alias_old, mpp->alias,
|
||||||
|
- conf->partition_delim, mpp->skip_kpartx);
|
||||||
|
- pthread_cleanup_pop(1);
|
||||||
|
- break;
|
||||||
|
-
|
||||||
|
- case ACT_FORCERENAME:
|
||||||
|
- conf = get_multipath_config();
|
||||||
|
- pthread_cleanup_push(put_multipath_config, conf);
|
||||||
|
- r = dm_rename(mpp->alias_old, mpp->alias,
|
||||||
|
- conf->partition_delim, mpp->skip_kpartx);
|
||||||
|
- pthread_cleanup_pop(1);
|
||||||
|
- if (r) {
|
||||||
|
- sysfs_set_max_sectors_kb(mpp, 1);
|
||||||
|
- if (mpp->ghost_delay_tick > 0 &&
|
||||||
|
- pathcount(mpp, PATH_UP))
|
||||||
|
- mpp->ghost_delay_tick = 0;
|
||||||
|
- r = dm_addmap_reload(mpp, params, 0);
|
||||||
|
- }
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
+ r = DOMAP_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
|
||||||
|
index 2bf73e65..9d935db3 100644
|
||||||
|
--- a/libmultipath/configure.h
|
||||||
|
+++ b/libmultipath/configure.h
|
||||||
|
@@ -18,9 +18,11 @@ enum actions {
|
||||||
|
ACT_RENAME,
|
||||||
|
ACT_CREATE,
|
||||||
|
ACT_RESIZE,
|
||||||
|
- ACT_FORCERENAME,
|
||||||
|
+ ACT_RELOAD_RENAME,
|
||||||
|
ACT_DRY_RUN,
|
||||||
|
ACT_IMPOSSIBLE,
|
||||||
|
+ ACT_RESIZE_RENAME,
|
||||||
|
+ ACT_SWITCHPG_RENAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
@ -0,0 +1,70 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Tue, 7 Feb 2023 15:39:26 -0600
|
||||||
|
Subject: [PATCH] multipath.rules: fix "smart" bug with failed valid path check
|
||||||
|
|
||||||
|
If "multipath -u" fails, udev doesn't import any values from the
|
||||||
|
program. This means that multipath.rules will continue to use the values
|
||||||
|
for DM_MULTIPATH_DEVICE_PATH and FIND_MULTIPATHS_WAIT_UNTIL that it has
|
||||||
|
already imported from the database. This is the correct thing to do for
|
||||||
|
every case except the MAYBE case for "find_multipaths smart". In that
|
||||||
|
case, DM_MULTIPATH_DEVICE_PATH will be set to 1, and the rules will
|
||||||
|
assume that the device has been definitively claimed.
|
||||||
|
|
||||||
|
In this case, we know that the device shouldn't have been claimed
|
||||||
|
before, but we don't know if it should be claimed now, or if we have hit
|
||||||
|
the timeout and it should be released, since we didn't get any
|
||||||
|
information from multipath. The safest thing to do is assume that this
|
||||||
|
was the timeout, and the device shouldn't be claimed. The only time when
|
||||||
|
this could be the wrong answer is when we first see a new multipath
|
||||||
|
device, and it could only cause problems if there is metadata on the
|
||||||
|
device that will cause it to get autoassembled by something else, before
|
||||||
|
multipathd can autoassemble it. If we assume that it is a multipath
|
||||||
|
device, or we assume that this wasn't actually the timeout uevent, we
|
||||||
|
can keep a necessary device from getting released to the reset of the
|
||||||
|
system.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
---
|
||||||
|
multipath/multipath.rules.in | 22 ++++++++++++++++------
|
||||||
|
1 file changed, 16 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/multipath/multipath.rules.in b/multipath/multipath.rules.in
|
||||||
|
index 5c4447a2..70b69a06 100644
|
||||||
|
--- a/multipath/multipath.rules.in
|
||||||
|
+++ b/multipath/multipath.rules.in
|
||||||
|
@@ -32,7 +32,8 @@ IMPORT{db}="DM_MULTIPATH_DEVICE_PATH"
|
||||||
|
|
||||||
|
# multipath -u sets DM_MULTIPATH_DEVICE_PATH and,
|
||||||
|
# if "find_multipaths smart", also FIND_MULTIPATHS_WAIT_UNTIL.
|
||||||
|
-IMPORT{program}="$env{MPATH_SBIN_PATH}/multipath -u %k"
|
||||||
|
+IMPORT{program}=="$env{MPATH_SBIN_PATH}/multipath -u %k", \
|
||||||
|
+ ENV{.MPATH_CHECK_PASSED}="1"
|
||||||
|
|
||||||
|
# case 1: this is definitely multipath
|
||||||
|
ENV{DM_MULTIPATH_DEVICE_PATH}=="1", \
|
||||||
|
@@ -83,10 +84,19 @@ LABEL="stop_wait"
|
||||||
|
# If timeout hasn't expired but we're not in "maybe" state any more, stop timer
|
||||||
|
# Do this only once, and only if the timer has been started before
|
||||||
|
IMPORT{db}="FIND_MULTIPATHS_WAIT_CANCELLED"
|
||||||
|
-ENV{FIND_MULTIPATHS_WAIT_CANCELLED}!="?*", \
|
||||||
|
- ENV{FIND_MULTIPATHS_WAIT_UNTIL}=="?*", \
|
||||||
|
- ENV{FIND_MULTIPATHS_WAIT_UNTIL}!="0", \
|
||||||
|
- ENV{FIND_MULTIPATHS_WAIT_CANCELLED}="1", \
|
||||||
|
- RUN+="/usr/bin/systemctl stop cancel-multipath-wait-$kernel.timer"
|
||||||
|
+ENV{FIND_MULTIPATHS_WAIT_CANCELLED}=="?*", GOTO="end_mpath"
|
||||||
|
+ENV{FIND_MULTIPATHS_WAIT_UNTIL}!="?*", GOTO="end_mpath"
|
||||||
|
+ENV{FIND_MULTIPATHS_WAIT_UNTIL}=="0", GOTO="end_mpath"
|
||||||
|
+
|
||||||
|
+ENV{FIND_MULTIPATHS_WAIT_CANCELLED}="1"
|
||||||
|
+RUN+="/usr/bin/systemctl stop cancel-multipath-wait-$kernel.timer"
|
||||||
|
+
|
||||||
|
+# If "multipath -u" failed, no values are imported from the program,
|
||||||
|
+# and we are still using the values for DM_MULTIPATH_DEVICE_PATH and
|
||||||
|
+# FIND_MULTIPATHS_WAIT_UNTIL that were imported from the database.
|
||||||
|
+# If we are in "smart" mode, we need to give up on the path now,
|
||||||
|
+# since this may have been the timeout event. Without the imports
|
||||||
|
+# from "multipath -u", we can't tell.
|
||||||
|
+ENV{.MPATH_CHECK_PASSED}!="?*", ENV{DM_MULTIPATH_DEVICE_PATH}="0"
|
||||||
|
|
||||||
|
LABEL="end_mpath"
|
@ -0,0 +1,64 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
Date: Wed, 8 Feb 2023 19:31:02 -0600
|
||||||
|
Subject: [PATCH] libmultipath: limit paths that can get wwid from environment
|
||||||
|
|
||||||
|
Currently, whenever getting the uid_attribute from udev database fails,
|
||||||
|
multipath will try to get it from the environment variables. This
|
||||||
|
normally isn't a problem, since either multipath -u is getting called
|
||||||
|
from a uevent, and the environment will have the correct value in that
|
||||||
|
variable, or that variable won't be set. However, when find_multipaths
|
||||||
|
is configured to "smart", this causes problems. For maybe devices,
|
||||||
|
multipath needs to get the WWIDs of all the other block devices, to see
|
||||||
|
if they match the maybe device wwid. If one of those devices doesn't
|
||||||
|
have uid_attribute set in its udev database, multipath will check the
|
||||||
|
environment for it, and it will find that variable set to the WWID
|
||||||
|
of the maybe device that this uevent is for. This means that all
|
||||||
|
devices with no WWID will end up appearing to have the same WWID as
|
||||||
|
the maybe device, causing multipath to incorrectly claim it.
|
||||||
|
|
||||||
|
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||||
|
---
|
||||||
|
libmultipath/discovery.c | 2 +-
|
||||||
|
libmultipath/structs.h | 1 +
|
||||||
|
multipath/main.c | 2 ++
|
||||||
|
3 files changed, 4 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
||||||
|
index f593a7bf..a592a54e 100644
|
||||||
|
--- a/libmultipath/discovery.c
|
||||||
|
+++ b/libmultipath/discovery.c
|
||||||
|
@@ -2032,7 +2032,7 @@ get_udev_uid(struct path * pp, char *uid_attribute, struct udev_device *udev)
|
||||||
|
const char *value;
|
||||||
|
|
||||||
|
value = udev_device_get_property_value(udev, uid_attribute);
|
||||||
|
- if (!value || strlen(value) == 0)
|
||||||
|
+ if ((!value || strlen(value) == 0) && pp->can_use_env_uid)
|
||||||
|
value = getenv(uid_attribute);
|
||||||
|
if (value && strlen(value)) {
|
||||||
|
len = strlcpy(pp->wwid, value, WWID_SIZE);
|
||||||
|
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||||
|
index 0867b91d..4b308561 100644
|
||||||
|
--- a/libmultipath/structs.h
|
||||||
|
+++ b/libmultipath/structs.h
|
||||||
|
@@ -360,6 +360,7 @@ struct path {
|
||||||
|
int fast_io_fail;
|
||||||
|
unsigned int dev_loss;
|
||||||
|
int eh_deadline;
|
||||||
|
+ bool can_use_env_uid;
|
||||||
|
/* configlet pointers */
|
||||||
|
vector hwe;
|
||||||
|
struct gen_path generic_path;
|
||||||
|
diff --git a/multipath/main.c b/multipath/main.c
|
||||||
|
index 41d01c7e..e056c51c 100644
|
||||||
|
--- a/multipath/main.c
|
||||||
|
+++ b/multipath/main.c
|
||||||
|
@@ -653,6 +653,8 @@ check_path_valid(const char *name, struct config *conf, bool is_uevent)
|
||||||
|
pp = alloc_path();
|
||||||
|
if (!pp)
|
||||||
|
return RTVL_FAIL;
|
||||||
|
+ if (is_uevent)
|
||||||
|
+ pp->can_use_env_uid = true;
|
||||||
|
|
||||||
|
r = is_path_valid(name, conf, pp, is_uevent);
|
||||||
|
if (r <= PATH_IS_ERROR || r >= PATH_MAX_VALID_RESULT)
|
@ -1,6 +1,6 @@
|
|||||||
Name: device-mapper-multipath
|
Name: device-mapper-multipath
|
||||||
Version: 0.8.7
|
Version: 0.8.7
|
||||||
Release: 11%{?dist}
|
Release: 20%{?dist}
|
||||||
Summary: Tools to manage multipath devices using device-mapper
|
Summary: Tools to manage multipath devices using device-mapper
|
||||||
License: GPLv2
|
License: GPLv2
|
||||||
URL: http://christophe.varoqui.free.fr/
|
URL: http://christophe.varoqui.free.fr/
|
||||||
@ -70,6 +70,30 @@ Patch0057: 0057-updated-HPE-MSA-builtin-config.patch
|
|||||||
Patch0058: 0058-libmultipath-unset-detect_checker-for-clariion-Unity.patch
|
Patch0058: 0058-libmultipath-unset-detect_checker-for-clariion-Unity.patch
|
||||||
Patch0059: 0059-multipathd-Add-missing-ctype-include.patch
|
Patch0059: 0059-multipathd-Add-missing-ctype-include.patch
|
||||||
Patch0060: 0060-multipathd-replace-libreadline-with-libedit.patch
|
Patch0060: 0060-multipathd-replace-libreadline-with-libedit.patch
|
||||||
|
Patch0061: 0061-multipath-fix-systemd-timers-in-the-initramfs.patch
|
||||||
|
Patch0062: 0062-multipathd-factor-out-the-code-to-flush-a-map-with-n.patch
|
||||||
|
Patch0063: 0063-libmultipath-return-success-if-we-raced-to-remove-a-.patch
|
||||||
|
Patch0064: 0064-multipathd-Handle-losing-all-path-in-update_map.patch
|
||||||
|
Patch0065: 0065-multipathd-ignore-duplicated-multipathd-command-keys.patch
|
||||||
|
Patch0066: 0066-multipath-tools-use-run-instead-of-dev-shm.patch
|
||||||
|
Patch0067: 0067-kpartx-hold-device-open-until-partitions-have-been-c.patch
|
||||||
|
Patch0068: 0068-libmultipath-cleanup-remove_feature.patch
|
||||||
|
Patch0069: 0069-libmultipath-cleanup-add_feature.patch
|
||||||
|
Patch0070: 0070-multipath-tests-tests-for-adding-and-removing-featur.patch
|
||||||
|
Patch0071: 0071-libmultipath-fix-queue_mode-feature-handling.patch
|
||||||
|
Patch0072: 0072-multipath-tests-tests-for-reconcile_features_with_qu.patch
|
||||||
|
Patch0073: 0073-libmultipath-prepare-proto_id-for-use-by-non-scsi-de.patch
|
||||||
|
Patch0074: 0074-libmultipath-get-nvme-path-transport-protocol.patch
|
||||||
|
Patch0075: 0075-libmultipath-enforce-queue_mode-bio-for-nmve-tcp-pat.patch
|
||||||
|
Patch0076: 0076-multipath.conf-5-remove-io-affinity-information.patch
|
||||||
|
Patch0077: 0077-libmultipath-don-t-leak-memory-on-invalid-strings.patch
|
||||||
|
Patch0078: 0078-libmutipath-validate-the-argument-count-of-config-st.patch
|
||||||
|
Patch0079: 0079-libmultipath-use-select_reload_action-in-select_acti.patch
|
||||||
|
Patch0080: 0080-libmultipath-select-resize-action-even-if-reload-is-.patch
|
||||||
|
Patch0081: 0081-libmultipath-cleanup-ACT_CREATE-code-in-select_actio.patch
|
||||||
|
Patch0082: 0082-libmultipath-keep-renames-from-stopping-other-multip.patch
|
||||||
|
Patch0083: 0083-multipath.rules-fix-smart-bug-with-failed-valid-path.patch
|
||||||
|
Patch0084: 0084-libmultipath-limit-paths-that-can-get-wwid-from-envi.patch
|
||||||
|
|
||||||
|
|
||||||
# runtime
|
# runtime
|
||||||
@ -161,7 +185,6 @@ cp %{SOURCE1} .
|
|||||||
%build
|
%build
|
||||||
%define _sbindir /usr/sbin
|
%define _sbindir /usr/sbin
|
||||||
%define _libdir /usr/%{_lib}
|
%define _libdir /usr/%{_lib}
|
||||||
%define _udevdir /usr/lib/udev
|
|
||||||
%define _libmpathdir %{_libdir}/multipath
|
%define _libmpathdir %{_libdir}/multipath
|
||||||
%define _pkgconfdir %{_libdir}/pkgconfig
|
%define _pkgconfdir %{_libdir}/pkgconfig
|
||||||
%make_build LIB=%{_lib}
|
%make_build LIB=%{_lib}
|
||||||
@ -175,7 +198,8 @@ cp %{SOURCE1} .
|
|||||||
rcdir=%{_initrddir} \
|
rcdir=%{_initrddir} \
|
||||||
unitdir=%{_unitdir} \
|
unitdir=%{_unitdir} \
|
||||||
includedir=%{_includedir} \
|
includedir=%{_includedir} \
|
||||||
pkgconfdir=%{_pkgconfdir}
|
pkgconfdir=%{_pkgconfdir} \
|
||||||
|
tmpfilesdir=%{_tmpfilesdir}
|
||||||
|
|
||||||
# tree fix up
|
# tree fix up
|
||||||
install -d %{buildroot}/etc/multipath
|
install -d %{buildroot}/etc/multipath
|
||||||
@ -214,6 +238,7 @@ fi
|
|||||||
%{_mandir}/man8/mpathpersist.8.gz
|
%{_mandir}/man8/mpathpersist.8.gz
|
||||||
%config %{_udevrulesdir}/62-multipath.rules
|
%config %{_udevrulesdir}/62-multipath.rules
|
||||||
%config %{_udevrulesdir}/11-dm-mpath.rules
|
%config %{_udevrulesdir}/11-dm-mpath.rules
|
||||||
|
%{_tmpfilesdir}/multipath.conf
|
||||||
%doc README.md
|
%doc README.md
|
||||||
%doc README.alua
|
%doc README.alua
|
||||||
%doc multipath.conf
|
%doc multipath.conf
|
||||||
@ -247,7 +272,7 @@ fi
|
|||||||
%license LICENSES/GPL-2.0
|
%license LICENSES/GPL-2.0
|
||||||
%doc README.md
|
%doc README.md
|
||||||
%{_sbindir}/kpartx
|
%{_sbindir}/kpartx
|
||||||
%{_udevdir}/kpartx_id
|
%{_udevrulesdir}/../kpartx_id
|
||||||
%{_mandir}/man8/kpartx.8.gz
|
%{_mandir}/man8/kpartx.8.gz
|
||||||
%config %{_udevrulesdir}/11-dm-parts.rules
|
%config %{_udevrulesdir}/11-dm-parts.rules
|
||||||
%config %{_udevrulesdir}/66-kpartx.rules
|
%config %{_udevrulesdir}/66-kpartx.rules
|
||||||
@ -270,6 +295,64 @@ fi
|
|||||||
%{_pkgconfdir}/libdmmp.pc
|
%{_pkgconfdir}/libdmmp.pc
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu Feb 9 2023 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-20
|
||||||
|
- Add 0083-multipath.rules-fix-smart-bug-with-failed-valid-path.patch
|
||||||
|
- Add 0084-libmultipath-limit-paths-that-can-get-wwid-from-envi.patch
|
||||||
|
- Change how the installation dir for kpartx_id is specified
|
||||||
|
- Resolves: bz #1926147
|
||||||
|
|
||||||
|
* Fri Feb 3 2023 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-19
|
||||||
|
- Fix bugzilla linked to the changes (was previously linked to
|
||||||
|
the wrong bug, 2162536)
|
||||||
|
- Resolves: bz #2166467
|
||||||
|
|
||||||
|
* Wed Feb 1 2023 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-18
|
||||||
|
- Add 0079-libmultipath-use-select_reload_action-in-select_acti.patch
|
||||||
|
- Add 0080-libmultipath-select-resize-action-even-if-reload-is-.patch
|
||||||
|
- Add 0081-libmultipath-cleanup-ACT_CREATE-code-in-select_actio.patch
|
||||||
|
- Add 0082-libmultipath-keep-renames-from-stopping-other-multip.patch
|
||||||
|
- Resolves: bz #2166467
|
||||||
|
|
||||||
|
* Wed Dec 21 2022 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-17
|
||||||
|
- Add 0077-libmultipath-don-t-leak-memory-on-invalid-strings.patch
|
||||||
|
- Add 0078-libmutipath-validate-the-argument-count-of-config-st.patch
|
||||||
|
- Resolves: bz #2145225
|
||||||
|
|
||||||
|
* Wed Nov 30 2022 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-16
|
||||||
|
- Add 0076-multipath.conf-5-remove-io-affinity-information.patch
|
||||||
|
- Resolves: bz #2143125
|
||||||
|
|
||||||
|
* Thu Nov 10 2022 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-15
|
||||||
|
- Add 0067-kpartx-hold-device-open-until-partitions-have-been-c.patch
|
||||||
|
* Fixes bz #2141860
|
||||||
|
- Add 0068-libmultipath-cleanup-remove_feature.patch
|
||||||
|
- Add 0069-libmultipath-cleanup-add_feature.patch
|
||||||
|
- Add 0070-multipath-tests-tests-for-adding-and-removing-featur.patch
|
||||||
|
- Add 0071-libmultipath-fix-queue_mode-feature-handling.patch
|
||||||
|
- Add 0072-multipath-tests-tests-for-reconcile_features_with_qu.patch
|
||||||
|
- Add 0073-libmultipath-prepare-proto_id-for-use-by-non-scsi-de.patch
|
||||||
|
- Add 0074-libmultipath-get-nvme-path-transport-protocol.patch
|
||||||
|
- Add 0075-libmultipath-enforce-queue_mode-bio-for-nmve-tcp-pat.patch
|
||||||
|
* Fixes bz #2033080
|
||||||
|
- Resolves: bz #2033080, #2141860
|
||||||
|
|
||||||
|
* Thu Oct 13 2022 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-14
|
||||||
|
- Add 0065-multipathd-ignore-duplicated-multipathd-command-keys.patch
|
||||||
|
* Fixes bz #2133999
|
||||||
|
- Add 0066-multipath-tools-use-run-instead-of-dev-shm.patch
|
||||||
|
* Fixes bz #2133989
|
||||||
|
- Resolves: bz #2133989, #2133999
|
||||||
|
|
||||||
|
* Fri Sep 9 2022 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-13
|
||||||
|
- Add 0062-multipathd-factor-out-the-code-to-flush-a-map-with-n.patch
|
||||||
|
- Add 0063-libmultipath-return-success-if-we-raced-to-remove-a-.patch
|
||||||
|
- Add 0064-multipathd-Handle-losing-all-path-in-update_map.patch
|
||||||
|
- Resolves: bz #2125357
|
||||||
|
|
||||||
|
* Wed Aug 24 2022 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-12
|
||||||
|
- Add 0061-multipath-fix-systemd-timers-in-the-initramfs.patch
|
||||||
|
- Resolves: bz #2121277
|
||||||
|
|
||||||
* Fri Aug 19 2022 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-11
|
* Fri Aug 19 2022 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-11
|
||||||
- Add 0059-multipathd-Add-missing-ctype-include.patch
|
- Add 0059-multipathd-Add-missing-ctype-include.patch
|
||||||
- Add 0060-multipathd-replace-libreadline-with-libedit.patch
|
- Add 0060-multipathd-replace-libreadline-with-libedit.patch
|
||||||
|
Loading…
Reference in New Issue
Block a user