import device-mapper-multipath-0.8.7-20.el9

This commit is contained in:
CentOS Sources 2023-03-28 08:57:18 +00:00 committed by root
parent a617125e1e
commit 952c4628fa
25 changed files with 2895 additions and 4 deletions

View File

@ -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"

View File

@ -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, &params, vecs)) {
condlog(0, "%s: failed to setup map for"

View File

@ -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 {

View File

@ -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) {

View File

@ -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);

View 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 -

View File

@ -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",

View 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);

View 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;

View File

@ -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;
+}

View 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, &params, 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

View File

@ -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;
}

View File

@ -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);

View 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

View File

@ -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, &params, 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

View File

@ -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
.

View File

@ -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);

View File

@ -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)
/*

View File

@ -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;
}

View File

@ -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");

View File

@ -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;
}

View File

@ -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,
};
/*

View File

@ -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"

View File

@ -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)

View File

@ -1,6 +1,6 @@
Name: device-mapper-multipath
Version: 0.8.7
Release: 11%{?dist}
Release: 20%{?dist}
Summary: Tools to manage multipath devices using device-mapper
License: GPLv2
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
Patch0059: 0059-multipathd-Add-missing-ctype-include.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
@ -161,7 +185,6 @@ cp %{SOURCE1} .
%build
%define _sbindir /usr/sbin
%define _libdir /usr/%{_lib}
%define _udevdir /usr/lib/udev
%define _libmpathdir %{_libdir}/multipath
%define _pkgconfdir %{_libdir}/pkgconfig
%make_build LIB=%{_lib}
@ -175,7 +198,8 @@ cp %{SOURCE1} .
rcdir=%{_initrddir} \
unitdir=%{_unitdir} \
includedir=%{_includedir} \
pkgconfdir=%{_pkgconfdir}
pkgconfdir=%{_pkgconfdir} \
tmpfilesdir=%{_tmpfilesdir}
# tree fix up
install -d %{buildroot}/etc/multipath
@ -214,6 +238,7 @@ fi
%{_mandir}/man8/mpathpersist.8.gz
%config %{_udevrulesdir}/62-multipath.rules
%config %{_udevrulesdir}/11-dm-mpath.rules
%{_tmpfilesdir}/multipath.conf
%doc README.md
%doc README.alua
%doc multipath.conf
@ -247,7 +272,7 @@ fi
%license LICENSES/GPL-2.0
%doc README.md
%{_sbindir}/kpartx
%{_udevdir}/kpartx_id
%{_udevrulesdir}/../kpartx_id
%{_mandir}/man8/kpartx.8.gz
%config %{_udevrulesdir}/11-dm-parts.rules
%config %{_udevrulesdir}/66-kpartx.rules
@ -270,6 +295,64 @@ fi
%{_pkgconfdir}/libdmmp.pc
%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
- Add 0059-multipathd-Add-missing-ctype-include.patch
- Add 0060-multipathd-replace-libreadline-with-libedit.patch