Compare commits
No commits in common. "c8" and "c10s" have entirely different histories.
@ -1 +0,0 @@
|
||||
b52c2be340449664f0a122070838f6d8edd42e4a SOURCES/multipath-tools-0.8.4.tgz
|
1
.fmf/version
Normal file
1
.fmf/version
Normal file
@ -0,0 +1 @@
|
||||
1
|
34
.gitignore
vendored
34
.gitignore
vendored
@ -1 +1,33 @@
|
||||
SOURCES/multipath-tools-0.8.4.tgz
|
||||
multipath-tools-091027.tar.gz
|
||||
/multipath-tools-120123.tgz
|
||||
/multipath-tools-120613.tgz
|
||||
/multipath-tools-120821.tgz
|
||||
/multipath-tools-130222.tgz
|
||||
/multipath-tools-f21166a.tgz
|
||||
/multipath.conf
|
||||
/multipath-tools-git847cc43.tgz
|
||||
/multipath-tools-0.7.3.tgz
|
||||
/multipath-tools-07e7bd5.tgz
|
||||
/multipath-tools-1cb704b.tgz
|
||||
/multipath-tools-0.7.7.tgz
|
||||
/multipath-tools-ef6d98b.tgz
|
||||
/multipath-tools-1a8625a.tgz
|
||||
/multipath-tools-b80318b.tgz
|
||||
/multipath-tools-0.7.8.tgz
|
||||
/multipath-tools-0.7.9.tgz
|
||||
/multipath-tools-17a6101.tgz
|
||||
/multipath-tools-2df6110.tgz
|
||||
/multipath-tools-0.8.0.tgz
|
||||
/multipath-tools-0.8.2.tgz
|
||||
/multipath-tools-0.8.4.tgz
|
||||
/multipath-tools-0.8.5.tgz
|
||||
/multipath-tools-0.8.6.tgz
|
||||
/multipath-tools-0.8.7.tgz
|
||||
/multipath-tools-0.8.9.tgz
|
||||
/multipath-tools-0.9.0.tgz
|
||||
/multipath-tools-0.9.3.tgz
|
||||
/multipath-tools-0.9.4.tgz
|
||||
/multipath-tools-0.9.5.tgz
|
||||
/multipath-tools-0.9.6.tgz
|
||||
/multipath-tools-0.9.7.tgz
|
||||
/multipath-tools-0.9.9.tgz
|
||||
|
28
0001-multipathd-fix-flush-check-in-flush_map.patch
Normal file
28
0001-multipathd-fix-flush-check-in-flush_map.patch
Normal file
@ -0,0 +1,28 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 5 Jun 2024 19:22:48 -0400
|
||||
Subject: [PATCH] multipathd: fix flush check in flush_map()
|
||||
|
||||
Forgot the comparison in the "if" statement.
|
||||
|
||||
Fixes 8a3898339 ("multipathd: sync features on flush_map failure corner case")
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
multipathd/main.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 09286dd0..58afe14a 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -813,7 +813,7 @@ flush_map(struct multipath * mpp, struct vectors * vecs)
|
||||
{
|
||||
int r = dm_suspend_and_flush_map(mpp->alias, 0);
|
||||
if (r != DM_FLUSH_OK) {
|
||||
- if (DM_FLUSH_FAIL_CANT_RESTORE)
|
||||
+ if (r == DM_FLUSH_FAIL_CANT_RESTORE)
|
||||
remove_feature(&mpp->features, "queue_if_no_path");
|
||||
condlog(0, "%s: can't flush", mpp->alias);
|
||||
return r;
|
63
0002-RH-fixup-udev-rules-for-redhat.patch
Normal file
63
0002-RH-fixup-udev-rules-for-redhat.patch
Normal file
@ -0,0 +1,63 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 13 Apr 2017 07:22:23 -0500
|
||||
Subject: [PATCH] RH: fixup udev rules for redhat
|
||||
|
||||
The multipath rules need to run after scsi_id is run. This means moving
|
||||
them after 60-persistent-storage.rules for redhat. Redhat also uses a
|
||||
different naming scheme for partitions than SuSE.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile.inc | 2 +-
|
||||
kpartx/kpartx.rules | 2 +-
|
||||
multipath/Makefile | 4 ++--
|
||||
3 files changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/Makefile.inc b/Makefile.inc
|
||||
index 81b86cd8..33dbb99c 100644
|
||||
--- a/Makefile.inc
|
||||
+++ b/Makefile.inc
|
||||
@@ -34,7 +34,7 @@ endif
|
||||
# Paths. All these can be overridden on the "make" command line.
|
||||
prefix :=
|
||||
# Prefix for binaries
|
||||
-exec_prefix := $(prefix)
|
||||
+exec_prefix := $(prefix)/usr
|
||||
# Prefix for non-essential libraries (libdmmp)
|
||||
usr_prefix := $(if $(prefix),$(prefix),/usr)
|
||||
# Prefix for configuration files (multipath.conf)
|
||||
diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules
|
||||
index 8dd3369c..7c3c7524 100644
|
||||
--- a/kpartx/kpartx.rules
|
||||
+++ b/kpartx/kpartx.rules
|
||||
@@ -39,6 +39,6 @@ LABEL="mpath_kpartx_end"
|
||||
GOTO="kpartx_end"
|
||||
|
||||
LABEL="run_kpartx"
|
||||
-RUN+="/sbin/kpartx -un -p -part /dev/$name"
|
||||
+RUN+="/sbin/kpartx -un /dev/$name"
|
||||
|
||||
LABEL="kpartx_end"
|
||||
diff --git a/multipath/Makefile b/multipath/Makefile
|
||||
index 67fb5e62..2ea9e528 100644
|
||||
--- a/multipath/Makefile
|
||||
+++ b/multipath/Makefile
|
||||
@@ -27,7 +27,7 @@ install:
|
||||
$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir)
|
||||
$(Q)$(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir)
|
||||
$(Q)$(INSTALL_PROGRAM) -m 644 99-z-dm-mpath-late.rules $(DESTDIR)$(udevrulesdir)
|
||||
- $(Q)$(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)$(udevrulesdir)/56-multipath.rules
|
||||
+ $(Q)$(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)$(udevrulesdir)/62-multipath.rules
|
||||
$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(tmpfilesdir)
|
||||
$(Q)$(INSTALL_PROGRAM) -m 644 tmpfiles.conf $(DESTDIR)$(tmpfilesdir)/multipath.conf
|
||||
$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)/man8
|
||||
@@ -50,7 +50,7 @@ uninstall:
|
||||
$(Q)$(RM) $(DESTDIR)$(udevrulesdir)/99-z-dm-mpath-late.rules
|
||||
$(Q)$(RM) $(DESTDIR)$(modulesloaddir)/multipath.conf
|
||||
$(Q)$(RM) $(DESTDIR)$(modulesloaddir)/scsi_dh.conf
|
||||
- $(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules
|
||||
+ $(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules
|
||||
$(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(EXEC).8
|
||||
$(Q)$(RM) $(DESTDIR)$(mandir)/man5/$(EXEC).conf.5
|
||||
$(Q)$(RM) $(DESTDIR)$(tmpfilesdir)/multipath.conf
|
@ -13,29 +13,25 @@ it.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/blacklist.c | 9 ++-------
|
||||
multipath/multipath.conf.5 | 11 ++++++-----
|
||||
tests/blacklist.c | 6 ++----
|
||||
3 files changed, 10 insertions(+), 16 deletions(-)
|
||||
libmultipath/blacklist.c | 5 ++---
|
||||
multipath/multipath.conf.5.in | 11 ++++++-----
|
||||
tests/blacklist.c | 7 ++-----
|
||||
3 files changed, 10 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
|
||||
index 00e8dbdb..d9691b17 100644
|
||||
index 75100b20..0b212078 100644
|
||||
--- a/libmultipath/blacklist.c
|
||||
+++ b/libmultipath/blacklist.c
|
||||
@@ -204,12 +204,6 @@ setup_default_blist (struct config * conf)
|
||||
if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
|
||||
return 1;
|
||||
@@ -230,8 +230,6 @@ setup_default_blist (struct config * conf)
|
||||
ORIGIN_DEFAULT))
|
||||
return 1;
|
||||
}
|
||||
- if (store_ble(conf->elist_property, "(SCSI_IDENT_|ID_WWN)", ORIGIN_DEFAULT))
|
||||
- return 1;
|
||||
|
||||
- str = STRDUP("(SCSI_IDENT_|ID_WWN)");
|
||||
- if (!str)
|
||||
- return 1;
|
||||
- if (store_ble(conf->elist_property, str, ORIGIN_DEFAULT))
|
||||
- return 1;
|
||||
-
|
||||
vector_foreach_slot (conf->hwtable, hwe, i) {
|
||||
if (hwe->bl_product) {
|
||||
if (find_blacklist_device(conf->blist_device,
|
||||
@@ -411,7 +405,8 @@ filter_property(struct config *conf, struct udev_device *udev, int lvl,
|
||||
@@ -438,7 +436,8 @@ filter_property(const struct config *conf, struct udev_device *udev,
|
||||
*uid_attribute != '\0';
|
||||
bool uid_attr_seen = false;
|
||||
|
||||
@ -45,11 +41,11 @@ index 00e8dbdb..d9691b17 100644
|
||||
udev_list_entry_foreach(list_entry,
|
||||
udev_device_get_properties_list_entry(udev)) {
|
||||
|
||||
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
||||
index 05a5e8ff..3455b1cc 100644
|
||||
--- a/multipath/multipath.conf.5
|
||||
+++ b/multipath/multipath.conf.5
|
||||
@@ -1286,9 +1286,14 @@ keywords. Both are regular expressions. For a full description of these keywords
|
||||
diff --git a/multipath/multipath.conf.5.in b/multipath/multipath.conf.5.in
|
||||
index dacb9b0e..645e8f88 100644
|
||||
--- a/multipath/multipath.conf.5.in
|
||||
+++ b/multipath/multipath.conf.5.in
|
||||
@@ -1468,9 +1468,14 @@ keywords. Both are regular expressions. For a full description of these keywords
|
||||
Regular expression for an udev property. All
|
||||
devices that have matching udev properties will be excluded/included.
|
||||
The handling of the \fIproperty\fR keyword is special,
|
||||
@ -65,7 +61,7 @@ index 05a5e8ff..3455b1cc 100644
|
||||
.
|
||||
.RS
|
||||
.PP
|
||||
@@ -1299,10 +1304,6 @@ Blacklisting by missing properties is only applied to devices which do have the
|
||||
@@ -1481,10 +1486,6 @@ Blacklisting by missing properties is only applied to devices which do have the
|
||||
property specified by \fIuid_attribute\fR (e.g. \fIID_SERIAL\fR)
|
||||
set. Previously, it was applied to every device, possibly causing devices to be
|
||||
blacklisted because of temporary I/O error conditions.
|
||||
@ -77,19 +73,21 @@ index 05a5e8ff..3455b1cc 100644
|
||||
.TP
|
||||
.B protocol
|
||||
diff --git a/tests/blacklist.c b/tests/blacklist.c
|
||||
index 6e7c1864..cc8a9a4a 100644
|
||||
index ba8dfd07..693db3fa 100644
|
||||
--- a/tests/blacklist.c
|
||||
+++ b/tests/blacklist.c
|
||||
@@ -271,7 +271,7 @@ static void test_property_missing(void **state)
|
||||
@@ -384,9 +384,8 @@ static void test_property_missing(void **state)
|
||||
{
|
||||
static struct udev_device udev = { "sdb", { "ID_FOO", "ID_BAZ", "ID_BAR", "ID_SERIAL", NULL } };
|
||||
conf.blist_property = blist_property_wwn;
|
||||
expect_condlog(3, "sdb: blacklisted, udev property missing\n");
|
||||
- expect_condlog(3, "sdb: blacklisted, udev property missing\n");
|
||||
assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
|
||||
- MATCH_PROPERTY_BLIST_MISSING);
|
||||
+ MATCH_NOTHING);
|
||||
assert_int_equal(filter_property(&conf, &udev, 3, "ID_BLAH"),
|
||||
MATCH_NOTHING);
|
||||
assert_int_equal(filter_property(&conf, &udev, 3, ""),
|
||||
@@ -363,9 +363,7 @@ static void test_filter_path_missing1(void **state)
|
||||
@@ -478,9 +477,7 @@ static void test_filter_path_missing1(void **state)
|
||||
conf.blist_device = blist_device_foo_bar;
|
||||
conf.blist_protocol = blist_protocol_fcp;
|
||||
conf.blist_wwid = blist_wwid_xyzzy;
|
||||
@ -100,6 +98,3 @@ index 6e7c1864..cc8a9a4a 100644
|
||||
}
|
||||
|
||||
/* This one matches the property whitelist, to test the other missing
|
||||
--
|
||||
2.17.2
|
||||
|
137
0004-RH-don-t-start-without-a-config-file.patch
Normal file
137
0004-RH-don-t-start-without-a-config-file.patch
Normal file
@ -0,0 +1,137 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 15 Oct 2014 10:39:30 -0500
|
||||
Subject: [PATCH] RH: don't start without a config file
|
||||
|
||||
If /etc/multipath.conf doesn't exist, don't start multipathd and blacklist
|
||||
all devices when running multipath. A completely blank configuration file
|
||||
is almost never what users want. Also, people may have the multipath
|
||||
packages installed but don't want to use them. This patch provides a
|
||||
simple way to disable multipath. Simply removing or renaming
|
||||
/etc/multipath.conf will keep multipath from doing anything.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/config.c | 13 +++++++++++++
|
||||
libmultipath/config.h | 1 +
|
||||
multipath/main.c | 6 ++++++
|
||||
multipath/multipath.rules.in | 1 +
|
||||
multipathd/multipathd.8.in | 2 ++
|
||||
multipathd/multipathd.service.in | 1 +
|
||||
multipathd/multipathd.socket | 1 +
|
||||
7 files changed, 25 insertions(+)
|
||||
|
||||
diff --git a/libmultipath/config.c b/libmultipath/config.c
|
||||
index 83fa7369..002027a7 100644
|
||||
--- a/libmultipath/config.c
|
||||
+++ b/libmultipath/config.c
|
||||
@@ -959,6 +959,19 @@ int _init_config (const char *file, struct config *conf)
|
||||
}
|
||||
factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
|
||||
validate_pctable(conf->overrides, 0, file);
|
||||
+ } else {
|
||||
+ condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
|
||||
+ if (conf->blist_devnode == NULL) {
|
||||
+ conf->blist_devnode = vector_alloc();
|
||||
+ if (!conf->blist_devnode) {
|
||||
+ condlog(0, "cannot allocate blacklist\n");
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+ if (store_ble(conf->blist_devnode, ".*", ORIGIN_NO_CONFIG)) {
|
||||
+ condlog(0, "cannot store default no-config blacklist\n");
|
||||
+ goto out;
|
||||
+ }
|
||||
}
|
||||
|
||||
conf->processed_main_config = 1;
|
||||
diff --git a/libmultipath/config.h b/libmultipath/config.h
|
||||
index 384193ab..158cebf0 100644
|
||||
--- a/libmultipath/config.h
|
||||
+++ b/libmultipath/config.h
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#define ORIGIN_DEFAULT 0
|
||||
#define ORIGIN_CONFIG 1
|
||||
+#define ORIGIN_NO_CONFIG 2
|
||||
|
||||
enum devtypes {
|
||||
DEV_NONE,
|
||||
diff --git a/multipath/main.c b/multipath/main.c
|
||||
index ce702e7f..c21e3e0b 100644
|
||||
--- a/multipath/main.c
|
||||
+++ b/multipath/main.c
|
||||
@@ -842,11 +842,14 @@ main (int argc, char *argv[])
|
||||
char *dev = NULL;
|
||||
struct config *conf;
|
||||
bool enable_foreign = false;
|
||||
+ bool have_config;
|
||||
+ struct stat buf;
|
||||
|
||||
libmultipath_init();
|
||||
if (atexit(dm_lib_exit) || atexit(libmultipath_exit))
|
||||
condlog(1, "failed to register cleanup handler for libmultipath: %m");
|
||||
logsink = LOGSINK_STDERR_WITH_TIME;
|
||||
+ have_config = (stat(DEFAULT_CONFIGFILE, &buf) == 0);
|
||||
if (init_config(DEFAULT_CONFIGFILE))
|
||||
exit(RTVL_FAIL);
|
||||
if (atexit(uninit_config))
|
||||
@@ -1097,6 +1100,9 @@ main (int argc, char *argv[])
|
||||
while ((r = configure(conf, cmd, dev_type, dev)) == RTVL_RETRY)
|
||||
condlog(3, "restart multipath configuration process");
|
||||
|
||||
+ if (!have_config && r == RTVL_OK &&
|
||||
+ (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG))
|
||||
+ r = RTVL_FAIL;
|
||||
out:
|
||||
put_multipath_config(conf);
|
||||
if (dev)
|
||||
diff --git a/multipath/multipath.rules.in b/multipath/multipath.rules.in
|
||||
index 780bf852..2c518378 100644
|
||||
--- a/multipath/multipath.rules.in
|
||||
+++ b/multipath/multipath.rules.in
|
||||
@@ -9,6 +9,7 @@ IMPORT{cmdline}="nompath"
|
||||
ENV{nompath}=="?*", GOTO="end_mpath"
|
||||
IMPORT{cmdline}="multipath"
|
||||
ENV{multipath}=="off", GOTO="end_mpath"
|
||||
+TEST!="/etc/multipath.conf", GOTO="end_mpath"
|
||||
|
||||
ENV{DEVTYPE}!="partition", GOTO="test_dev"
|
||||
IMPORT{parent}="DM_MULTIPATH_DEVICE_PATH"
|
||||
diff --git a/multipathd/multipathd.8.in b/multipathd/multipathd.8.in
|
||||
index 7bc8806e..315884eb 100644
|
||||
--- a/multipathd/multipathd.8.in
|
||||
+++ b/multipathd/multipathd.8.in
|
||||
@@ -49,6 +49,8 @@ map regains its maximum performance and redundancy.
|
||||
With the \fB-k\fR option, \fBmultipathd\fR acts as a client utility that
|
||||
sends commands to a running instance of the multipathd daemon (see
|
||||
\fBCOMMANDS\fR below).
|
||||
+
|
||||
+In this Linux distribution, multipathd does not run unless a /etc/multipath.conf file exists.
|
||||
.
|
||||
.
|
||||
.\" ----------------------------------------------------------------------------
|
||||
diff --git a/multipathd/multipathd.service.in b/multipathd/multipathd.service.in
|
||||
index a63ddd9a..01ceff7d 100644
|
||||
--- a/multipathd/multipathd.service.in
|
||||
+++ b/multipathd/multipathd.service.in
|
||||
@@ -6,6 +6,7 @@ Wants=systemd-udevd-kernel.socket @MODPROBE_UNIT@
|
||||
After=systemd-udevd-kernel.socket @MODPROBE_UNIT@
|
||||
After=multipathd.socket systemd-remount-fs.service
|
||||
Before=initrd-cleanup.service
|
||||
+ConditionPathExists=/etc/multipath.conf
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
Conflicts=initrd-cleanup.service
|
||||
diff --git a/multipathd/multipathd.socket b/multipathd/multipathd.socket
|
||||
index 6a62f5fd..263b6b0c 100644
|
||||
--- a/multipathd/multipathd.socket
|
||||
+++ b/multipathd/multipathd.socket
|
||||
@@ -1,6 +1,7 @@
|
||||
[Unit]
|
||||
Description=multipathd control socket
|
||||
DefaultDependencies=no
|
||||
+ConditionPathExists=/etc/multipath.conf
|
||||
ConditionKernelCommandLine=!nompath
|
||||
ConditionKernelCommandLine=!multipath=off
|
||||
ConditionVirtualization=!container
|
@ -1,7 +1,10 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jan 2019 14:54:56 -0600
|
||||
Subject: [PATCH] RH: Fix nvme compilation warning
|
||||
Subject: [PATCH] RH: Fix nvme function missing argument
|
||||
|
||||
A future patch will change the compilation options to error when
|
||||
function declarations have unspecified arguments.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
@ -21,6 +24,3 @@ index adb192b6..bfd10ef8 100644
|
||||
void argconfig_append_usage(const char *str);
|
||||
void argconfig_print_help(const char *program_desc,
|
||||
const struct argconfig_commandline_options *options);
|
||||
--
|
||||
2.17.2
|
||||
|
55
0006-RH-use-rpm-optflags-if-present.patch
Normal file
55
0006-RH-use-rpm-optflags-if-present.patch
Normal file
@ -0,0 +1,55 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 19 Apr 2017 06:10:01 -0500
|
||||
Subject: [PATCH] RH: use rpm optflags if present
|
||||
|
||||
Use the passed in optflags when compiling as an RPM, and keep the
|
||||
default flags as close as possible to the current fedora flags, while
|
||||
still being generic.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile.inc | 22 +++++++++++++++++-----
|
||||
1 file changed, 17 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/Makefile.inc b/Makefile.inc
|
||||
index 33dbb99c..94e0ec85 100644
|
||||
--- a/Makefile.inc
|
||||
+++ b/Makefile.inc
|
||||
@@ -95,11 +95,23 @@ SYSTEMD_LIBDEPS := $(if $(SYSTEMD),$(if $(shell test $(SYSTEMD) -gt 209 && echo
|
||||
MODPROBE_UNIT := $(shell test "0$(SYSTEMD)" -lt 245 2>/dev/null || \
|
||||
echo "modprobe@dm_multipath.service")
|
||||
|
||||
-OPTFLAGS := -O2 -g $(STACKPROT) --param=ssp-buffer-size=4
|
||||
-WARNFLAGS := -Werror -Wall -Wextra -Wformat=2 $(WFORMATOVERFLOW) -Werror=implicit-int \
|
||||
+ifndef RPM_OPT_FLAGS
|
||||
+ OPTFLAGS := -O2 -g $(STACKPROT) --param=ssp-buffer-size=4 \
|
||||
+ -Wall $(FORTIFY_OPT) -fexceptions -grecord-gcc-switches \
|
||||
+ -fasynchronous-unwind-tables
|
||||
+ ifeq ($(shell test -f /usr/lib/rpm/redhat/redhat-hardened-cc1 && echo 1),1)
|
||||
+ OPTFLAGS += -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1
|
||||
+ endif
|
||||
+ ifeq ($(shell test -f /usr/lib/rpm/redhat/redhat-annobin-cc1 && echo 1),1)
|
||||
+ OPTFLAGS += -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1
|
||||
+ endif
|
||||
+else
|
||||
+ OPTFLAGS := $(RPM_OPT_FLAGS) --param=ssp-buffer-size=4
|
||||
+endif
|
||||
+WARNFLAGS := -Werror -Wextra -Wformat=2 $(WFORMATOVERFLOW) -Werror=implicit-int \
|
||||
-Werror=implicit-function-declaration -Werror=format-security \
|
||||
- $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) $(W_URCU_TYPE_LIMITS)
|
||||
-CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) \
|
||||
+ $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) $(W_URCU_TYPE_LIMITS) -Wstrict-prototypes
|
||||
+CPPFLAGS := $(CPPFLAGS) $(D_URCU_VERSION) \
|
||||
-D_FILE_OFFSET_BITS=64 \
|
||||
-DBIN_DIR=\"$(bindir)\" -DMULTIPATH_DIR=\"$(TGTDIR)$(plugindir)\" \
|
||||
-DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(TGTDIR)$(configdir)\" \
|
||||
@@ -109,7 +121,7 @@ CFLAGS := -std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe
|
||||
BIN_CFLAGS := -fPIE -DPIE
|
||||
LIB_CFLAGS := -fPIC
|
||||
SHARED_FLAGS := -shared
|
||||
-LDFLAGS := $(LDFLAGS) -Wl,-z,relro -Wl,-z,now -Wl,-z,defs
|
||||
+LDFLAGS := $(LDFLAGS) $(RPM_LD_FLAGS) -Wl,-z,relro -Wl,-z,now -Wl,-z,defs
|
||||
BIN_LDFLAGS := -pie
|
||||
|
||||
# Source code directories. Don't modify.
|
@ -10,22 +10,23 @@ command line. But, mostly it is used to get a multipath.conf file
|
||||
with the OS defaults, and to enable and disable multipathing via
|
||||
a single command.
|
||||
|
||||
Co-authored-by: Paul Donohue <git@PaulSD.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/config.c | 2 +
|
||||
multipath/Makefile | 5 +
|
||||
multipath/mpathconf | 555 ++++++++++++++++++++++++++++++++++++++++++
|
||||
multipath/mpathconf.8 | 135 ++++++++++
|
||||
4 files changed, 697 insertions(+)
|
||||
multipath/Makefile | 4 +
|
||||
multipath/mpathconf | 658 ++++++++++++++++++++++++++++++++++++++++++
|
||||
multipath/mpathconf.8 | 151 ++++++++++
|
||||
4 files changed, 815 insertions(+)
|
||||
create mode 100644 multipath/mpathconf
|
||||
create mode 100644 multipath/mpathconf.8
|
||||
|
||||
diff --git a/libmultipath/config.c b/libmultipath/config.c
|
||||
index b36778b0..26f8e050 100644
|
||||
index 002027a7..3d5943d3 100644
|
||||
--- a/libmultipath/config.c
|
||||
+++ b/libmultipath/config.c
|
||||
@@ -781,6 +781,8 @@ load_config (char * file)
|
||||
factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
|
||||
@@ -961,6 +961,8 @@ int _init_config (const char *file, struct config *conf)
|
||||
validate_pctable(conf->overrides, 0, file);
|
||||
} else {
|
||||
condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
|
||||
+ condlog(0, "You can run \"/sbin/mpathconf --enable\" to create");
|
||||
@ -34,45 +35,46 @@ index b36778b0..26f8e050 100644
|
||||
conf->blist_devnode = vector_alloc();
|
||||
if (!conf->blist_devnode) {
|
||||
diff --git a/multipath/Makefile b/multipath/Makefile
|
||||
index b9bbb3cf..e720c7f6 100644
|
||||
index 2ea9e528..3dc241cc 100644
|
||||
--- a/multipath/Makefile
|
||||
+++ b/multipath/Makefile
|
||||
@@ -18,10 +18,12 @@ $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
|
||||
$(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS)
|
||||
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
|
||||
$(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz
|
||||
+ $(GZIP) mpathconf.8 > mpathconf.8.gz
|
||||
|
||||
@@ -24,6 +24,7 @@ $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
|
||||
install:
|
||||
$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
|
||||
$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
||||
+ $(INSTALL_PROGRAM) -m 755 mpathconf $(DESTDIR)$(bindir)/
|
||||
$(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
|
||||
@@ -29,13 +31,16 @@ install:
|
||||
$(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir)
|
||||
$(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir)
|
||||
$(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir)
|
||||
+ $(INSTALL_PROGRAM) -m 644 mpathconf.8.gz $(DESTDIR)$(man8dir)
|
||||
$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
|
||||
$(Q)$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
||||
+ $(Q)$(INSTALL_PROGRAM) -m 755 mpathconf $(DESTDIR)$(bindir)/
|
||||
$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir)
|
||||
$(Q)$(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir)
|
||||
$(Q)$(INSTALL_PROGRAM) -m 644 99-z-dm-mpath-late.rules $(DESTDIR)$(udevrulesdir)
|
||||
@@ -32,6 +33,7 @@ install:
|
||||
$(Q)$(INSTALL_PROGRAM) -m 644 tmpfiles.conf $(DESTDIR)$(tmpfilesdir)/multipath.conf
|
||||
$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)/man8
|
||||
$(Q)$(INSTALL_PROGRAM) -m 644 $(EXEC).8 $(DESTDIR)$(mandir)/man8
|
||||
+ $(Q)$(INSTALL_PROGRAM) -m 644 mpathconf.8 $(DESTDIR)$(mandir)/man8
|
||||
$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)/man5
|
||||
$(Q)$(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5 $(DESTDIR)$(mandir)/man5
|
||||
$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(modulesloaddir)
|
||||
@@ -46,12 +48,14 @@ endif
|
||||
|
||||
uninstall:
|
||||
$(RM) $(DESTDIR)$(bindir)/$(EXEC)
|
||||
$(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules
|
||||
$(RM) $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules
|
||||
+ $(RM) $(DESTDIR)$(bindir)/mpathconf
|
||||
$(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz
|
||||
$(RM) $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz
|
||||
+ $(RM) $(DESTDIR)$(man8dir)/mpathconf.8.gz
|
||||
$(Q)$(RM) $(DESTDIR)$(bindir)/$(EXEC)
|
||||
+ $(Q)$(RM) $(DESTDIR)$(bindir)/mpathconf
|
||||
$(Q)$(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules
|
||||
$(Q)$(RM) $(DESTDIR)$(udevrulesdir)/99-z-dm-mpath-late.rules
|
||||
$(Q)$(RM) $(DESTDIR)$(modulesloaddir)/multipath.conf
|
||||
$(Q)$(RM) $(DESTDIR)$(modulesloaddir)/scsi_dh.conf
|
||||
$(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules
|
||||
$(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(EXEC).8
|
||||
+ $(Q)$(RM) $(DESTDIR)$(mandir)/man8/mpathconf.8
|
||||
$(Q)$(RM) $(DESTDIR)$(mandir)/man5/$(EXEC).conf.5
|
||||
$(Q)$(RM) $(DESTDIR)$(tmpfilesdir)/multipath.conf
|
||||
|
||||
clean: dep_clean
|
||||
$(RM) core *.o $(EXEC) *.gz
|
||||
diff --git a/multipath/mpathconf b/multipath/mpathconf
|
||||
new file mode 100644
|
||||
index 00000000..f34003c9
|
||||
index 00000000..ce430075
|
||||
--- /dev/null
|
||||
+++ b/multipath/mpathconf
|
||||
@@ -0,0 +1,555 @@
|
||||
@@ -0,0 +1,658 @@
|
||||
+#!/bin/bash
|
||||
+#
|
||||
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
||||
@ -92,7 +94,7 @@ index 00000000..f34003c9
|
||||
+# This program was largely ripped off from lvmconf
|
||||
+#
|
||||
+
|
||||
+unset ENABLE FIND FRIENDLY PROPERTY FOREIGN MODULE MULTIPATHD HAVE_DISABLE HAVE_WWID_DISABLE HAVE_FIND HAVE_BLACKLIST HAVE_EXCEPTIONS HAVE_DEFAULTS HAVE_FRIENDLY HAVE_PROPERTY HAVE_FOREIGN HAVE_MULTIPATHD HAVE_MODULE HAVE_OUTFILE SHOW_STATUS CHANGED_CONFIG WWID_LIST
|
||||
+unset ENABLE FIND FRIENDLY PROPERTY FOREIGN MODULE MULTIPATHD HAVE_DISABLE HAVE_WWID_DISABLE HAVE_FIND HAVE_BLACKLIST HAVE_EXCEPTIONS HAVE_DEFAULTS HAVE_FRIENDLY HAVE_PROPERTY HAVE_FOREIGN HAVE_MULTIPATHD HAVE_MODULE HAVE_OUTFILE SHOW_STATUS CHANGED_CONFIG WWID_LIST HAVE_OPTION OPTION_NAME OPTION_VALUE HAVE_RECHECK_WWID RECHECK_WWID
|
||||
+
|
||||
+DEFAULT_CONFIG="# device-mapper-multipath configuration file
|
||||
+
|
||||
@ -106,12 +108,7 @@ index 00000000..f34003c9
|
||||
+
|
||||
+defaults {
|
||||
+ user_friendly_names yes
|
||||
+ find_multipaths yes
|
||||
+ enable_foreign \"^$\"
|
||||
+}
|
||||
+
|
||||
+blacklist_exceptions {
|
||||
+ property \"(SCSI_IDENT_|ID_WWN)\"
|
||||
+ find_multipaths on
|
||||
+}"
|
||||
+
|
||||
+CONFIGFILE="/etc/multipath.conf"
|
||||
@ -129,9 +126,11 @@ index 00000000..f34003c9
|
||||
+ echo "Disable: --disable"
|
||||
+ echo "Only allow certain wwids (instead of enable): --allow <WWID>"
|
||||
+ echo "Set user_friendly_names (Default y): --user_friendly_names <y|n>"
|
||||
+ echo "Set find_multipaths (Default y): --find_multipaths <y|n>"
|
||||
+ echo "Set default property blacklist (Default y): --property_blacklist <y|n>"
|
||||
+ echo "Set find_multipaths (Default on): --find_multipaths <on|yes|y|off|no|n|strict|greedy|smart>"
|
||||
+ echo "Set default property blacklist (Default n): --property_blacklist <y|n>"
|
||||
+ echo "Set enable_foreign to show foreign devices (Default n): --enable_foreign <y|n>"
|
||||
+ echo "Set recheck_wwid (Defaut n): --recheck_wwid <y|n>"
|
||||
+ echo "Add/Change/Remove option in defaults section: --option <option_name>:<value>"
|
||||
+ echo "Load the dm-multipath modules on enable (Default y): --with_module <y|n>"
|
||||
+ echo "start/stop/reload multipathd (Default n): --with_multipathd <y|n>"
|
||||
+ echo "select output file (Default /etc/multipath.conf): --outfile <FILE>"
|
||||
@ -224,6 +223,15 @@ index 00000000..f34003c9
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ ;;
|
||||
+ --recheck_wwid)
|
||||
+ if [ -n "$2" ]; then
|
||||
+ RECHECK_WWID=$2
|
||||
+ shift 2
|
||||
+ else
|
||||
+ usage
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ ;;
|
||||
+ --find_multipaths)
|
||||
+ if [ -n "$2" ]; then
|
||||
+ FIND=$2
|
||||
@ -242,6 +250,20 @@ index 00000000..f34003c9
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ ;;
|
||||
+ --option)
|
||||
+ if [ -n "$2" ]; then
|
||||
+ OPTION_NAME=$(echo $2 | cut -s -f1 -d:)
|
||||
+ OPTION_VALUE=$(echo $2 | cut -s -f2 -d:)
|
||||
+ if [ -z "$OPTION_NAME" ]; then
|
||||
+ usage
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ shift 2
|
||||
+ else
|
||||
+ usage
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ ;;
|
||||
+ --enable_foreign)
|
||||
+ if [ -n "$2" ]; then
|
||||
+ FOREIGN=$2
|
||||
@ -288,19 +310,31 @@ index 00000000..f34003c9
|
||||
+
|
||||
+function validate_args
|
||||
+{
|
||||
+ if [ "$ENABLE" = "0" ] && [ -n "$FRIENDLY" -o -n "$FIND" -o -n "$PROPERTY" -o -n "$MODULE" ]; then
|
||||
+ if [ "$ENABLE" = "0" ] && [ -n "$FRIENDLY" -o -n "$FIND" -o -n "$PROPERTY" -o -n "$MODULE" -o -n "$FOREIGN" -o -n "$OPTION_NAME" -o -n "$RECHECK_WWID" ]; then
|
||||
+ echo "ignoring extra parameters on disable"
|
||||
+ FRIENDLY=""
|
||||
+ FIND=""
|
||||
+ PROPERTY=""
|
||||
+ MODULE=""
|
||||
+ FOREIGN=""
|
||||
+ OPTION_NAME=""
|
||||
+ OPTION_VALUE=""
|
||||
+ RECHECK_WWID=""
|
||||
+ fi
|
||||
+ if [ -n "$FRIENDLY" ] && [ "$FRIENDLY" != "y" -a "$FRIENDLY" != "n" ]; then
|
||||
+ echo "--user_friendly_names must be either 'y' or 'n'"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ if [ -n "$FIND" ] && [ "$FIND" != "y" -a "$FIND" != "n" ]; then
|
||||
+ echo "--find_multipaths must be either 'y' or 'n'"
|
||||
+ if [ -n "$RECHECK_WWID" ] && [ "$RECHECK_WWID" != "y" -a "$RECHECK_WWID" != "n" ]; then
|
||||
+ echo "--recheck_wwid must be either 'y' or 'n'"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ if [ "$FIND" = "y" ]; then
|
||||
+ FIND="on"
|
||||
+ elif [ "$FIND" = "n" ]; then
|
||||
+ FIND="off"
|
||||
+ elif [ -n "$FIND" ] && [ "$FIND" != "on" -a "$FIND" != "yes" -a "$FIND" != "off" -a "$FIND" != "no" -a "$FIND" != "strict" -a "$FIND" != "greedy" -a "$FIND" != "smart" ]; then
|
||||
+ echo "--find_multipaths must be one of 'on' 'yes' 'y' 'off' 'no' 'n' 'strict' 'greedy' or 'smart'"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ if [ -n "$PROPERTY" ] && [ "$PROPERTY" != "y" -a "$PROPERTY" != "n" ]; then
|
||||
@ -311,7 +345,19 @@ index 00000000..f34003c9
|
||||
+ echo "--enable_foreign must be either 'y' or 'n'"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ if [ -z "$ENABLE" -a -z "$FIND" -a -z "$FRIENDLY" -a -z "$PROPERTY" ]; then
|
||||
+ if [ -n "$OPTION_NAME" ]; then
|
||||
+ if [[ $OPTION_NAME =~ [[:space:]]|#|\"|!|\{|\} ]]; then
|
||||
+ echo "--option name \"$OPTION_NAME\" is invalid"
|
||||
+ exit 1
|
||||
+ elif [[ $OPTION_VALUE =~ \"|#|!|\{|\} ]]; then
|
||||
+ echo "--option value \"$OPTION_VALUE\" is invalid"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ if [[ $OPTION_VALUE =~ [[:space:]] ]]; then
|
||||
+ OPTION_VALUE=\"$OPTION_VALUE\"
|
||||
+ fi
|
||||
+ fi
|
||||
+ if [ -z "$ENABLE" -a -z "$FIND" -a -z "$FRIENDLY" -a -z "$PROPERTY" -a -z "$FOREIGN" -a -z "$OPTION_NAME" -a -z "$RECHECK_WWID" ]; then
|
||||
+ SHOW_STATUS=1
|
||||
+ fi
|
||||
+ if [ -n "$MODULE" ] && [ "$MODULE" != "y" -a "$MODULE" != "n" ]; then
|
||||
@ -386,45 +432,62 @@ index 00000000..f34003c9
|
||||
+fi
|
||||
+
|
||||
+if [ "$HAVE_BLACKLIST" = "1" ]; then
|
||||
+ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*devnode \"\.\?\*\"" ; then
|
||||
+ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"" ; then
|
||||
+ HAVE_DISABLE=1
|
||||
+ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*devnode \"\.\?\*\"" ; then
|
||||
+ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"" ; then
|
||||
+ HAVE_DISABLE=0
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+if [ "$HAVE_BLACKLIST" = "1" ]; then
|
||||
+ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*wwid \"\.\?\*\"" ; then
|
||||
+ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*wwid[[:space:]][[:space:]]*\"\.\?\*\"" ; then
|
||||
+ HAVE_WWID_DISABLE=1
|
||||
+ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*wwid \"\.\?\*\"" ; then
|
||||
+ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*wwid[[:space:]][[:space:]]*\"\.\?\*\"" ; then
|
||||
+ HAVE_WWID_DISABLE=0
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+if [ "$HAVE_DEFAULTS" = "1" ]; then
|
||||
+ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*find_multipaths[[:space:]]*\(yes\|1\)" ; then
|
||||
+ HAVE_FIND=1
|
||||
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*find_multipaths[[:space:]]*\(no\|0\)" ; then
|
||||
+ HAVE_FIND=0
|
||||
+ HAVE_FIND=`sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | sed -n 's/^[[:blank:]]*find_multipaths[[:blank:]][[:blank:]]*\([^[:blank:]]*\).*$/\1/p' | sed -n 1p`
|
||||
+ if [ "$HAVE_FIND" = "1" ]; then
|
||||
+ HAVE_FIND="yes"
|
||||
+ elif [ "$HAVE_FIND" = "0" ]; then
|
||||
+ HAVE_FIND="no"
|
||||
+ fi
|
||||
+ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]]*\(yes\|1\)" ; then
|
||||
+ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]][[:space:]]*\(yes\|1\)" ; then
|
||||
+ HAVE_FRIENDLY=1
|
||||
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]]*\(no\|0\)" ; then
|
||||
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]][[:space:]]*\(no\|0\)" ; then
|
||||
+ HAVE_FRIENDLY=0
|
||||
+ fi
|
||||
+ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*recheck_wwid[[:space:]][[:space:]]*\(yes\|1\)" ; then
|
||||
+ HAVE_RECHECK_WWID=1
|
||||
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*recheck_wwid[[:space:]][[:space:]]*\(no\|0\)" ; then
|
||||
+ HAVE_RECHECK_WWID=0
|
||||
+ fi
|
||||
+ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*enable_foreign" ; then
|
||||
+ HAVE_FOREIGN=0
|
||||
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign[[:space:]]*\"\^\$\"" ; then
|
||||
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign[[:space:]][[:space:]]*\"\.\*\"" ; then
|
||||
+ HAVE_FOREIGN=1
|
||||
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign" ; then
|
||||
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign[[:space:]][[:space:]]*\"\^\$\"" ; then
|
||||
+ HAVE_FOREIGN=2
|
||||
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign[[:space:]][[:space:]]*\"NONE\"" ; then
|
||||
+ HAVE_FOREIGN=2
|
||||
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign" ; then
|
||||
+ HAVE_FOREIGN=3
|
||||
+ fi
|
||||
+ if [ -n "$OPTION_NAME" ]; then
|
||||
+ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q '^[[:space:]]*'"$OPTION_NAME"'[[:space:]][[:space:]]*'"$OPTION_VALUE" ; then
|
||||
+ HAVE_OPTION=1
|
||||
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q '^[[:space:]]*'"$OPTION_NAME"'\([[:space:]].*\)\?$' ; then
|
||||
+ HAVE_OPTION=0
|
||||
+ fi
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+if [ "$HAVE_EXCEPTIONS" = "1" ]; then
|
||||
+ if sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then
|
||||
+ if sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*property[[:space:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then
|
||||
+ HAVE_PROPERTY=1
|
||||
+ elif sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then
|
||||
+ elif sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*property[[:space:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then
|
||||
+ HAVE_PROPERTY=0
|
||||
+ fi
|
||||
+fi
|
||||
@ -435,24 +498,31 @@ index 00000000..f34003c9
|
||||
+ else
|
||||
+ echo "multipath is disabled"
|
||||
+ fi
|
||||
+ if [ -z "$HAVE_FIND" -o "$HAVE_FIND" = 0 ]; then
|
||||
+ echo "find_multipaths is disabled"
|
||||
+ if [ -z "$HAVE_FIND" ]; then
|
||||
+ echo "find_multipaths is off"
|
||||
+ else
|
||||
+ echo "find_multipaths is enabled"
|
||||
+ echo "find_multipaths is $HAVE_FIND"
|
||||
+ fi
|
||||
+ if [ -z "$HAVE_FRIENDLY" -o "$HAVE_FRIENDLY" = 0 ]; then
|
||||
+ echo "user_friendly_names is disabled"
|
||||
+ else
|
||||
+ echo "user_friendly_names is enabled"
|
||||
+ fi
|
||||
+ if [ -z "$HAVE_RECHECK_WWID" -o "$HAVE_RECHECK_WWID" = 0 ]; then
|
||||
+ echo "recheck_wwid is disabled"
|
||||
+ else
|
||||
+ echo "recheck_wwid is enabled"
|
||||
+ fi
|
||||
+ if [ -z "$HAVE_PROPERTY" -o "$HAVE_PROPERTY" = 0 ]; then
|
||||
+ echo "default property blacklist is disabled"
|
||||
+ else
|
||||
+ echo "default property blacklist is enabled"
|
||||
+ fi
|
||||
+ if [ -z "$HAVE_FOREIGN" -o "$HAVE_FOREIGN" = 0 ]; then
|
||||
+ echo "enable_foreign is not set (all foreign multipath devices will be shown)"
|
||||
+ echo "enable_foreign is not set (no foreign multipath devices will be shown)"
|
||||
+ elif [ "$HAVE_FOREIGN" = 1 ]; then
|
||||
+ echo "enable_foreign is set (all foreign multipath devices will be shown)"
|
||||
+ elif [ "$HAVE_FOREIGN" = 2 ]; then
|
||||
+ echo "enable_foreign is set (no foreign multipath devices will be shown)"
|
||||
+ else
|
||||
+ echo "enable_foreign is set (foreign multipath devices may not be shown)"
|
||||
@ -497,14 +567,14 @@ index 00000000..f34003c9
|
||||
+
|
||||
+if [ "$ENABLE" = 2 ]; then
|
||||
+ if [ "$HAVE_DISABLE" = 1 ]; then
|
||||
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode \"\.\?\*\"/# devnode ".*"/' $TMPFILE
|
||||
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"/# devnode ".*"/' $TMPFILE
|
||||
+ fi
|
||||
+ if [ -z "$HAVE_WWID_DISABLE" ]; then
|
||||
+ sed -i '/^blacklist[[:space:]]*{/ a\
|
||||
+ wwid ".*"
|
||||
+' $TMPFILE
|
||||
+ elif [ "$HAVE_WWID_DISABLE" = 0 ]; then
|
||||
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*wwid \"\.\?\*\"/ wwid ".*"/' $TMPFILE
|
||||
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*wwid[[:space:]][[:space:]]*\"\.\?\*\"/ wwid ".*"/' $TMPFILE
|
||||
+ fi
|
||||
+ if [ "$HAVE_EXCEPTIONS" = 1 ]; then
|
||||
+ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ {/^[[:space:]]*wwid/ d}' $TMPFILE
|
||||
@ -518,7 +588,7 @@ index 00000000..f34003c9
|
||||
+ add_blacklist_exceptions
|
||||
+elif [ "$ENABLE" = 1 ]; then
|
||||
+ if [ "$HAVE_DISABLE" = 1 ]; then
|
||||
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode \"\.\?\*\"/# devnode ".*"/' $TMPFILE
|
||||
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"/# devnode ".*"/' $TMPFILE
|
||||
+ fi
|
||||
+elif [ "$ENABLE" = 0 ]; then
|
||||
+ if [ -z "$HAVE_DISABLE" ]; then
|
||||
@ -526,30 +596,25 @@ index 00000000..f34003c9
|
||||
+ devnode ".*"
|
||||
+' $TMPFILE
|
||||
+ elif [ "$HAVE_DISABLE" = 0 ]; then
|
||||
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*devnode \"\.\?\*\"/ devnode ".*"/' $TMPFILE
|
||||
+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"/ devnode ".*"/' $TMPFILE
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+if [ "$FIND" = "n" ]; then
|
||||
+ if [ "$HAVE_FIND" = 1 ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*find_multipaths[[:space:]]*\(yes\|1\)/ find_multipaths no/' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ fi
|
||||
+elif [ "$FIND" = "y" ]; then
|
||||
+if [ -n "$FIND" ]; then
|
||||
+ if [ -z "$HAVE_FIND" ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/ a\
|
||||
+ find_multipaths yes
|
||||
+ find_multipaths '"$FIND"'
|
||||
+' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ elif [ "$HAVE_FIND" = 0 ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*find_multipaths[[:space:]]*\(no\|0\)/ find_multipaths yes/' $TMPFILE
|
||||
+ elif [ "$FIND" != "$HAVE_FIND" ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:blank:]]*find_multipaths[[:blank:]][[:blank:]]*[^[:blank:]]*/ find_multipaths '"$FIND"'/' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+if [ "$FRIENDLY" = "n" ]; then
|
||||
+ if [ "$HAVE_FRIENDLY" = 1 ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]]*\(yes\|1\)/ user_friendly_names no/' $TMPFILE
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]][[:space:]]*\(yes\|1\)/ user_friendly_names no/' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ fi
|
||||
+elif [ "$FRIENDLY" = "y" ]; then
|
||||
@ -559,45 +624,85 @@ index 00000000..f34003c9
|
||||
+' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ elif [ "$HAVE_FRIENDLY" = 0 ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]]*\(no\|0\)/ user_friendly_names yes/' $TMPFILE
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]][[:space:]]*\(no\|0\)/ user_friendly_names yes/' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+if [ "$RECHECK_WWID" = "n" ]; then
|
||||
+ if [ "$HAVE_RECHECK_WWID" = 1 ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*recheck_wwid[[:space:]][[:space:]]*\(yes\|1\)/ recheck_wwid no/' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ fi
|
||||
+elif [ "$RECHECK_WWID" = "y" ]; then
|
||||
+ if [ -z "$HAVE_RECHECK_WWID" ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/ a\
|
||||
+ recheck_wwid yes
|
||||
+' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ elif [ "$HAVE_RECHECK_WWID" = 0 ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*recheck_wwid[[:space:]][[:space:]]*\(no\|0\)/ recheck_wwid yes/' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+if [ "$PROPERTY" = "n" ]; then
|
||||
+ if [ "$HAVE_PROPERTY" = 1 ]; then
|
||||
+ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/# property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE
|
||||
+ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*property[[:space:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/# property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ fi
|
||||
+elif [ "$PROPERTY" = "y" ]; then
|
||||
+ if [ -z "$HAVE_PROPERTY" ]; then
|
||||
+ if [ -z "$HAVE_PROPERTY" -a -z "$HAVE_EXCEPTIONS" ]; then
|
||||
+ cat >> $TMPFILE << _EOF_
|
||||
+
|
||||
+blacklist_exceptions {
|
||||
+ property "(SCSI_IDENT_|ID_WWN)"
|
||||
+}
|
||||
+_EOF_
|
||||
+ CHANGED_CONFIG=1
|
||||
+ elif [ -z "$HAVE_PROPERTY" ]; then
|
||||
+ sed -i '/^blacklist_exceptions[[:space:]]*{/ a\
|
||||
+ property "(SCSI_IDENT_|ID_WWN)"
|
||||
+' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ elif [ "$HAVE_PROPERTY" = 0 ]; then
|
||||
+ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/ property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE
|
||||
+ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*property[[:space:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/ property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+if [ "$FOREIGN" = "y" ]; then
|
||||
+ if [ "$HAVE_FOREIGN" = 1 -o "$HAVE_FOREIGN" = 2 ]; then
|
||||
+if [ "$FOREIGN" = "n" ]; then
|
||||
+ if [ "$HAVE_FOREIGN" = 1 -o "$HAVE_FOREIGN" = 3 ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*enable_foreign/# enable_foreign/' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ fi
|
||||
+elif [ "$FOREIGN" = "n" ]; then
|
||||
+elif [ "$FOREIGN" = "y" ]; then
|
||||
+ if [ -z "$HAVE_FOREIGN" ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/ a\
|
||||
+ enable_foreign "^$"
|
||||
+ enable_foreign ".*"
|
||||
+' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ elif [ "$HAVE_FOREIGN" = 0 -o "$HAVE_FOREIGN" = 2 ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*#\?[[:space:]]*enable_foreign.*$/ enable_foreign "^$"/' $TMPFILE
|
||||
+ elif [ "$HAVE_FOREIGN" = 0 -o "$HAVE_FOREIGN" = 2 -o "$HAVE_FOREIGN" = 3 ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*#\?[[:space:]]*enable_foreign.*$/ enable_foreign ".*"/' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+if [ -n "$OPTION_NAME" -a -n "$OPTION_VALUE" ]; then
|
||||
+ if [ -z "$HAVE_OPTION" ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/ a\
|
||||
+ '"$OPTION_NAME"' '"$OPTION_VALUE"'
|
||||
+' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ elif [ "$HAVE_OPTION" = 0 ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*'"$OPTION_NAME"'\([[:space:]].*\)\?$/ '"$OPTION_NAME"' '"$OPTION_VALUE"'/' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+ fi
|
||||
+elif [ -n "$OPTION_NAME" -a -n "$HAVE_OPTION" ]; then
|
||||
+ sed -i '/^defaults[[:space:]]*{/,/^}/{/^[[:space:]]*'"$OPTION_NAME"'\([[:space:]].*\)\?$/d}' $TMPFILE
|
||||
+ CHANGED_CONFIG=1
|
||||
+fi
|
||||
+
|
||||
+if [ -f "$OUTPUTFILE" ]; then
|
||||
+ cp $OUTPUTFILE $OUTPUTFILE.old
|
||||
+ if [ $? != 0 ]; then
|
||||
@ -630,10 +735,10 @@ index 00000000..f34003c9
|
||||
+fi
|
||||
diff --git a/multipath/mpathconf.8 b/multipath/mpathconf.8
|
||||
new file mode 100644
|
||||
index 00000000..b82961d6
|
||||
index 00000000..ea025f31
|
||||
--- /dev/null
|
||||
+++ b/multipath/mpathconf.8
|
||||
@@ -0,0 +1,135 @@
|
||||
@@ -0,0 +1,151 @@
|
||||
+.TH MPATHCONF 8 "June 2010" "" "Linux Administrator's Manual"
|
||||
+.SH NAME
|
||||
+mpathconf - A tool for configuring device-mapper-multipath
|
||||
@ -674,12 +779,12 @@ index 00000000..b82961d6
|
||||
+already exists, mpathconf will edit it. If it does not exist, mpathconf will
|
||||
+create a default file with
|
||||
+.B user_friendly_names
|
||||
+and
|
||||
+set and
|
||||
+.B find_multipaths
|
||||
+set. To disable these, use the
|
||||
+set to \fBon\fP. To disable these, use the
|
||||
+.B --user_friendly_names n
|
||||
+and
|
||||
+.B --find_multipaths n
|
||||
+.B --find_multipaths off
|
||||
+options
|
||||
+.SH COMMANDS
|
||||
+.TP
|
||||
@ -713,13 +818,22 @@ index 00000000..b82961d6
|
||||
+defaults section. If set to \fBn\fP, this removes the line, if present. This
|
||||
+command can be used along with any other command.
|
||||
+.TP
|
||||
+.B --find_multipaths\fP { \fBy\fP | \fBn\fP }
|
||||
+.B --recheck_wwid \fP { \fBy\fP | \fBn\fP }
|
||||
+If set to \fBy\fP, this adds the line
|
||||
+.B find_multipaths yes
|
||||
+.B recheck_wwid yes
|
||||
+to the
|
||||
+.B /etc/multipath.conf
|
||||
+defaults section. If set to \fBn\fP, this removes the line, if present. This
|
||||
+command can be used along with any other command.
|
||||
+defaults section, or sets an existing line to \fByes\fP. If set to \fBn\fP, this
|
||||
+sets an existing \fBrecheck_wwid\fP line to \fBno\fP. This command can be used
|
||||
+along with any other command.
|
||||
+.TP
|
||||
+.B --find_multipaths\fP { \fBon\fP | \fByes\fP | \fBy\fP | \fBoff\fP | \fBno\fP | \fBn\fP | \fBstrict\fP | \fBgreedy\fP | \fBsmart\fP }
|
||||
+If set to \fB<value>\fP, this adds the line
|
||||
+.B find_multipaths <value>
|
||||
+to the
|
||||
+.B /etc/multipath.conf
|
||||
+defaults section. This command can be used along with any other command.
|
||||
+\fBy\fP and \fBn\fP can be used instead of \fByes\fP and \fBno\fP.
|
||||
+.TP
|
||||
+.B --property_blacklist \fP { \fBy\fP | \fBn\fP }
|
||||
+If set to \fBy\fP, this adds the line
|
||||
@ -730,11 +844,18 @@ index 00000000..b82961d6
|
||||
+present. This command can be used along with any other command.
|
||||
+.TP
|
||||
+.B --enable_foreign\fP { \fBy\fP | \fBn\fP }
|
||||
+If set to \fBn\fP, this adds the line
|
||||
+.B enable_foreign "^$"
|
||||
+If set to \fBy\fP, this adds the line
|
||||
+.B enable_foreign ".*"
|
||||
+to the
|
||||
+.B /etc/multipath.conf
|
||||
+defaults section. if set to \fBy\fP, this removes the line, if present. This
|
||||
+defaults section. if set to \fBn\fP, this removes the line, if present. This
|
||||
+command can be used along with any other command.
|
||||
+.TP
|
||||
+.B --option \fB<option_name>:[<value>]\fP
|
||||
+Sets the defaults section option \fB<option_name>\fP to \fB<value>\fP. If the
|
||||
+option was not previously set in the defaults section, it is added. If it was
|
||||
+set, its value is changed to \fB<value>\fP. If \fB<value>\fP is left blank,
|
||||
+then the option is removed from the defaults section, if was set there. This
|
||||
+command can be used along with any other command.
|
||||
+.TP
|
||||
+.B --outfile \fB<filename>\fP
|
||||
@ -769,6 +890,3 @@ index 00000000..b82961d6
|
||||
+.BR service (8),
|
||||
+.SH AUTHOR
|
||||
+Benjamin Marzinski <bmarzins@redhat.com>
|
||||
--
|
||||
2.17.2
|
||||
|
@ -14,23 +14,38 @@ multipathd.service
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/wwids.c | 44 +++++++++++++++++++++++++++++++++++
|
||||
libmultipath/wwids.h | 1 +
|
||||
multipath/main.c | 10 ++++++--
|
||||
multipath/multipath.8 | 7 +++++-
|
||||
multipathd/multipathd.service | 1 +
|
||||
5 files changed, 60 insertions(+), 3 deletions(-)
|
||||
multipath/main.c | 54 ++++++++++++++++++++++++++++++--
|
||||
multipath/multipath.8.in | 7 ++++-
|
||||
multipathd/multipathd.service.in | 1 +
|
||||
3 files changed, 59 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
|
||||
index 28a2150d..fab6fc8f 100644
|
||||
--- a/libmultipath/wwids.c
|
||||
+++ b/libmultipath/wwids.c
|
||||
@@ -454,3 +454,47 @@ int op ## _wwid(const char *wwid) \
|
||||
declare_failed_wwid_op(is_failed, false)
|
||||
declare_failed_wwid_op(mark_failed, true)
|
||||
declare_failed_wwid_op(unmark_failed, true)
|
||||
+
|
||||
+int remember_cmdline_wwid(void)
|
||||
diff --git a/multipath/main.c b/multipath/main.c
|
||||
index c21e3e0b..3f3ac9fb 100644
|
||||
--- a/multipath/main.c
|
||||
+++ b/multipath/main.c
|
||||
@@ -120,7 +120,7 @@ usage (char * progname)
|
||||
fprintf (stderr, " %s [-v level] [-R retries] -F\n", progname);
|
||||
fprintf (stderr, " %s [-v level] [-l|-ll] [device]\n", progname);
|
||||
fprintf (stderr, " %s [-v level] [-a|-w] device\n", progname);
|
||||
- fprintf (stderr, " %s [-v level] -W\n", progname);
|
||||
+ fprintf (stderr, " %s [-v level] [-A|-W]\n", progname);
|
||||
fprintf (stderr, " %s [-v level] [-i] [-c|-C] device\n", progname);
|
||||
fprintf (stderr, " %s [-v level] [-i] [-u|-U]\n", progname);
|
||||
fprintf (stderr, " %s [-h|-t|-T]\n", progname);
|
||||
@@ -134,6 +134,8 @@ usage (char * progname)
|
||||
" -f flush a multipath device map\n"
|
||||
" -F flush all multipath device maps\n"
|
||||
" -a add a device wwid to the wwids file\n"
|
||||
+ " -A add devices from kernel command line mpath.wwids\n"
|
||||
+ " parameters to wwids file\n"
|
||||
" -c check if a device should be a path in a multipath device\n"
|
||||
" -C check if a multipath device has usable paths\n"
|
||||
" -q allow queue_if_no_path when multipathd is not running\n"
|
||||
@@ -448,6 +450,50 @@ static void cleanup_vecs(void)
|
||||
free_pathvec(vecs.pathvec, FREE_PATHS);
|
||||
}
|
||||
|
||||
+static int remember_cmdline_wwid(void)
|
||||
+{
|
||||
+ FILE *f = NULL;
|
||||
+ char buf[LINE_MAX], *next, *ptr;
|
||||
@ -73,50 +88,20 @@ index 28a2150d..fab6fc8f 100644
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
diff --git a/libmultipath/wwids.h b/libmultipath/wwids.h
|
||||
index 0c6ee54d..e32a0b0e 100644
|
||||
--- a/libmultipath/wwids.h
|
||||
+++ b/libmultipath/wwids.h
|
||||
@@ -17,6 +17,7 @@ int remember_wwid(char *wwid);
|
||||
int check_wwids_file(char *wwid, int write_wwid);
|
||||
int remove_wwid(char *wwid);
|
||||
int replace_wwids(vector mp);
|
||||
+int remember_cmdline_wwid(void);
|
||||
|
||||
enum {
|
||||
WWID_IS_NOT_FAILED = 0,
|
||||
diff --git a/multipath/main.c b/multipath/main.c
|
||||
index cf9d2a28..78822ee1 100644
|
||||
--- a/multipath/main.c
|
||||
+++ b/multipath/main.c
|
||||
@@ -138,7 +138,7 @@ usage (char * progname)
|
||||
fprintf (stderr, " %s [-v level] [-R retries] -F\n", progname);
|
||||
fprintf (stderr, " %s [-v level] [-l|-ll] [device]\n", progname);
|
||||
fprintf (stderr, " %s [-v level] [-a|-w] device\n", progname);
|
||||
- fprintf (stderr, " %s [-v level] -W\n", progname);
|
||||
+ fprintf (stderr, " %s [-v level] [-A|-W]\n", progname);
|
||||
fprintf (stderr, " %s [-v level] [-i] [-c|-C] device\n", progname);
|
||||
fprintf (stderr, " %s [-v level] [-i] [-u|-U]\n", progname);
|
||||
fprintf (stderr, " %s [-h|-t|-T]\n", progname);
|
||||
@@ -151,6 +151,8 @@ usage (char * progname)
|
||||
" -f flush a multipath device map\n"
|
||||
" -F flush all multipath device maps\n"
|
||||
" -a add a device wwid to the wwids file\n"
|
||||
+ " -A add devices from kernel command line mpath.wwids\n"
|
||||
+ " parameters to wwids file\n"
|
||||
" -c check if a device should be a path in a multipath device\n"
|
||||
" -C check if a multipath device has usable paths\n"
|
||||
" -q allow queue_if_no_path when multipathd is not running\n"
|
||||
@@ -907,7 +909,7 @@ main (int argc, char *argv[])
|
||||
multipath_conf = conf;
|
||||
conf->retrigger_tries = 0;
|
||||
conf->force_sync = 1;
|
||||
- while ((arg = getopt(argc, argv, ":adcChl::FfM:v:p:b:BrR:itTquUwW")) != EOF ) {
|
||||
+ while ((arg = getopt(argc, argv, ":aAdcChl::FfM:v:p:b:BrR:itTquUwW")) != EOF ) {
|
||||
+
|
||||
static int
|
||||
configure (struct config *conf, enum mpath_cmds cmd,
|
||||
enum devtypes dev_type, char *devpath)
|
||||
@@ -861,7 +907,7 @@ main (int argc, char *argv[])
|
||||
condlog(1, "failed to register cleanup handler for vecs: %m");
|
||||
if (atexit(cleanup_bindings))
|
||||
condlog(1, "failed to register cleanup handler for bindings: %m");
|
||||
- while ((arg = getopt(argc, argv, ":adDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) {
|
||||
+ while ((arg = getopt(argc, argv, ":aAdDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) {
|
||||
switch(arg) {
|
||||
case 1: printf("optarg : %s\n",optarg);
|
||||
break;
|
||||
@@ -977,6 +979,10 @@ main (int argc, char *argv[])
|
||||
case 'v':
|
||||
if (!isdigit(optarg[0])) {
|
||||
@@ -932,6 +978,10 @@ main (int argc, char *argv[])
|
||||
case 'T':
|
||||
cmd = CMD_DUMP_CONFIG;
|
||||
break;
|
||||
@ -127,11 +112,11 @@ index cf9d2a28..78822ee1 100644
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
exit(RTVL_OK);
|
||||
diff --git a/multipath/multipath.8 b/multipath/multipath.8
|
||||
index 9cdd05a3..8befc45a 100644
|
||||
--- a/multipath/multipath.8
|
||||
+++ b/multipath/multipath.8
|
||||
@@ -63,7 +63,7 @@ multipath \- Device mapper target autoconfig.
|
||||
diff --git a/multipath/multipath.8.in b/multipath/multipath.8.in
|
||||
index b88e9a4c..edd742aa 100644
|
||||
--- a/multipath/multipath.8.in
|
||||
+++ b/multipath/multipath.8.in
|
||||
@@ -64,7 +64,7 @@ multipath \- Device mapper target autoconfig.
|
||||
.B multipath
|
||||
.RB [\| \-v\ \c
|
||||
.IR level \|]
|
||||
@ -140,7 +125,7 @@ index 9cdd05a3..8befc45a 100644
|
||||
.
|
||||
.LP
|
||||
.B multipath
|
||||
@@ -145,6 +145,11 @@ device mapper, path checkers ...).
|
||||
@@ -146,6 +146,11 @@ device mapper, path checkers ...).
|
||||
Add the WWID for the specified device to the WWIDs file.
|
||||
.
|
||||
.TP
|
||||
@ -152,18 +137,15 @@ index 9cdd05a3..8befc45a 100644
|
||||
.B \-w
|
||||
Remove the WWID for the specified device from the WWIDs file.
|
||||
.
|
||||
diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service
|
||||
index 17434cef..0fbcc46b 100644
|
||||
--- a/multipathd/multipathd.service
|
||||
+++ b/multipathd/multipathd.service
|
||||
@@ -15,6 +15,7 @@ Type=notify
|
||||
diff --git a/multipathd/multipathd.service.in b/multipathd/multipathd.service.in
|
||||
index 01ceff7d..e0c2011b 100644
|
||||
--- a/multipathd/multipathd.service.in
|
||||
+++ b/multipathd/multipathd.service.in
|
||||
@@ -17,6 +17,7 @@ ConditionVirtualization=!container
|
||||
[Service]
|
||||
Type=notify
|
||||
NotifyAccess=main
|
||||
LimitCORE=infinity
|
||||
ExecStartPre=-/sbin/modprobe -a scsi_dh_alua scsi_dh_emc scsi_dh_rdac dm-multipath
|
||||
+ExecStartPre=-/sbin/multipath -A
|
||||
ExecStart=/sbin/multipathd -d -s
|
||||
ExecReload=/sbin/multipathd reconfigure
|
||||
TasksMax=infinity
|
||||
--
|
||||
2.17.2
|
||||
|
@ -6,16 +6,18 @@ Subject: [PATCH] RH: reset default find_mutipaths value to off
|
||||
Upstream has changed to default find_multipaths to "strict". For now
|
||||
Redhat will retain the previous default of "off".
|
||||
|
||||
Co-authored-by: Paul Donohue <git@PaulSD.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/defaults.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
libmultipath/defaults.h | 2 +-
|
||||
multipath/multipath.conf.5.in | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
|
||||
index e5ee6afe..52fe05b9 100644
|
||||
index ed08c251..4b033ff9 100644
|
||||
--- a/libmultipath/defaults.h
|
||||
+++ b/libmultipath/defaults.h
|
||||
@@ -22,7 +22,7 @@
|
||||
@@ -23,7 +23,7 @@
|
||||
#define DEFAULT_NO_PATH_RETRY NO_PATH_RETRY_UNDEF
|
||||
#define DEFAULT_VERBOSITY 2
|
||||
#define DEFAULT_REASSIGN_MAPS 0
|
||||
@ -24,6 +26,16 @@ index e5ee6afe..52fe05b9 100644
|
||||
#define DEFAULT_FAST_IO_FAIL 5
|
||||
#define DEFAULT_DEV_LOSS_TMO 600
|
||||
#define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_ON
|
||||
--
|
||||
2.17.2
|
||||
|
||||
diff --git a/multipath/multipath.conf.5.in b/multipath/multipath.conf.5.in
|
||||
index 645e8f88..a7543939 100644
|
||||
--- a/multipath/multipath.conf.5.in
|
||||
+++ b/multipath/multipath.conf.5.in
|
||||
@@ -1225,7 +1225,7 @@ as non-multipath and passed on to upper layers.
|
||||
\fBNote:\fR this may cause delays during device detection if
|
||||
there are single-path devices which aren\'t blacklisted.
|
||||
.TP
|
||||
-The default is: \fBstrict\fR
|
||||
+The default is: \fBoff\fR
|
||||
.RE
|
||||
.
|
||||
.
|
@ -13,7 +13,7 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
1 file changed, 29 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/prioritizers/ana.c b/libmultipath/prioritizers/ana.c
|
||||
index b5c7873d..e139360c 100644
|
||||
index e9827dca..80a32aa3 100644
|
||||
--- a/libmultipath/prioritizers/ana.c
|
||||
+++ b/libmultipath/prioritizers/ana.c
|
||||
@@ -24,6 +24,7 @@
|
||||
@ -68,7 +68,7 @@ index b5c7873d..e139360c 100644
|
||||
static int get_ana_info(struct path * pp)
|
||||
{
|
||||
int rc;
|
||||
@@ -210,8 +234,11 @@ int getprio(struct path *pp, __attribute__((unused)) char *args,
|
||||
@@ -209,8 +233,11 @@ int getprio(struct path *pp, __attribute__((unused)) char *args)
|
||||
|
||||
if (pp->fd < 0)
|
||||
rc = -ANA_ERR_NO_INFORMATION;
|
||||
@ -82,6 +82,3 @@ index b5c7873d..e139360c 100644
|
||||
|
||||
switch (rc) {
|
||||
case NVME_ANA_OPTIMIZED:
|
||||
--
|
||||
2.17.2
|
||||
|
96
0011-RH-make-parse_vpd_pg83-match-scsi_id-output.patch
Normal file
96
0011-RH-make-parse_vpd_pg83-match-scsi_id-output.patch
Normal file
@ -0,0 +1,96 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 25 Mar 2021 13:05:10 -0500
|
||||
Subject: [PATCH] RH: make parse_vpd_pg83 match scsi_id output
|
||||
|
||||
Red Hat sets ID_SERIAL based on the result of scsi_id, instead of using
|
||||
the result of sg_inq and 55-scsi-sg3_id.rules. Make parse_vpd_pg83 match
|
||||
that.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/discovery.c | 12 ++----------
|
||||
tests/vpd.c | 6 ++++++
|
||||
2 files changed, 8 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
||||
index e2052422..3bcd94ce 100644
|
||||
--- a/libmultipath/discovery.c
|
||||
+++ b/libmultipath/discovery.c
|
||||
@@ -1221,13 +1221,9 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
|
||||
good_len = 8;
|
||||
break;
|
||||
case 2:
|
||||
- /* IEEE Extended: Prio 6 */
|
||||
- new_prio = 6;
|
||||
- good_len = 8;
|
||||
- break;
|
||||
case 3:
|
||||
- /* IEEE Locally assigned: Prio 1 */
|
||||
- new_prio = 1;
|
||||
+ /* IEEE Extended or Locally assigned: Prio 6 */
|
||||
+ new_prio = 6;
|
||||
good_len = 8;
|
||||
break;
|
||||
default:
|
||||
@@ -1245,10 +1241,6 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
|
||||
break;
|
||||
case 0x8:
|
||||
/* SCSI Name: Prio 3 */
|
||||
- invalid = (d[3] < 4 || (memcmp(d + 4, "eui.", 4) &&
|
||||
- memcmp(d + 4, "naa.", 4) &&
|
||||
- memcmp(d + 4, "iqn.", 4)));
|
||||
- new_prio = 3;
|
||||
break;
|
||||
case 0x1:
|
||||
/* T-10 Vendor ID: Prio 2 */
|
||||
diff --git a/tests/vpd.c b/tests/vpd.c
|
||||
index e3212e61..cdb111bb 100644
|
||||
--- a/tests/vpd.c
|
||||
+++ b/tests/vpd.c
|
||||
@@ -232,11 +232,13 @@ static const char * const str_prefix[] = {
|
||||
[STR_IQN] = "iqn.",
|
||||
};
|
||||
|
||||
+#if 0
|
||||
static const char byte0[] = {
|
||||
[STR_EUI] = '2',
|
||||
[STR_NAA] = '3',
|
||||
[STR_IQN] = '8',
|
||||
};
|
||||
+#endif
|
||||
|
||||
/**
|
||||
* create_scsi_string_desc() - create a SCSI name string descriptor.
|
||||
@@ -767,6 +769,7 @@ make_test_vpd_naa(2, 18);
|
||||
make_test_vpd_naa(2, 17);
|
||||
make_test_vpd_naa(2, 16);
|
||||
|
||||
+#if 0
|
||||
/* SCSI Name string: EUI64, WWID size: 17 */
|
||||
make_test_vpd_str(0, 20, 18)
|
||||
make_test_vpd_str(0, 20, 17)
|
||||
@@ -802,6 +805,7 @@ make_test_vpd_str(18, 20, 18)
|
||||
make_test_vpd_str(18, 20, 17)
|
||||
make_test_vpd_str(18, 20, 16)
|
||||
make_test_vpd_str(18, 20, 15)
|
||||
+#endif
|
||||
|
||||
static int test_vpd(void)
|
||||
{
|
||||
@@ -910,6 +914,7 @@ static int test_vpd(void)
|
||||
cmocka_unit_test(test_vpd_naa_2_18),
|
||||
cmocka_unit_test(test_vpd_naa_2_17),
|
||||
cmocka_unit_test(test_vpd_naa_2_16),
|
||||
+/*
|
||||
cmocka_unit_test(test_vpd_str_0_20_18),
|
||||
cmocka_unit_test(test_vpd_str_0_20_17),
|
||||
cmocka_unit_test(test_vpd_str_0_20_16),
|
||||
@@ -934,6 +939,7 @@ static int test_vpd(void)
|
||||
cmocka_unit_test(test_vpd_str_18_20_17),
|
||||
cmocka_unit_test(test_vpd_str_18_20_16),
|
||||
cmocka_unit_test(test_vpd_str_18_20_15),
|
||||
+*/
|
||||
};
|
||||
return cmocka_run_group_tests(tests, setup, teardown);
|
||||
}
|
25
0012-RH-add-scsi-device-handlers-to-modules-load.d.patch
Normal file
25
0012-RH-add-scsi-device-handlers-to-modules-load.d.patch
Normal file
@ -0,0 +1,25 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Mar 2022 18:12:06 -0500
|
||||
Subject: [PATCH] RH: add scsi device handlers to modules-load.d
|
||||
|
||||
Make scsi_dh_alua scsi_dh_emc and scsi_dh_rdac get loaded in early boot.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile.inc | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/Makefile.inc b/Makefile.inc
|
||||
index 94e0ec85..49514b06 100644
|
||||
--- a/Makefile.inc
|
||||
+++ b/Makefile.inc
|
||||
@@ -16,7 +16,7 @@ READLINE :=
|
||||
|
||||
# List of scsi device handler modules to load on boot, e.g.
|
||||
# SCSI_DH_MODULES_PRELOAD := scsi_dh_alua scsi_dh_rdac
|
||||
-SCSI_DH_MODULES_PRELOAD :=
|
||||
+SCSI_DH_MODULES_PRELOAD := scsi_dh_alua scsi_dh_emc scsi_dh_rdac
|
||||
|
||||
EXTRAVERSION := $(shell rev=$$(git rev-parse --short=7 HEAD 2>/dev/null); echo $${rev:+-g$$rev})
|
||||
|
26
0013-RH-compile-with-libreadline-support.patch
Normal file
26
0013-RH-compile-with-libreadline-support.patch
Normal file
@ -0,0 +1,26 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 15 Nov 2022 18:03:33 -0600
|
||||
Subject: [PATCH] RH: compile with libreadline support
|
||||
|
||||
Since the license issue has been resolved, and there are problems with
|
||||
the command completion with libedit, use libreadline.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile.inc | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/Makefile.inc b/Makefile.inc
|
||||
index 49514b06..a3ed9f28 100644
|
||||
--- a/Makefile.inc
|
||||
+++ b/Makefile.inc
|
||||
@@ -12,7 +12,7 @@
|
||||
# Readline library to use, libedit, libreadline, or empty
|
||||
# Caution: Using libreadline may make the multipathd binary undistributable,
|
||||
# see https://github.com/opensvc/multipath-tools/issues/36
|
||||
-READLINE :=
|
||||
+READLINE := libreadline
|
||||
|
||||
# List of scsi device handler modules to load on boot, e.g.
|
||||
# SCSI_DH_MODULES_PRELOAD := scsi_dh_alua scsi_dh_rdac
|
186
0014-RH-Add-mpathcleanup.patch
Normal file
186
0014-RH-Add-mpathcleanup.patch
Normal file
@ -0,0 +1,186 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 7 Jul 2023 15:25:59 -0500
|
||||
Subject: [PATCH] RH: Add mpathcleanup
|
||||
|
||||
mpathcleanup is a program that will remove a multipath device as well as
|
||||
all of the scsi path devices that make it up.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipath/Makefile | 2 +
|
||||
multipath/mpathcleanup | 145 +++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 147 insertions(+)
|
||||
create mode 100755 multipath/mpathcleanup
|
||||
|
||||
diff --git a/multipath/Makefile b/multipath/Makefile
|
||||
index 3dc241cc..47e82234 100644
|
||||
--- a/multipath/Makefile
|
||||
+++ b/multipath/Makefile
|
||||
@@ -25,6 +25,7 @@ install:
|
||||
$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
|
||||
$(Q)$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
||||
$(Q)$(INSTALL_PROGRAM) -m 755 mpathconf $(DESTDIR)$(bindir)/
|
||||
+ $(Q)$(INSTALL_PROGRAM) -m 755 mpathcleanup $(DESTDIR)$(bindir)/
|
||||
$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir)
|
||||
$(Q)$(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir)
|
||||
$(Q)$(INSTALL_PROGRAM) -m 644 99-z-dm-mpath-late.rules $(DESTDIR)$(udevrulesdir)
|
||||
@@ -49,6 +50,7 @@ endif
|
||||
uninstall:
|
||||
$(Q)$(RM) $(DESTDIR)$(bindir)/$(EXEC)
|
||||
$(Q)$(RM) $(DESTDIR)$(bindir)/mpathconf
|
||||
+ $(Q)$(RM) $(DESTDIR)$(bindir)/mpathcleanup
|
||||
$(Q)$(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules
|
||||
$(Q)$(RM) $(DESTDIR)$(udevrulesdir)/99-z-dm-mpath-late.rules
|
||||
$(Q)$(RM) $(DESTDIR)$(modulesloaddir)/multipath.conf
|
||||
diff --git a/multipath/mpathcleanup b/multipath/mpathcleanup
|
||||
new file mode 100755
|
||||
index 00000000..6fd921e4
|
||||
--- /dev/null
|
||||
+++ b/multipath/mpathcleanup
|
||||
@@ -0,0 +1,145 @@
|
||||
+#!/bin/bash
|
||||
+#
|
||||
+# Copyright (C) 2023 Red Hat, Inc. All rights reserved.
|
||||
+#
|
||||
+# This file is part of the device-mapper-multipath package.
|
||||
+#
|
||||
+# This copyrighted material is made available to anyone wishing to use,
|
||||
+# modify, copy, or redistribute it subject to the terms and conditions
|
||||
+# of the GNU General Public License v.2.
|
||||
+#
|
||||
+# You should have received a copy of the GNU General Public License
|
||||
+# along with this program; if not, write to the Free Software Foundation,
|
||||
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
+
|
||||
+unset PROGRAM FLUSH DEVICE DEVNAME MAJOR MINOR PATHDEVS PATHDEV HAVE_MULTIPATHD QUEUEING
|
||||
+
|
||||
+function usage
|
||||
+{
|
||||
+ echo "usage: $PROGRAM [-h] [--flush] <device>"
|
||||
+ echo ""
|
||||
+ echo "remove a multipath device and its scsi path devices"
|
||||
+ echo ""
|
||||
+ echo "options:"
|
||||
+ echo " -h, --help show this help message and exit"
|
||||
+ echo " --flush disable queuing on the multipath device and"
|
||||
+ echo " flush the path devices before removing"
|
||||
+}
|
||||
+
|
||||
+function parse_args
|
||||
+{
|
||||
+ while [ -n "$1" ]; do
|
||||
+ case $1 in
|
||||
+ --flush)
|
||||
+ FLUSH=1
|
||||
+ shift
|
||||
+ ;;
|
||||
+ --help | -h)
|
||||
+ usage
|
||||
+ exit 1
|
||||
+ ;;
|
||||
+ *)
|
||||
+ if [ -n "$DEVICE" ]; then
|
||||
+ usage
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ DEVICE=$1
|
||||
+ shift
|
||||
+ ;;
|
||||
+ esac
|
||||
+ done
|
||||
+}
|
||||
+
|
||||
+function validate_device
|
||||
+{
|
||||
+ if [ -z "$DEVICE" ]; then
|
||||
+ usage
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ if [[ "$DEVICE" =~ ^[[:digit:]]+:[[:digit:]]+$ ]]; then
|
||||
+ MAJOR=${DEVICE%%:*}
|
||||
+ MINOR=${DEVICE##*:}
|
||||
+ DEVNAME=`dmsetup ls --target multipath | grep "($MAJOR, $MINOR)$" | awk '{print $1}'`
|
||||
+ else
|
||||
+ DEVNAME=`dmsetup ls --target multipath | awk '{print $1}' | grep "^$DEVICE$"`
|
||||
+ fi
|
||||
+ if [ -z "$DEVNAME" ]; then
|
||||
+ DEVNAME=`multipath -v 1 -l $DEVICE 2>/dev/null`
|
||||
+ if [ -z "$DEVNAME" ]; then
|
||||
+ echo "$DEVICE is not a multipath device"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ # verify that this is not a native nvme multipath device
|
||||
+ dmsetup ls --target multipath | awk '{print $1}' | grep -q "^$DEVNAME$"
|
||||
+ if test $? -eq 1; then
|
||||
+ echo "$DEVICE is not a device-mapper multipath device"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ fi
|
||||
+ if [ -z "$MINOR" ]; then
|
||||
+ MINOR=`dmsetup info -c --noheadings -o minor $DEVNAME`
|
||||
+ fi
|
||||
+}
|
||||
+
|
||||
+function get_paths
|
||||
+{
|
||||
+ PATHDEVS=`ls /sys/block/dm-$MINOR/slaves`
|
||||
+ for PATHDEV in $PATHDEVS; do
|
||||
+ if [[ ! "$PATHDEV" =~ ^sd[a-z]+$ ]]; then
|
||||
+ echo "$PATHDEV is not a scsi device. $PROGRAM only works with scsi devices"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ done
|
||||
+}
|
||||
+
|
||||
+function remove_devs
|
||||
+{
|
||||
+ pidof multipathd > /dev/null
|
||||
+ HAVE_MULTIPATHD=$?
|
||||
+ multipath -v2 -l "$DEVNAME" | grep features | grep -q queue_if_no_path
|
||||
+ QUEUEING=$?
|
||||
+ if [ -n "$FLUSH" ] && [ "$QUEUEING" -eq 0 ]; then
|
||||
+ if test $HAVE_MULTIPATHD -eq 0; then
|
||||
+ multipathd disablequeueing map "$DEVNAME" > /dev/null
|
||||
+ else
|
||||
+ dmsetup message "$DEVNAME" 0 fail_if_no_path
|
||||
+ fi
|
||||
+ sleep 1
|
||||
+ fi
|
||||
+ if test $HAVE_MULTIPATHD -eq 0; then
|
||||
+ multipath -f "$DEVNAME"
|
||||
+ else
|
||||
+ multipathd -Df "$DEVNAME"
|
||||
+ fi
|
||||
+ if test $? -eq 1; then
|
||||
+ echo "$DEVICE cannot be removed"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ for PATHDEV in $PATHDEVS; do
|
||||
+ if [ -n "$FLUSH" ]; then
|
||||
+ blockdev --flushbufs /dev/"$PATHDEV"
|
||||
+ fi
|
||||
+ echo 1 > /sys/block/"$PATHDEV"/device/delete
|
||||
+ done
|
||||
+}
|
||||
+
|
||||
+function verify_removal
|
||||
+{
|
||||
+ multipath -v 1 -d $DEVNAME | grep -q "^$DEVNAME$"
|
||||
+ if test $? -eq 0; then
|
||||
+ echo "$DEVICE removed but path devices still exist"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ multipath -v 1 -l $DEVNAME | grep -q "^$DEVNAME$"
|
||||
+ if test $? -eq 0; then
|
||||
+ echo "$DEVICE removal succeeded, but device still exists"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+}
|
||||
+
|
||||
+PROGRAM="$0"
|
||||
+parse_args "$@"
|
||||
+validate_device
|
||||
+get_paths
|
||||
+remove_devs
|
||||
+verify_removal
|
@ -0,0 +1,77 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 7 Aug 2024 18:59:10 -0400
|
||||
Subject: [PATCH] libmultipath: fix ontap prioritizer snprintf limits
|
||||
|
||||
The ontap prioritizer functions dump_cdb() and process_sg_error() both
|
||||
incorrectly set the snprintf() limits larger than the available space.
|
||||
Instead of multiplying the number of elements to print by the size of an
|
||||
element to calculate the limit, they multiplied the number of elements
|
||||
to print by the maximum number of elements that the buffer could hold.
|
||||
|
||||
Fix this by making these functions use strbufs instead.
|
||||
|
||||
mwilck: removed log message in print_strbuf() failure case.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmultipath/prioritizers/ontap.c | 24 +++++++++++-------------
|
||||
1 file changed, 11 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/prioritizers/ontap.c b/libmultipath/prioritizers/ontap.c
|
||||
index 117886ea..90eaf274 100644
|
||||
--- a/libmultipath/prioritizers/ontap.c
|
||||
+++ b/libmultipath/prioritizers/ontap.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "prio.h"
|
||||
#include "structs.h"
|
||||
#include "unaligned.h"
|
||||
+#include "strbuf.h"
|
||||
|
||||
#define INQUIRY_CMD 0x12
|
||||
#define INQUIRY_CMDLEN 6
|
||||
@@ -35,32 +36,29 @@
|
||||
static void dump_cdb(unsigned char *cdb, int size)
|
||||
{
|
||||
int i;
|
||||
- char buf[10*5+1];
|
||||
- char * p = &buf[0];
|
||||
+ STRBUF_ON_STACK(buf);
|
||||
|
||||
- condlog(0, "- SCSI CDB: ");
|
||||
- for (i=0; i<size; i++) {
|
||||
- p += snprintf(p, 10*(size-i), "0x%02x ", cdb[i]);
|
||||
+ for (i = 0; i < size; i++) {
|
||||
+ if (print_strbuf(&buf, "0x%02x ", cdb[i]) < 0)
|
||||
+ return;
|
||||
}
|
||||
- condlog(0, "%s", buf);
|
||||
+ condlog(0, "- SCSI CDB: %s", get_strbuf_str(&buf));
|
||||
}
|
||||
|
||||
static void process_sg_error(struct sg_io_hdr *io_hdr)
|
||||
{
|
||||
int i;
|
||||
- char buf[128*5+1];
|
||||
- char * p = &buf[0];
|
||||
+ STRBUF_ON_STACK(buf);
|
||||
|
||||
condlog(0, "- masked_status=0x%02x, host_status=0x%02x, "
|
||||
"driver_status=0x%02x", io_hdr->masked_status,
|
||||
io_hdr->host_status, io_hdr->driver_status);
|
||||
if (io_hdr->sb_len_wr > 0) {
|
||||
- condlog(0, "- SCSI sense data: ");
|
||||
- for (i=0; i<io_hdr->sb_len_wr; i++) {
|
||||
- p += snprintf(p, 128*(io_hdr->sb_len_wr-i), "0x%02x ",
|
||||
- io_hdr->sbp[i]);
|
||||
+ for (i = 0; i < io_hdr->sb_len_wr; i++) {
|
||||
+ if (print_strbuf(&buf, "0x%02x ", io_hdr->sbp[i]) < 0)
|
||||
+ return;
|
||||
}
|
||||
- condlog(0, "%s", buf);
|
||||
+ condlog(0, "- SCSI sense data: %s", get_strbuf_str(&buf));
|
||||
}
|
||||
}
|
||||
|
38
0016-multipathd-checker-port_state-before-setting-it.patch
Normal file
38
0016-multipathd-checker-port_state-before-setting-it.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 16 Sep 2024 19:29:13 -0400
|
||||
Subject: [PATCH] multipathd: checker port_state before setting it.
|
||||
|
||||
If the rport port_state is already Marginal, trying to set it to
|
||||
Marginal causes an error like the following:
|
||||
|
||||
multipathd[365376]: /sys/devices/pci0000:c0/0000:c0:01.1/0000:c4:00.0/host0/rport-0:0-5/fc_remote_ports/rport-0:0-5: failed to set port_state to marginal: Invalid argument
|
||||
|
||||
To avoid causing this confusing error message, check if the port_state
|
||||
is already marginal before trying to set it.
|
||||
|
||||
Cc: Muneendra Kumar <muneendra.kumar@broadcom.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/fpin_handlers.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/multipathd/fpin_handlers.c b/multipathd/fpin_handlers.c
|
||||
index be087ca0..6b56f9b7 100644
|
||||
--- a/multipathd/fpin_handlers.c
|
||||
+++ b/multipathd/fpin_handlers.c
|
||||
@@ -169,9 +169,14 @@ fpin_els_add_li_frame(struct fc_nl_event *fc_event)
|
||||
/*Sets the rport port_state to marginal*/
|
||||
static void fpin_set_rport_marginal(struct udev_device *rport_dev)
|
||||
{
|
||||
+ char old_value[20]; /* match kernel show_fc_rport_port_state() size */
|
||||
static const char marginal[] = "Marginal";
|
||||
ssize_t ret;
|
||||
|
||||
+ ret = sysfs_attr_get_value(rport_dev, "port_state",
|
||||
+ old_value, sizeof(old_value));
|
||||
+ if (ret == sizeof(marginal) - 1 && strcmp(old_value, marginal) == 0)
|
||||
+ return;
|
||||
ret = sysfs_attr_set_value(rport_dev, "port_state",
|
||||
marginal, sizeof(marginal) - 1);
|
||||
if (ret != sizeof(marginal) - 1)
|
@ -12,10 +12,10 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmultipath/foreign/nvme.c b/libmultipath/foreign/nvme.c
|
||||
index 5feb1e95..1d48b08d 100644
|
||||
index 6f2d8800..235306ff 100644
|
||||
--- a/libmultipath/foreign/nvme.c
|
||||
+++ b/libmultipath/foreign/nvme.c
|
||||
@@ -697,6 +697,7 @@ static void _find_controllers(struct context *ctx, struct nvme_map *map)
|
||||
@@ -708,6 +708,7 @@ static void _find_controllers(struct context *ctx, struct nvme_map *map)
|
||||
path = _find_path_by_syspath(map,
|
||||
udev_device_get_syspath(udev));
|
||||
if (path != NULL) {
|
||||
@ -23,7 +23,7 @@ index 5feb1e95..1d48b08d 100644
|
||||
path->seen = true;
|
||||
condlog(4, "%s: %s already known",
|
||||
__func__, fn);
|
||||
@@ -704,8 +705,10 @@ static void _find_controllers(struct context *ctx, struct nvme_map *map)
|
||||
@@ -715,8 +716,10 @@ static void _find_controllers(struct context *ctx, struct nvme_map *map)
|
||||
}
|
||||
|
||||
path = calloc(1, sizeof(*path));
|
@ -0,0 +1,65 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Tue, 11 Feb 2025 16:51:59 +0100
|
||||
Subject: [PATCH] multipath-tools: move DEFAULT_SOCKET definition into
|
||||
Makefile.inc
|
||||
|
||||
This enables configuring the socket name. Follow up patches will
|
||||
add more flexibility for configuring the sockets.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile.inc | 5 ++++-
|
||||
libmpathcmd/mpath_cmd.h | 1 -
|
||||
libmultipath/defaults.h | 1 -
|
||||
3 files changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/Makefile.inc b/Makefile.inc
|
||||
index a3ed9f28..80de8ecb 100644
|
||||
--- a/Makefile.inc
|
||||
+++ b/Makefile.inc
|
||||
@@ -75,6 +75,8 @@ devmapper_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir devmapper),
|
||||
libudev_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir libudev),/usr/include)
|
||||
kernel_incdir := /usr/include
|
||||
|
||||
+abstract_socket := /org/kernel/linux/storage/multipathd
|
||||
+
|
||||
ifeq ($(V),)
|
||||
Q := @
|
||||
# make's "Entering directory" messages are confusing in parallel mode
|
||||
@@ -116,7 +118,8 @@ CPPFLAGS := $(CPPFLAGS) $(D_URCU_VERSION) \
|
||||
-DBIN_DIR=\"$(bindir)\" -DMULTIPATH_DIR=\"$(TGTDIR)$(plugindir)\" \
|
||||
-DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(TGTDIR)$(configdir)\" \
|
||||
-DDEFAULT_CONFIGFILE=\"$(TGTDIR)$(configfile)\" -DSTATE_DIR=\"$(TGTDIR)$(statedir)\" \
|
||||
- -DEXTRAVERSION=\"$(EXTRAVERSION)\" -MMD -MP
|
||||
+ -DEXTRAVERSION=\"$(EXTRAVERSION)\" \
|
||||
+ -DDEFAULT_SOCKET=\"$(abstract_socket)\" -MMD -MP
|
||||
CFLAGS := -std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe
|
||||
BIN_CFLAGS := -fPIE -DPIE
|
||||
LIB_CFLAGS := -fPIC
|
||||
diff --git a/libmpathcmd/mpath_cmd.h b/libmpathcmd/mpath_cmd.h
|
||||
index 0c293c71..5ab5a6e5 100644
|
||||
--- a/libmpathcmd/mpath_cmd.h
|
||||
+++ b/libmpathcmd/mpath_cmd.h
|
||||
@@ -30,7 +30,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
-#define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd"
|
||||
#define DEFAULT_REPLY_TIMEOUT 4000
|
||||
|
||||
|
||||
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
|
||||
index 4b033ff9..3602636c 100644
|
||||
--- a/libmultipath/defaults.h
|
||||
+++ b/libmultipath/defaults.h
|
||||
@@ -66,7 +66,6 @@
|
||||
#define DEV_LOSS_TMO_UNSET 0U
|
||||
#define MAX_DEV_LOSS_TMO UINT_MAX
|
||||
#define DEFAULT_PIDFILE RUNTIME_DIR "/multipathd.pid"
|
||||
-#define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd"
|
||||
#define DEFAULT_BINDINGS_FILE STATE_DIR "/bindings"
|
||||
#define DEFAULT_WWIDS_FILE STATE_DIR "/wwids"
|
||||
#define DEFAULT_PRKEYS_FILE STATE_DIR "/prkeys"
|
243
0019-multipath-tools-add-helper-mpath_fill_sockaddr__.patch
Normal file
243
0019-multipath-tools-add-helper-mpath_fill_sockaddr__.patch
Normal file
@ -0,0 +1,243 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Fri, 14 Feb 2025 21:57:02 +0100
|
||||
Subject: [PATCH] multipath-tools: add helper mpath_fill_sockaddr__()
|
||||
|
||||
Create a static new helper function which is used by both libmpathcmd
|
||||
and libmpathutil and fills in the socket address name from the compile-time
|
||||
default. The function is able to handle both abstract and pathname sockets,
|
||||
but more changes are needed to make the latter actually work.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
.gitignore | 1 +
|
||||
Makefile.inc | 8 +++--
|
||||
create-config.mk | 1 +
|
||||
libmpathcmd/mpath_cmd.c | 11 ++-----
|
||||
libmpathcmd/mpath_fill_sockaddr.c | 32 +++++++++++++++++++
|
||||
libmpathutil/uxsock.c | 15 ++++-----
|
||||
multipathd/Makefile | 4 +--
|
||||
...multipathd.socket => multipathd.socket.in} | 2 +-
|
||||
8 files changed, 51 insertions(+), 23 deletions(-)
|
||||
create mode 100644 libmpathcmd/mpath_fill_sockaddr.c
|
||||
rename multipathd/{multipathd.socket => multipathd.socket.in} (88%)
|
||||
|
||||
diff --git a/.gitignore b/.gitignore
|
||||
index 049ffe88..87446d9f 100644
|
||||
--- a/.gitignore
|
||||
+++ b/.gitignore
|
||||
@@ -22,6 +22,7 @@ multipathd/multipathd
|
||||
multipathd/multipathd.8
|
||||
multipathd/multipathc
|
||||
multipathd/multipathd.service
|
||||
+multipathd/multipathd.socket
|
||||
mpathpersist/mpathpersist
|
||||
mpathpersist/mpathpersist.8
|
||||
abi.tar.gz
|
||||
diff --git a/Makefile.inc b/Makefile.inc
|
||||
index 80de8ecb..1ef3f7f8 100644
|
||||
--- a/Makefile.inc
|
||||
+++ b/Makefile.inc
|
||||
@@ -75,7 +75,7 @@ devmapper_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir devmapper),
|
||||
libudev_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir libudev),/usr/include)
|
||||
kernel_incdir := /usr/include
|
||||
|
||||
-abstract_socket := /org/kernel/linux/storage/multipathd
|
||||
+abstract_socket := @/org/kernel/linux/storage/multipathd
|
||||
|
||||
ifeq ($(V),)
|
||||
Q := @
|
||||
@@ -119,7 +119,9 @@ CPPFLAGS := $(CPPFLAGS) $(D_URCU_VERSION) \
|
||||
-DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(TGTDIR)$(configdir)\" \
|
||||
-DDEFAULT_CONFIGFILE=\"$(TGTDIR)$(configfile)\" -DSTATE_DIR=\"$(TGTDIR)$(statedir)\" \
|
||||
-DEXTRAVERSION=\"$(EXTRAVERSION)\" \
|
||||
- -DDEFAULT_SOCKET=\"$(abstract_socket)\" -MMD -MP
|
||||
+ -DDEFAULT_SOCKET=\"$(abstract_socket)\" \
|
||||
+ -DWSTRINGOP_TRUNCATION=$(if $(WSTRINGOP_TRUNCATION),1,0) \
|
||||
+ -MMD -MP
|
||||
CFLAGS := -std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe
|
||||
BIN_CFLAGS := -fPIE -DPIE
|
||||
LIB_CFLAGS := -fPIC
|
||||
@@ -164,4 +166,4 @@ NV_VERSION_SCRIPT = $(DEVLIB:%.so=%-nv.version)
|
||||
|
||||
%: %.in
|
||||
@echo creating $@
|
||||
- $(Q)sed 's:@CONFIGFILE@:'$(TGTDIR)$(configfile)':g;s:@CONFIGDIR@:'$(TGTDIR)$(configdir)':g;s:@STATE_DIR@:'$(TGTDIR)$(statedir)':g;s:@RUNTIME_DIR@:'$(runtimedir)':g;s/@MODPROBE_UNIT@/'$(MODPROBE_UNIT)'/g;s:@BINDIR@:'$(bindir)':g' $< >$@
|
||||
+ $(Q)sed 's:@CONFIGFILE@:'$(TGTDIR)$(configfile)':g;s:@CONFIGDIR@:'$(TGTDIR)$(configdir)':g;s:@STATE_DIR@:'$(TGTDIR)$(statedir)':g;s:@RUNTIME_DIR@:'$(runtimedir)':g;s/@MODPROBE_UNIT@/'$(MODPROBE_UNIT)'/g;s:@BINDIR@:'$(bindir)':g;s,@MPATH_SOCKET@,'$(abstract_socket)',g' $< >$@
|
||||
diff --git a/create-config.mk b/create-config.mk
|
||||
index 4d318b96..5cdff69a 100644
|
||||
--- a/create-config.mk
|
||||
+++ b/create-config.mk
|
||||
@@ -179,6 +179,7 @@ $(TOPDIR)/config.mk: $(multipathdir)/autoconfig.h
|
||||
@echo "ERROR_DISCARDED_QUALIFIERS := $(call TEST_CC_OPTION,-Werror=discarded-qualifiers,)" >>$@
|
||||
@echo "WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered -Wno-error=clobbered,)" >>$@
|
||||
@echo "WFORMATOVERFLOW := $(call TEST_CC_OPTION,-Wformat-overflow=2,)" >>$@
|
||||
+ @echo "WSTRINGOP_TRUNCATION := $(call TEST_CC_OPTION,-Wstringop-truncation)" >>$@
|
||||
@echo "W_MISSING_INITIALIZERS := $(call TEST_MISSING_INITIALIZERS)" >>$@
|
||||
@echo "W_URCU_TYPE_LIMITS := $(call TEST_URCU_TYPE_LIMITS)" >>$@
|
||||
@echo "ENABLE_LIBDMMP := $(ENABLE_LIBDMMP)" >>$@
|
||||
diff --git a/libmpathcmd/mpath_cmd.c b/libmpathcmd/mpath_cmd.c
|
||||
index 60b2d965..146e790d 100644
|
||||
--- a/libmpathcmd/mpath_cmd.c
|
||||
+++ b/libmpathcmd/mpath_cmd.c
|
||||
@@ -24,11 +24,13 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <poll.h>
|
||||
+#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "mpath_cmd.h"
|
||||
+#include "mpath_fill_sockaddr.c"
|
||||
|
||||
/*
|
||||
* keep reading until its all read
|
||||
@@ -101,14 +103,6 @@ int __mpath_connect(int nonblocking)
|
||||
struct sockaddr_un addr;
|
||||
int flags = 0;
|
||||
|
||||
- memset(&addr, 0, sizeof(addr));
|
||||
- addr.sun_family = AF_LOCAL;
|
||||
- addr.sun_path[0] = '\0';
|
||||
- strncpy(&addr.sun_path[1], DEFAULT_SOCKET, sizeof(addr.sun_path) - 1);
|
||||
- len = strlen(DEFAULT_SOCKET) + 1 + sizeof(sa_family_t);
|
||||
- if (len > sizeof(struct sockaddr_un))
|
||||
- len = sizeof(struct sockaddr_un);
|
||||
-
|
||||
fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
@@ -119,6 +113,7 @@ int __mpath_connect(int nonblocking)
|
||||
(void)fcntl(fd, F_SETFL, flags|O_NONBLOCK);
|
||||
}
|
||||
|
||||
+ len = mpath_fill_sockaddr__(&addr, DEFAULT_SOCKET);
|
||||
if (connect(fd, (struct sockaddr *)&addr, len) == -1) {
|
||||
int err = errno;
|
||||
|
||||
diff --git a/libmpathcmd/mpath_fill_sockaddr.c b/libmpathcmd/mpath_fill_sockaddr.c
|
||||
new file mode 100644
|
||||
index 00000000..750ef3ee
|
||||
--- /dev/null
|
||||
+++ b/libmpathcmd/mpath_fill_sockaddr.c
|
||||
@@ -0,0 +1,32 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2025 SUSE LLC
|
||||
+ * SPDX-license-identifier: LGPL-2.1-or-newer
|
||||
+ */
|
||||
+
|
||||
+static size_t mpath_fill_sockaddr__(struct sockaddr_un *addr, const char *name)
|
||||
+{
|
||||
+ size_t len;
|
||||
+
|
||||
+ addr->sun_family = AF_LOCAL;
|
||||
+
|
||||
+ if (name[0] != '@') {
|
||||
+ /* Pathname socket. This should be NULL-terminated. */
|
||||
+ strncpy(&addr->sun_path[0], name, sizeof(addr->sun_path) - 1);
|
||||
+ addr->sun_path[sizeof(addr->sun_path) - 1] = '\0';
|
||||
+ len = offsetof(struct sockaddr_un, sun_path) + strlen(name) + 1;
|
||||
+ } else {
|
||||
+ addr->sun_path[0] = '\0';
|
||||
+ /*
|
||||
+ * The abstract socket's name doesn't need to be NULL terminated.
|
||||
+ * Actually, a trailing NULL would be considered part of the socket name.
|
||||
+ */
|
||||
+#pragma GCC diagnostic push
|
||||
+#if WSTRINGOP_TRUNCATION
|
||||
+#pragma GCC diagnostic ignored "-Wstringop-truncation"
|
||||
+#endif
|
||||
+ strncpy(&addr->sun_path[1], &name[1], sizeof(addr->sun_path) - 1);
|
||||
+#pragma GCC diagnostic pop
|
||||
+ len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
|
||||
+ }
|
||||
+ return len > sizeof(*addr) ? sizeof(*addr) : len;
|
||||
+}
|
||||
diff --git a/libmpathutil/uxsock.c b/libmpathutil/uxsock.c
|
||||
index 2135476d..12c46084 100644
|
||||
--- a/libmpathutil/uxsock.c
|
||||
+++ b/libmpathutil/uxsock.c
|
||||
@@ -6,12 +6,15 @@
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
+#include <stddef.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
+#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
@@ -33,6 +36,8 @@
|
||||
static int _recv_packet(int fd, char **buf, unsigned int timeout,
|
||||
ssize_t limit);
|
||||
|
||||
+#include "../libmpathcmd/mpath_fill_sockaddr.c"
|
||||
+
|
||||
/*
|
||||
* create a unix domain socket and start listening on it
|
||||
* return a file descriptor open on the socket
|
||||
@@ -63,15 +68,7 @@ int ux_socket_listen(const char *name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
- memset(&addr, 0, sizeof(addr));
|
||||
- addr.sun_family = AF_LOCAL;
|
||||
- addr.sun_path[0] = '\0';
|
||||
- len = strlen(name) + 1;
|
||||
- if (len >= sizeof(addr.sun_path))
|
||||
- len = sizeof(addr.sun_path) - 1;
|
||||
- memcpy(&addr.sun_path[1], name, len);
|
||||
-
|
||||
- len += sizeof(sa_family_t);
|
||||
+ len = mpath_fill_sockaddr__(&addr, name);
|
||||
if (bind(fd, (struct sockaddr *)&addr, len) == -1) {
|
||||
condlog(3, "Couldn't bind to ux_socket, error %d", errno);
|
||||
close(fd);
|
||||
diff --git a/multipathd/Makefile b/multipathd/Makefile
|
||||
index 997b40cf..61cf1af6 100644
|
||||
--- a/multipathd/Makefile
|
||||
+++ b/multipathd/Makefile
|
||||
@@ -41,7 +41,7 @@ ifeq ($(FPIN_SUPPORT),1)
|
||||
OBJS += fpin_handlers.o
|
||||
endif
|
||||
|
||||
-all : $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service
|
||||
+all : $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service $(EXEC).socket
|
||||
|
||||
$(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
|
||||
@echo building $@ because of $?
|
||||
@@ -78,7 +78,7 @@ uninstall:
|
||||
$(Q)$(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket
|
||||
|
||||
clean: dep_clean
|
||||
- $(Q)$(RM) core *.o $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service
|
||||
+ $(Q)$(RM) core *.o $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service $(EXEC).socket
|
||||
|
||||
include $(wildcard $(OBJS:.o=.d) $(CLI_OBJS:.o=.d))
|
||||
|
||||
diff --git a/multipathd/multipathd.socket b/multipathd/multipathd.socket.in
|
||||
similarity index 88%
|
||||
rename from multipathd/multipathd.socket
|
||||
rename to multipathd/multipathd.socket.in
|
||||
index 263b6b0c..4ed9c1ff 100644
|
||||
--- a/multipathd/multipathd.socket
|
||||
+++ b/multipathd/multipathd.socket.in
|
||||
@@ -8,7 +8,7 @@ ConditionVirtualization=!container
|
||||
Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
-ListenStream=@/org/kernel/linux/storage/multipathd
|
||||
+ListenStream=@MPATH_SOCKET@
|
||||
|
||||
[Install]
|
||||
# Socket activation for multipathd is disabled by default.
|
@ -0,0 +1,49 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Fri, 14 Feb 2025 22:00:24 +0100
|
||||
Subject: [PATCH] libmpathutil: add support for Unix pathname sockets
|
||||
|
||||
Pathname sockets need to be world read/writable in order to allow regular
|
||||
users to read information from multipathd. Our SO_PEERCRED permission check
|
||||
will make sure that they can't make configuration changes. Also, SO_REUSEADDR
|
||||
doesn't work for pathname sockets as it does for abstract Unix sockets. A
|
||||
possibly pre-existing socket file must be removed before trying to recreate it.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathutil/uxsock.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/libmpathutil/uxsock.c b/libmpathutil/uxsock.c
|
||||
index 12c46084..889d7a17 100644
|
||||
--- a/libmpathutil/uxsock.c
|
||||
+++ b/libmpathutil/uxsock.c
|
||||
@@ -62,6 +62,11 @@ int ux_socket_listen(const char *name)
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
+
|
||||
+ /* This is after the PID check, so unlinking should be fine */
|
||||
+ if (name[0] != '@' && unlink(name) == -1 && errno != ENOENT)
|
||||
+ condlog(1, "Failed to unlink %s", name);
|
||||
+
|
||||
fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
condlog(3, "Couldn't create ux_socket, error %d", errno);
|
||||
@@ -75,6 +80,14 @@ int ux_socket_listen(const char *name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * Socket needs to have rw permissions for everone.
|
||||
+ * SO_PEERCRED makes sure that only root can modify things.
|
||||
+ */
|
||||
+ if (name[0] != '@' &&
|
||||
+ chmod(name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) == -1)
|
||||
+ condlog(3, "failed to set permissions on %s: %s", name, strerror(errno));
|
||||
+
|
||||
if (listen(fd, 10) == -1) {
|
||||
condlog(3, "Couldn't listen to ux_socket, error %d", errno);
|
||||
close(fd);
|
@ -0,0 +1,91 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Wed, 12 Feb 2025 19:12:35 +0100
|
||||
Subject: [PATCH] libmpathutil: move systemd_listen_fds() support into
|
||||
multipathd
|
||||
|
||||
This feature is only used by multipathd.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathutil/uxsock.c | 15 ---------------
|
||||
multipathd/main.c | 28 +++++++++++++++++++++++++++-
|
||||
2 files changed, 27 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/libmpathutil/uxsock.c b/libmpathutil/uxsock.c
|
||||
index 889d7a17..59c47170 100644
|
||||
--- a/libmpathutil/uxsock.c
|
||||
+++ b/libmpathutil/uxsock.c
|
||||
@@ -46,23 +46,8 @@ int ux_socket_listen(const char *name)
|
||||
{
|
||||
int fd;
|
||||
size_t len;
|
||||
-#ifdef USE_SYSTEMD
|
||||
- int num;
|
||||
-#endif
|
||||
struct sockaddr_un addr;
|
||||
|
||||
-#ifdef USE_SYSTEMD
|
||||
- num = sd_listen_fds(0);
|
||||
- if (num > 1) {
|
||||
- condlog(3, "sd_listen_fds returned %d fds", num);
|
||||
- return -1;
|
||||
- } else if (num == 1) {
|
||||
- fd = SD_LISTEN_FDS_START + 0;
|
||||
- condlog(3, "using fd %d from sd_listen_fds", fd);
|
||||
- return fd;
|
||||
- }
|
||||
-#endif
|
||||
-
|
||||
/* This is after the PID check, so unlinking should be fine */
|
||||
if (name[0] != '@' && unlink(name) == -1 && errno != ENOENT)
|
||||
condlog(1, "Failed to unlink %s", name);
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 58afe14a..24048408 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -1859,15 +1859,41 @@ uevqloop (void * ap)
|
||||
pthread_cleanup_pop(1);
|
||||
return NULL;
|
||||
}
|
||||
+
|
||||
+#ifdef USE_SYSTEMD
|
||||
+static int get_systemd_sockets(long *ux_sock)
|
||||
+{
|
||||
+ int num = sd_listen_fds(0);
|
||||
+
|
||||
+ if (num > 1) {
|
||||
+ condlog(3, "sd_listen_fds returned %d fds", num);
|
||||
+ return -1;
|
||||
+ } else if (num == 1) {
|
||||
+ ux_sock[0] = SD_LISTEN_FDS_START + 0;
|
||||
+ condlog(3, "using fd %ld from sd_listen_fds", ux_sock[0]);
|
||||
+ }
|
||||
+ return num;
|
||||
+}
|
||||
+#else
|
||||
+static int get_systemd_sockets(long *ux_sock __attribute__((unused)))
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
static void *
|
||||
uxlsnrloop (void * ap)
|
||||
{
|
||||
long ux_sock;
|
||||
+ int num;
|
||||
|
||||
pthread_cleanup_push(rcu_unregister, NULL);
|
||||
rcu_register_thread();
|
||||
|
||||
- ux_sock = ux_socket_listen(DEFAULT_SOCKET);
|
||||
+ num = get_systemd_sockets(&ux_sock);
|
||||
+ if (num < 1)
|
||||
+ ux_sock = ux_socket_listen(DEFAULT_SOCKET);
|
||||
if (ux_sock == -1) {
|
||||
condlog(1, "could not create uxsock: %d", errno);
|
||||
exit_daemon();
|
@ -0,0 +1,85 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Wed, 12 Feb 2025 20:08:28 +0100
|
||||
Subject: [PATCH] multipathd: make uxsock_listen() take a pointer to fd
|
||||
|
||||
This prepares being able to pass multiple socket fds.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/main.c | 2 +-
|
||||
multipathd/uxlsnr.c | 11 ++++++++---
|
||||
multipathd/uxlsnr.h | 3 +--
|
||||
3 files changed, 10 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 24048408..9f15d2f7 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -1920,7 +1920,7 @@ uxlsnrloop (void * ap)
|
||||
== DAEMON_CONFIGURE)
|
||||
handle_signals(false);
|
||||
|
||||
- uxsock_listen(ux_sock, ap);
|
||||
+ uxsock_listen(1, &ux_sock, ap);
|
||||
|
||||
out_sock:
|
||||
pthread_cleanup_pop(1); /* uxsock_cleanup */
|
||||
diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c
|
||||
index 185e0a0a..51b5e51d 100644
|
||||
--- a/multipathd/uxlsnr.c
|
||||
+++ b/multipathd/uxlsnr.c
|
||||
@@ -614,7 +614,7 @@ static void handle_client(struct client *c, struct vectors *vecs, short revents)
|
||||
/*
|
||||
* entry point
|
||||
*/
|
||||
-void *uxsock_listen(long ux_sock, void *trigger_data)
|
||||
+void *uxsock_listen(int n_socks, long *ux_sock, void *trigger_data)
|
||||
{
|
||||
sigset_t mask;
|
||||
int max_pfds = MIN_POLLS + POLLFDS_BASE;
|
||||
@@ -623,6 +623,11 @@ void *uxsock_listen(long ux_sock, void *trigger_data)
|
||||
struct watch_descriptors wds = { .conf_wd = -1, .dir_wd = -1, .mp_wd = -1, };
|
||||
struct vectors *vecs = trigger_data;
|
||||
|
||||
+ if (n_socks != 1) {
|
||||
+ condlog(0, "uxsock: no socket fds");
|
||||
+ exit_daemon();
|
||||
+ return NULL;
|
||||
+ }
|
||||
condlog(3, "uxsock: startup listener");
|
||||
polls = calloc(1, max_pfds * sizeof(*polls));
|
||||
if (!polls) {
|
||||
@@ -673,7 +678,7 @@ void *uxsock_listen(long ux_sock, void *trigger_data)
|
||||
}
|
||||
}
|
||||
if (num_clients < MAX_CLIENTS) {
|
||||
- polls[POLLFD_UX].fd = ux_sock;
|
||||
+ polls[POLLFD_UX].fd = ux_sock[0];
|
||||
polls[POLLFD_UX].events = POLLIN;
|
||||
} else {
|
||||
/*
|
||||
@@ -767,7 +772,7 @@ void *uxsock_listen(long ux_sock, void *trigger_data)
|
||||
|
||||
/* see if we got a new client */
|
||||
if (polls[POLLFD_UX].revents & POLLIN) {
|
||||
- new_client(ux_sock);
|
||||
+ new_client(ux_sock[0]);
|
||||
}
|
||||
|
||||
/* handle inotify events on config files */
|
||||
diff --git a/multipathd/uxlsnr.h b/multipathd/uxlsnr.h
|
||||
index 3e45930b..f07b1f8b 100644
|
||||
--- a/multipathd/uxlsnr.h
|
||||
+++ b/multipathd/uxlsnr.h
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
bool waiting_clients(void);
|
||||
void uxsock_cleanup(void *arg);
|
||||
-void *uxsock_listen(long ux_sock,
|
||||
- void * trigger_data);
|
||||
+void *uxsock_listen(int n_socks, long *ux_sock, void *trigger_data);
|
||||
|
||||
#endif
|
194
0023-multipathd-allow-receiving-two-socket-fds-from-syste.patch
Normal file
194
0023-multipathd-allow-receiving-two-socket-fds-from-syste.patch
Normal file
@ -0,0 +1,194 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Wed, 12 Feb 2025 20:27:18 +0100
|
||||
Subject: [PATCH] multipathd: allow receiving two socket fds from systemd
|
||||
|
||||
Add another ListenStream directive in multipathd.socket for a Unix pathname
|
||||
socket. In multipathd, read both socket fds from systemd, and open both
|
||||
when they are defined.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile.inc | 3 ++-
|
||||
multipathd/main.c | 18 ++++++++++++------
|
||||
multipathd/multipathd.socket.in | 3 ++-
|
||||
multipathd/uxlsnr.c | 33 ++++++++++++++++++++++-----------
|
||||
4 files changed, 38 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/Makefile.inc b/Makefile.inc
|
||||
index 1ef3f7f8..07c0ae80 100644
|
||||
--- a/Makefile.inc
|
||||
+++ b/Makefile.inc
|
||||
@@ -76,6 +76,7 @@ libudev_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir libudev),/usr
|
||||
kernel_incdir := /usr/include
|
||||
|
||||
abstract_socket := @/org/kernel/linux/storage/multipathd
|
||||
+pathname_socket := /run/multipathd.socket
|
||||
|
||||
ifeq ($(V),)
|
||||
Q := @
|
||||
@@ -166,4 +167,4 @@ NV_VERSION_SCRIPT = $(DEVLIB:%.so=%-nv.version)
|
||||
|
||||
%: %.in
|
||||
@echo creating $@
|
||||
- $(Q)sed 's:@CONFIGFILE@:'$(TGTDIR)$(configfile)':g;s:@CONFIGDIR@:'$(TGTDIR)$(configdir)':g;s:@STATE_DIR@:'$(TGTDIR)$(statedir)':g;s:@RUNTIME_DIR@:'$(runtimedir)':g;s/@MODPROBE_UNIT@/'$(MODPROBE_UNIT)'/g;s:@BINDIR@:'$(bindir)':g;s,@MPATH_SOCKET@,'$(abstract_socket)',g' $< >$@
|
||||
+ $(Q)sed 's:@CONFIGFILE@:'$(TGTDIR)$(configfile)':g;s:@CONFIGDIR@:'$(TGTDIR)$(configdir)':g;s:@STATE_DIR@:'$(TGTDIR)$(statedir)':g;s:@RUNTIME_DIR@:'$(runtimedir)':g;s/@MODPROBE_UNIT@/'$(MODPROBE_UNIT)'/g;s:@BINDIR@:'$(bindir)':g;s,@ABSTRACT_SOCKET@,'$(abstract_socket)',g;s,@PATHNAME_SOCKET@,'$(pathname_socket)',g' $< >$@
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 9f15d2f7..2fef0c64 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -1865,9 +1865,13 @@ static int get_systemd_sockets(long *ux_sock)
|
||||
{
|
||||
int num = sd_listen_fds(0);
|
||||
|
||||
- if (num > 1) {
|
||||
+ if (num > 2) {
|
||||
condlog(3, "sd_listen_fds returned %d fds", num);
|
||||
return -1;
|
||||
+ } else if (num == 2) {
|
||||
+ ux_sock[0] = SD_LISTEN_FDS_START + 0;
|
||||
+ ux_sock[1] = SD_LISTEN_FDS_START + 1;
|
||||
+ condlog(3, "using fd %ld and %ld from sd_listen_fds", ux_sock[0], ux_sock[1]);
|
||||
} else if (num == 1) {
|
||||
ux_sock[0] = SD_LISTEN_FDS_START + 0;
|
||||
condlog(3, "using fd %ld from sd_listen_fds", ux_sock[0]);
|
||||
@@ -1885,16 +1889,18 @@ static int get_systemd_sockets(long *ux_sock __attribute__((unused)))
|
||||
static void *
|
||||
uxlsnrloop (void * ap)
|
||||
{
|
||||
- long ux_sock;
|
||||
+ long ux_sock[2] = {-1, -1};
|
||||
int num;
|
||||
|
||||
pthread_cleanup_push(rcu_unregister, NULL);
|
||||
rcu_register_thread();
|
||||
|
||||
num = get_systemd_sockets(&ux_sock);
|
||||
- if (num < 1)
|
||||
- ux_sock = ux_socket_listen(DEFAULT_SOCKET);
|
||||
- if (ux_sock == -1) {
|
||||
+ if (num < 1) {
|
||||
+ ux_sock[0] = ux_socket_listen(DEFAULT_SOCKET);
|
||||
+ num = 1;
|
||||
+ }
|
||||
+ if (ux_sock[0] == -1) {
|
||||
condlog(1, "could not create uxsock: %d", errno);
|
||||
exit_daemon();
|
||||
goto out;
|
||||
@@ -1920,7 +1926,7 @@ uxlsnrloop (void * ap)
|
||||
== DAEMON_CONFIGURE)
|
||||
handle_signals(false);
|
||||
|
||||
- uxsock_listen(1, &ux_sock, ap);
|
||||
+ uxsock_listen(num, ux_sock, ap);
|
||||
|
||||
out_sock:
|
||||
pthread_cleanup_pop(1); /* uxsock_cleanup */
|
||||
diff --git a/multipathd/multipathd.socket.in b/multipathd/multipathd.socket.in
|
||||
index 4ed9c1ff..5ed24757 100644
|
||||
--- a/multipathd/multipathd.socket.in
|
||||
+++ b/multipathd/multipathd.socket.in
|
||||
@@ -8,7 +8,8 @@ ConditionVirtualization=!container
|
||||
Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
-ListenStream=@MPATH_SOCKET@
|
||||
+ListenStream=@ABSTRACT_SOCKET@
|
||||
+ListenStream=@PATHNAME_SOCKET@
|
||||
|
||||
[Install]
|
||||
# Socket activation for multipathd is disabled by default.
|
||||
diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c
|
||||
index 51b5e51d..bbf891ba 100644
|
||||
--- a/multipathd/uxlsnr.c
|
||||
+++ b/multipathd/uxlsnr.c
|
||||
@@ -69,7 +69,8 @@ struct client {
|
||||
|
||||
/* Indices for array of poll fds */
|
||||
enum {
|
||||
- POLLFD_UX = 0,
|
||||
+ POLLFD_UX1 = 0,
|
||||
+ POLLFD_UX2,
|
||||
POLLFD_NOTIFY,
|
||||
POLLFD_IDLE,
|
||||
POLLFDS_BASE,
|
||||
@@ -164,9 +165,10 @@ void uxsock_cleanup(void *arg)
|
||||
{
|
||||
struct client *client_loop;
|
||||
struct client *client_tmp;
|
||||
- long ux_sock = (long)arg;
|
||||
+ long *ux_sock = (long *)arg;
|
||||
|
||||
- close(ux_sock);
|
||||
+ close(ux_sock[0]);
|
||||
+ close(ux_sock[1]);
|
||||
close(notify_fd);
|
||||
|
||||
list_for_each_entry_safe(client_loop, client_tmp, &clients, node) {
|
||||
@@ -614,20 +616,24 @@ static void handle_client(struct client *c, struct vectors *vecs, short revents)
|
||||
/*
|
||||
* entry point
|
||||
*/
|
||||
-void *uxsock_listen(int n_socks, long *ux_sock, void *trigger_data)
|
||||
+void *uxsock_listen(int n_socks, long *ux_sock_in, void *trigger_data)
|
||||
{
|
||||
sigset_t mask;
|
||||
int max_pfds = MIN_POLLS + POLLFDS_BASE;
|
||||
+ long ux_sock[2] = {-1, -1};
|
||||
/* conf->sequence_nr will be 1 when uxsock_listen is first called */
|
||||
unsigned int sequence_nr = 0;
|
||||
struct watch_descriptors wds = { .conf_wd = -1, .dir_wd = -1, .mp_wd = -1, };
|
||||
struct vectors *vecs = trigger_data;
|
||||
|
||||
- if (n_socks != 1) {
|
||||
- condlog(0, "uxsock: no socket fds");
|
||||
+ if (n_socks < 1 || n_socks > 2) {
|
||||
+ condlog(0, "uxsock: unsupported number of socket fds");
|
||||
exit_daemon();
|
||||
return NULL;
|
||||
- }
|
||||
+ } else if (n_socks == 2)
|
||||
+ ux_sock[1] = ux_sock_in[1];
|
||||
+ ux_sock[0] = ux_sock_in[0];
|
||||
+
|
||||
condlog(3, "uxsock: startup listener");
|
||||
polls = calloc(1, max_pfds * sizeof(*polls));
|
||||
if (!polls) {
|
||||
@@ -678,8 +684,10 @@ void *uxsock_listen(int n_socks, long *ux_sock, void *trigger_data)
|
||||
}
|
||||
}
|
||||
if (num_clients < MAX_CLIENTS) {
|
||||
- polls[POLLFD_UX].fd = ux_sock[0];
|
||||
- polls[POLLFD_UX].events = POLLIN;
|
||||
+ polls[POLLFD_UX1].fd = ux_sock[0];
|
||||
+ polls[POLLFD_UX1].events = POLLIN;
|
||||
+ polls[POLLFD_UX2].fd = ux_sock[1];
|
||||
+ polls[POLLFD_UX2].events = POLLIN;
|
||||
} else {
|
||||
/*
|
||||
* New clients can't connect, num_clients won't grow
|
||||
@@ -687,7 +695,7 @@ void *uxsock_listen(int n_socks, long *ux_sock, void *trigger_data)
|
||||
*/
|
||||
condlog(1, "%s: max client connections reached, pausing polling",
|
||||
__func__);
|
||||
- polls[POLLFD_UX].fd = -1;
|
||||
+ polls[POLLFD_UX1].fd = polls[POLLFD_UX2].fd = -1;
|
||||
}
|
||||
|
||||
reset_watch(notify_fd, &wds, &sequence_nr);
|
||||
@@ -771,9 +779,12 @@ void *uxsock_listen(int n_socks, long *ux_sock, void *trigger_data)
|
||||
handle_signals(true);
|
||||
|
||||
/* see if we got a new client */
|
||||
- if (polls[POLLFD_UX].revents & POLLIN) {
|
||||
+ if (polls[POLLFD_UX1].revents & POLLIN) {
|
||||
new_client(ux_sock[0]);
|
||||
}
|
||||
+ if (polls[POLLFD_UX2].revents & POLLIN) {
|
||||
+ new_client(ux_sock[1]);
|
||||
+ }
|
||||
|
||||
/* handle inotify events on config files */
|
||||
if (polls[POLLFD_NOTIFY].revents & POLLIN)
|
@ -0,0 +1,67 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Wed, 12 Feb 2025 20:35:36 +0100
|
||||
Subject: [PATCH] multipathd: listen on pathname and abstract socket by default
|
||||
|
||||
Pass both ABSTRACT_SOCKET and PATHNAME_SOCKET to the compiler at
|
||||
build time, and listen on both sockets by default.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile.inc | 2 +-
|
||||
libmpathcmd/mpath_cmd.c | 2 +-
|
||||
multipathd/main.c | 11 ++++++-----
|
||||
3 files changed, 8 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/Makefile.inc b/Makefile.inc
|
||||
index 07c0ae80..69a0d64c 100644
|
||||
--- a/Makefile.inc
|
||||
+++ b/Makefile.inc
|
||||
@@ -120,7 +120,7 @@ CPPFLAGS := $(CPPFLAGS) $(D_URCU_VERSION) \
|
||||
-DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(TGTDIR)$(configdir)\" \
|
||||
-DDEFAULT_CONFIGFILE=\"$(TGTDIR)$(configfile)\" -DSTATE_DIR=\"$(TGTDIR)$(statedir)\" \
|
||||
-DEXTRAVERSION=\"$(EXTRAVERSION)\" \
|
||||
- -DDEFAULT_SOCKET=\"$(abstract_socket)\" \
|
||||
+ -DABSTRACT_SOCKET=\"$(abstract_socket)\" -DPATHNAME_SOCKET=\"$(pathname_socket)\" \
|
||||
-DWSTRINGOP_TRUNCATION=$(if $(WSTRINGOP_TRUNCATION),1,0) \
|
||||
-MMD -MP
|
||||
CFLAGS := -std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe
|
||||
diff --git a/libmpathcmd/mpath_cmd.c b/libmpathcmd/mpath_cmd.c
|
||||
index 146e790d..54143fb1 100644
|
||||
--- a/libmpathcmd/mpath_cmd.c
|
||||
+++ b/libmpathcmd/mpath_cmd.c
|
||||
@@ -113,7 +113,7 @@ int __mpath_connect(int nonblocking)
|
||||
(void)fcntl(fd, F_SETFL, flags|O_NONBLOCK);
|
||||
}
|
||||
|
||||
- len = mpath_fill_sockaddr__(&addr, DEFAULT_SOCKET);
|
||||
+ len = mpath_fill_sockaddr__(&addr, ABSTRACT_SOCKET);
|
||||
if (connect(fd, (struct sockaddr *)&addr, len) == -1) {
|
||||
int err = errno;
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 2fef0c64..bdbcea49 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -1895,13 +1895,14 @@ uxlsnrloop (void * ap)
|
||||
pthread_cleanup_push(rcu_unregister, NULL);
|
||||
rcu_register_thread();
|
||||
|
||||
- num = get_systemd_sockets(&ux_sock);
|
||||
+ num = get_systemd_sockets(ux_sock);
|
||||
if (num < 1) {
|
||||
- ux_sock[0] = ux_socket_listen(DEFAULT_SOCKET);
|
||||
- num = 1;
|
||||
+ ux_sock[0] = ux_socket_listen(ABSTRACT_SOCKET);
|
||||
+ ux_sock[1] = ux_socket_listen(PATHNAME_SOCKET);
|
||||
+ num = 2;
|
||||
}
|
||||
- if (ux_sock[0] == -1) {
|
||||
- condlog(1, "could not create uxsock: %d", errno);
|
||||
+ if (ux_sock[0] == -1 && ux_sock[1] == -1) {
|
||||
+ condlog(1, "could not create sockets: %d", errno);
|
||||
exit_daemon();
|
||||
goto out;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Wed, 12 Feb 2025 20:45:11 +0100
|
||||
Subject: [PATCH] libmpathcmd: try both abstract and pathname sockets
|
||||
|
||||
When connecting to the multipathd socket, try the pathname socket
|
||||
first, then the abstract socket. Fail only if both connection attempts
|
||||
fail.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathcmd/mpath_cmd.c | 13 ++++++++++---
|
||||
1 file changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libmpathcmd/mpath_cmd.c b/libmpathcmd/mpath_cmd.c
|
||||
index 54143fb1..267e3dd7 100644
|
||||
--- a/libmpathcmd/mpath_cmd.c
|
||||
+++ b/libmpathcmd/mpath_cmd.c
|
||||
@@ -102,7 +102,10 @@ int __mpath_connect(int nonblocking)
|
||||
size_t len;
|
||||
struct sockaddr_un addr;
|
||||
int flags = 0;
|
||||
+ const char *const names[2] = {PATHNAME_SOCKET, ABSTRACT_SOCKET};
|
||||
+ int name_idx = 0;
|
||||
|
||||
+retry:
|
||||
fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
@@ -113,13 +116,17 @@ int __mpath_connect(int nonblocking)
|
||||
(void)fcntl(fd, F_SETFL, flags|O_NONBLOCK);
|
||||
}
|
||||
|
||||
- len = mpath_fill_sockaddr__(&addr, ABSTRACT_SOCKET);
|
||||
+ len = mpath_fill_sockaddr__(&addr, names[name_idx]);
|
||||
if (connect(fd, (struct sockaddr *)&addr, len) == -1) {
|
||||
int err = errno;
|
||||
|
||||
close(fd);
|
||||
- errno = err;
|
||||
- return -1;
|
||||
+ if (++name_idx == 1)
|
||||
+ goto retry;
|
||||
+ else {
|
||||
+ errno = err;
|
||||
+ return -1;
|
||||
+ }
|
||||
}
|
||||
|
||||
if (nonblocking && flags != -1)
|
@ -0,0 +1,53 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Wed, 12 Feb 2025 21:17:41 +0100
|
||||
Subject: [PATCH] libmpathcmd: honor MULTIPATH_SOCKET_NAME environment variable
|
||||
|
||||
In systemd installments, users can already override the socket names
|
||||
that systemd listens on. With this patch, clients using libmpathcmd
|
||||
can be customized to use a non-standard socket by setting an environment
|
||||
variable.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathcmd/mpath_cmd.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libmpathcmd/mpath_cmd.c b/libmpathcmd/mpath_cmd.c
|
||||
index 267e3dd7..7f805abb 100644
|
||||
--- a/libmpathcmd/mpath_cmd.c
|
||||
+++ b/libmpathcmd/mpath_cmd.c
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@@ -104,6 +105,7 @@ int __mpath_connect(int nonblocking)
|
||||
int flags = 0;
|
||||
const char *const names[2] = {PATHNAME_SOCKET, ABSTRACT_SOCKET};
|
||||
int name_idx = 0;
|
||||
+ const char *env_name = getenv("MULTIPATH_SOCKET_NAME"), *name;
|
||||
|
||||
retry:
|
||||
fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||
@@ -116,12 +118,13 @@ retry:
|
||||
(void)fcntl(fd, F_SETFL, flags|O_NONBLOCK);
|
||||
}
|
||||
|
||||
- len = mpath_fill_sockaddr__(&addr, names[name_idx]);
|
||||
+ name = env_name ? env_name : names[name_idx];
|
||||
+ len = mpath_fill_sockaddr__(&addr, name);
|
||||
if (connect(fd, (struct sockaddr *)&addr, len) == -1) {
|
||||
int err = errno;
|
||||
|
||||
close(fd);
|
||||
- if (++name_idx == 1)
|
||||
+ if (name != env_name && ++name_idx == 1)
|
||||
goto retry;
|
||||
else {
|
||||
errno = err;
|
@ -0,0 +1,43 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Fri, 14 Feb 2025 22:18:06 +0100
|
||||
Subject: [PATCH] multipathd: honor MULTIPATH_SOCKET_NAME environment variable
|
||||
|
||||
If multipathd is started via socket activation, it will obtain
|
||||
sockets from systemd. The names of these sockets, and whether
|
||||
the abstract and / or pathname socket is created, is configurable
|
||||
in the systemd unit file.
|
||||
|
||||
Add support for passing a socket name via the environment, so that
|
||||
it's possible to configure the socket name at runtime even without
|
||||
socket activation. In this case, only this single socket will be created.
|
||||
If creating the socket fails, multipathd startup will fail, too.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/main.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index bdbcea49..0fa4a404 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -1891,11 +1891,16 @@ uxlsnrloop (void * ap)
|
||||
{
|
||||
long ux_sock[2] = {-1, -1};
|
||||
int num;
|
||||
+ const char *env_name = getenv("MULTIPATH_SOCKET_NAME");
|
||||
|
||||
pthread_cleanup_push(rcu_unregister, NULL);
|
||||
rcu_register_thread();
|
||||
|
||||
num = get_systemd_sockets(ux_sock);
|
||||
+ if (num < 1 && env_name != NULL) {
|
||||
+ ux_sock[0] = ux_socket_listen(env_name);
|
||||
+ num = 1;
|
||||
+ }
|
||||
if (num < 1) {
|
||||
ux_sock[0] = ux_socket_listen(ABSTRACT_SOCKET);
|
||||
ux_sock[1] = ux_socket_listen(PATHNAME_SOCKET);
|
25
0028-multipath-clean-up-find_multipaths-documentation.patch
Normal file
25
0028-multipath-clean-up-find_multipaths-documentation.patch
Normal file
@ -0,0 +1,25 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 6 Mar 2025 16:56:34 -0500
|
||||
Subject: [PATCH] multipath: clean up find_multipaths documentation
|
||||
|
||||
The preferred term is "on" instead of "yes".
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipath/multipath.conf.5.in | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/multipath/multipath.conf.5.in b/multipath/multipath.conf.5.in
|
||||
index a7543939..31740a1f 100644
|
||||
--- a/multipath/multipath.conf.5.in
|
||||
+++ b/multipath/multipath.conf.5.in
|
||||
@@ -1213,7 +1213,7 @@ Both multipathd and multipath treat every non-blacklisted device as multipath
|
||||
device path.
|
||||
.TP
|
||||
.I smart
|
||||
-This differs from \fIfind_multipaths yes\fR only in
|
||||
+This differs from \fIfind_multipaths on\fR only in
|
||||
the way it treats new devices for which only one path has been
|
||||
detected yet. When such a device is first encountered in udev rules, it is
|
||||
treated as a multipath device. multipathd waits whether additional paths with
|
@ -0,0 +1,63 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 6 Mar 2025 18:52:02 -0500
|
||||
Subject: [PATCH] multipathd: Add multipathd man page section about sockets
|
||||
|
||||
Add a section with information about how to communicate with the
|
||||
multipathd daemon to the man page. Also mention that multipathd
|
||||
CLI commands can be run without the -k option.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/multipathd.8.in | 31 +++++++++++++++++++++++++++++++
|
||||
1 file changed, 31 insertions(+)
|
||||
|
||||
diff --git a/multipathd/multipathd.8.in b/multipathd/multipathd.8.in
|
||||
index 315884eb..5b1aeb42 100644
|
||||
--- a/multipathd/multipathd.8.in
|
||||
+++ b/multipathd/multipathd.8.in
|
||||
@@ -83,6 +83,11 @@ multipathd executes the given command (see \fBCOMMANDS\fR below). If the
|
||||
command contains whitespace or shell special characters, it needs to be quoted
|
||||
like in \fImultipathd -k'show topology'\fR. No whitespace is allowed between
|
||||
the \fB-k\fR and the command string.
|
||||
+
|
||||
+Commands can also be issued without using \fB-k\fR. In this case, the command
|
||||
+string should not be quoted. Command arguments that contain whitespace or
|
||||
+special characters still need to be quoted, like in \fImultipathd show paths
|
||||
+format "%n %w"\fR
|
||||
.
|
||||
.TP
|
||||
.B \-k
|
||||
@@ -103,6 +108,32 @@ multipath devices on dmevents. Use this flag to force it to use the old event
|
||||
waiting method, based on creating a separate thread for each device.
|
||||
.
|
||||
.
|
||||
+.\" ----------------------------------------------------------------------------
|
||||
+.SH COMMUNICATING WITH MULTIPATHD
|
||||
+.\" ----------------------------------------------------------------------------
|
||||
+
|
||||
+In addition to the multipathd CLI, the \fBlibmpathcmd\fR library can be used to
|
||||
+send commands (see \fBCOMMANDS\fR below) to the multipathd daemon from other
|
||||
+programs. By default, multipathd listens on both the \fI@ABSTRACT_SOCKET@\fR
|
||||
+abstract namespace socket and the \fI@PATHNAME_SOCKET@\fR socket file.
|
||||
+libmpathcmd will use either of these sockets to connect to multipathd. The
|
||||
+socket file can be useful to communicate with multipathd from different
|
||||
+namespaces since it can be bind mounted in them, unlike the abstract namespace
|
||||
+socket. Multipathd will accept \fBlist|show\fR commands from any user. All
|
||||
+other commands must be issued by root.
|
||||
+
|
||||
+It is possible to change the sockets that multipathd listens on. If
|
||||
+\fImultipathd.socket\fR is running, multipathd will use the sockets it listens
|
||||
+on. A maximum of two sockets can be defined by \fImultipathd.socket\fR, and by
|
||||
+default it listens on \fI@ABSTRACT_SOCKET@\fR and \fI@PATHNAME_SOCKET@\fR. If
|
||||
+\fImultipathd.socket\fR is not running, a single socket can be configured for
|
||||
+listening on by setting the \fIMULTIPATH_SOCKET_NAME\fR environment variable
|
||||
+when starting multipathd. This environment variable must also be set to make
|
||||
+multipathd CLI commands (or any other program using libmpathcmd) connect to the
|
||||
+multipathd daemon using a non-default socket, regardless of whether that socket
|
||||
+was set for the daemon using \fImultipathd.socket\fR or the
|
||||
+\fIMULTIPATH_SOCKET_NAME\fR environment variable.
|
||||
+.
|
||||
.
|
||||
.\" ----------------------------------------------------------------------------
|
||||
.SH COMMANDS
|
@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 2 Apr 2025 19:13:19 -0400
|
||||
Subject: [PATCH] multipathd: monitor new multipath dev even if we can't update
|
||||
it
|
||||
|
||||
If a multipath device was created by the multipath command, multipathd
|
||||
might not agree with how the device was created. ev_add_map() can reload
|
||||
the device with a different table by calling add_map_without_path() ->
|
||||
update_map(). If this reloading of the map failed, multipathd was simply
|
||||
ignoring the multipath device, even though it still existed.
|
||||
|
||||
One way that reloading can fail is if a path that multipathd already has
|
||||
initialized goes offline. If a multipath device is created by the
|
||||
multipath command while the path is offline, it will not use the offline
|
||||
path, since multipath won't be able to get the necessary pathinfo.
|
||||
However, multipathd will already have the pathinfo for the path, and may
|
||||
not even know that it's offline, since the path is an orphan. When it
|
||||
tries to reload the device, it will include the offline path, and the
|
||||
reload will fail.
|
||||
|
||||
Instead of ignoring the device if it can't reload it, multipathd should
|
||||
just montior it as it is. When the path device is no longer offline, it
|
||||
can be added back to the multipath device by calling
|
||||
"multipathd reconfigure" or "multipathd add path <path>".
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
multipathd/main.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 0fa4a404..8ce36a3c 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -686,7 +686,7 @@ retry:
|
||||
}
|
||||
|
||||
fail:
|
||||
- if (new_map && (retries < 0 || wait_for_events(mpp, vecs))) {
|
||||
+ if (new_map && wait_for_events(mpp, vecs)) {
|
||||
condlog(0, "%s: failed to create new map", mpp->alias);
|
||||
remove_map(mpp, vecs->pathvec, vecs->mpvec);
|
||||
return 1;
|
@ -0,0 +1,74 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 2 Apr 2025 19:13:20 -0400
|
||||
Subject: [PATCH] libmultipath: add helper function check_path_wwid_change
|
||||
|
||||
Wrap some code from select_recheck_wwid() in a helper function. A future
|
||||
patch will call this code from a different function.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmultipath/discovery.c | 12 +++++++++++-
|
||||
libmultipath/discovery.h | 2 +-
|
||||
libmultipath/propsel.c | 4 +---
|
||||
3 files changed, 13 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
||||
index 3bcd94ce..a1284e73 100644
|
||||
--- a/libmultipath/discovery.c
|
||||
+++ b/libmultipath/discovery.c
|
||||
@@ -2244,7 +2244,7 @@ static ssize_t uid_fallback(struct path *pp, int path_state,
|
||||
return len;
|
||||
}
|
||||
|
||||
-bool has_uid_fallback(struct path *pp)
|
||||
+static bool has_uid_fallback(const struct path *pp)
|
||||
{
|
||||
/*
|
||||
* Falling back to direct WWID determination is dangerous
|
||||
@@ -2265,6 +2265,16 @@ bool has_uid_fallback(struct path *pp)
|
||||
!strcmp(pp->uid_attribute, ""))));
|
||||
}
|
||||
|
||||
+bool can_recheck_wwid(const struct path *pp)
|
||||
+{
|
||||
+ /*
|
||||
+ * check_path_wwid_change() only works for scsi devices, and it
|
||||
+ * is only guaranteed to give the same WWID if the path uses
|
||||
+ * the default uid_attribute
|
||||
+ */
|
||||
+ return (pp->bus == SYSFS_BUS_SCSI && has_uid_fallback(pp));
|
||||
+}
|
||||
+
|
||||
int
|
||||
get_uid (struct path * pp, int path_state, struct udev_device *udev,
|
||||
int allow_fallback)
|
||||
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
|
||||
index acd51792..2298abac 100644
|
||||
--- a/libmultipath/discovery.h
|
||||
+++ b/libmultipath/discovery.h
|
||||
@@ -53,7 +53,7 @@ ssize_t sysfs_get_inquiry(struct udev_device *udev,
|
||||
unsigned char *buff, size_t len);
|
||||
int sysfs_get_asymmetric_access_state(struct path *pp,
|
||||
char *buff, int buflen);
|
||||
-bool has_uid_fallback(struct path *pp);
|
||||
+bool can_recheck_wwid(const struct path *pp);
|
||||
int get_uid(struct path * pp, int path_state, struct udev_device *udev,
|
||||
int allow_fallback);
|
||||
bool is_vpd_page_supported(int fd, int pg);
|
||||
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
|
||||
index e2dcb316..5ad0b78c 100644
|
||||
--- a/libmultipath/propsel.c
|
||||
+++ b/libmultipath/propsel.c
|
||||
@@ -734,9 +734,7 @@ int select_recheck_wwid(struct config *conf, struct path * pp)
|
||||
pp_set_conf(recheck_wwid);
|
||||
pp_set_default(recheck_wwid, DEFAULT_RECHECK_WWID);
|
||||
out:
|
||||
- if (pp->recheck_wwid == RECHECK_WWID_ON &&
|
||||
- (pp->bus != SYSFS_BUS_SCSI ||
|
||||
- !has_uid_fallback(pp))) {
|
||||
+ if (pp->recheck_wwid == RECHECK_WWID_ON && !can_recheck_wwid(pp)) {
|
||||
pp->recheck_wwid = RECHECK_WWID_OFF;
|
||||
origin = "(setting: unsupported by device type/config)";
|
||||
}
|
202
0032-multipathd-re-add-paths-skipped-because-they-were-of.patch
Normal file
202
0032-multipathd-re-add-paths-skipped-because-they-were-of.patch
Normal file
@ -0,0 +1,202 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 2 Apr 2025 19:13:21 -0400
|
||||
Subject: [PATCH] multipathd: re-add paths skipped because they were offline
|
||||
|
||||
When a new device is added by the multipath command, multipathd may know
|
||||
of other paths that cannot be added to the device because they are
|
||||
currently offline. Instead of ignoring these paths, multipathd will now
|
||||
re-add them when they come back online. To do this, it multipathd needs
|
||||
a new path variable add_when_online, to track devices that could not be
|
||||
added to an existing multipath device because they were offline. These
|
||||
paths are handled along with the other uninitialized paths.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmultipath/libmultipath.version | 5 +++
|
||||
libmultipath/print.c | 5 ++-
|
||||
libmultipath/structs.h | 1 +
|
||||
libmultipath/structs_vec.c | 5 +++
|
||||
multipathd/main.c | 53 ++++++++++++++++++++++++++++++-
|
||||
multipathd/multipathd.8.in | 5 +--
|
||||
6 files changed, 70 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version
|
||||
index eb511749..0b7a1a2b 100644
|
||||
--- a/libmultipath/libmultipath.version
|
||||
+++ b/libmultipath/libmultipath.version
|
||||
@@ -241,3 +241,8 @@ global:
|
||||
local:
|
||||
*;
|
||||
};
|
||||
+
|
||||
+LIBMULTIPATH_24.0.1 {
|
||||
+global:
|
||||
+ can_recheck_wwid;
|
||||
+} LIBMULTIPATH_24.0.0;
|
||||
diff --git a/libmultipath/print.c b/libmultipath/print.c
|
||||
index d592001d..fbed2dd5 100644
|
||||
--- a/libmultipath/print.c
|
||||
+++ b/libmultipath/print.c
|
||||
@@ -664,8 +664,11 @@ snprint_path_serial (struct strbuf *buff, const struct path * pp)
|
||||
static int
|
||||
snprint_path_mpp (struct strbuf *buff, const struct path * pp)
|
||||
{
|
||||
- if (!pp->mpp)
|
||||
+ if (!pp->mpp) {
|
||||
+ if (pp->add_when_online)
|
||||
+ return append_strbuf_str(buff, "[offline]");
|
||||
return append_strbuf_str(buff, "[orphan]");
|
||||
+ }
|
||||
if (!pp->mpp->alias)
|
||||
return append_strbuf_str(buff, "[unknown]");
|
||||
return snprint_str(buff, pp->mpp->alias);
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index dbaf4d43..5dc00fbc 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -396,6 +396,7 @@ struct path {
|
||||
int eh_deadline;
|
||||
bool is_checked;
|
||||
bool can_use_env_uid;
|
||||
+ bool add_when_online;
|
||||
unsigned int checker_timeout;
|
||||
/* configlet pointers */
|
||||
vector hwe;
|
||||
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
|
||||
index ccc4efc7..23e135ce 100644
|
||||
--- a/libmultipath/structs_vec.c
|
||||
+++ b/libmultipath/structs_vec.c
|
||||
@@ -374,6 +374,9 @@ static void orphan_paths(vector pathvec, struct multipath *mpp, const char *reas
|
||||
free_path(pp);
|
||||
} else
|
||||
orphan_path(pp, reason);
|
||||
+ } else if (pp->add_when_online &&
|
||||
+ strncmp(mpp->wwid, pp->wwid, WWID_SIZE) == 0) {
|
||||
+ pp->add_when_online = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -560,6 +563,8 @@ void sync_paths(struct multipath *mpp, vector pathvec)
|
||||
found = 0;
|
||||
vector_foreach_slot(mpp->pg, pgp, j) {
|
||||
if (find_slot(pgp->paths, (void *)pp) != -1) {
|
||||
+ if (pp->add_when_online)
|
||||
+ pp->add_when_online = false;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 8ce36a3c..a565ade5 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -651,11 +651,44 @@ pr_register_active_paths(struct multipath *mpp)
|
||||
}
|
||||
}
|
||||
|
||||
+static void
|
||||
+save_offline_paths(const struct multipath *mpp, vector offline_paths)
|
||||
+{
|
||||
+ unsigned int i, j;
|
||||
+ struct path *pp;
|
||||
+ struct pathgroup *pgp;
|
||||
+
|
||||
+ vector_foreach_slot (mpp->pg, pgp, i)
|
||||
+ vector_foreach_slot (pgp->paths, pp, j)
|
||||
+ if (pp->initialized == INIT_OK && pp->offline)
|
||||
+ /* ignore failures storing the paths. */
|
||||
+ store_path(offline_paths, pp);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+handle_orphaned_offline_paths(vector offline_paths)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+ struct path *pp;
|
||||
+
|
||||
+ vector_foreach_slot (offline_paths, pp, i)
|
||||
+ if (pp->mpp == NULL)
|
||||
+ pp->add_when_online = true;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+cleanup_reset_vec(struct _vector **v)
|
||||
+{
|
||||
+ vector_reset(*v);
|
||||
+}
|
||||
+
|
||||
static int
|
||||
update_map (struct multipath *mpp, struct vectors *vecs, int new_map)
|
||||
{
|
||||
int retries = 3;
|
||||
char *params __attribute__((cleanup(cleanup_charp))) = NULL;
|
||||
+ struct _vector offline_paths_vec = { .allocated = 0 };
|
||||
+ vector offline_paths __attribute__((cleanup(cleanup_reset_vec))) = &offline_paths_vec;
|
||||
|
||||
retry:
|
||||
condlog(4, "%s: updating new map", mpp->alias);
|
||||
@@ -692,6 +725,9 @@ fail:
|
||||
return 1;
|
||||
}
|
||||
|
||||
+ if (new_map && retries < 0)
|
||||
+ save_offline_paths(mpp, offline_paths);
|
||||
+
|
||||
if (setup_multipath(vecs, mpp))
|
||||
return 1;
|
||||
|
||||
@@ -702,6 +738,9 @@ fail:
|
||||
if (mpp->prflag == PRFLAG_SET)
|
||||
pr_register_active_paths(mpp);
|
||||
|
||||
+ if (VECTOR_SIZE(offline_paths) != 0)
|
||||
+ handle_orphaned_offline_paths(offline_paths);
|
||||
+
|
||||
if (retries < 0)
|
||||
condlog(0, "%s: failed reload in new map update", mpp->alias);
|
||||
return 0;
|
||||
@@ -2360,7 +2399,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
bool need_reload;
|
||||
|
||||
if (((pp->initialized == INIT_OK || pp->initialized == INIT_PARTIAL ||
|
||||
- pp->initialized == INIT_REQUESTED_UDEV) && !pp->mpp) ||
|
||||
+ pp->initialized == INIT_REQUESTED_UDEV) && !pp->mpp &&
|
||||
+ !pp->add_when_online) ||
|
||||
pp->initialized == INIT_REMOVED)
|
||||
return 0;
|
||||
|
||||
@@ -2481,6 +2521,17 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
*/
|
||||
pp->checkint = max_checkint;
|
||||
}
|
||||
+ } else if (pp->initialized == INIT_OK && pp->add_when_online &&
|
||||
+ (newstate == PATH_UP || newstate == PATH_GHOST)) {
|
||||
+ pp->add_when_online = false;
|
||||
+ if (can_recheck_wwid(pp) &&
|
||||
+ check_path_wwid_change(pp)) {
|
||||
+ condlog(0, "%s: path wwid change detected. Removing", pp->dev);
|
||||
+ handle_path_wwid_change(pp, vecs);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ ev_add_path(pp, vecs, 1);
|
||||
+ pp->tick = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
diff --git a/multipathd/multipathd.8.in b/multipathd/multipathd.8.in
|
||||
index 5b1aeb42..342e363e 100644
|
||||
--- a/multipathd/multipathd.8.in
|
||||
+++ b/multipathd/multipathd.8.in
|
||||
@@ -597,8 +597,9 @@ The device serial number.
|
||||
The device marginal state, either \fImarginal\fR or \fInormal\fR.
|
||||
.TP
|
||||
.B %m
|
||||
-The multipath device that this device is a path of, or \fI[orphan]\fR if
|
||||
-it is not part of any multipath device.
|
||||
+The multipath device that this device is a path of, or \fI[offline]\fR
|
||||
+if this device could not be added to a device because it is offline or
|
||||
+\fI[orphan]\fR if it is not part of any multipath device.
|
||||
.TP
|
||||
.B %N
|
||||
The host World Wide Node Name (WWNN) of the device, if any.
|
@ -0,0 +1,37 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Xose Vazquez Perez <xose.vazquez@gmail.com>
|
||||
Date: Thu, 5 Dec 2024 23:49:16 +0100
|
||||
Subject: [PATCH] multipath-tools: add HPE MSA Gen7 (2070/2072) to hwtable
|
||||
|
||||
https://support.hpe.com/connect/s/product?kmpmoid=1014856412
|
||||
|
||||
Just guessing, confirmation from manufacturer is needed.
|
||||
|
||||
Cc: Jon Paul <Jon.Paul@hpe.com>
|
||||
Cc: Martin Wilck <mwilck@suse.com>
|
||||
Cc: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Cc: Christophe Varoqui <christophe.varoqui@opensvc.com>
|
||||
Cc: DM-DEVEL ML <dm-devel@lists.linux.dev>
|
||||
Signed-off-by: Xose Vazquez Perez <xose.vazquez@gmail.com>
|
||||
Acked-by: Jon Paul <jon.paul@hpe.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/hwtable.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
|
||||
index 9e008df6..17ba5b45 100644
|
||||
--- a/libmultipath/hwtable.c
|
||||
+++ b/libmultipath/hwtable.c
|
||||
@@ -190,9 +190,9 @@ static struct hwentry default_hw[] = {
|
||||
.prio_name = PRIO_ALUA,
|
||||
},
|
||||
{
|
||||
- /* MSA 1040, 1050, 1060, 2040, 2050 and 2060 families */
|
||||
+ /* MSA 1040, 1050, 1060, 2040, 2050, 2060 and 2070 families */
|
||||
.vendor = "(HP|HPE)",
|
||||
- .product = "MSA [12]0[456]0 (SAN|SAS|FC|iSCSI)",
|
||||
+ .product = "MSA [12]0[4567]0 (SAN|SAS|FC|iSCSI)",
|
||||
.pgpolicy = GROUP_BY_PRIO,
|
||||
.pgfailback = -FAILBACK_IMMEDIATE,
|
||||
.no_path_retry = 18,
|
84
0034-libmultipath-fix-crash-in-print_foreign_topology.patch
Normal file
84
0034-libmultipath-fix-crash-in-print_foreign_topology.patch
Normal file
@ -0,0 +1,84 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 20 Aug 2025 18:25:03 -0400
|
||||
Subject: [PATCH] libmultipath: fix crash in print_foreign_topology
|
||||
|
||||
print_foreign_topology() called get_paths() to get a vector of
|
||||
(struct gen_path *) items and then called get_multipath_layout__(),
|
||||
which expects a vector of (struct gen_multipath *) items, with the path
|
||||
vector. This can easily end badly. Fix it to correctly call
|
||||
get_path_layout__(), and rename width to p_width in the functions that
|
||||
end up calling snprint_multipath_topology__(), which is expecting to get
|
||||
passed the path field widths.
|
||||
|
||||
Signed-off-by: Lin Li <lilin@redhat.com>
|
||||
---
|
||||
libmultipath/foreign.c | 16 ++++++++--------
|
||||
1 file changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/foreign.c b/libmultipath/foreign.c
|
||||
index d01a5ef0..b91e3898 100644
|
||||
--- a/libmultipath/foreign.c
|
||||
+++ b/libmultipath/foreign.c
|
||||
@@ -500,7 +500,7 @@ void foreign_multipath_layout(fieldwidth_t *width)
|
||||
}
|
||||
|
||||
static int __snprint_foreign_topology(struct strbuf *buf, int verbosity,
|
||||
- const fieldwidth_t *width)
|
||||
+ const fieldwidth_t *p_width)
|
||||
{
|
||||
struct foreign *fgn;
|
||||
int i;
|
||||
@@ -518,7 +518,7 @@ static int __snprint_foreign_topology(struct strbuf *buf, int verbosity,
|
||||
if (vec != NULL) {
|
||||
vector_foreach_slot(vec, gm, j) {
|
||||
if (_snprint_multipath_topology(
|
||||
- gm, buf, verbosity, width) < 0)
|
||||
+ gm, buf, verbosity, p_width) < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -530,7 +530,7 @@ static int __snprint_foreign_topology(struct strbuf *buf, int verbosity,
|
||||
}
|
||||
|
||||
int snprint_foreign_topology(struct strbuf *buf, int verbosity,
|
||||
- const fieldwidth_t *width)
|
||||
+ const fieldwidth_t *p_width)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -540,7 +540,7 @@ int snprint_foreign_topology(struct strbuf *buf, int verbosity,
|
||||
return 0;
|
||||
}
|
||||
pthread_cleanup_push(unlock_foreigns, NULL);
|
||||
- rc = __snprint_foreign_topology(buf, verbosity, width);
|
||||
+ rc = __snprint_foreign_topology(buf, verbosity, p_width);
|
||||
pthread_cleanup_pop(1);
|
||||
return rc;
|
||||
}
|
||||
@@ -550,9 +550,9 @@ void print_foreign_topology(int verbosity)
|
||||
STRBUF_ON_STACK(buf);
|
||||
struct foreign *fgn;
|
||||
int i;
|
||||
- fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
|
||||
+ fieldwidth_t *p_width __attribute__((cleanup(cleanup_ucharp))) = NULL;
|
||||
|
||||
- if ((width = alloc_path_layout()) == NULL)
|
||||
+ if ((p_width = alloc_path_layout()) == NULL)
|
||||
return;
|
||||
rdlock_foreigns();
|
||||
if (foreigns == NULL) {
|
||||
@@ -566,11 +566,11 @@ void print_foreign_topology(int verbosity)
|
||||
fgn->lock(fgn->context);
|
||||
pthread_cleanup_push(fgn->unlock, fgn->context);
|
||||
vec = fgn->get_paths(fgn->context);
|
||||
- _get_multipath_layout(vec, LAYOUT_RESET_NOT, width);
|
||||
+ _get_path_layout(vec, LAYOUT_RESET_NOT, p_width);
|
||||
fgn->release_paths(fgn->context, vec);
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
- __snprint_foreign_topology(&buf, verbosity, width);
|
||||
+ __snprint_foreign_topology(&buf, verbosity, p_width);
|
||||
pthread_cleanup_pop(1);
|
||||
printf("%s", get_strbuf_str(&buf));
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Mon, 5 May 2025 12:47:47 +0200
|
||||
Subject: [PATCH] libmpathpersist: fix memory leak in mpath_prout_rel()
|
||||
|
||||
Found by Fedora's static analysis [1].
|
||||
|
||||
[1] https://openscanhub.fedoraproject.org/task/51915/log/device-mapper-multipath-0.11.1-1.fc43/scan-results.html#def44
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 178c2f54..7df74fb7 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -460,10 +460,10 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int count = 0;
|
||||
int status = MPATH_PR_SUCCESS;
|
||||
struct prin_resp resp;
|
||||
- struct prout_param_descriptor *pamp;
|
||||
+ struct prout_param_descriptor *pamp = NULL;
|
||||
struct prin_resp *pr_buff;
|
||||
int length;
|
||||
- struct transportid *pptr;
|
||||
+ struct transportid *pptr = NULL;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -570,7 +570,7 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
pamp = (struct prout_param_descriptor *)malloc (length);
|
||||
if (!pamp){
|
||||
condlog (0, "%s: failed to alloc pr out parameter.", mpp->wwid);
|
||||
- goto out1;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
memset(pamp, 0, length);
|
||||
@@ -580,6 +580,7 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
condlog (0, "%s: failed to alloc pr out transportid.", mpp->wwid);
|
||||
goto out1;
|
||||
}
|
||||
+ pptr = pamp->trnptid_list[0];
|
||||
|
||||
if (get_be64(mpp->reservation_key)){
|
||||
memcpy (pamp->key, &mpp->reservation_key, 8);
|
||||
@@ -591,11 +592,10 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
|
||||
if (status) {
|
||||
condlog(0, "%s: failed to send CLEAR_SA", mpp->wwid);
|
||||
- goto out1;
|
||||
+ goto out2;
|
||||
}
|
||||
|
||||
pamp->num_transportid = 1;
|
||||
- pptr=pamp->trnptid_list[0];
|
||||
|
||||
for (i = 0; i < num; i++){
|
||||
if (get_be64(mpp->reservation_key) &&
|
||||
@@ -639,7 +639,7 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);
|
||||
}
|
||||
|
||||
-
|
||||
+out2:
|
||||
free(pptr);
|
||||
out1:
|
||||
free (pamp);
|
164
0036-libmpathpersist-retry-commands-on-other-paths-in-mpa.patch
Normal file
164
0036-libmpathpersist-retry-commands-on-other-paths-in-mpa.patch
Normal file
@ -0,0 +1,164 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 3 Jun 2025 23:35:03 -0400
|
||||
Subject: [PATCH] libmpathpersist: retry commands on other paths in
|
||||
mpath_prout_common
|
||||
|
||||
mpath_prout_common() will only try sending the prout command to one
|
||||
path. If that fails, it will give up. There are a number of cases where
|
||||
it is reasonable to assume that sending the command down another path
|
||||
could succeed. Keep trying other available paths in these cases.
|
||||
|
||||
Do do this, this patch adds a new error code, MPATH_PR_RETRYABLE_ERROR.
|
||||
libmpathpersist will not return this error to users. It will change it
|
||||
to MPATH_PR_OTHER if it fails trying on all the paths.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
.github/actions/spelling/expect.txt | 1 +
|
||||
libmpathpersist/mpath_persist.h | 3 +++
|
||||
libmpathpersist/mpath_persist_int.c | 13 +++++++++----
|
||||
libmpathpersist/mpath_pr_ioctl.c | 25 ++++++++++++++-----------
|
||||
4 files changed, 27 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt
|
||||
index def43a52..e2d4acf9 100644
|
||||
--- a/.github/actions/spelling/expect.txt
|
||||
+++ b/.github/actions/spelling/expect.txt
|
||||
@@ -169,6 +169,7 @@ reconfig
|
||||
redhat
|
||||
restorequeueing
|
||||
retrigger
|
||||
+RETRYABLE
|
||||
rhabarber
|
||||
rootprefix
|
||||
rootprefixdir
|
||||
diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h
|
||||
index 0046f120..b83fc3bd 100644
|
||||
--- a/libmpathpersist/mpath_persist.h
|
||||
+++ b/libmpathpersist/mpath_persist.h
|
||||
@@ -63,6 +63,9 @@ extern "C" {
|
||||
#define MPATH_PR_THREAD_ERROR 14 /* pthreads error (e.g. unable to create new thread) */
|
||||
#define MPATH_PR_OTHER 15 /*other error/warning has occurred(transport
|
||||
or driver error) */
|
||||
+#define MPATH_PR_RETRYABLE_ERROR 16 /* error that might be succeed
|
||||
+ down another path. Internal
|
||||
+ only. */
|
||||
|
||||
/* PR MASK */
|
||||
#define MPATH_F_APTPL_MASK 0x01 /* APTPL MASK*/
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 7df74fb7..db105c6b 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -92,7 +92,7 @@ static int mpath_prin_activepath (struct multipath *mpp, int rq_servact,
|
||||
}
|
||||
}
|
||||
}
|
||||
- return ret;
|
||||
+ return (ret == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : ret;
|
||||
}
|
||||
|
||||
void *mpath_alloc_prin_response(int prin_sa)
|
||||
@@ -382,7 +382,7 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
- return (status);
|
||||
+ return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
static int send_prout_activepath(char *dev, int rq_servact, int rq_scope,
|
||||
@@ -426,6 +426,7 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
int i,j, ret;
|
||||
struct pathgroup *pgp = NULL;
|
||||
struct path *pp = NULL;
|
||||
+ bool found = false;
|
||||
|
||||
vector_foreach_slot (mpp->pg, pgp, j){
|
||||
vector_foreach_slot (pgp->paths, pp, i){
|
||||
@@ -436,12 +437,16 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
}
|
||||
|
||||
condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
|
||||
+ found = true;
|
||||
ret = send_prout_activepath(pp->dev, rq_servact,
|
||||
rq_scope, rq_type,
|
||||
paramp, noisy);
|
||||
- return ret ;
|
||||
+ if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
+ return ret;
|
||||
}
|
||||
}
|
||||
+ if (found)
|
||||
+ return MPATH_PR_OTHER;
|
||||
condlog (0, "%s: no path available", mpp->wwid);
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
}
|
||||
@@ -645,7 +650,7 @@ out1:
|
||||
free (pamp);
|
||||
out:
|
||||
free (pr_buff);
|
||||
- return (status);
|
||||
+ return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c
|
||||
index 093ec71b..7e1d2896 100644
|
||||
--- a/libmpathpersist/mpath_pr_ioctl.c
|
||||
+++ b/libmpathpersist/mpath_pr_ioctl.c
|
||||
@@ -52,7 +52,7 @@ int prout_do_scsi_ioctl(char * dev, int rq_servact, int rq_scope,
|
||||
fd = open(devname, O_RDONLY);
|
||||
if(fd < 0){
|
||||
condlog (1, "%s: unable to open device.", dev);
|
||||
- return MPATH_PR_FILE_ERROR;
|
||||
+ return MPATH_PR_RETRYABLE_ERROR;
|
||||
}
|
||||
|
||||
unsigned char cdb[MPATH_PROUT_CMDLEN] =
|
||||
@@ -123,14 +123,17 @@ retry :
|
||||
goto retry;
|
||||
}
|
||||
|
||||
- if (((status == MPATH_PR_SENSE_NOT_READY )&& (Sensedata.ASC == 0x04)&&
|
||||
- (Sensedata.ASCQ == 0x07))&& (retry > 0))
|
||||
- {
|
||||
- usleep(1000);
|
||||
- --retry;
|
||||
- condlog(3, "%s: retrying for sense 02/04/07."
|
||||
- " Remaining retries = %d", dev, retry);
|
||||
- goto retry;
|
||||
+ if (status == MPATH_PR_SENSE_NOT_READY) {
|
||||
+ if (Sensedata.ASC == 0x04 && Sensedata.ASCQ == 0x07 && retry > 0) {
|
||||
+ usleep(1000);
|
||||
+ --retry;
|
||||
+ condlog(3,
|
||||
+ "%s: retrying for sense 02/04/07."
|
||||
+ " Remaining retries = %d",
|
||||
+ dev, retry);
|
||||
+ goto retry;
|
||||
+ } else
|
||||
+ status = MPATH_PR_RETRYABLE_ERROR;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
@@ -342,7 +345,7 @@ int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int
|
||||
fd = open(devname, O_RDONLY);
|
||||
if(fd < 0){
|
||||
condlog(0, "%s: Unable to open device ", dev);
|
||||
- return MPATH_PR_FILE_ERROR;
|
||||
+ return MPATH_PR_RETRYABLE_ERROR;
|
||||
}
|
||||
|
||||
if (mpath_mx_alloc_len)
|
||||
@@ -488,7 +491,7 @@ int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr,
|
||||
case DID_OK :
|
||||
break;
|
||||
default :
|
||||
- return MPATH_PR_OTHER;
|
||||
+ return MPATH_PR_RETRYABLE_ERROR;
|
||||
}
|
||||
switch(io_hdr.driver_status)
|
||||
{
|
@ -0,0 +1,39 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 3 Jun 2025 23:35:04 -0400
|
||||
Subject: [PATCH] libmpathpersist: check released key against the reservation
|
||||
key
|
||||
|
||||
According to the SCSI Spec, if a persistent reservation RELEASE is
|
||||
issued using the correct key for the I_T_L Nexus that it is issued on
|
||||
but the reservation is held by a different key, the command should
|
||||
return Success and do nothing. When libmpathpersist tried to release a
|
||||
reservation that was held by a different key, it ended up using the
|
||||
failback code designed to release a reservation held by a failed path to
|
||||
release it anyways. This means that any node could release a scsi
|
||||
persistent reservation held by another node. Fix this to follow the SCSI
|
||||
Spec.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index db105c6b..128671e5 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -551,6 +551,12 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
condlog (2, "%s: Path holding reservation is released.", mpp->wwid);
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
+ if (!get_be64(mpp->reservation_key) ||
|
||||
+ memcmp(&mpp->reservation_key, resp.prin_descriptor.prin_readresv.key, 8)) {
|
||||
+ condlog(2, "%s: Releasing key not holding reservation.", mpp->wwid);
|
||||
+ return MPATH_PR_SUCCESS;
|
||||
+ }
|
||||
+
|
||||
condlog (2, "%s: Path holding reservation is not available.", mpp->wwid);
|
||||
|
||||
pr_buff = mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA);
|
@ -0,0 +1,98 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:46 -0400
|
||||
Subject: [PATCH] multipathd: remove thread from mpath_pr_event_handle
|
||||
|
||||
mpath_pr_event_handle() creates a separate thread to do the persistent
|
||||
reservation work, but it doesn't take any advantage of the work being
|
||||
done in another thread. Merge mpath_pr_event_handle() and
|
||||
mpath_pr_event_handler_fn() into a single function with no separate
|
||||
thread.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
multipathd/main.c | 50 +++++++++++------------------------------------
|
||||
1 file changed, 11 insertions(+), 39 deletions(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index a565ade5..04ca47d1 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -89,8 +89,7 @@
|
||||
#define CMDSIZE 160
|
||||
#define MSG_SIZE 32
|
||||
|
||||
-int mpath_pr_event_handle(struct path *pp);
|
||||
-void * mpath_pr_event_handler_fn (void * );
|
||||
+static void mpath_pr_event_handle(struct path *pp);
|
||||
|
||||
#define LOG_MSG(lvl, pp) \
|
||||
do { \
|
||||
@@ -3945,17 +3944,24 @@ main (int argc, char *argv[])
|
||||
return (child(NULL));
|
||||
}
|
||||
|
||||
-void * mpath_pr_event_handler_fn (void * pathp )
|
||||
+static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
struct multipath * mpp;
|
||||
unsigned int i;
|
||||
int ret, isFound;
|
||||
- struct path * pp = (struct path *)pathp;
|
||||
struct prout_param_descriptor *param;
|
||||
struct prin_resp *resp;
|
||||
|
||||
- rcu_register_thread();
|
||||
mpp = pp->mpp;
|
||||
+ if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
+ mpp->prflag = PRFLAG_UNSET;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!get_be64(mpp->reservation_key)) {
|
||||
+ mpp->prflag = PRFLAG_UNSET;
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
if (!resp){
|
||||
@@ -4022,38 +4028,4 @@ void * mpath_pr_event_handler_fn (void * pathp )
|
||||
out:
|
||||
if (resp)
|
||||
free(resp);
|
||||
- rcu_unregister_thread();
|
||||
- return NULL;
|
||||
-}
|
||||
-
|
||||
-int mpath_pr_event_handle(struct path *pp)
|
||||
-{
|
||||
- pthread_t thread;
|
||||
- int rc;
|
||||
- pthread_attr_t attr;
|
||||
- struct multipath * mpp;
|
||||
-
|
||||
- if (pp->bus != SYSFS_BUS_SCSI)
|
||||
- goto no_pr;
|
||||
-
|
||||
- mpp = pp->mpp;
|
||||
-
|
||||
- if (!get_be64(mpp->reservation_key))
|
||||
- goto no_pr;
|
||||
-
|
||||
- pthread_attr_init(&attr);
|
||||
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
-
|
||||
- rc = pthread_create(&thread, NULL , mpath_pr_event_handler_fn, pp);
|
||||
- if (rc) {
|
||||
- condlog(0, "%s: ERROR; return code from pthread_create() is %d", pp->dev, rc);
|
||||
- return -1;
|
||||
- }
|
||||
- pthread_attr_destroy(&attr);
|
||||
- rc = pthread_join(thread, NULL);
|
||||
- return 0;
|
||||
-
|
||||
-no_pr:
|
||||
- pp->mpp->prflag = PRFLAG_UNSET;
|
||||
- return 0;
|
||||
}
|
47
0039-libmpathpersist-remove-uneeded-wrapper-function.patch
Normal file
47
0039-libmpathpersist-remove-uneeded-wrapper-function.patch
Normal file
@ -0,0 +1,47 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:47 -0400
|
||||
Subject: [PATCH] libmpathpersist: remove uneeded wrapper function.
|
||||
|
||||
mpath_send_prin_activepath() just calls prin_do_scsi_ioctl() with exactly
|
||||
the same arguments that it is passed, and returns the same return. remove
|
||||
it.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 14 +-------------
|
||||
1 file changed, 1 insertion(+), 13 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 128671e5..fb1d0081 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -49,17 +49,6 @@ struct threadinfo {
|
||||
struct prout_param param;
|
||||
};
|
||||
|
||||
-static int mpath_send_prin_activepath (char * dev, int rq_servact,
|
||||
- struct prin_resp * resp, int noisy)
|
||||
-{
|
||||
-
|
||||
- int rc;
|
||||
-
|
||||
- rc = prin_do_scsi_ioctl(dev, rq_servact, resp, noisy);
|
||||
-
|
||||
- return (rc);
|
||||
-}
|
||||
-
|
||||
static int mpath_prin_activepath (struct multipath *mpp, int rq_servact,
|
||||
struct prin_resp * resp, int noisy)
|
||||
{
|
||||
@@ -80,8 +69,7 @@ static int mpath_prin_activepath (struct multipath *mpp, int rq_servact,
|
||||
|
||||
condlog(3, "%s: sending pr in command to %s ",
|
||||
mpp->wwid, pp->dev);
|
||||
- ret = mpath_send_prin_activepath(pp->dev, rq_servact,
|
||||
- resp, noisy);
|
||||
+ ret = prin_do_scsi_ioctl(pp->dev, rq_servact, resp, noisy);
|
||||
switch(ret)
|
||||
{
|
||||
case MPATH_PR_SUCCESS:
|
102
0040-libmpathpersist-reduce-log-level-for-persistent-rese.patch
Normal file
102
0040-libmpathpersist-reduce-log-level-for-persistent-rese.patch
Normal file
@ -0,0 +1,102 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:48 -0400
|
||||
Subject: [PATCH] libmpathpersist: reduce log level for persistent reservation
|
||||
checking
|
||||
|
||||
Move logging of minor expected behavior to INFO level. Modify the log
|
||||
level of some messages by whether or not mpp->prflag changed values.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 34 +++++++++++++++++++----------
|
||||
1 file changed, 22 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index fb1d0081..6233e6b0 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -60,7 +60,7 @@ static int mpath_prin_activepath (struct multipath *mpp, int rq_servact,
|
||||
vector_foreach_slot (pgp->paths, pp, i){
|
||||
if (!((pp->state == PATH_UP) ||
|
||||
(pp->state == PATH_GHOST))){
|
||||
- condlog(2, "%s: %s not available. Skip.",
|
||||
+ condlog(3, "%s: %s not available. Skip.",
|
||||
mpp->wwid, pp->dev);
|
||||
condlog(3, "%s: status = %d.",
|
||||
mpp->wwid, pp->state);
|
||||
@@ -733,12 +733,14 @@ int update_map_pr(struct multipath *mpp)
|
||||
struct prin_resp *resp;
|
||||
unsigned int i;
|
||||
int ret = MPATH_PR_OTHER, isFound;
|
||||
+ bool was_set = (mpp->prflag == PRFLAG_SET);
|
||||
|
||||
if (!get_be64(mpp->reservation_key))
|
||||
{
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
mpp->prflag = PRFLAG_UNSET;
|
||||
- condlog(4, "%s: reservation_key not set in multipath.conf",
|
||||
+ condlog(was_set ? 2 : 4,
|
||||
+ "%s: reservation_key not set in multipath.conf",
|
||||
mpp->alias);
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
@@ -751,8 +753,7 @@ int update_map_pr(struct multipath *mpp)
|
||||
}
|
||||
if (count_active_paths(mpp) == 0)
|
||||
{
|
||||
- condlog(0,"%s: No available paths to check pr status",
|
||||
- mpp->alias);
|
||||
+ condlog(2, "%s: No available paths to check pr status", mpp->alias);
|
||||
goto out;
|
||||
}
|
||||
mpp->prflag = PRFLAG_UNSET;
|
||||
@@ -768,22 +769,31 @@ int update_map_pr(struct multipath *mpp)
|
||||
|
||||
if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
{
|
||||
- condlog(3,"%s: No key found. Device may not be registered. ", mpp->alias);
|
||||
+ condlog(was_set ? 1 : 3,
|
||||
+ "%s: No key found. Device may not be registered. ",
|
||||
+ mpp->alias);
|
||||
goto out;
|
||||
}
|
||||
|
||||
- condlog(2, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
+ condlog(3, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
get_be64(mpp->reservation_key));
|
||||
|
||||
isFound =0;
|
||||
for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
|
||||
{
|
||||
- condlog(2, "%s: PR IN READKEYS[%d] reservation key:", mpp->alias, i);
|
||||
- dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i*8], 8 , 1);
|
||||
+ if (libmp_verbosity >= 3) {
|
||||
+ condlog(3, "%s: PR IN READKEYS[%d] reservation key:",
|
||||
+ mpp->alias, i);
|
||||
+ dumpHex((char *)&resp->prin_descriptor.prin_readkeys
|
||||
+ .key_list[i * 8],
|
||||
+ 8, 1);
|
||||
+ }
|
||||
|
||||
- if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8))
|
||||
- {
|
||||
- condlog(2, "%s: reservation key found in pr in readkeys response", mpp->alias);
|
||||
+ if (!memcmp(&mpp->reservation_key,
|
||||
+ &resp->prin_descriptor.prin_readkeys.key_list[i * 8],
|
||||
+ 8)) {
|
||||
+ condlog(3, "%s: reservation key found in pr in readkeys response",
|
||||
+ mpp->alias);
|
||||
isFound =1;
|
||||
}
|
||||
}
|
||||
@@ -791,7 +801,7 @@ int update_map_pr(struct multipath *mpp)
|
||||
if (isFound)
|
||||
{
|
||||
mpp->prflag = PRFLAG_SET;
|
||||
- condlog(2, "%s: prflag flag set.", mpp->alias );
|
||||
+ condlog(was_set ? 3 : 2, "%s: prflag flag set.", mpp->alias);
|
||||
}
|
||||
|
||||
out:
|
@ -0,0 +1,28 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:49 -0400
|
||||
Subject: [PATCH] libmpathpersist: remove pointless update_map_pr ret value
|
||||
code
|
||||
|
||||
Don't set ret to MPATH_PR_SUCCESS, after the code just made sure that
|
||||
it was already set to MPATH_PR_SUCCESS.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 6233e6b0..39bfc953 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -765,8 +765,6 @@ int update_map_pr(struct multipath *mpp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
- ret = MPATH_PR_SUCCESS;
|
||||
-
|
||||
if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
{
|
||||
condlog(was_set ? 1 : 3,
|
217
0042-multipathd-use-update_map_pr-in-mpath_pr_event_handl.patch
Normal file
217
0042-multipathd-use-update_map_pr-in-mpath_pr_event_handl.patch
Normal file
@ -0,0 +1,217 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:50 -0400
|
||||
Subject: [PATCH] multipathd: use update_map_pr in mpath_pr_event_handle
|
||||
|
||||
Clean up the duplicate code in mpath_pr_event_handle() and
|
||||
update_map_pr() by making update_map_pr() take an optional path device
|
||||
to use for its check, instead of checking all path devices and make
|
||||
mpath_pr_event_handle() call update_map_pr() to do its checking.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/libmpathpersist.version | 2 +-
|
||||
libmpathpersist/mpath_persist_int.c | 18 ++++---
|
||||
libmpathpersist/mpath_persist_int.h | 2 +-
|
||||
multipathd/main.c | 68 ++++---------------------
|
||||
4 files changed, 22 insertions(+), 68 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/libmpathpersist.version b/libmpathpersist/libmpathpersist.version
|
||||
index a8c6aae7..faa4257b 100644
|
||||
--- a/libmpathpersist/libmpathpersist.version
|
||||
+++ b/libmpathpersist/libmpathpersist.version
|
||||
@@ -27,7 +27,7 @@ global:
|
||||
local: *;
|
||||
};
|
||||
|
||||
-__LIBMPATHPERSIST_INT_1.0.0 {
|
||||
+__LIBMPATHPERSIST_INT_2.0.0 {
|
||||
/* Internal use by multipath-tools */
|
||||
dumpHex;
|
||||
mpath_alloc_prin_response;
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 39bfc953..8b01492f 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -727,7 +727,7 @@ out1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-int update_map_pr(struct multipath *mpp)
|
||||
+int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
{
|
||||
int noisy=0;
|
||||
struct prin_resp *resp;
|
||||
@@ -742,7 +742,7 @@ int update_map_pr(struct multipath *mpp)
|
||||
condlog(was_set ? 2 : 4,
|
||||
"%s: reservation_key not set in multipath.conf",
|
||||
mpp->alias);
|
||||
- return MPATH_PR_SUCCESS;
|
||||
+ return MPATH_PR_SKIP;
|
||||
}
|
||||
|
||||
resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
@@ -751,13 +751,15 @@ int update_map_pr(struct multipath *mpp)
|
||||
condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
|
||||
return MPATH_PR_OTHER;
|
||||
}
|
||||
- if (count_active_paths(mpp) == 0)
|
||||
- {
|
||||
+ if (!pp && count_active_paths(mpp) == 0) {
|
||||
condlog(2, "%s: No available paths to check pr status", mpp->alias);
|
||||
goto out;
|
||||
}
|
||||
mpp->prflag = PRFLAG_UNSET;
|
||||
- ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
+ if (pp)
|
||||
+ ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
+ else
|
||||
+ ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
@@ -799,8 +801,10 @@ int update_map_pr(struct multipath *mpp)
|
||||
if (isFound)
|
||||
{
|
||||
mpp->prflag = PRFLAG_SET;
|
||||
- condlog(was_set ? 3 : 2, "%s: prflag flag set.", mpp->alias);
|
||||
- }
|
||||
+ condlog(was_set ? 3 : 2, "%s: key found. prflag set.", mpp->alias);
|
||||
+ } else
|
||||
+ condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
+ mpp->alias);
|
||||
|
||||
out:
|
||||
free(resp);
|
||||
diff --git a/libmpathpersist/mpath_persist_int.h b/libmpathpersist/mpath_persist_int.h
|
||||
index 31457535..73c95863 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.h
|
||||
+++ b/libmpathpersist/mpath_persist_int.h
|
||||
@@ -20,6 +20,6 @@ int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int
|
||||
int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
|
||||
void dumpHex(const char* , int len, int no_ascii);
|
||||
-int update_map_pr(struct multipath *mpp);
|
||||
+int update_map_pr(struct multipath *mpp, struct path *pp);
|
||||
|
||||
#endif /* _MPATH_PERSIST_INT_H */
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 04ca47d1..390632a6 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -733,7 +733,7 @@ fail:
|
||||
sync_map_state(mpp);
|
||||
|
||||
if (mpp->prflag != PRFLAG_SET)
|
||||
- update_map_pr(mpp);
|
||||
+ update_map_pr(mpp, NULL);
|
||||
if (mpp->prflag == PRFLAG_SET)
|
||||
pr_register_active_paths(mpp);
|
||||
|
||||
@@ -1383,7 +1383,7 @@ rescan:
|
||||
|
||||
if (retries >= 0) {
|
||||
if (start_waiter)
|
||||
- update_map_pr(mpp);
|
||||
+ update_map_pr(mpp, NULL);
|
||||
if (mpp->prflag == PRFLAG_SET && prflag != PRFLAG_SET)
|
||||
pr_register_active_paths(mpp);
|
||||
condlog(2, "%s [%s]: path added to devmap %s",
|
||||
@@ -3028,7 +3028,7 @@ configure (struct vectors * vecs, enum force_reload_types reload_type)
|
||||
vector_foreach_slot(mpvec, mpp, i){
|
||||
if (remember_wwid(mpp->wwid) == 1)
|
||||
trigger_paths_udev_change(mpp, true);
|
||||
- update_map_pr(mpp);
|
||||
+ update_map_pr(mpp, NULL);
|
||||
if (mpp->prflag == PRFLAG_SET)
|
||||
pr_register_active_paths(mpp);
|
||||
}
|
||||
@@ -3946,70 +3946,24 @@ main (int argc, char *argv[])
|
||||
|
||||
static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
- struct multipath * mpp;
|
||||
- unsigned int i;
|
||||
- int ret, isFound;
|
||||
+ struct multipath *mpp = pp->mpp;
|
||||
+ int ret;
|
||||
struct prout_param_descriptor *param;
|
||||
- struct prin_resp *resp;
|
||||
|
||||
- mpp = pp->mpp;
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
mpp->prflag = PRFLAG_UNSET;
|
||||
return;
|
||||
}
|
||||
|
||||
- if (!get_be64(mpp->reservation_key)) {
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS)
|
||||
return;
|
||||
- }
|
||||
-
|
||||
- resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
- if (!resp){
|
||||
- condlog(0,"%s Alloc failed for prin response", pp->dev);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
- ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, 0);
|
||||
- if (ret != MPATH_PR_SUCCESS )
|
||||
- {
|
||||
- condlog(0,"%s : pr in read keys service action failed. Error=%d", pp->dev, ret);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- condlog(3, " event pr=%d addlen=%d",resp->prin_descriptor.prin_readkeys.prgeneration,
|
||||
- resp->prin_descriptor.prin_readkeys.additional_length );
|
||||
-
|
||||
- if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
- {
|
||||
- condlog(1, "%s: No key found. Device may not be registered.", pp->dev);
|
||||
- goto out;
|
||||
- }
|
||||
- condlog(2, "Multipath reservation_key: 0x%" PRIx64 " ",
|
||||
- get_be64(mpp->reservation_key));
|
||||
|
||||
- isFound =0;
|
||||
- for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
|
||||
- {
|
||||
- condlog(2, "PR IN READKEYS[%d] reservation key:",i);
|
||||
- dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i*8], 8 , -1);
|
||||
- if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8))
|
||||
- {
|
||||
- condlog(2, "%s: pr key found in prin readkeys response", mpp->alias);
|
||||
- isFound =1;
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
- if (!isFound)
|
||||
- {
|
||||
- condlog(0, "%s: Either device not registered or ", pp->dev);
|
||||
- condlog(0, "host is not authorised for registration. Skip path");
|
||||
- goto out;
|
||||
- }
|
||||
+ if (mpp->prflag != PRFLAG_SET)
|
||||
+ return;
|
||||
|
||||
param = (struct prout_param_descriptor *)calloc(1, sizeof(struct prout_param_descriptor));
|
||||
if (!param)
|
||||
- goto out;
|
||||
+ return;
|
||||
|
||||
param->sa_flags = mpp->sa_flags;
|
||||
memcpy(param->sa_key, &mpp->reservation_key, 8);
|
||||
@@ -4022,10 +3976,6 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
condlog(0,"%s: Reservation registration failed. Error: %d", pp->dev, ret);
|
||||
}
|
||||
- mpp->prflag = PRFLAG_SET;
|
||||
|
||||
free(param);
|
||||
-out:
|
||||
- if (resp)
|
||||
- free(resp);
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:51 -0400
|
||||
Subject: [PATCH] libmpathpersist: limit changing prflag in update_map_pr
|
||||
|
||||
Do not unset mpp->prflag in update_map_pr() unless the device doesn't
|
||||
support persistent reservations or it successfully reads the registered
|
||||
keys and discovers that the device's key is not there. Also, nothing in
|
||||
the libmpathpersist ever returns MPATH_PR_SENSE_INVALID_OP. It instead
|
||||
returns MPATH_PR_ILLEGAL_REQ if the device doesn't support persistent
|
||||
reservations, so check for that instead.
|
||||
|
||||
Also, do not even check for the registered keys in update_map_pr() if
|
||||
mpp->prflag is unset. Otherwise, multipathd will set mpp->prflag if the
|
||||
key was unregistered (and thus prflag was unset) while a path is down
|
||||
(and thus could not have its key unregistered) and then that path comes
|
||||
back up. I should note that the above issue can only occur if multipath
|
||||
is defining PR keys in /etc/multipath.conf, instead of the prkeys file.
|
||||
|
||||
If a device has no registered keys, it must unset prflag, since that
|
||||
means it's no longer registered. Possibly its registration was removed
|
||||
by a CLEAR or PREEMPT action. But if a device has a registered key but
|
||||
it is supposed to be unregistered, it should remain unregistered, since
|
||||
that key is likely one that libmpathpersist could not unregister at the
|
||||
time.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 8b01492f..c34bc785 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -73,7 +73,7 @@ static int mpath_prin_activepath (struct multipath *mpp, int rq_servact,
|
||||
switch(ret)
|
||||
{
|
||||
case MPATH_PR_SUCCESS:
|
||||
- case MPATH_PR_SENSE_INVALID_OP:
|
||||
+ case MPATH_PR_ILLEGAL_REQ:
|
||||
return ret;
|
||||
default:
|
||||
continue;
|
||||
@@ -735,6 +735,10 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
int ret = MPATH_PR_OTHER, isFound;
|
||||
bool was_set = (mpp->prflag == PRFLAG_SET);
|
||||
|
||||
+ /* If pr is explicitly unset, it must be manually set */
|
||||
+ if (mpp->prflag == PRFLAG_UNSET)
|
||||
+ return MPATH_PR_SKIP;
|
||||
+
|
||||
if (!get_be64(mpp->reservation_key))
|
||||
{
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
@@ -755,7 +759,6 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
condlog(2, "%s: No available paths to check pr status", mpp->alias);
|
||||
goto out;
|
||||
}
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
if (pp)
|
||||
ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
else
|
||||
@@ -763,9 +766,12 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
+ if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
+ mpp->prflag = PRFLAG_UNSET;
|
||||
condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
|
||||
goto out;
|
||||
}
|
||||
+ mpp->prflag = PRFLAG_UNSET;
|
||||
|
||||
if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
{
|
77
0044-multipathd-Don-t-call-update_map_pr-unnecessarily.patch
Normal file
77
0044-multipathd-Don-t-call-update_map_pr-unnecessarily.patch
Normal file
@ -0,0 +1,77 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:52 -0400
|
||||
Subject: [PATCH] multipathd: Don't call update_map_pr unnecessarily
|
||||
|
||||
None of the calls to update_map_pr() outside of mpath_pr_event_handle()
|
||||
add any benefit. When update_map_pr() is called without a path, it tries
|
||||
to read the pr keys list on each usable path until it succeeds, and then
|
||||
checks the keys to see if they include the configured key.
|
||||
|
||||
In all cases where update_map_pr() is called outside of
|
||||
mpath_pr_event_handle(), after it is called, pr_register_active_paths()
|
||||
is called if a matching key was found. pr_register_active_paths() calls
|
||||
mpath_pr_event_handle() on each usable path, which calls update_map_pr()
|
||||
with a path, so it only checks that path. If a matching key is found, it
|
||||
registers a key on the current path. The result is that after
|
||||
pr_register_active_paths() is called, update_map_pr() will be called for
|
||||
each usable path, just like update_map_pr() did. So calling
|
||||
update_map_pr() first doesn't change the results for multipathd, it just
|
||||
adds duplicate work, so remove those calls.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
multipathd/main.c | 18 +++++++-----------
|
||||
1 file changed, 7 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 390632a6..4a1b38e9 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -644,6 +644,8 @@ pr_register_active_paths(struct multipath *mpp)
|
||||
|
||||
vector_foreach_slot (mpp->pg, pgp, i) {
|
||||
vector_foreach_slot (pgp->paths, pp, j) {
|
||||
+ if (mpp->prflag == PRFLAG_UNSET)
|
||||
+ return;
|
||||
if ((pp->state == PATH_UP) || (pp->state == PATH_GHOST))
|
||||
mpath_pr_event_handle(pp);
|
||||
}
|
||||
@@ -732,10 +734,7 @@ fail:
|
||||
|
||||
sync_map_state(mpp);
|
||||
|
||||
- if (mpp->prflag != PRFLAG_SET)
|
||||
- update_map_pr(mpp, NULL);
|
||||
- if (mpp->prflag == PRFLAG_SET)
|
||||
- pr_register_active_paths(mpp);
|
||||
+ pr_register_active_paths(mpp);
|
||||
|
||||
if (VECTOR_SIZE(offline_paths) != 0)
|
||||
handle_orphaned_offline_paths(offline_paths);
|
||||
@@ -1382,10 +1381,9 @@ rescan:
|
||||
sync_map_state(mpp);
|
||||
|
||||
if (retries >= 0) {
|
||||
- if (start_waiter)
|
||||
- update_map_pr(mpp, NULL);
|
||||
- if (mpp->prflag == PRFLAG_SET && prflag != PRFLAG_SET)
|
||||
- pr_register_active_paths(mpp);
|
||||
+ if ((mpp->prflag == PRFLAG_SET && prflag != PRFLAG_SET) ||
|
||||
+ start_waiter)
|
||||
+ pr_register_active_paths(mpp);
|
||||
condlog(2, "%s [%s]: path added to devmap %s",
|
||||
pp->dev, pp->dev_t, mpp->alias);
|
||||
return 0;
|
||||
@@ -3028,9 +3026,7 @@ configure (struct vectors * vecs, enum force_reload_types reload_type)
|
||||
vector_foreach_slot(mpvec, mpp, i){
|
||||
if (remember_wwid(mpp->wwid) == 1)
|
||||
trigger_paths_udev_change(mpp, true);
|
||||
- update_map_pr(mpp, NULL);
|
||||
- if (mpp->prflag == PRFLAG_SET)
|
||||
- pr_register_active_paths(mpp);
|
||||
+ pr_register_active_paths(mpp);
|
||||
}
|
||||
|
||||
/*
|
@ -0,0 +1,74 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:53 -0400
|
||||
Subject: [PATCH] libmpathpersist: remove useless function
|
||||
send_prout_activepath
|
||||
|
||||
send_prout_activepath() creates a single separate thread that just calls
|
||||
prout_do_scsi_ioctl() and it doesn't take any advantage of the work
|
||||
being done in another thread. Remove the function and call
|
||||
prout_do_scsi_ioctl() directly.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 39 ++---------------------------
|
||||
1 file changed, 2 insertions(+), 37 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index c34bc785..d8f757b7 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -373,40 +373,6 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
-static int send_prout_activepath(char *dev, int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type,
|
||||
- struct prout_param_descriptor * paramp, int noisy)
|
||||
-{
|
||||
- struct prout_param param;
|
||||
- param.rq_servact = rq_servact;
|
||||
- param.rq_scope = rq_scope;
|
||||
- param.rq_type = rq_type;
|
||||
- param.paramp = paramp;
|
||||
- param.noisy = noisy;
|
||||
- param.status = -1;
|
||||
-
|
||||
- pthread_t thread;
|
||||
- pthread_attr_t attr;
|
||||
- int rc;
|
||||
-
|
||||
- memset(&thread, 0, sizeof(thread));
|
||||
- strlcpy(param.dev, dev, FILE_NAME_SIZE);
|
||||
- /* Initialize and set thread joinable attribute */
|
||||
- pthread_attr_init(&attr);
|
||||
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
-
|
||||
- rc = pthread_create(&thread, &attr, mpath_prout_pthread_fn, (void *)(¶m));
|
||||
- if (rc){
|
||||
- condlog (3, "%s: failed to create thread %d", dev, rc);
|
||||
- return MPATH_PR_THREAD_ERROR;
|
||||
- }
|
||||
- /* Free attribute and wait for the other threads */
|
||||
- pthread_attr_destroy(&attr);
|
||||
- rc = pthread_join(thread, NULL);
|
||||
-
|
||||
- return (param.status);
|
||||
-}
|
||||
-
|
||||
static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type,
|
||||
struct prout_param_descriptor* paramp, int noisy)
|
||||
@@ -426,9 +392,8 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
|
||||
condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
|
||||
found = true;
|
||||
- ret = send_prout_activepath(pp->dev, rq_servact,
|
||||
- rq_scope, rq_type,
|
||||
- paramp, noisy);
|
||||
+ ret = prout_do_scsi_ioctl(pp->dev, rq_servact, rq_scope,
|
||||
+ rq_type, paramp, noisy);
|
||||
if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
return ret;
|
||||
}
|
293
0046-libmpathpersist-redesign-failed-release-workaround.patch
Normal file
293
0046-libmpathpersist-redesign-failed-release-workaround.patch
Normal file
@ -0,0 +1,293 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:54 -0400
|
||||
Subject: [PATCH] libmpathpersist: redesign failed release workaround
|
||||
|
||||
The workaround for releasing a reservation held by a failed path
|
||||
(clearing all persistent reservation data and then reregistering all the
|
||||
keys) has several problems. It requires devices that support the READ
|
||||
FULL STATUS command and are capable of specifying TransportIDs with
|
||||
REGISTRATION commands (SIP_C), neither of which are mandatory to support
|
||||
SCSI Persistent Reservations. Non SIP_C devices will be left with no
|
||||
registered keys. Also, not all cleared keys are registered, just the
|
||||
ones going to the Target Port receiving the REGISTRATION command. To
|
||||
reregister all the keys, the code would have to also use the "All Target
|
||||
Ports" flag to register keys on different Target Ports, but this could
|
||||
end up registering keys on paths they aren't supposed to be on (for
|
||||
instance if one of the registered keys was only there because the path
|
||||
was down and it couldn't be released).
|
||||
|
||||
The redesign avoids these issues by only using mandatory Persistent
|
||||
Reservation commands, without extra optional parameters or flags, and
|
||||
only effects the keys of the multipath device it is being issued on.
|
||||
The new workaround is:
|
||||
1. Suspend the multipath device to prevent I/O
|
||||
2. Preempt the key to move the reservation to an available path. This
|
||||
also removes the registered keys from every path except the path
|
||||
issuing the PREEMPT command. Since the device is suspended, not I/O
|
||||
can go to these unregisted paths and fail.
|
||||
3. Release the reservation on the path that now holds it.
|
||||
4. Resume the device (since it no longer matters that most of the paths
|
||||
no longer have a registered key)
|
||||
5. Reregister the keys on all the paths.
|
||||
|
||||
If steps 3 or 4 fail, the code will attempt to reregister the keys, and
|
||||
then attempt (or possibly re-attempt) the resume.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 182 +++++++++++++---------------
|
||||
libmultipath/libmultipath.version | 5 +
|
||||
2 files changed, 87 insertions(+), 100 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index d8f757b7..36743d41 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -373,9 +373,10 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
-static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type,
|
||||
- struct prout_param_descriptor* paramp, int noisy)
|
||||
+static int
|
||||
+mpath_prout_common(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
+ unsigned int rq_type, struct prout_param_descriptor *paramp,
|
||||
+ int noisy, struct path **pptr)
|
||||
{
|
||||
int i,j, ret;
|
||||
struct pathgroup *pgp = NULL;
|
||||
@@ -394,6 +395,8 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
found = true;
|
||||
ret = prout_do_scsi_ioctl(pp->dev, rq_servact, rq_scope,
|
||||
rq_type, paramp, noisy);
|
||||
+ if (ret == MPATH_PR_SUCCESS && pptr)
|
||||
+ *pptr = pp;
|
||||
if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
return ret;
|
||||
}
|
||||
@@ -414,14 +417,12 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
struct path *pp = NULL;
|
||||
int active_pathcount = 0;
|
||||
pthread_attr_t attr;
|
||||
- int rc, found = 0;
|
||||
+ int rc;
|
||||
int count = 0;
|
||||
int status = MPATH_PR_SUCCESS;
|
||||
- struct prin_resp resp;
|
||||
- struct prout_param_descriptor *pamp = NULL;
|
||||
- struct prin_resp *pr_buff;
|
||||
- int length;
|
||||
- struct transportid *pptr = NULL;
|
||||
+ struct prin_resp resp = {{{.prgeneration = 0}}};
|
||||
+ uint16_t udev_flags = (mpp->skip_kpartx) ? MPATH_UDEV_NO_KPARTX_FLAG : 0;
|
||||
+ bool did_resume = false;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -511,104 +512,78 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
}
|
||||
|
||||
condlog (2, "%s: Path holding reservation is not available.", mpp->wwid);
|
||||
-
|
||||
- pr_buff = mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA);
|
||||
- if (!pr_buff){
|
||||
- condlog (0, "%s: failed to alloc pr in response buffer.", mpp->wwid);
|
||||
+ /*
|
||||
+ * Cannot free the reservation because the path that is holding it
|
||||
+ * is not usable. Workaround this by:
|
||||
+ * 1. Suspending the device
|
||||
+ * 2. Preempting the reservation to move it to a usable path
|
||||
+ * (this removes the registered keys on all paths except the
|
||||
+ * preempting one. Since the device is suspended, no IO can
|
||||
+ * go to these unregistered paths and fail).
|
||||
+ * 3. Releasing the reservation on the path that now holds it.
|
||||
+ * 4. Resuming the device (since it no longer matters that most of
|
||||
+ * that paths no longer have a registered key)
|
||||
+ * 5. Reregistering keys on all the paths
|
||||
+ */
|
||||
+
|
||||
+ if (!dm_simplecmd_noflush(DM_DEVICE_SUSPEND, mpp->alias, 0)) {
|
||||
+ condlog(0, "%s: release: failed to suspend dm device.", mpp->wwid);
|
||||
return MPATH_PR_OTHER;
|
||||
}
|
||||
|
||||
- status = mpath_prin_activepath (mpp, MPATH_PRIN_RFSTAT_SA, pr_buff, noisy);
|
||||
-
|
||||
- if (status != MPATH_PR_SUCCESS){
|
||||
- condlog (0, "%s: pr in read full status command failed.", mpp->wwid);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
|
||||
- if (0 == num){
|
||||
- goto out;
|
||||
- }
|
||||
- length = sizeof (struct prout_param_descriptor) + (sizeof (struct transportid *));
|
||||
-
|
||||
- pamp = (struct prout_param_descriptor *)malloc (length);
|
||||
- if (!pamp){
|
||||
- condlog (0, "%s: failed to alloc pr out parameter.", mpp->wwid);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- memset(pamp, 0, length);
|
||||
-
|
||||
- pamp->trnptid_list[0] = (struct transportid *) malloc (sizeof (struct transportid));
|
||||
- if (!pamp->trnptid_list[0]){
|
||||
- condlog (0, "%s: failed to alloc pr out transportid.", mpp->wwid);
|
||||
- goto out1;
|
||||
- }
|
||||
- pptr = pamp->trnptid_list[0];
|
||||
-
|
||||
- if (get_be64(mpp->reservation_key)){
|
||||
- memcpy (pamp->key, &mpp->reservation_key, 8);
|
||||
- condlog (3, "%s: reservation key set.", mpp->wwid);
|
||||
- }
|
||||
-
|
||||
- status = mpath_prout_common (mpp, MPATH_PROUT_CLEAR_SA,
|
||||
- rq_scope, rq_type, pamp, noisy);
|
||||
-
|
||||
- if (status) {
|
||||
- condlog(0, "%s: failed to send CLEAR_SA", mpp->wwid);
|
||||
- goto out2;
|
||||
+ memset(paramp, 0, sizeof(*paramp));
|
||||
+ memcpy(paramp->key, &mpp->reservation_key, 8);
|
||||
+ memcpy(paramp->sa_key, &mpp->reservation_key, 8);
|
||||
+ status = mpath_prout_common(mpp, MPATH_PROUT_PREE_SA, rq_scope,
|
||||
+ rq_type, paramp, noisy, &pp);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: release: pr preempt command failed.", mpp->wwid);
|
||||
+ goto fail_resume;
|
||||
}
|
||||
|
||||
- pamp->num_transportid = 1;
|
||||
-
|
||||
- for (i = 0; i < num; i++){
|
||||
- if (get_be64(mpp->reservation_key) &&
|
||||
- memcmp(pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key,
|
||||
- &mpp->reservation_key, 8)){
|
||||
- /*register with transport id*/
|
||||
- memset(pamp, 0, length);
|
||||
- pamp->trnptid_list[0] = pptr;
|
||||
- memset (pamp->trnptid_list[0], 0, sizeof (struct transportid));
|
||||
- memcpy (pamp->sa_key,
|
||||
- pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
|
||||
- pamp->sa_flags = MPATH_F_SPEC_I_PT_MASK;
|
||||
- pamp->num_transportid = 1;
|
||||
-
|
||||
- memcpy (pamp->trnptid_list[0],
|
||||
- &pr_buff->prin_descriptor.prin_readfd.descriptors[i]->trnptid,
|
||||
- sizeof (struct transportid));
|
||||
- status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
|
||||
- pamp, noisy);
|
||||
-
|
||||
- pamp->sa_flags = 0;
|
||||
- memcpy (pamp->key, pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
|
||||
- memset (pamp->sa_key, 0, 8);
|
||||
- pamp->num_transportid = 0;
|
||||
- status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
|
||||
- pamp, noisy);
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- if (get_be64(mpp->reservation_key))
|
||||
- found = 1;
|
||||
- }
|
||||
-
|
||||
-
|
||||
+ memset(paramp, 0, sizeof(*paramp));
|
||||
+ memcpy(paramp->key, &mpp->reservation_key, 8);
|
||||
+ status = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REL_SA, rq_scope,
|
||||
+ rq_type, paramp, noisy);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: release on alternate path failed.", mpp->wwid);
|
||||
+ goto out_reregister;
|
||||
}
|
||||
|
||||
- if (found){
|
||||
- memset (pamp, 0, length);
|
||||
- memcpy (pamp->sa_key, &mpp->reservation_key, 8);
|
||||
- memset (pamp->key, 0, 8);
|
||||
- status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);
|
||||
+ if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
+ condlog(0, "%s release: failed to resume dm device.", mpp->wwid);
|
||||
+ /*
|
||||
+ * leave status set to MPATH_PR_SUCCESS, we will have another
|
||||
+ * chance to resume the device.
|
||||
+ */
|
||||
+ goto out_reregister;
|
||||
+ }
|
||||
+ did_resume = true;
|
||||
+
|
||||
+out_reregister:
|
||||
+ memset(paramp, 0, sizeof(*paramp));
|
||||
+ memcpy(paramp->sa_key, &mpp->reservation_key, 8);
|
||||
+ rc = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope, rq_type,
|
||||
+ paramp, noisy);
|
||||
+ if (rc != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: release: failed to reregister paths.", mpp->wwid);
|
||||
+
|
||||
+ /*
|
||||
+ * If we failed releasing the reservation or resuming earlier
|
||||
+ * try resuming now. Otherwise, return with the reregistering status
|
||||
+ * This means we will report failure, even though the resevation
|
||||
+ * has been released, since the keys were not reregistered.
|
||||
+ */
|
||||
+ if (did_resume)
|
||||
+ return rc;
|
||||
+ else if (status == MPATH_PR_SUCCESS)
|
||||
+ status = rc;
|
||||
+fail_resume:
|
||||
+ if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
+ condlog(0, "%s: release: failed to resume dm device.", mpp->wwid);
|
||||
+ if (status == MPATH_PR_SUCCESS)
|
||||
+ status = MPATH_PR_OTHER;
|
||||
}
|
||||
-
|
||||
-out2:
|
||||
- free(pptr);
|
||||
-out1:
|
||||
- free (pamp);
|
||||
-out:
|
||||
- free (pr_buff);
|
||||
return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
@@ -629,6 +604,12 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
conf = get_multipath_config();
|
||||
select_reservation_key(conf, mpp);
|
||||
select_all_tg_pt(conf, mpp);
|
||||
+ /*
|
||||
+ * If a device preempts itself, it will need to suspend and resume.
|
||||
+ * Set mpp->skip_kpartx to make sure we set the flags to skip kpartx
|
||||
+ * if necessary, when doing this.
|
||||
+ */
|
||||
+ select_skip_kpartx(conf, mpp);
|
||||
put_multipath_config(conf);
|
||||
|
||||
memcpy(&prkey, paramp->sa_key, 8);
|
||||
@@ -665,7 +646,8 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
case MPATH_PROUT_PREE_SA :
|
||||
case MPATH_PROUT_PREE_AB_SA :
|
||||
case MPATH_PROUT_CLEAR_SA:
|
||||
- ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
+ ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
+ paramp, noisy, NULL);
|
||||
break;
|
||||
case MPATH_PROUT_REL_SA:
|
||||
ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version
|
||||
index 0b7a1a2b..db125779 100644
|
||||
--- a/libmultipath/libmultipath.version
|
||||
+++ b/libmultipath/libmultipath.version
|
||||
@@ -246,3 +246,8 @@ LIBMULTIPATH_24.0.1 {
|
||||
global:
|
||||
can_recheck_wwid;
|
||||
} LIBMULTIPATH_24.0.0;
|
||||
+
|
||||
+LIBMULTIPATH_24.0.2 {
|
||||
+global:
|
||||
+ select_skip_kpartx;
|
||||
+} LIBMULTIPATH_24.0.1;
|
@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:55 -0400
|
||||
Subject: [PATCH] libmpathpersist: fail the release if all threads fail
|
||||
|
||||
If none of the threads succeeds in issuing the release, simply return
|
||||
failure, instead of trying the workaround.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 36743d41..553fa509 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -423,6 +423,7 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
struct prin_resp resp = {{{.prgeneration = 0}}};
|
||||
uint16_t udev_flags = (mpp->skip_kpartx) ? MPATH_UDEV_NO_KPARTX_FLAG : 0;
|
||||
bool did_resume = false;
|
||||
+ bool all_threads_failed;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -484,15 +485,22 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
}
|
||||
}
|
||||
|
||||
+ all_threads_failed = true;
|
||||
for (i = 0; i < count; i++){
|
||||
/* check thread status here and return the status */
|
||||
|
||||
- if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
|
||||
+ if (thread[i].param.status == MPATH_PR_SUCCESS)
|
||||
+ all_threads_failed = false;
|
||||
+ else if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
|
||||
status = MPATH_PR_RESERV_CONFLICT;
|
||||
- else if (status == MPATH_PR_SUCCESS
|
||||
- && thread[i].param.status != MPATH_PR_RESERV_CONFLICT)
|
||||
+ else if (status == MPATH_PR_SUCCESS)
|
||||
status = thread[i].param.status;
|
||||
}
|
||||
+ if (all_threads_failed) {
|
||||
+ condlog(0, "%s: all threads failed to release reservation.",
|
||||
+ mpp->wwid);
|
||||
+ return status;
|
||||
+ }
|
||||
|
||||
status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
if (status != MPATH_PR_SUCCESS){
|
191
0048-libmpathpersist-Handle-changing-key-corner-case.patch
Normal file
191
0048-libmpathpersist-Handle-changing-key-corner-case.patch
Normal file
@ -0,0 +1,191 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:56 -0400
|
||||
Subject: [PATCH] libmpathpersist: Handle changing key corner case
|
||||
|
||||
When you change the reservation key of a registered multipath device,
|
||||
some of paths might be down or even deleted since you originally
|
||||
registered the key. libmpathpersist won't be able to change these
|
||||
registrations. This can be a problem if the path that is down is holding
|
||||
the reservation. Other nodes will assume that the reservation is now
|
||||
under your new key, when it is still under the old one. If they try to
|
||||
preempt the reservation, they will succeed. But they will just
|
||||
unregister all the paths with the new key. They won't take over the
|
||||
reservation, and if the path holding it comes back up, it will still be
|
||||
able to write to the device.
|
||||
|
||||
To avoid this, after libmpathpersist changes the key of a registered
|
||||
device, it now checks to see if its old key is still holding the
|
||||
reservation. If it is, limpathpersist preempts the reservation.
|
||||
Currently this only works on REGISTER commands, not REGISTER AND IGNORE
|
||||
ones. A future patch will add that capability. This patch also moves
|
||||
mpath_prout_common() up, without changing it at all.
|
||||
|
||||
I should note that this relies on the fact that libmpathpersist has
|
||||
never worked correctly if two nodes use the same reservation key for the
|
||||
same device. If another node used the same key, it could be the one
|
||||
holding the reservation, and preempting the reservation would deregister
|
||||
it. However, multipathd has always relied on the fact that two nodes
|
||||
will not use the same registration key to know if it is safe to register
|
||||
a key on a path that was just added or just came back up. If there is
|
||||
already a registered key matching the configured key, multipathd assumes
|
||||
that the device has not been preempted, and registers the key on the
|
||||
path. If there are no keys matching the configured key, multipathd
|
||||
assumes that the device has been preempted, and won't register a key.
|
||||
Again, if another node shared the same key, multipathd could registered
|
||||
paths on a node that had been preempted.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 127 ++++++++++++++++++++--------
|
||||
1 file changed, 93 insertions(+), 34 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 553fa509..02b3e59a 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -230,6 +230,97 @@ static void *mpath_prout_pthread_fn(void *p)
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
+static int
|
||||
+mpath_prout_common(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
+ unsigned int rq_type, struct prout_param_descriptor *paramp,
|
||||
+ int noisy, struct path **pptr)
|
||||
+{
|
||||
+ int i, j, ret;
|
||||
+ struct pathgroup *pgp = NULL;
|
||||
+ struct path *pp = NULL;
|
||||
+ bool found = false;
|
||||
+
|
||||
+ vector_foreach_slot (mpp->pg, pgp, j) {
|
||||
+ vector_foreach_slot (pgp->paths, pp, i) {
|
||||
+ if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))) {
|
||||
+ condlog(1, "%s: %s path not up. Skip",
|
||||
+ mpp->wwid, pp->dev);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ condlog(3, "%s: sending pr out command to %s",
|
||||
+ mpp->wwid, pp->dev);
|
||||
+ found = true;
|
||||
+ ret = prout_do_scsi_ioctl(pp->dev, rq_servact, rq_scope,
|
||||
+ rq_type, paramp, noisy);
|
||||
+ if (ret == MPATH_PR_SUCCESS && pptr)
|
||||
+ *pptr = pp;
|
||||
+ if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+ if (found)
|
||||
+ return MPATH_PR_OTHER;
|
||||
+ condlog(0, "%s: no path available", mpp->wwid);
|
||||
+ return MPATH_PR_DMMP_ERROR;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * If you are changing the key registered to a device, and that device is
|
||||
+ * holding the reservation on a path that couldn't get its key updated,
|
||||
+ * either because it is down or no longer part of the multipath device,
|
||||
+ * you need to preempt the reservation to a usable path with the new key
|
||||
+ */
|
||||
+void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
+ int noisy)
|
||||
+{
|
||||
+ uint8_t zero[8] = {0};
|
||||
+ struct prin_resp resp = {{{.prgeneration = 0}}};
|
||||
+ int rq_scope;
|
||||
+ unsigned int rq_type;
|
||||
+ struct prout_param_descriptor paramp = {.sa_flags = 0};
|
||||
+ int status;
|
||||
+
|
||||
+ /*
|
||||
+ * If you previously didn't have a key registered or you didn't
|
||||
+ * switch to a different key, there's no need to preempt. Also, you
|
||||
+ * can't preempt if you no longer have a registered key
|
||||
+ */
|
||||
+ if (memcmp(key, zero, 8) == 0 || memcmp(sa_key, zero, 8) == 0 ||
|
||||
+ memcmp(key, sa_key, 8) == 0)
|
||||
+ return;
|
||||
+
|
||||
+ status = mpath_prin_activepath(mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: register: pr in read reservation command failed.",
|
||||
+ mpp->wwid);
|
||||
+ return;
|
||||
+ }
|
||||
+ /* If there is no reservation, there's nothing to preempt */
|
||||
+ if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
+ return;
|
||||
+ /*
|
||||
+ * If there reservation is not held by the old key, you don't
|
||||
+ * want to preempt it
|
||||
+ */
|
||||
+ if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) != 0)
|
||||
+ return;
|
||||
+ /* Assume this key is being held by an inaccessable path on this
|
||||
+ * node. libmpathpersist has never worked if multiple nodes share
|
||||
+ * the same reservation key for a device
|
||||
+ */
|
||||
+ rq_type = resp.prin_descriptor.prin_readresv.scope_type & MPATH_PR_TYPE_MASK;
|
||||
+ rq_scope = (resp.prin_descriptor.prin_readresv.scope_type &
|
||||
+ MPATH_PR_SCOPE_MASK) >>
|
||||
+ 4;
|
||||
+ memcpy(paramp.key, sa_key, 8);
|
||||
+ memcpy(paramp.sa_key, key, 8);
|
||||
+ status = mpath_prout_common(mpp, MPATH_PROUT_PREE_SA, rq_scope,
|
||||
+ rq_type, ¶mp, noisy, NULL);
|
||||
+ if (status != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: register: pr preempt command failed.", mpp->wwid);
|
||||
+}
|
||||
+
|
||||
static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type,
|
||||
struct prout_param_descriptor * paramp, int noisy)
|
||||
@@ -370,43 +461,11 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
+ if (status == MPATH_PR_SUCCESS)
|
||||
+ preempt_missing_path(mpp, paramp->key, paramp->sa_key, noisy);
|
||||
return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
-static int
|
||||
-mpath_prout_common(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, struct prout_param_descriptor *paramp,
|
||||
- int noisy, struct path **pptr)
|
||||
-{
|
||||
- int i,j, ret;
|
||||
- struct pathgroup *pgp = NULL;
|
||||
- struct path *pp = NULL;
|
||||
- bool found = false;
|
||||
-
|
||||
- vector_foreach_slot (mpp->pg, pgp, j){
|
||||
- vector_foreach_slot (pgp->paths, pp, i){
|
||||
- if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
|
||||
- condlog (1, "%s: %s path not up. Skip",
|
||||
- mpp->wwid, pp->dev);
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
|
||||
- found = true;
|
||||
- ret = prout_do_scsi_ioctl(pp->dev, rq_servact, rq_scope,
|
||||
- rq_type, paramp, noisy);
|
||||
- if (ret == MPATH_PR_SUCCESS && pptr)
|
||||
- *pptr = pp;
|
||||
- if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
- return ret;
|
||||
- }
|
||||
- }
|
||||
- if (found)
|
||||
- return MPATH_PR_OTHER;
|
||||
- condlog (0, "%s: no path available", mpp->wwid);
|
||||
- return MPATH_PR_DMMP_ERROR;
|
||||
-}
|
||||
-
|
||||
static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type,
|
||||
struct prout_param_descriptor * paramp, int noisy)
|
182
0049-libmpathpersist-Handle-REGISTER-AND-IGNORE-changing-.patch
Normal file
182
0049-libmpathpersist-Handle-REGISTER-AND-IGNORE-changing-.patch
Normal file
@ -0,0 +1,182 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:57 -0400
|
||||
Subject: [PATCH] libmpathpersist: Handle REGISTER AND IGNORE changing key
|
||||
corner case
|
||||
|
||||
When you use REGISTER to change the reservation key of a registered
|
||||
multipath device, where the path holding the reservation is down,
|
||||
libmpathpersist will PREEMPT the failed path to move the reservation to
|
||||
a usable path, so the reservation key will be updated. However, when you
|
||||
use REGISTER AND IGNORE, you don't pass in the old key, so
|
||||
libmpathpersist can't use it to check against the key holding the
|
||||
reservation, which is necessary to know if it needs to PREEMPT.
|
||||
|
||||
Since the SCSI spec says that devices must ignore any passed-in key on
|
||||
REGISTER AND IGNORE, libmpathpersist can still use it to pass in the old
|
||||
key value. But unlike with REGISTER, the command won't fail if device
|
||||
isn't actually registered with the old key, so libmpathpersist needs to
|
||||
check that itself. To do this, it calls update_map_pr() just like
|
||||
multipathd does to check that the device is registered before
|
||||
registering new paths. However, libmpathpersist doesn't track the
|
||||
persistent reservation state like multipathd, so it needs to ask
|
||||
multipathd if it thinks the device is registered, using the "get
|
||||
prstatus map <map>" command.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 20 ++++++++++
|
||||
libmpathpersist/mpath_updatepr.c | 59 +++++++++++++++++++++--------
|
||||
libmpathpersist/mpathpr.h | 1 +
|
||||
3 files changed, 65 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 02b3e59a..19220d7a 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -654,6 +654,23 @@ fail_resume:
|
||||
return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * for MPATH_PROUT_REG_IGN_SA, we use the ignored paramp->key to store the
|
||||
+ * currently registered key.
|
||||
+ */
|
||||
+static void set_ignored_key(struct multipath *mpp, uint8_t *key)
|
||||
+{
|
||||
+ memset(key, 0, 8);
|
||||
+ if (!get_be64(mpp->reservation_key))
|
||||
+ return;
|
||||
+ if (get_prflag(mpp->alias) == PRFLAG_UNSET)
|
||||
+ return;
|
||||
+ update_map_pr(mpp, NULL);
|
||||
+ if (mpp->prflag != PRFLAG_SET)
|
||||
+ return;
|
||||
+ memcpy(key, &mpp->reservation_key, 8);
|
||||
+}
|
||||
+
|
||||
int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
int rq_servact, int rq_scope, unsigned int rq_type,
|
||||
struct prout_param_descriptor *paramp, int noisy)
|
||||
@@ -679,6 +696,9 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
select_skip_kpartx(conf, mpp);
|
||||
put_multipath_config(conf);
|
||||
|
||||
+ if (rq_servact == MPATH_PROUT_REG_IGN_SA)
|
||||
+ set_ignored_key(mpp, paramp->key);
|
||||
+
|
||||
memcpy(&prkey, paramp->sa_key, 8);
|
||||
if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c
|
||||
index 36bd777e..7cf82f50 100644
|
||||
--- a/libmpathpersist/mpath_updatepr.c
|
||||
+++ b/libmpathpersist/mpath_updatepr.c
|
||||
@@ -19,14 +19,12 @@
|
||||
#include "config.h"
|
||||
#include "uxsock.h"
|
||||
#include "mpathpr.h"
|
||||
+#include "structs.h"
|
||||
|
||||
-
|
||||
-static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
+static char *do_pr(char *alias, char *str)
|
||||
{
|
||||
int fd;
|
||||
- char str[256];
|
||||
char *reply;
|
||||
- int ret = 0;
|
||||
int timeout;
|
||||
struct config *conf;
|
||||
|
||||
@@ -37,24 +35,35 @@ static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
fd = mpath_connect();
|
||||
if (fd == -1) {
|
||||
condlog (0, "ux socket connect error");
|
||||
- return -1;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
- if (key)
|
||||
- snprintf(str,sizeof(str),"%s map %s key %s", cmd, alias, key);
|
||||
- else
|
||||
- snprintf(str,sizeof(str),"%s map %s", cmd, alias);
|
||||
condlog (2, "%s: pr message=%s", alias, str);
|
||||
if (send_packet(fd, str) != 0) {
|
||||
condlog(2, "%s: message=%s send error=%d", alias, str, errno);
|
||||
mpath_disconnect(fd);
|
||||
- return -1;
|
||||
+ return NULL;
|
||||
}
|
||||
- ret = recv_packet(fd, &reply, timeout);
|
||||
- if (ret < 0) {
|
||||
+ if (recv_packet(fd, &reply, timeout) < 0)
|
||||
condlog(2, "%s: message=%s recv error=%d", alias, str, errno);
|
||||
- ret = -1;
|
||||
- } else {
|
||||
+
|
||||
+ mpath_disconnect(fd);
|
||||
+ return reply;
|
||||
+}
|
||||
+
|
||||
+static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
+{
|
||||
+ char str[256];
|
||||
+ char *reply = NULL;
|
||||
+ int ret = -1;
|
||||
+
|
||||
+ if (key)
|
||||
+ snprintf(str, sizeof(str), "%s map %s key %s", cmd, alias, key);
|
||||
+ else
|
||||
+ snprintf(str, sizeof(str), "%s map %s", cmd, alias);
|
||||
+
|
||||
+ reply = do_pr(alias, str);
|
||||
+ if (reply) {
|
||||
condlog (2, "%s: message=%s reply=%s", alias, str, reply);
|
||||
if (reply && strncmp(reply,"ok", 2) == 0)
|
||||
ret = 0;
|
||||
@@ -63,10 +72,30 @@ static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
}
|
||||
|
||||
free(reply);
|
||||
- mpath_disconnect(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+int get_prflag(char *mapname)
|
||||
+{
|
||||
+ char str[256];
|
||||
+ char *reply;
|
||||
+ int prflag;
|
||||
+
|
||||
+ snprintf(str, sizeof(str), "getprstatus map %s", mapname);
|
||||
+ reply = do_pr(mapname, str);
|
||||
+ if (!reply)
|
||||
+ prflag = PRFLAG_UNKNOWN;
|
||||
+ else if (strncmp(reply, "unset", 5) == 0)
|
||||
+ prflag = PRFLAG_UNSET;
|
||||
+ else if (strncmp(reply, "set", 3) == 0)
|
||||
+ prflag = PRFLAG_SET;
|
||||
+ else
|
||||
+ prflag = PRFLAG_UNKNOWN;
|
||||
+
|
||||
+ free(reply);
|
||||
+ return prflag;
|
||||
+}
|
||||
+
|
||||
int update_prflag(char *mapname, int set) {
|
||||
return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus",
|
||||
NULL);
|
||||
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
|
||||
index 39a7d8ed..614be530 100644
|
||||
--- a/libmpathpersist/mpathpr.h
|
||||
+++ b/libmpathpersist/mpathpr.h
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
int update_prflag(char *mapname, int set);
|
||||
int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags);
|
||||
+int get_prflag(char *mapname);
|
||||
#define update_prkey(mapname, prkey) update_prkey_flags(mapname, prkey, 0)
|
||||
|
||||
#endif
|
249
0050-libmultipath-rename-prflag_value-enums.patch
Normal file
249
0050-libmultipath-rename-prflag_value-enums.patch
Normal file
@ -0,0 +1,249 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:58 -0400
|
||||
Subject: [PATCH] libmultipath: rename prflag_value enums
|
||||
|
||||
These will also be used by another variable, so make their name more
|
||||
generic.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 16 ++++++++--------
|
||||
libmpathpersist/mpath_updatepr.c | 8 ++++----
|
||||
libmultipath/structs.h | 9 ++++-----
|
||||
multipathd/cli_handlers.c | 22 +++++++++++-----------
|
||||
multipathd/main.c | 17 ++++++++---------
|
||||
5 files changed, 35 insertions(+), 37 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 19220d7a..d596b5bd 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -663,10 +663,10 @@ static void set_ignored_key(struct multipath *mpp, uint8_t *key)
|
||||
memset(key, 0, 8);
|
||||
if (!get_be64(mpp->reservation_key))
|
||||
return;
|
||||
- if (get_prflag(mpp->alias) == PRFLAG_UNSET)
|
||||
+ if (get_prflag(mpp->alias) == PR_UNSET)
|
||||
return;
|
||||
update_map_pr(mpp, NULL);
|
||||
- if (mpp->prflag != PRFLAG_SET)
|
||||
+ if (mpp->prflag != PR_SET)
|
||||
return;
|
||||
memcpy(key, &mpp->reservation_key, 8);
|
||||
}
|
||||
@@ -767,16 +767,16 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
struct prin_resp *resp;
|
||||
unsigned int i;
|
||||
int ret = MPATH_PR_OTHER, isFound;
|
||||
- bool was_set = (mpp->prflag == PRFLAG_SET);
|
||||
+ bool was_set = (mpp->prflag == PR_SET);
|
||||
|
||||
/* If pr is explicitly unset, it must be manually set */
|
||||
- if (mpp->prflag == PRFLAG_UNSET)
|
||||
+ if (mpp->prflag == PR_UNSET)
|
||||
return MPATH_PR_SKIP;
|
||||
|
||||
if (!get_be64(mpp->reservation_key))
|
||||
{
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
condlog(was_set ? 2 : 4,
|
||||
"%s: reservation_key not set in multipath.conf",
|
||||
mpp->alias);
|
||||
@@ -801,11 +801,11 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
|
||||
goto out;
|
||||
}
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
|
||||
if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
{
|
||||
@@ -840,7 +840,7 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
|
||||
if (isFound)
|
||||
{
|
||||
- mpp->prflag = PRFLAG_SET;
|
||||
+ mpp->prflag = PR_SET;
|
||||
condlog(was_set ? 3 : 2, "%s: key found. prflag set.", mpp->alias);
|
||||
} else
|
||||
condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c
|
||||
index 7cf82f50..c8fbe4a2 100644
|
||||
--- a/libmpathpersist/mpath_updatepr.c
|
||||
+++ b/libmpathpersist/mpath_updatepr.c
|
||||
@@ -84,13 +84,13 @@ int get_prflag(char *mapname)
|
||||
snprintf(str, sizeof(str), "getprstatus map %s", mapname);
|
||||
reply = do_pr(mapname, str);
|
||||
if (!reply)
|
||||
- prflag = PRFLAG_UNKNOWN;
|
||||
+ prflag = PR_UNKNOWN;
|
||||
else if (strncmp(reply, "unset", 5) == 0)
|
||||
- prflag = PRFLAG_UNSET;
|
||||
+ prflag = PR_UNSET;
|
||||
else if (strncmp(reply, "set", 3) == 0)
|
||||
- prflag = PRFLAG_SET;
|
||||
+ prflag = PR_SET;
|
||||
else
|
||||
- prflag = PRFLAG_UNKNOWN;
|
||||
+ prflag = PR_UNKNOWN;
|
||||
|
||||
free(reply);
|
||||
return prflag;
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index 5dc00fbc..24135aa6 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -406,11 +406,10 @@ struct path {
|
||||
|
||||
typedef int (pgpolicyfn) (struct multipath *, vector);
|
||||
|
||||
-
|
||||
-enum prflag_value {
|
||||
- PRFLAG_UNKNOWN,
|
||||
- PRFLAG_UNSET,
|
||||
- PRFLAG_SET,
|
||||
+enum pr_value {
|
||||
+ PR_UNKNOWN,
|
||||
+ PR_UNSET,
|
||||
+ PR_SET,
|
||||
};
|
||||
|
||||
struct multipath {
|
||||
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||||
index 117570e1..8e2e2cea 100644
|
||||
--- a/multipathd/cli_handlers.c
|
||||
+++ b/multipathd/cli_handlers.c
|
||||
@@ -1240,14 +1240,15 @@ cli_shutdown (void * v, struct strbuf *reply, void * data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const char *const pr_str[] = {
|
||||
+ [PR_UNKNOWN] = "unknown\n",
|
||||
+ [PR_UNSET] = "unset\n",
|
||||
+ [PR_SET] = "set\n",
|
||||
+};
|
||||
+
|
||||
static int
|
||||
cli_getprstatus (void * v, struct strbuf *reply, void * data)
|
||||
{
|
||||
- static const char * const prflag_str[] = {
|
||||
- [PRFLAG_UNKNOWN] = "unknown\n",
|
||||
- [PRFLAG_UNSET] = "unset\n",
|
||||
- [PRFLAG_SET] = "set\n",
|
||||
- };
|
||||
struct multipath * mpp;
|
||||
struct vectors * vecs = (struct vectors *)data;
|
||||
char * param = get_keyparam(v, KEY_MAP);
|
||||
@@ -1258,7 +1259,7 @@ cli_getprstatus (void * v, struct strbuf *reply, void * data)
|
||||
if (!mpp)
|
||||
return -ENODEV;
|
||||
|
||||
- append_strbuf_str(reply, prflag_str[mpp->prflag]);
|
||||
+ append_strbuf_str(reply, pr_str[mpp->prflag]);
|
||||
|
||||
condlog(3, "%s: reply = %s", param, get_strbuf_str(reply));
|
||||
|
||||
@@ -1278,12 +1279,11 @@ cli_setprstatus(void * v, struct strbuf *reply, void * data)
|
||||
if (!mpp)
|
||||
return -ENODEV;
|
||||
|
||||
- if (mpp->prflag != PRFLAG_SET) {
|
||||
- mpp->prflag = PRFLAG_SET;
|
||||
+ if (mpp->prflag != PR_SET) {
|
||||
+ mpp->prflag = PR_SET;
|
||||
condlog(2, "%s: prflag set", param);
|
||||
}
|
||||
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1300,8 +1300,8 @@ cli_unsetprstatus(void * v, struct strbuf *reply, void * data)
|
||||
if (!mpp)
|
||||
return -ENODEV;
|
||||
|
||||
- if (mpp->prflag != PRFLAG_UNSET) {
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ if (mpp->prflag != PR_UNSET) {
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
condlog(2, "%s: prflag unset", param);
|
||||
}
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 4a1b38e9..bd4342a3 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -644,7 +644,7 @@ pr_register_active_paths(struct multipath *mpp)
|
||||
|
||||
vector_foreach_slot (mpp->pg, pgp, i) {
|
||||
vector_foreach_slot (pgp->paths, pp, j) {
|
||||
- if (mpp->prflag == PRFLAG_UNSET)
|
||||
+ if (mpp->prflag == PR_UNSET)
|
||||
return;
|
||||
if ((pp->state == PATH_UP) || (pp->state == PATH_GHOST))
|
||||
mpath_pr_event_handle(pp);
|
||||
@@ -1253,7 +1253,7 @@ ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map)
|
||||
int start_waiter = 0;
|
||||
int ret;
|
||||
int ro;
|
||||
- unsigned char prflag = PRFLAG_UNSET;
|
||||
+ unsigned char prflag = PR_UNSET;
|
||||
|
||||
/*
|
||||
* need path UID to go any further
|
||||
@@ -1381,8 +1381,7 @@ rescan:
|
||||
sync_map_state(mpp);
|
||||
|
||||
if (retries >= 0) {
|
||||
- if ((mpp->prflag == PRFLAG_SET && prflag != PRFLAG_SET) ||
|
||||
- start_waiter)
|
||||
+ if ((mpp->prflag == PR_SET && prflag != PR_SET) || start_waiter)
|
||||
pr_register_active_paths(mpp);
|
||||
condlog(2, "%s [%s]: path added to devmap %s",
|
||||
pp->dev, pp->dev_t, mpp->alias);
|
||||
@@ -2645,7 +2644,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
}
|
||||
|
||||
if (newstate == PATH_UP || newstate == PATH_GHOST) {
|
||||
- if (pp->mpp->prflag != PRFLAG_UNSET) {
|
||||
+ if (pp->mpp->prflag != PR_UNSET) {
|
||||
int prflag = pp->mpp->prflag;
|
||||
/*
|
||||
* Check Persistent Reservation.
|
||||
@@ -2653,8 +2652,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
condlog(2, "%s: checking persistent "
|
||||
"reservation registration", pp->dev);
|
||||
mpath_pr_event_handle(pp);
|
||||
- if (pp->mpp->prflag == PRFLAG_SET &&
|
||||
- prflag != PRFLAG_SET)
|
||||
+ if (pp->mpp->prflag == PR_SET &&
|
||||
+ prflag != PR_SET)
|
||||
pr_register_active_paths(pp->mpp);
|
||||
}
|
||||
}
|
||||
@@ -3947,14 +3946,14 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
struct prout_param_descriptor *param;
|
||||
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
return;
|
||||
}
|
||||
|
||||
if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS)
|
||||
return;
|
||||
|
||||
- if (mpp->prflag != PRFLAG_SET)
|
||||
+ if (mpp->prflag != PR_SET)
|
||||
return;
|
||||
|
||||
param = (struct prout_param_descriptor *)calloc(1, sizeof(struct prout_param_descriptor));
|
@ -0,0 +1,44 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:10:59 -0400
|
||||
Subject: [PATCH] libmpathpersist: use a switch statement for prout command
|
||||
finalizing
|
||||
|
||||
Change the code at the end of do_mpath_persistent_reserve_out() to
|
||||
use a switch statement instead of multiple if statements. A future
|
||||
patch will add more actions here, and a switch statement looks cleaner.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 12 ++++++++----
|
||||
1 file changed, 8 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index d596b5bd..679e82be 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -744,15 +744,19 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
goto out1;
|
||||
}
|
||||
|
||||
- if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) ||
|
||||
- (rq_servact == MPATH_PROUT_REG_IGN_SA)))
|
||||
- {
|
||||
+ if (ret != MPATH_PR_SUCCESS)
|
||||
+ goto out1;
|
||||
+
|
||||
+ switch (rq_servact) {
|
||||
+ case MPATH_PROUT_REG_SA:
|
||||
+ case MPATH_PROUT_REG_IGN_SA:
|
||||
if (prkey == 0) {
|
||||
update_prflag(alias, 0);
|
||||
update_prkey(alias, 0);
|
||||
} else
|
||||
update_prflag(alias, 1);
|
||||
- } else if ((ret == MPATH_PR_SUCCESS) && (rq_servact == MPATH_PROUT_CLEAR_SA)) {
|
||||
+ break;
|
||||
+ case MPATH_PROUT_CLEAR_SA:
|
||||
update_prflag(alias, 0);
|
||||
update_prkey(alias, 0);
|
||||
}
|
444
0052-libmpathpersist-Add-safety-check-for-preempting-on-k.patch
Normal file
444
0052-libmpathpersist-Add-safety-check-for-preempting-on-k.patch
Normal file
@ -0,0 +1,444 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 14:11:00 -0400
|
||||
Subject: [PATCH] libmpathpersist: Add safety check for preempting on key
|
||||
change
|
||||
|
||||
When a reservation key is changed from one non-zero value to another,
|
||||
libmpathpersist checks if the old key is still holding the reservation,
|
||||
and preempts it if it is. This was only safe if two nodes never share
|
||||
the same key. If a node uses the same key as another node that is
|
||||
holding the reservation, and switches keys so that it no longer matches,
|
||||
it will end up preempting the reservation. This is clearly unexpected
|
||||
behavior, and it can come about by a simple accident of registering a
|
||||
device with the wrong key, and then immediately fixing it.
|
||||
|
||||
To handle this, add code to track if a device is the reservation holder
|
||||
to multipathd. multipathd now has three new commands "getprhold",
|
||||
"setprhold", and "unsetprhold". These commands work like the equivalent
|
||||
*prstatus commands. libmpathpersist calls setprhold on RESERVE commands
|
||||
and PREEMPT commands when the preempted key is holding the reservation
|
||||
and unsetprhold on RELEASE commands. Also, calling unsetprflag causes
|
||||
prhold to be unset as well, so CLEAR commands and REGISTER commands with
|
||||
a 0x0 service action key will also unset prhold. libmpathpersist() will
|
||||
also unset prhold if it notices that the device cannot be holding a
|
||||
reservation in preempt_missing_path().
|
||||
|
||||
When a new multipath device is created, its initial prhold state is
|
||||
PR_UNKNOWN until it checks the current reservation, just like with
|
||||
prflag. If multipathd ever finds that a device's registration has been
|
||||
preempted or cleared in update_map_pr(), it unsets prhold, just like
|
||||
with prflag.
|
||||
|
||||
Now, before libmpathpersist preempts a reservation when changing keys
|
||||
it also checks if multipathd thinks that the device is holding
|
||||
the reservation. If it does not, then libmpathpersist won't preempt
|
||||
the key. It will assume that another node is holding the reservation
|
||||
with the same key.
|
||||
|
||||
I should note that this safety check only stops a node not holding the
|
||||
reservation from preempting the node holding the reservation. If the
|
||||
node holding the reservation changes its key, but it fails to change the
|
||||
resevation key, because that path is down or gone, it will still issue
|
||||
the preempt to move the reservation to a usable path, even if another
|
||||
node is using the same key. This will remove the registrations for that
|
||||
other node. It also will not work correctly if multipathd stops tracking
|
||||
a device for some reason. It's only a best-effort safety check.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 85 ++++++++++++++++++++++++-----
|
||||
libmpathpersist/mpath_updatepr.c | 19 ++++++-
|
||||
libmpathpersist/mpathpr.h | 2 +
|
||||
libmultipath/structs.h | 1 +
|
||||
multipathd/callbacks.c | 3 +
|
||||
multipathd/cli.c | 4 +-
|
||||
multipathd/cli.h | 3 +
|
||||
multipathd/cli_handlers.c | 46 ++++++++++++++++
|
||||
multipathd/main.c | 34 +++++++++++-
|
||||
9 files changed, 179 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 679e82be..1948de8d 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -270,6 +270,10 @@ mpath_prout_common(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
* holding the reservation on a path that couldn't get its key updated,
|
||||
* either because it is down or no longer part of the multipath device,
|
||||
* you need to preempt the reservation to a usable path with the new key
|
||||
+ *
|
||||
+ * Also, it's possible that the reservation was preempted, and the device
|
||||
+ * is being re-registered. If it appears that is the case, clear
|
||||
+ * mpp->prhold in multipathd.
|
||||
*/
|
||||
void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
int noisy)
|
||||
@@ -282,12 +286,19 @@ void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
int status;
|
||||
|
||||
/*
|
||||
- * If you previously didn't have a key registered or you didn't
|
||||
- * switch to a different key, there's no need to preempt. Also, you
|
||||
- * can't preempt if you no longer have a registered key
|
||||
+ * If you previously didn't have a key registered, you can't
|
||||
+ * be holding the reservation. Also, you can't preempt if you
|
||||
+ * no longer have a registered key
|
||||
*/
|
||||
- if (memcmp(key, zero, 8) == 0 || memcmp(sa_key, zero, 8) == 0 ||
|
||||
- memcmp(key, sa_key, 8) == 0)
|
||||
+ if (memcmp(key, zero, 8) == 0 || memcmp(sa_key, zero, 8) == 0) {
|
||||
+ update_prhold(mpp->alias, false);
|
||||
+ return;
|
||||
+ }
|
||||
+ /*
|
||||
+ * If you didn't switch to a different key, there is no need to
|
||||
+ * preempt.
|
||||
+ */
|
||||
+ if (memcmp(key, sa_key, 8) == 0)
|
||||
return;
|
||||
|
||||
status = mpath_prin_activepath(mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
@@ -297,13 +308,29 @@ void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
return;
|
||||
}
|
||||
/* If there is no reservation, there's nothing to preempt */
|
||||
- if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
+ if (!resp.prin_descriptor.prin_readresv.additional_length) {
|
||||
+ update_prhold(mpp->alias, false);
|
||||
return;
|
||||
+ }
|
||||
/*
|
||||
* If there reservation is not held by the old key, you don't
|
||||
* want to preempt it
|
||||
*/
|
||||
- if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) != 0)
|
||||
+ if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) != 0) {
|
||||
+ /*
|
||||
+ * If reservation key doesn't match either the old or
|
||||
+ * the new key, then clear prhold.
|
||||
+ */
|
||||
+ if (memcmp(sa_key, resp.prin_descriptor.prin_readresv.key, 8) != 0)
|
||||
+ update_prhold(mpp->alias, false);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * If multipathd doesn't think it is holding the reservation, don't
|
||||
+ * preempt it
|
||||
+ */
|
||||
+ if (get_prhold(mpp->alias) != PR_SET)
|
||||
return;
|
||||
/* Assume this key is being held by an inaccessable path on this
|
||||
* node. libmpathpersist has never worked if multiple nodes share
|
||||
@@ -654,19 +681,36 @@ fail_resume:
|
||||
return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
+static int reservation_key_matches(struct multipath *mpp, uint8_t *key, int noisy)
|
||||
+{
|
||||
+ struct prin_resp resp = {{{.prgeneration = 0}}};
|
||||
+ int status;
|
||||
+
|
||||
+ status = mpath_prin_activepath(mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: pr in read reservation command failed.", mpp->wwid);
|
||||
+ return YNU_UNDEF;
|
||||
+ }
|
||||
+ if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
+ return YNU_NO;
|
||||
+ if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) == 0)
|
||||
+ return YNU_YES;
|
||||
+ return YNU_NO;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* for MPATH_PROUT_REG_IGN_SA, we use the ignored paramp->key to store the
|
||||
- * currently registered key.
|
||||
+ * currently registered key for use in preempt_missing_path(), but only if
|
||||
+ * the key is holding the reservation.
|
||||
*/
|
||||
static void set_ignored_key(struct multipath *mpp, uint8_t *key)
|
||||
{
|
||||
memset(key, 0, 8);
|
||||
if (!get_be64(mpp->reservation_key))
|
||||
return;
|
||||
- if (get_prflag(mpp->alias) == PR_UNSET)
|
||||
+ if (get_prhold(mpp->alias) == PR_UNSET)
|
||||
return;
|
||||
- update_map_pr(mpp, NULL);
|
||||
- if (mpp->prflag != PR_SET)
|
||||
+ if (reservation_key_matches(mpp, key, 0) == YNU_NO)
|
||||
return;
|
||||
memcpy(key, &mpp->reservation_key, 8);
|
||||
}
|
||||
@@ -680,6 +724,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
int ret;
|
||||
uint64_t prkey;
|
||||
struct config *conf;
|
||||
+ bool preempting_reservation = false;
|
||||
|
||||
ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
@@ -729,9 +774,12 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
case MPATH_PROUT_REG_IGN_SA:
|
||||
ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
break;
|
||||
- case MPATH_PROUT_RES_SA :
|
||||
- case MPATH_PROUT_PREE_SA :
|
||||
- case MPATH_PROUT_PREE_AB_SA :
|
||||
+ case MPATH_PROUT_PREE_SA:
|
||||
+ case MPATH_PROUT_PREE_AB_SA:
|
||||
+ if (reservation_key_matches(mpp, paramp->sa_key, noisy) == YNU_YES)
|
||||
+ preempting_reservation = true;
|
||||
+ /* fallthrough */
|
||||
+ case MPATH_PROUT_RES_SA:
|
||||
case MPATH_PROUT_CLEAR_SA:
|
||||
ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
paramp, noisy, NULL);
|
||||
@@ -759,6 +807,15 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
case MPATH_PROUT_CLEAR_SA:
|
||||
update_prflag(alias, 0);
|
||||
update_prkey(alias, 0);
|
||||
+ break;
|
||||
+ case MPATH_PROUT_RES_SA:
|
||||
+ case MPATH_PROUT_REL_SA:
|
||||
+ update_prhold(alias, (rq_servact == MPATH_PROUT_RES_SA));
|
||||
+ break;
|
||||
+ case MPATH_PROUT_PREE_SA:
|
||||
+ case MPATH_PROUT_PREE_AB_SA:
|
||||
+ if (preempting_reservation)
|
||||
+ update_prhold(alias, true);
|
||||
}
|
||||
out1:
|
||||
free(alias);
|
||||
diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c
|
||||
index c8fbe4a2..dd8dd48e 100644
|
||||
--- a/libmpathpersist/mpath_updatepr.c
|
||||
+++ b/libmpathpersist/mpath_updatepr.c
|
||||
@@ -75,13 +75,13 @@ static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
return ret;
|
||||
}
|
||||
|
||||
-int get_prflag(char *mapname)
|
||||
+static int do_get_pr(char *mapname, const char *cmd)
|
||||
{
|
||||
char str[256];
|
||||
char *reply;
|
||||
int prflag;
|
||||
|
||||
- snprintf(str, sizeof(str), "getprstatus map %s", mapname);
|
||||
+ snprintf(str, sizeof(str), "%s map %s", cmd, mapname);
|
||||
reply = do_pr(mapname, str);
|
||||
if (!reply)
|
||||
prflag = PR_UNKNOWN;
|
||||
@@ -96,11 +96,26 @@ int get_prflag(char *mapname)
|
||||
return prflag;
|
||||
}
|
||||
|
||||
+int get_prflag(char *mapname)
|
||||
+{
|
||||
+ return do_get_pr(mapname, "getprstatus");
|
||||
+}
|
||||
+
|
||||
+int get_prhold(char *mapname)
|
||||
+{
|
||||
+ return do_get_pr(mapname, "getprhold");
|
||||
+}
|
||||
+
|
||||
int update_prflag(char *mapname, int set) {
|
||||
return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus",
|
||||
NULL);
|
||||
}
|
||||
|
||||
+int update_prhold(char *mapname, bool set)
|
||||
+{
|
||||
+ return do_update_pr(mapname, (set) ? "setprhold" : "unsetprhold", NULL);
|
||||
+}
|
||||
+
|
||||
int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags) {
|
||||
char str[256];
|
||||
|
||||
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
|
||||
index 614be530..b668ef58 100644
|
||||
--- a/libmpathpersist/mpathpr.h
|
||||
+++ b/libmpathpersist/mpathpr.h
|
||||
@@ -9,6 +9,8 @@
|
||||
int update_prflag(char *mapname, int set);
|
||||
int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags);
|
||||
int get_prflag(char *mapname);
|
||||
+int get_prhold(char *mapname);
|
||||
+int update_prhold(char *mapname, bool set);
|
||||
#define update_prkey(mapname, prkey) update_prkey_flags(mapname, prkey, 0)
|
||||
|
||||
#endif
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index 24135aa6..6d0cd867 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -489,6 +489,7 @@ struct multipath {
|
||||
struct be64 reservation_key;
|
||||
uint8_t sa_flags;
|
||||
int prflag;
|
||||
+ int prhold;
|
||||
int all_tg_pt;
|
||||
struct gen_multipath generic_mp;
|
||||
bool fpin_must_reload;
|
||||
diff --git a/multipathd/callbacks.c b/multipathd/callbacks.c
|
||||
index fb87b280..b6b57f45 100644
|
||||
--- a/multipathd/callbacks.c
|
||||
+++ b/multipathd/callbacks.c
|
||||
@@ -69,4 +69,7 @@ void init_handler_callbacks(void)
|
||||
set_handler_callback(VRB_UNSETMARGINAL | Q1_PATH, HANDLER(cli_unset_marginal));
|
||||
set_handler_callback(VRB_UNSETMARGINAL | Q1_MAP,
|
||||
HANDLER(cli_unset_all_marginal));
|
||||
+ set_handler_callback(VRB_GETPRHOLD | Q1_MAP, HANDLER(cli_getprhold));
|
||||
+ set_handler_callback(VRB_SETPRHOLD | Q1_MAP, HANDLER(cli_setprhold));
|
||||
+ set_handler_callback(VRB_UNSETPRHOLD | Q1_MAP, HANDLER(cli_unsetprhold));
|
||||
}
|
||||
diff --git a/multipathd/cli.c b/multipathd/cli.c
|
||||
index 0c89b7cd..bccdda48 100644
|
||||
--- a/multipathd/cli.c
|
||||
+++ b/multipathd/cli.c
|
||||
@@ -224,7 +224,9 @@ load_keys (void)
|
||||
r += add_key(keys, "setmarginal", VRB_SETMARGINAL, 0);
|
||||
r += add_key(keys, "unsetmarginal", VRB_UNSETMARGINAL, 0);
|
||||
r += add_key(keys, "all", KEY_ALL, 0);
|
||||
-
|
||||
+ r += add_key(keys, "getprhold", VRB_GETPRHOLD, 0);
|
||||
+ r += add_key(keys, "setprhold", VRB_SETPRHOLD, 0);
|
||||
+ r += add_key(keys, "unsetprhold", VRB_UNSETPRHOLD, 0);
|
||||
|
||||
if (r) {
|
||||
free_keys(keys);
|
||||
diff --git a/multipathd/cli.h b/multipathd/cli.h
|
||||
index c6b79c9d..925575ad 100644
|
||||
--- a/multipathd/cli.h
|
||||
+++ b/multipathd/cli.h
|
||||
@@ -38,6 +38,9 @@ enum {
|
||||
VRB_UNSETMARGINAL = 23,
|
||||
VRB_SHUTDOWN = 24,
|
||||
VRB_QUIT = 25,
|
||||
+ VRB_GETPRHOLD = 26,
|
||||
+ VRB_SETPRHOLD = 27,
|
||||
+ VRB_UNSETPRHOLD = 28,
|
||||
|
||||
/* Qualifiers, values must be different from verbs */
|
||||
KEY_PATH = 65,
|
||||
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||||
index 8e2e2cea..94d0b63f 100644
|
||||
--- a/multipathd/cli_handlers.c
|
||||
+++ b/multipathd/cli_handlers.c
|
||||
@@ -1304,6 +1304,10 @@ cli_unsetprstatus(void * v, struct strbuf *reply, void * data)
|
||||
mpp->prflag = PR_UNSET;
|
||||
condlog(2, "%s: prflag unset", param);
|
||||
}
|
||||
+ if (mpp->prhold != PR_UNSET) {
|
||||
+ mpp->prhold = PR_UNSET;
|
||||
+ condlog(2, "%s: prhold unset (by clearing prflag)", param);
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1391,6 +1395,48 @@ cli_setprkey(void * v, struct strbuf *reply, void * data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int do_prhold(struct vectors *vecs, char *param, int prhold)
|
||||
+{
|
||||
+ struct multipath *mpp = find_mp_by_str(vecs->mpvec, param);
|
||||
+
|
||||
+ if (!mpp)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ if (mpp->prhold != prhold) {
|
||||
+ mpp->prhold = prhold;
|
||||
+ condlog(2, "%s: prhold %s", param, pr_str[prhold]);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int cli_setprhold(void *v, struct strbuf *reply, void *data)
|
||||
+{
|
||||
+ return do_prhold((struct vectors *)data, get_keyparam(v, KEY_MAP), PR_SET);
|
||||
+}
|
||||
+
|
||||
+static int cli_unsetprhold(void *v, struct strbuf *reply, void *data)
|
||||
+{
|
||||
+ return do_prhold((struct vectors *)data, get_keyparam(v, KEY_MAP), PR_UNSET);
|
||||
+}
|
||||
+
|
||||
+static int cli_getprhold(void *v, struct strbuf *reply, void *data)
|
||||
+{
|
||||
+ struct multipath *mpp;
|
||||
+ struct vectors *vecs = (struct vectors *)data;
|
||||
+ char *param = get_keyparam(v, KEY_MAP);
|
||||
+
|
||||
+ param = convert_dev(param, 0);
|
||||
+
|
||||
+ mpp = find_mp_by_str(vecs->mpvec, param);
|
||||
+ if (!mpp)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ append_strbuf_str(reply, pr_str[mpp->prhold]);
|
||||
+ condlog(3, "%s: reply = %s", param, get_strbuf_str(reply));
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int cli_set_marginal(void * v, struct strbuf *reply, void * data)
|
||||
{
|
||||
struct vectors * vecs = (struct vectors *)data;
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index bd4342a3..d1d209d3 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -3939,6 +3939,33 @@ main (int argc, char *argv[])
|
||||
return (child(NULL));
|
||||
}
|
||||
|
||||
+static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
+{
|
||||
+ struct prin_resp resp = {{{.prgeneration = 0}}};
|
||||
+ int status;
|
||||
+
|
||||
+ if (mpp->prflag == PR_UNSET) {
|
||||
+ mpp->prhold = PR_UNSET;
|
||||
+ return;
|
||||
+ }
|
||||
+ if (mpp->prflag != PR_SET || mpp->prhold != PR_UNKNOWN)
|
||||
+ return;
|
||||
+
|
||||
+ status = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RRES_SA, &resp, 0);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: pr in read reservation command failed: %d",
|
||||
+ mpp->wwid, status);
|
||||
+ return;
|
||||
+ }
|
||||
+ mpp->prhold = PR_UNSET;
|
||||
+ if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
+ return;
|
||||
+
|
||||
+ if (memcmp(&mpp->reservation_key,
|
||||
+ resp.prin_descriptor.prin_readresv.key, 8) == 0)
|
||||
+ mpp->prhold = PR_SET;
|
||||
+}
|
||||
+
|
||||
static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
struct multipath *mpp = pp->mpp;
|
||||
@@ -3950,8 +3977,13 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
return;
|
||||
}
|
||||
|
||||
- if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS)
|
||||
+ if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS) {
|
||||
+ if (mpp->prflag == PR_UNSET)
|
||||
+ mpp->prhold = PR_UNSET;
|
||||
return;
|
||||
+ }
|
||||
+
|
||||
+ check_prhold(mpp, pp);
|
||||
|
||||
if (mpp->prflag != PR_SET)
|
||||
return;
|
@ -0,0 +1,35 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:42 -0400
|
||||
Subject: [PATCH] libmpathpersist: remove update_map_pr code for NULL pp
|
||||
|
||||
Since update_map_pr is always called with pp set now, remove the code
|
||||
to handle being called with NULL pp.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 9 +--------
|
||||
1 file changed, 1 insertion(+), 8 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 1948de8d..04bbc455 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -850,15 +850,8 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
|
||||
return MPATH_PR_OTHER;
|
||||
}
|
||||
- if (!pp && count_active_paths(mpp) == 0) {
|
||||
- condlog(2, "%s: No available paths to check pr status", mpp->alias);
|
||||
- goto out;
|
||||
- }
|
||||
- if (pp)
|
||||
- ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
- else
|
||||
- ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
|
||||
+ ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
if (ret == MPATH_PR_ILLEGAL_REQ)
|
222
0054-libmpathpersist-move-update_map_pr-to-multipathd.patch
Normal file
222
0054-libmpathpersist-move-update_map_pr-to-multipathd.patch
Normal file
@ -0,0 +1,222 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:43 -0400
|
||||
Subject: [PATCH] libmpathpersist: move update_map_pr to multipathd
|
||||
|
||||
multipathd is now the only program that calls update_map_pr(), so move
|
||||
it there, and make it static. There are no other code changes.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/libmpathpersist.version | 1 -
|
||||
libmpathpersist/mpath_persist_int.c | 83 -------------------------
|
||||
libmpathpersist/mpath_persist_int.h | 3 +-
|
||||
multipathd/main.c | 80 ++++++++++++++++++++++++
|
||||
4 files changed, 81 insertions(+), 86 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/libmpathpersist.version b/libmpathpersist/libmpathpersist.version
|
||||
index faa4257b..8068920e 100644
|
||||
--- a/libmpathpersist/libmpathpersist.version
|
||||
+++ b/libmpathpersist/libmpathpersist.version
|
||||
@@ -33,5 +33,4 @@ __LIBMPATHPERSIST_INT_2.0.0 {
|
||||
mpath_alloc_prin_response;
|
||||
prin_do_scsi_ioctl;
|
||||
prout_do_scsi_ioctl;
|
||||
- update_map_pr;
|
||||
};
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 04bbc455..76bdbc63 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -821,86 +821,3 @@ out1:
|
||||
free(alias);
|
||||
return ret;
|
||||
}
|
||||
-
|
||||
-int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
-{
|
||||
- int noisy=0;
|
||||
- struct prin_resp *resp;
|
||||
- unsigned int i;
|
||||
- int ret = MPATH_PR_OTHER, isFound;
|
||||
- bool was_set = (mpp->prflag == PR_SET);
|
||||
-
|
||||
- /* If pr is explicitly unset, it must be manually set */
|
||||
- if (mpp->prflag == PR_UNSET)
|
||||
- return MPATH_PR_SKIP;
|
||||
-
|
||||
- if (!get_be64(mpp->reservation_key))
|
||||
- {
|
||||
- /* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
- mpp->prflag = PR_UNSET;
|
||||
- condlog(was_set ? 2 : 4,
|
||||
- "%s: reservation_key not set in multipath.conf",
|
||||
- mpp->alias);
|
||||
- return MPATH_PR_SKIP;
|
||||
- }
|
||||
-
|
||||
- resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
- if (!resp)
|
||||
- {
|
||||
- condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
|
||||
- return MPATH_PR_OTHER;
|
||||
- }
|
||||
-
|
||||
- ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
- if (ret != MPATH_PR_SUCCESS )
|
||||
- {
|
||||
- if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
- mpp->prflag = PR_UNSET;
|
||||
- condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
|
||||
- goto out;
|
||||
- }
|
||||
- mpp->prflag = PR_UNSET;
|
||||
-
|
||||
- if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
- {
|
||||
- condlog(was_set ? 1 : 3,
|
||||
- "%s: No key found. Device may not be registered. ",
|
||||
- mpp->alias);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- condlog(3, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
- get_be64(mpp->reservation_key));
|
||||
-
|
||||
- isFound =0;
|
||||
- for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
|
||||
- {
|
||||
- if (libmp_verbosity >= 3) {
|
||||
- condlog(3, "%s: PR IN READKEYS[%d] reservation key:",
|
||||
- mpp->alias, i);
|
||||
- dumpHex((char *)&resp->prin_descriptor.prin_readkeys
|
||||
- .key_list[i * 8],
|
||||
- 8, 1);
|
||||
- }
|
||||
-
|
||||
- if (!memcmp(&mpp->reservation_key,
|
||||
- &resp->prin_descriptor.prin_readkeys.key_list[i * 8],
|
||||
- 8)) {
|
||||
- condlog(3, "%s: reservation key found in pr in readkeys response",
|
||||
- mpp->alias);
|
||||
- isFound =1;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (isFound)
|
||||
- {
|
||||
- mpp->prflag = PR_SET;
|
||||
- condlog(was_set ? 3 : 2, "%s: key found. prflag set.", mpp->alias);
|
||||
- } else
|
||||
- condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
- mpp->alias);
|
||||
-
|
||||
-out:
|
||||
- free(resp);
|
||||
- return ret;
|
||||
-}
|
||||
diff --git a/libmpathpersist/mpath_persist_int.h b/libmpathpersist/mpath_persist_int.h
|
||||
index 73c95863..d9fc7448 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.h
|
||||
+++ b/libmpathpersist/mpath_persist_int.h
|
||||
@@ -19,7 +19,6 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int noisy);
|
||||
int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
|
||||
-void dumpHex(const char* , int len, int no_ascii);
|
||||
-int update_map_pr(struct multipath *mpp, struct path *pp);
|
||||
+void dumpHex(const char *, int len, int no_ascii);
|
||||
|
||||
#endif /* _MPATH_PERSIST_INT_H */
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index d1d209d3..0af9cb1c 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -3966,6 +3966,86 @@ static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
mpp->prhold = PR_SET;
|
||||
}
|
||||
|
||||
+static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
+{
|
||||
+ int noisy = 0;
|
||||
+ struct prin_resp *resp;
|
||||
+ unsigned int i;
|
||||
+ int ret = MPATH_PR_OTHER, isFound;
|
||||
+ bool was_set = (mpp->prflag == PR_SET);
|
||||
+
|
||||
+ /* If pr is explicitly unset, it must be manually set */
|
||||
+ if (mpp->prflag == PR_UNSET)
|
||||
+ return MPATH_PR_SKIP;
|
||||
+
|
||||
+ if (!get_be64(mpp->reservation_key)) {
|
||||
+ /* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
+ condlog(was_set ? 2 : 4,
|
||||
+ "%s: reservation_key not set in multipath.conf",
|
||||
+ mpp->alias);
|
||||
+ return MPATH_PR_SKIP;
|
||||
+ }
|
||||
+
|
||||
+ resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
+ if (!resp) {
|
||||
+ condlog(0, "%s : failed to alloc resp in update_map_pr",
|
||||
+ mpp->alias);
|
||||
+ return MPATH_PR_OTHER;
|
||||
+ }
|
||||
+
|
||||
+ ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
+ if (ret != MPATH_PR_SUCCESS) {
|
||||
+ if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
+ condlog(0, "%s : pr in read keys service action failed Error=%d",
|
||||
+ mpp->alias, ret);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
+
|
||||
+ if (resp->prin_descriptor.prin_readkeys.additional_length == 0) {
|
||||
+ condlog(was_set ? 1 : 3,
|
||||
+ "%s: No key found. Device may not be registered. ",
|
||||
+ mpp->alias);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ condlog(3, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
+ get_be64(mpp->reservation_key));
|
||||
+
|
||||
+ isFound = 0;
|
||||
+ for (i = 0;
|
||||
+ i < resp->prin_descriptor.prin_readkeys.additional_length / 8; i++) {
|
||||
+ if (libmp_verbosity >= 3) {
|
||||
+ condlog(3, "%s: PR IN READKEYS[%d] reservation key:",
|
||||
+ mpp->alias, i);
|
||||
+ dumpHex((char *)&resp->prin_descriptor.prin_readkeys
|
||||
+ .key_list[i * 8],
|
||||
+ 8, 1);
|
||||
+ }
|
||||
+
|
||||
+ if (!memcmp(&mpp->reservation_key,
|
||||
+ &resp->prin_descriptor.prin_readkeys.key_list[i * 8],
|
||||
+ 8)) {
|
||||
+ condlog(3, "%s: reservation key found in pr in readkeys response",
|
||||
+ mpp->alias);
|
||||
+ isFound = 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (isFound) {
|
||||
+ mpp->prflag = PR_SET;
|
||||
+ condlog(was_set ? 3 : 2, "%s: key found. prflag set.", mpp->alias);
|
||||
+ } else
|
||||
+ condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
+ mpp->alias);
|
||||
+
|
||||
+out:
|
||||
+ free(resp);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
struct multipath *mpp = pp->mpp;
|
139
0055-multipathd-clean-up-update_map_pr-and-mpath_pr_event.patch
Normal file
139
0055-multipathd-clean-up-update_map_pr-and-mpath_pr_event.patch
Normal file
@ -0,0 +1,139 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:44 -0400
|
||||
Subject: [PATCH] multipathd: clean up update_map_pr and mpath_pr_event_handle
|
||||
|
||||
Store the READ KEYS response and the prout_param_descriptor on the stack
|
||||
to avoid having to fail these functions for allocation reasons. Don't
|
||||
explicitly check for additional_length == 0, since the for-loop already
|
||||
handles that. Also cleanup formatting issues,remove redundant messages,
|
||||
and reduce the log level of others.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/main.c | 62 +++++++++++++++--------------------------------
|
||||
1 file changed, 19 insertions(+), 43 deletions(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 0af9cb1c..bc42f2fa 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -3968,8 +3968,7 @@ static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
|
||||
static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
{
|
||||
- int noisy = 0;
|
||||
- struct prin_resp *resp;
|
||||
+ struct prin_resp resp;
|
||||
unsigned int i;
|
||||
int ret = MPATH_PR_OTHER, isFound;
|
||||
bool was_set = (mpp->prflag == PR_SET);
|
||||
@@ -3987,51 +3986,34 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
return MPATH_PR_SKIP;
|
||||
}
|
||||
|
||||
- resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
- if (!resp) {
|
||||
- condlog(0, "%s : failed to alloc resp in update_map_pr",
|
||||
- mpp->alias);
|
||||
- return MPATH_PR_OTHER;
|
||||
- }
|
||||
+ memset(&resp, 0, sizeof(resp));
|
||||
|
||||
- ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
+ ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, &resp, 0);
|
||||
if (ret != MPATH_PR_SUCCESS) {
|
||||
if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
mpp->prflag = PR_UNSET;
|
||||
condlog(0, "%s : pr in read keys service action failed Error=%d",
|
||||
mpp->alias, ret);
|
||||
- goto out;
|
||||
+ return ret;
|
||||
}
|
||||
mpp->prflag = PR_UNSET;
|
||||
|
||||
- if (resp->prin_descriptor.prin_readkeys.additional_length == 0) {
|
||||
- condlog(was_set ? 1 : 3,
|
||||
- "%s: No key found. Device may not be registered. ",
|
||||
- mpp->alias);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- condlog(3, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
+ condlog(4, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
get_be64(mpp->reservation_key));
|
||||
|
||||
isFound = 0;
|
||||
for (i = 0;
|
||||
- i < resp->prin_descriptor.prin_readkeys.additional_length / 8; i++) {
|
||||
- if (libmp_verbosity >= 3) {
|
||||
- condlog(3, "%s: PR IN READKEYS[%d] reservation key:",
|
||||
+ i < resp.prin_descriptor.prin_readkeys.additional_length / 8; i++) {
|
||||
+ uint8_t *keyp = &resp.prin_descriptor.prin_readkeys.key_list[i * 8];
|
||||
+
|
||||
+ if (libmp_verbosity >= 4) {
|
||||
+ condlog(4, "%s: PR IN READKEYS[%d] reservation key:",
|
||||
mpp->alias, i);
|
||||
- dumpHex((char *)&resp->prin_descriptor.prin_readkeys
|
||||
- .key_list[i * 8],
|
||||
- 8, 1);
|
||||
+ dumpHex((char *)keyp, 8, 1);
|
||||
}
|
||||
|
||||
- if (!memcmp(&mpp->reservation_key,
|
||||
- &resp->prin_descriptor.prin_readkeys.key_list[i * 8],
|
||||
- 8)) {
|
||||
- condlog(3, "%s: reservation key found in pr in readkeys response",
|
||||
- mpp->alias);
|
||||
+ if (!memcmp(&mpp->reservation_key, keyp, 8))
|
||||
isFound = 1;
|
||||
- }
|
||||
}
|
||||
|
||||
if (isFound) {
|
||||
@@ -4041,16 +4023,14 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
mpp->alias);
|
||||
|
||||
-out:
|
||||
- free(resp);
|
||||
- return ret;
|
||||
+ return MPATH_PR_SUCCESS;
|
||||
}
|
||||
|
||||
static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
struct multipath *mpp = pp->mpp;
|
||||
int ret;
|
||||
- struct prout_param_descriptor *param;
|
||||
+ struct prout_param_descriptor param;
|
||||
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
mpp->prflag = PR_UNSET;
|
||||
@@ -4068,21 +4048,17 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
if (mpp->prflag != PR_SET)
|
||||
return;
|
||||
|
||||
- param = (struct prout_param_descriptor *)calloc(1, sizeof(struct prout_param_descriptor));
|
||||
- if (!param)
|
||||
- return;
|
||||
+ memset(¶m, 0, sizeof(param));
|
||||
|
||||
- param->sa_flags = mpp->sa_flags;
|
||||
- memcpy(param->sa_key, &mpp->reservation_key, 8);
|
||||
- param->num_transportid = 0;
|
||||
+ param.sa_flags = mpp->sa_flags;
|
||||
+ memcpy(param.sa_key, &mpp->reservation_key, 8);
|
||||
+ param.num_transportid = 0;
|
||||
|
||||
condlog(3, "device %s:%s", pp->dev, pp->mpp->wwid);
|
||||
|
||||
- ret = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REG_IGN_SA, 0, 0, param, 0);
|
||||
+ ret = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REG_IGN_SA, 0, 0, ¶m, 0);
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
condlog(0,"%s: Reservation registration failed. Error: %d", pp->dev, ret);
|
||||
}
|
||||
-
|
||||
- free(param);
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:45 -0400
|
||||
Subject: [PATCH] libmpathpersist: clean up duplicate function declarations
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.h | 1 -
|
||||
libmpathpersist/mpath_pr_ioctl.c | 10 +++-------
|
||||
mpathpersist/main.c | 2 --
|
||||
3 files changed, 3 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.h b/libmpathpersist/mpath_persist_int.h
|
||||
index d9fc7448..aefc17e4 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.h
|
||||
+++ b/libmpathpersist/mpath_persist_int.h
|
||||
@@ -6,7 +6,6 @@
|
||||
* but aren't part of the public libmpathpersist API.
|
||||
*/
|
||||
|
||||
-void * mpath_alloc_prin_response(int prin_sa);
|
||||
int do_mpath_persistent_reserve_in(vector curmp, vector pathvec,
|
||||
int fd, int rq_servact,
|
||||
struct prin_resp *resp, int noisy);
|
||||
diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c
|
||||
index 7e1d2896..dfdbbb65 100644
|
||||
--- a/libmpathpersist/mpath_pr_ioctl.c
|
||||
+++ b/libmpathpersist/mpath_pr_ioctl.c
|
||||
@@ -14,19 +14,15 @@
|
||||
#include "mpath_pr_ioctl.h"
|
||||
#include "mpath_persist.h"
|
||||
#include "unaligned.h"
|
||||
-
|
||||
#include "debug.h"
|
||||
#include "structs.h" /* FILE_NAME_SIZE */
|
||||
+#include "mpath_persist_int.h"
|
||||
|
||||
#define TIMEOUT 2000
|
||||
#define MAXRETRY 5
|
||||
|
||||
-int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp *resp, int noisy);
|
||||
-int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr,
|
||||
- SenseData_t *Sensedata);
|
||||
-void dumpHex(const char* str, int len, int no_ascii);
|
||||
-int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
|
||||
+int mpath_translate_response(char *dev, struct sg_io_hdr io_hdr,
|
||||
+ SenseData_t *Sensedata);
|
||||
uint32_t format_transportids(struct prout_param_descriptor *paramp);
|
||||
void convert_be32_to_cpu(uint32_t *num);
|
||||
void convert_be16_to_cpu(uint16_t *num);
|
||||
diff --git a/mpathpersist/main.c b/mpathpersist/main.c
|
||||
index b6617902..2cacafb7 100644
|
||||
--- a/mpathpersist/main.c
|
||||
+++ b/mpathpersist/main.c
|
||||
@@ -38,8 +38,6 @@ void mpath_print_buf_readcap(struct prin_resp *pr_buff);
|
||||
void mpath_print_buf_readfullstat(struct prin_resp *pr_buff);
|
||||
void mpath_print_buf_readresv(struct prin_resp *pr_buff);
|
||||
void mpath_print_buf_readkeys(struct prin_resp *pr_buff);
|
||||
-void dumpHex(const char* str, int len, int no_ascii);
|
||||
-void * mpath_alloc_prin_response(int prin_sa);
|
||||
void mpath_print_transport_id(struct prin_fulldescr *fdesc);
|
||||
int construct_transportid(const char * inp, struct transportid transid[], int num_transportids);
|
||||
|
148
0057-multipathd-wrap-setting-and-unsetting-prflag.patch
Normal file
148
0057-multipathd-wrap-setting-and-unsetting-prflag.patch
Normal file
@ -0,0 +1,148 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:46 -0400
|
||||
Subject: [PATCH] multipathd: wrap setting and unsetting prflag
|
||||
|
||||
When prflag is unset, prhold and sa_flags should also be unset. A future
|
||||
patch will add another variable to be set when prflag is set. Wrap all
|
||||
these actions in set_pr() and unset_pr().
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
multipathd/cli_handlers.c | 10 ++++------
|
||||
multipathd/main.c | 34 ++++++++++++++++++++--------------
|
||||
multipathd/main.h | 2 ++
|
||||
3 files changed, 26 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||||
index 94d0b63f..ee2764b9 100644
|
||||
--- a/multipathd/cli_handlers.c
|
||||
+++ b/multipathd/cli_handlers.c
|
||||
@@ -1280,7 +1280,7 @@ cli_setprstatus(void * v, struct strbuf *reply, void * data)
|
||||
return -ENODEV;
|
||||
|
||||
if (mpp->prflag != PR_SET) {
|
||||
- mpp->prflag = PR_SET;
|
||||
+ set_pr(mpp);
|
||||
condlog(2, "%s: prflag set", param);
|
||||
}
|
||||
|
||||
@@ -1301,12 +1301,10 @@ cli_unsetprstatus(void * v, struct strbuf *reply, void * data)
|
||||
return -ENODEV;
|
||||
|
||||
if (mpp->prflag != PR_UNSET) {
|
||||
- mpp->prflag = PR_UNSET;
|
||||
condlog(2, "%s: prflag unset", param);
|
||||
- }
|
||||
- if (mpp->prhold != PR_UNSET) {
|
||||
- mpp->prhold = PR_UNSET;
|
||||
- condlog(2, "%s: prhold unset (by clearing prflag)", param);
|
||||
+ if (mpp->prhold != PR_UNSET)
|
||||
+ condlog(2, "%s: prhold unset (by clearing prflag)", param);
|
||||
+ unset_pr(mpp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index bc42f2fa..e29ab2b8 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -3944,10 +3944,6 @@ static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
struct prin_resp resp = {{{.prgeneration = 0}}};
|
||||
int status;
|
||||
|
||||
- if (mpp->prflag == PR_UNSET) {
|
||||
- mpp->prhold = PR_UNSET;
|
||||
- return;
|
||||
- }
|
||||
if (mpp->prflag != PR_SET || mpp->prhold != PR_UNKNOWN)
|
||||
return;
|
||||
|
||||
@@ -3966,6 +3962,18 @@ static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
mpp->prhold = PR_SET;
|
||||
}
|
||||
|
||||
+void set_pr(struct multipath *mpp)
|
||||
+{
|
||||
+ mpp->prflag = PR_SET;
|
||||
+}
|
||||
+
|
||||
+void unset_pr(struct multipath *mpp)
|
||||
+{
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
+ mpp->prhold = PR_UNSET;
|
||||
+ mpp->sa_flags = 0;
|
||||
+}
|
||||
+
|
||||
static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
{
|
||||
struct prin_resp resp;
|
||||
@@ -3979,7 +3987,7 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
|
||||
if (!get_be64(mpp->reservation_key)) {
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
- mpp->prflag = PR_UNSET;
|
||||
+ unset_pr(mpp);
|
||||
condlog(was_set ? 2 : 4,
|
||||
"%s: reservation_key not set in multipath.conf",
|
||||
mpp->alias);
|
||||
@@ -3991,12 +3999,11 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, &resp, 0);
|
||||
if (ret != MPATH_PR_SUCCESS) {
|
||||
if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
- mpp->prflag = PR_UNSET;
|
||||
+ unset_pr(mpp);
|
||||
condlog(0, "%s : pr in read keys service action failed Error=%d",
|
||||
mpp->alias, ret);
|
||||
return ret;
|
||||
}
|
||||
- mpp->prflag = PR_UNSET;
|
||||
|
||||
condlog(4, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
get_be64(mpp->reservation_key));
|
||||
@@ -4017,11 +4024,13 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
}
|
||||
|
||||
if (isFound) {
|
||||
- mpp->prflag = PR_SET;
|
||||
+ set_pr(mpp);
|
||||
condlog(was_set ? 3 : 2, "%s: key found. prflag set.", mpp->alias);
|
||||
- } else
|
||||
+ } else {
|
||||
+ unset_pr(mpp);
|
||||
condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
mpp->alias);
|
||||
+ }
|
||||
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
@@ -4033,15 +4042,12 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
struct prout_param_descriptor param;
|
||||
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
- mpp->prflag = PR_UNSET;
|
||||
+ unset_pr(mpp);
|
||||
return;
|
||||
}
|
||||
|
||||
- if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS) {
|
||||
- if (mpp->prflag == PR_UNSET)
|
||||
- mpp->prhold = PR_UNSET;
|
||||
+ if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS)
|
||||
return;
|
||||
- }
|
||||
|
||||
check_prhold(mpp, pp);
|
||||
|
||||
diff --git a/multipathd/main.h b/multipathd/main.h
|
||||
index 4fcd6402..c9b3e0fd 100644
|
||||
--- a/multipathd/main.h
|
||||
+++ b/multipathd/main.h
|
||||
@@ -52,4 +52,6 @@ bool check_path_wwid_change(struct path *pp);
|
||||
int finish_path_init(struct path *pp, struct vectors * vecs);
|
||||
int resize_map(struct multipath *mpp, unsigned long long size,
|
||||
struct vectors *vecs);
|
||||
+void set_pr(struct multipath *mpp);
|
||||
+void unset_pr(struct multipath *mpp);
|
||||
#endif /* MAIN_H */
|
145
0058-multipathd-unregister-PR-key-when-path-is-restored-i.patch
Normal file
145
0058-multipathd-unregister-PR-key-when-path-is-restored-i.patch
Normal file
@ -0,0 +1,145 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:47 -0400
|
||||
Subject: [PATCH] multipathd: unregister PR key when path is restored if
|
||||
necessary
|
||||
|
||||
It is possible that a path was unavailable and either the registered PR
|
||||
key was removed or the registered PR key was changed and then that new
|
||||
key was preempted. In both of these situations, this path will still
|
||||
have a registered key (just not one that matches mpp->reservation_key)
|
||||
but it should not have one. If the path becomes usable again in this
|
||||
state, it may allow the multipath device to access storage that it
|
||||
shouldn't be allowed to access.
|
||||
|
||||
To deal with this, track if a multipath device ever had a registered PR
|
||||
key. If so, and the device no longer has a registered key, explicitly
|
||||
clear the key when paths get restored.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmultipath/structs.h | 2 ++
|
||||
multipathd/main.c | 46 ++++++++++++++++++++++++++++++++----------
|
||||
2 files changed, 37 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index 6d0cd867..90127641 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -491,6 +491,8 @@ struct multipath {
|
||||
int prflag;
|
||||
int prhold;
|
||||
int all_tg_pt;
|
||||
+ bool ever_registered_pr;
|
||||
+
|
||||
struct gen_multipath generic_mp;
|
||||
bool fpin_must_reload;
|
||||
};
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index e29ab2b8..484c8ac1 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -2644,7 +2644,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
}
|
||||
|
||||
if (newstate == PATH_UP || newstate == PATH_GHOST) {
|
||||
- if (pp->mpp->prflag != PR_UNSET) {
|
||||
+ if (pp->mpp->prflag != PR_UNSET ||
|
||||
+ pp->mpp->ever_registered_pr) {
|
||||
int prflag = pp->mpp->prflag;
|
||||
/*
|
||||
* Check Persistent Reservation.
|
||||
@@ -3964,6 +3965,7 @@ static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
|
||||
void set_pr(struct multipath *mpp)
|
||||
{
|
||||
+ mpp->ever_registered_pr = true;
|
||||
mpp->prflag = PR_SET;
|
||||
}
|
||||
|
||||
@@ -3974,16 +3976,21 @@ void unset_pr(struct multipath *mpp)
|
||||
mpp->sa_flags = 0;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Returns MPATH_PR_SUCCESS unless if fails to read the PR keys. If
|
||||
+ * MPATH_PR_SUCCESS is returned, mpp->prflag will be either PR_SET or
|
||||
+ * PR_UNSET.
|
||||
+ */
|
||||
static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
{
|
||||
struct prin_resp resp;
|
||||
unsigned int i;
|
||||
- int ret = MPATH_PR_OTHER, isFound;
|
||||
+ int ret, isFound;
|
||||
bool was_set = (mpp->prflag == PR_SET);
|
||||
|
||||
/* If pr is explicitly unset, it must be manually set */
|
||||
if (mpp->prflag == PR_UNSET)
|
||||
- return MPATH_PR_SKIP;
|
||||
+ return MPATH_PR_SUCCESS;
|
||||
|
||||
if (!get_be64(mpp->reservation_key)) {
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
@@ -3991,7 +3998,7 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
condlog(was_set ? 2 : 4,
|
||||
"%s: reservation_key not set in multipath.conf",
|
||||
mpp->alias);
|
||||
- return MPATH_PR_SKIP;
|
||||
+ return MPATH_PR_SUCCESS;
|
||||
}
|
||||
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
@@ -4040,6 +4047,7 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
struct multipath *mpp = pp->mpp;
|
||||
int ret;
|
||||
struct prout_param_descriptor param;
|
||||
+ bool clear_reg = false;
|
||||
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
unset_pr(mpp);
|
||||
@@ -4051,20 +4059,36 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
|
||||
check_prhold(mpp, pp);
|
||||
|
||||
- if (mpp->prflag != PR_SET)
|
||||
- return;
|
||||
+ if (mpp->prflag != PR_SET) {
|
||||
+ if (!mpp->ever_registered_pr)
|
||||
+ return;
|
||||
+ /*
|
||||
+ * This path may have been unusable and either the
|
||||
+ * registration was cleared or the registered
|
||||
+ * key was switched and then that new key was preempted.
|
||||
+ * In either case, this path should not have a registration
|
||||
+ * but it might still have one, just with a different
|
||||
+ * key than mpp->reservation_key is currently set to.
|
||||
+ * clear it to be sure.
|
||||
+ */
|
||||
+ clear_reg = true;
|
||||
+ }
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
|
||||
- param.sa_flags = mpp->sa_flags;
|
||||
- memcpy(param.sa_key, &mpp->reservation_key, 8);
|
||||
- param.num_transportid = 0;
|
||||
+ if (!clear_reg) {
|
||||
+ param.sa_flags = mpp->sa_flags;
|
||||
+ memcpy(param.sa_key, &mpp->reservation_key, 8);
|
||||
+ param.num_transportid = 0;
|
||||
+ }
|
||||
|
||||
- condlog(3, "device %s:%s", pp->dev, pp->mpp->wwid);
|
||||
+ condlog(3, "%s registration for device %s:%s",
|
||||
+ clear_reg ? "Clearing" : "Setting", pp->dev, pp->mpp->wwid);
|
||||
|
||||
ret = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REG_IGN_SA, 0, 0, ¶m, 0);
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
- condlog(0,"%s: Reservation registration failed. Error: %d", pp->dev, ret);
|
||||
+ condlog(0, "%s: %s reservation registration failed. Error: %d",
|
||||
+ clear_reg ? "Clearing" : "Setting", pp->dev, ret);
|
||||
}
|
||||
}
|
112
0059-libmpathpersist-Fix-up-reservation_key-checking.patch
Normal file
112
0059-libmpathpersist-Fix-up-reservation_key-checking.patch
Normal file
@ -0,0 +1,112 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:48 -0400
|
||||
Subject: [PATCH] libmpathpersist: Fix-up reservation_key checking
|
||||
|
||||
The reservation key checking in do_mpath_persistent_reserve_out() was
|
||||
slightly wrong. It allowed invalid keys for preempting. It now correctly
|
||||
checks the reservation key for the preempt commands.
|
||||
|
||||
It also was a little overly strict in some places. Formerly, it only
|
||||
allowed registering from any key to the configured key or registering
|
||||
from the configured key to any key (as long as you use the prkeys file).
|
||||
Now it also allows unregistering from any key and registering an
|
||||
unregistered device to any key (as long as you use the prkeys file).
|
||||
|
||||
Also, clarify the code by replacing prkey with a bool tracking if you
|
||||
are registering or unregistering.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 53 +++++++++++++++++++++++------
|
||||
1 file changed, 42 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 76bdbc63..ded1af38 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -722,9 +722,9 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
struct multipath *mpp;
|
||||
char *alias;
|
||||
int ret;
|
||||
- uint64_t prkey;
|
||||
+ uint64_t zerokey = 0;
|
||||
struct config *conf;
|
||||
- bool preempting_reservation = false;
|
||||
+ bool unregistering, preempting_reservation = false;
|
||||
|
||||
ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
@@ -744,11 +744,12 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
if (rq_servact == MPATH_PROUT_REG_IGN_SA)
|
||||
set_ignored_key(mpp, paramp->key);
|
||||
|
||||
- memcpy(&prkey, paramp->sa_key, 8);
|
||||
- if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey &&
|
||||
+ unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
|
||||
+ if (mpp->prkey_source == PRKEY_SOURCE_FILE && !unregistering &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
(rq_servact == MPATH_PROUT_REG_SA &&
|
||||
(!get_be64(mpp->reservation_key) ||
|
||||
+ memcmp(paramp->key, &zerokey, 8) == 0 ||
|
||||
memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) {
|
||||
memcpy(&mpp->reservation_key, paramp->sa_key, 8);
|
||||
if (update_prkey_flags(alias, get_be64(mpp->reservation_key),
|
||||
@@ -760,12 +761,42 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
}
|
||||
}
|
||||
|
||||
- if (memcmp(paramp->key, &mpp->reservation_key, 8) &&
|
||||
- memcmp(paramp->sa_key, &mpp->reservation_key, 8) &&
|
||||
- (prkey || rq_servact != MPATH_PROUT_REG_IGN_SA)) {
|
||||
- condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64, alias, get_be64(mpp->reservation_key));
|
||||
- ret = MPATH_PR_SYNTAX_ERROR;
|
||||
- goto out1;
|
||||
+ /*
|
||||
+ * If you are registering a non-zero key, mpp->reservation_key
|
||||
+ * must be set and must equal paramp->sa_key.
|
||||
+ * If you're not registering a key, mpp->reservation_key must be
|
||||
+ * set, and must equal paramp->key
|
||||
+ * If you updated the reservation key above, then you cannot fail
|
||||
+ * these checks, since mpp->reservation_key has already been set
|
||||
+ * to match paramp->sa_key, and if you are registering a non-zero
|
||||
+ * key, then it must be set to a non-zero value.
|
||||
+ */
|
||||
+ if ((rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
+ rq_servact == MPATH_PROUT_REG_SA)) {
|
||||
+ if (!unregistering && !get_be64(mpp->reservation_key)) {
|
||||
+ condlog(0, "%s: no configured reservation key", alias);
|
||||
+ ret = MPATH_PR_SYNTAX_ERROR;
|
||||
+ goto out1;
|
||||
+ }
|
||||
+ if (!unregistering &&
|
||||
+ memcmp(paramp->sa_key, &mpp->reservation_key, 8)) {
|
||||
+ condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64,
|
||||
+ alias, get_be64(mpp->reservation_key));
|
||||
+ ret = MPATH_PR_SYNTAX_ERROR;
|
||||
+ goto out1;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (!get_be64(mpp->reservation_key)) {
|
||||
+ condlog(0, "%s: no configured reservation key", alias);
|
||||
+ ret = MPATH_PR_SYNTAX_ERROR;
|
||||
+ goto out1;
|
||||
+ }
|
||||
+ if (memcmp(paramp->key, &mpp->reservation_key, 8)) {
|
||||
+ condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64,
|
||||
+ alias, get_be64(mpp->reservation_key));
|
||||
+ ret = MPATH_PR_SYNTAX_ERROR;
|
||||
+ goto out1;
|
||||
+ }
|
||||
}
|
||||
|
||||
switch(rq_servact)
|
||||
@@ -798,7 +829,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
switch (rq_servact) {
|
||||
case MPATH_PROUT_REG_SA:
|
||||
case MPATH_PROUT_REG_IGN_SA:
|
||||
- if (prkey == 0) {
|
||||
+ if (unregistering) {
|
||||
update_prflag(alias, 0);
|
||||
update_prkey(alias, 0);
|
||||
} else
|
139
0060-libmpathpersist-change-how-reservation-conflicts-are.patch
Normal file
139
0060-libmpathpersist-change-how-reservation-conflicts-are.patch
Normal file
@ -0,0 +1,139 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:49 -0400
|
||||
Subject: [PATCH] libmpathpersist: change how reservation conflicts are handled
|
||||
|
||||
If registering a key on a path fails with a reservation conflict in
|
||||
mpath_prout_reg(), libmpathpersist currently tries to roll back the
|
||||
registration. This code doesn't always make much sense. First, it
|
||||
updates the configured key, but doesn't fix it if it does a rollback.
|
||||
Second, it always rolls the key back to 0x0, unregistering paths that
|
||||
may have been previously registered. These rollback only happen on the
|
||||
paths where the registration succeeded, meaning that they were in the
|
||||
expected state when the command was run. The paths where the command
|
||||
failed, that were in an unexpected state, remain in that state.
|
||||
|
||||
The code no longer attempts to rollback registrations that failed
|
||||
with a reservation conflict. Instead, it checks that at least one
|
||||
path was in the expected state and was successfully registered. If
|
||||
so, then it assumes that the registration command was a resonable one
|
||||
and retries it on the paths that failed with a reservation conflict.
|
||||
But instead of using MPATH_PROUT_REG_SA, it uses MPATH_PROUT_REG_IGN_SA
|
||||
so that it will ignore the current key. This will keep it from
|
||||
failing with a reservation conflict because the path doesn't have the
|
||||
expected key registered on it. If path reservations failed for reasons
|
||||
other than a reservation conflict, the command still returns failure.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 71 ++++++++++++++++++-----------
|
||||
1 file changed, 45 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index ded1af38..e2dc5773 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -356,13 +356,13 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int i, j, k;
|
||||
struct pathgroup *pgp = NULL;
|
||||
struct path *pp = NULL;
|
||||
- int rollback = 0;
|
||||
+ bool can_retry = false;
|
||||
+ bool need_retry = false;
|
||||
int active_pathcount=0;
|
||||
int rc;
|
||||
int count=0;
|
||||
int status = MPATH_PR_SUCCESS;
|
||||
int all_tg_pt;
|
||||
- uint64_t sa_key = 0;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -451,43 +451,62 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
condlog (0, "%s: Thread[%d] failed to join thread %d", mpp->wwid, i, rc);
|
||||
}
|
||||
}
|
||||
- if (!rollback && (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)){
|
||||
- rollback = 1;
|
||||
- sa_key = get_unaligned_be64(¶mp->sa_key[0]);
|
||||
- status = MPATH_PR_RESERV_CONFLICT ;
|
||||
- }
|
||||
- if (!rollback && (status == MPATH_PR_SUCCESS)){
|
||||
+ /*
|
||||
+ * We only retry if there is at least one registration that
|
||||
+ * returned a reservation conflict (which we need to retry)
|
||||
+ * and at least one registration the return success, so we
|
||||
+ * know that the command worked on some of the paths. If
|
||||
+ * the registation fails on all paths, then it wasn't a
|
||||
+ * valid request, so there's no need to retry.
|
||||
+ */
|
||||
+ if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
|
||||
+ need_retry = true;
|
||||
+ else if (thread[i].param.status == MPATH_PR_SUCCESS)
|
||||
+ can_retry = true;
|
||||
+ else if (status == MPATH_PR_SUCCESS)
|
||||
status = thread[i].param.status;
|
||||
- }
|
||||
}
|
||||
- if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){
|
||||
- condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid);
|
||||
- memcpy(¶mp->key, ¶mp->sa_key, 8);
|
||||
- memset(¶mp->sa_key, 0, 8);
|
||||
- for( i=0 ; i < count ; i++){
|
||||
- if(thread[i].param.status == MPATH_PR_SUCCESS) {
|
||||
- rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn,
|
||||
- (void *)(&thread[i].param));
|
||||
- if (rc){
|
||||
- condlog (0, "%s: failed to create thread for rollback. %d", mpp->wwid, rc);
|
||||
- thread[i].param.status = MPATH_PR_THREAD_ERROR;
|
||||
- }
|
||||
- } else
|
||||
+ if (need_retry && can_retry && rq_servact == MPATH_PROUT_REG_SA &&
|
||||
+ status == MPATH_PR_SUCCESS) {
|
||||
+ condlog(3, "%s: ERROR: initiating pr out retry", mpp->wwid);
|
||||
+ for (i = 0; i < count; i++) {
|
||||
+ if (thread[i].param.status != MPATH_PR_RESERV_CONFLICT) {
|
||||
thread[i].param.status = MPATH_PR_SKIP;
|
||||
+ continue;
|
||||
+ }
|
||||
+ /*
|
||||
+ * retry using MPATH_PROUT_REG_IGN_SA to avoid
|
||||
+ * conflicts. We already know that some paths
|
||||
+ * succeeded using MPATH_PROUT_REG_SA.
|
||||
+ */
|
||||
+ thread[i].param.rq_servact = MPATH_PROUT_REG_IGN_SA;
|
||||
+ rc = pthread_create(&thread[i].id, &attr,
|
||||
+ mpath_prout_pthread_fn,
|
||||
+ (void *)(&thread[i].param));
|
||||
+ if (rc) {
|
||||
+ condlog(0, "%s: failed to create thread for retry. %d",
|
||||
+ mpp->wwid, rc);
|
||||
+ thread[i].param.status = MPATH_PR_THREAD_ERROR;
|
||||
+ }
|
||||
}
|
||||
- for(i=0; i < count ; i++){
|
||||
+ for (i = 0; i < count; i++) {
|
||||
if (thread[i].param.status != MPATH_PR_SKIP &&
|
||||
thread[i].param.status != MPATH_PR_THREAD_ERROR) {
|
||||
rc = pthread_join(thread[i].id, NULL);
|
||||
- if (rc){
|
||||
- condlog (3, "%s: failed to join thread while rolling back %d",
|
||||
- mpp->wwid, i);
|
||||
+ if (rc) {
|
||||
+ condlog(3, "%s: failed to join thread while retrying %d",
|
||||
+ mpp->wwid, i);
|
||||
}
|
||||
+ if (status == MPATH_PR_SUCCESS)
|
||||
+ status = thread[i].param.status;
|
||||
}
|
||||
}
|
||||
+ need_retry = false;
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
+ if (need_retry)
|
||||
+ status = MPATH_PR_RESERV_CONFLICT;
|
||||
if (status == MPATH_PR_SUCCESS)
|
||||
preempt_missing_path(mpp, paramp->key, paramp->sa_key, noisy);
|
||||
return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:50 -0400
|
||||
Subject: [PATCH] libmpathpersist: Clear prkey in multipathd before
|
||||
unregistering
|
||||
|
||||
When you register or switch keys in libmpathpersist, it updates
|
||||
mpp->reservation_key in multipathd before doing the registration. This
|
||||
means that any paths that come online while you are doing the
|
||||
registration get the new key registered. libmpathpersist didn't do
|
||||
this when unregistering a key. This could cause the same problem. A
|
||||
path that got restored while unregistering the device could end up
|
||||
getting the old key registered on it. Fix this by unsetting the key
|
||||
before doing the unregister, instead of afterwards.
|
||||
|
||||
There is still a race condition associated with updating
|
||||
mpp->reservation_key before doing the registration (but not on
|
||||
unregistration). This will be dealt with by a future patch.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index e2dc5773..dd056135 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -764,7 +764,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
set_ignored_key(mpp, paramp->key);
|
||||
|
||||
unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
|
||||
- if (mpp->prkey_source == PRKEY_SOURCE_FILE && !unregistering &&
|
||||
+ if (mpp->prkey_source == PRKEY_SOURCE_FILE &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
(rq_servact == MPATH_PROUT_REG_SA &&
|
||||
(!get_be64(mpp->reservation_key) ||
|
||||
@@ -848,10 +848,9 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
switch (rq_servact) {
|
||||
case MPATH_PROUT_REG_SA:
|
||||
case MPATH_PROUT_REG_IGN_SA:
|
||||
- if (unregistering) {
|
||||
+ if (unregistering)
|
||||
update_prflag(alias, 0);
|
||||
- update_prkey(alias, 0);
|
||||
- } else
|
||||
+ else
|
||||
update_prflag(alias, 1);
|
||||
break;
|
||||
case MPATH_PROUT_CLEAR_SA:
|
@ -0,0 +1,28 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:51 -0400
|
||||
Subject: [PATCH] libmpathpersist: only clear the key if we are using the
|
||||
prkeys file
|
||||
|
||||
Otherwise this request will create a useless prkeys file.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index dd056135..a6940d12 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -855,7 +855,8 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
break;
|
||||
case MPATH_PROUT_CLEAR_SA:
|
||||
update_prflag(alias, 0);
|
||||
- update_prkey(alias, 0);
|
||||
+ if (mpp->prkey_source == PRKEY_SOURCE_FILE)
|
||||
+ update_prkey(alias, 0);
|
||||
break;
|
||||
case MPATH_PROUT_RES_SA:
|
||||
case MPATH_PROUT_REL_SA:
|
@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:52 -0400
|
||||
Subject: [PATCH] libmpathpersist: Restore old reservation key on failure
|
||||
|
||||
If we updated the key and then failed, restore the old key.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index a6940d12..302bebc2 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -742,8 +742,10 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
char *alias;
|
||||
int ret;
|
||||
uint64_t zerokey = 0;
|
||||
+ struct be64 oldkey = {0};
|
||||
struct config *conf;
|
||||
bool unregistering, preempting_reservation = false;
|
||||
+ bool updated_prkey = false;
|
||||
|
||||
ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
@@ -770,6 +772,8 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
(!get_be64(mpp->reservation_key) ||
|
||||
memcmp(paramp->key, &zerokey, 8) == 0 ||
|
||||
memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) {
|
||||
+ updated_prkey = true;
|
||||
+ memcpy(&oldkey, &mpp->reservation_key, 8);
|
||||
memcpy(&mpp->reservation_key, paramp->sa_key, 8);
|
||||
if (update_prkey_flags(alias, get_be64(mpp->reservation_key),
|
||||
paramp->sa_flags)) {
|
||||
@@ -842,8 +846,12 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
goto out1;
|
||||
}
|
||||
|
||||
- if (ret != MPATH_PR_SUCCESS)
|
||||
+ if (ret != MPATH_PR_SUCCESS) {
|
||||
+ if (updated_prkey)
|
||||
+ update_prkey_flags(mpp->alias, get_be64(oldkey),
|
||||
+ mpp->sa_flags);
|
||||
goto out1;
|
||||
+ }
|
||||
|
||||
switch (rq_servact) {
|
||||
case MPATH_PROUT_REG_SA:
|
151
0064-libmpathpersist-update-reservation-key-before-checki.patch
Normal file
151
0064-libmpathpersist-update-reservation-key-before-checki.patch
Normal file
@ -0,0 +1,151 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:53 -0400
|
||||
Subject: [PATCH] libmpathpersist: update reservation key before checking paths
|
||||
|
||||
There is a race condition when changing reservation keys where a failed
|
||||
path could come back online after libmpathpersist checks the paths, but
|
||||
before it updates the reservation key. In this case, the path would come
|
||||
up and get reregistered with the old key by multipathd, and
|
||||
libmpathpersist would not update its key, because the path was down
|
||||
when it checked.
|
||||
|
||||
To fix this, check the paths after updating the key, so any path that
|
||||
comes up after getting checked will use the updated key.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 80 ++++++++++++-----------------
|
||||
1 file changed, 34 insertions(+), 46 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 302bebc2..d498e69e 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -110,39 +110,18 @@ void *mpath_alloc_prin_response(int prin_sa)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
-static int get_mpvec(vector curmp, vector pathvec, char *refwwid)
|
||||
+static int get_path_info(struct multipath *mpp, vector pathvec)
|
||||
{
|
||||
- int i;
|
||||
- struct multipath *mpp;
|
||||
-
|
||||
- vector_foreach_slot (curmp, mpp, i){
|
||||
- /*
|
||||
- * discard out of scope maps
|
||||
- */
|
||||
- if (!mpp->alias) {
|
||||
- condlog(0, "%s: map with empty alias!", __func__);
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- if (mpp->pg != NULL)
|
||||
- /* Already seen this one */
|
||||
- continue;
|
||||
-
|
||||
- if (refwwid && strncmp (mpp->alias, refwwid, WWID_SIZE - 1))
|
||||
- continue;
|
||||
-
|
||||
- if (update_multipath_table(mpp, pathvec, DI_CHECKER) != DMP_OK ||
|
||||
- update_mpp_paths(mpp, pathvec)) {
|
||||
- condlog(1, "error parsing map %s", mpp->wwid);
|
||||
- remove_map(mpp, pathvec, curmp);
|
||||
- i--;
|
||||
- } else
|
||||
- extract_hwe_from_path(mpp);
|
||||
+ if (update_multipath_table(mpp, pathvec, DI_CHECKER) != DMP_OK ||
|
||||
+ update_mpp_paths(mpp, pathvec)) {
|
||||
+ condlog(0, "error parsing map %s", mpp->wwid);
|
||||
+ return MPATH_PR_DMMP_ERROR;
|
||||
}
|
||||
+ extract_hwe_from_path(mpp);
|
||||
return MPATH_PR_SUCCESS ;
|
||||
}
|
||||
|
||||
-static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
|
||||
+static int mpath_get_map(vector curmp, int fd, char **palias,
|
||||
struct multipath **pmpp)
|
||||
{
|
||||
int ret = MPATH_PR_DMMP_ERROR;
|
||||
@@ -178,12 +157,6 @@ static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- /* get info of all paths from the dm device */
|
||||
- if (get_mpvec(curmp, pathvec, alias)){
|
||||
- condlog(0, "%s: failed to get device info.", alias);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
mpp = find_mp_by_alias(curmp, alias);
|
||||
|
||||
if (!mpp) {
|
||||
@@ -210,7 +183,11 @@ int do_mpath_persistent_reserve_in(vector curmp, vector pathvec,
|
||||
struct multipath *mpp;
|
||||
int ret;
|
||||
|
||||
- ret = mpath_get_map(curmp, pathvec, fd, NULL, &mpp);
|
||||
+ ret = mpath_get_map(curmp, fd, NULL, &mpp);
|
||||
+ if (ret != MPATH_PR_SUCCESS)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = get_path_info(mpp, pathvec);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
return ret;
|
||||
|
||||
@@ -747,24 +724,14 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
bool unregistering, preempting_reservation = false;
|
||||
bool updated_prkey = false;
|
||||
|
||||
- ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
|
||||
+ ret = mpath_get_map(curmp, fd, &alias, &mpp);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
return ret;
|
||||
|
||||
conf = get_multipath_config();
|
||||
select_reservation_key(conf, mpp);
|
||||
- select_all_tg_pt(conf, mpp);
|
||||
- /*
|
||||
- * If a device preempts itself, it will need to suspend and resume.
|
||||
- * Set mpp->skip_kpartx to make sure we set the flags to skip kpartx
|
||||
- * if necessary, when doing this.
|
||||
- */
|
||||
- select_skip_kpartx(conf, mpp);
|
||||
put_multipath_config(conf);
|
||||
|
||||
- if (rq_servact == MPATH_PROUT_REG_IGN_SA)
|
||||
- set_ignored_key(mpp, paramp->key);
|
||||
-
|
||||
unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
|
||||
if (mpp->prkey_source == PRKEY_SOURCE_FILE &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
@@ -822,6 +789,27 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
}
|
||||
}
|
||||
|
||||
+ ret = get_path_info(mpp, pathvec);
|
||||
+ if (ret != MPATH_PR_SUCCESS) {
|
||||
+ if (updated_prkey)
|
||||
+ update_prkey_flags(alias, get_be64(oldkey),
|
||||
+ mpp->sa_flags);
|
||||
+ goto out1;
|
||||
+ }
|
||||
+
|
||||
+ conf = get_multipath_config();
|
||||
+ select_all_tg_pt(conf, mpp);
|
||||
+ /*
|
||||
+ * If a device preempts itself, it will need to suspend and resume.
|
||||
+ * Set mpp->skip_kpartx to make sure we set the flags to skip kpartx
|
||||
+ * if necessary, when doing this.
|
||||
+ */
|
||||
+ select_skip_kpartx(conf, mpp);
|
||||
+ put_multipath_config(conf);
|
||||
+
|
||||
+ if (rq_servact == MPATH_PROUT_REG_IGN_SA)
|
||||
+ set_ignored_key(mpp, paramp->key);
|
||||
+
|
||||
switch(rq_servact)
|
||||
{
|
||||
case MPATH_PROUT_REG_SA:
|
@ -0,0 +1,79 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:54 -0400
|
||||
Subject: [PATCH] libmpathpersist: retry on conflicts in mpath_prout_common
|
||||
|
||||
mpath_prout_common() just needs to execute a prout command down one
|
||||
path. If it uses a path that was down when the key was changed and has
|
||||
since been restored, but multipathd hasn't noticed yet, that path will
|
||||
still be using the old key. This was causing mpath_prout_common() to
|
||||
fail with MPATH_PR_RESERV_CONFLICT, even if there were other paths that
|
||||
would work.
|
||||
|
||||
Now, if prout command fails with MPATH_PR_RESERV_CONFLICT,
|
||||
mpath_prout_common() checks if pp->dmstate is PSTATE_FAILED. If it is,
|
||||
mpath_prout_common() assumes that multipathd has not yet noticed that
|
||||
the path is back online and it might still have and old key, so it
|
||||
doesn't immediately return. If it can't successfully send the command
|
||||
down another path, it will still return MPATH_PR_RESERV_CONFLICT.
|
||||
|
||||
Also, make sure prout_do_scsi_ioctl() always returns a MPATH_PR_*
|
||||
type error.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 14 +++++++++++++-
|
||||
libmpathpersist/mpath_pr_ioctl.c | 2 +-
|
||||
2 files changed, 14 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index d498e69e..762958e8 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -216,6 +216,7 @@ mpath_prout_common(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
struct pathgroup *pgp = NULL;
|
||||
struct path *pp = NULL;
|
||||
bool found = false;
|
||||
+ bool conflict = false;
|
||||
|
||||
vector_foreach_slot (mpp->pg, pgp, j) {
|
||||
vector_foreach_slot (pgp->paths, pp, i) {
|
||||
@@ -232,12 +233,23 @@ mpath_prout_common(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
rq_type, paramp, noisy);
|
||||
if (ret == MPATH_PR_SUCCESS && pptr)
|
||||
*pptr = pp;
|
||||
+ /*
|
||||
+ * If this path is considered down by the kernel,
|
||||
+ * it may have just come back up, and multipathd
|
||||
+ * may not have had time to update the key. Allow
|
||||
+ * reservation conflicts.
|
||||
+ */
|
||||
+ if (ret == MPATH_PR_RESERV_CONFLICT &&
|
||||
+ pp->dmstate == PSTATE_FAILED) {
|
||||
+ conflict = true;
|
||||
+ continue;
|
||||
+ }
|
||||
if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
- return MPATH_PR_OTHER;
|
||||
+ return conflict ? MPATH_PR_RESERV_CONFLICT : MPATH_PR_OTHER;
|
||||
condlog(0, "%s: no path available", mpp->wwid);
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
}
|
||||
diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c
|
||||
index dfdbbb65..6eaec7cd 100644
|
||||
--- a/libmpathpersist/mpath_pr_ioctl.c
|
||||
+++ b/libmpathpersist/mpath_pr_ioctl.c
|
||||
@@ -103,7 +103,7 @@ retry :
|
||||
{
|
||||
condlog(0, "%s: ioctl failed %d", dev, ret);
|
||||
close(fd);
|
||||
- return ret;
|
||||
+ return MPATH_PR_OTHER;
|
||||
}
|
||||
|
||||
condlog(4, "%s: Duration=%u (ms)", dev, io_hdr.duration);
|
154
0066-libmpathpersist-Don-t-always-fail-registrations-for-.patch
Normal file
154
0066-libmpathpersist-Don-t-always-fail-registrations-for-.patch
Normal file
@ -0,0 +1,154 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 23:58:55 -0400
|
||||
Subject: [PATCH] libmpathpersist: Don't always fail registrations for
|
||||
retryable errors
|
||||
|
||||
When libmpathpersist registers a key, it's possible that a path fails
|
||||
between when it checks the path's status, and when it tries to do the
|
||||
registrations on the path. In this case, the registration will fail with
|
||||
a retryable error. If the registration was allowed to succeed,
|
||||
multipathd would update the now failed path's key when it came back
|
||||
online, and everything would work correctly. However it is possible for
|
||||
a registration to fail with a retryable error on a path that is still
|
||||
usable.
|
||||
|
||||
Libmpathpersist needs to avoid the case where it does not update the
|
||||
key of a usable path. Otherwise the path might be able to write to
|
||||
storage it shouldn't be allowed to. Or it could fail writing to storage
|
||||
that it should be allowed to write to. So if a registration would
|
||||
succeed except for retryable errors, libmpathpersist now rechecks all
|
||||
those paths to see if they are still usable. If they are, then it fails
|
||||
the registration as before. If they are not, then the registration
|
||||
succeeds.
|
||||
|
||||
Also, rename can_retry to had_success, since it is used for checking
|
||||
more than retries now.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 72 ++++++++++++++++++++++++++---
|
||||
1 file changed, 65 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 762958e8..de757c09 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -337,6 +337,48 @@ void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
condlog(0, "%s: register: pr preempt command failed.", mpp->wwid);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * If libmpathpersist fails at updating the key on a path with a retryable
|
||||
+ * error, it has probably failed. But there is a chance that the path is
|
||||
+ * still usable. To make sure a path isn't active without a key, when it
|
||||
+ * should have one, or with a key, when it shouldn't have one, check if
|
||||
+ * the path is still usable. If it is, we must fail the registration.
|
||||
+ */
|
||||
+static int
|
||||
+check_failed_paths(struct multipath *mpp, struct threadinfo *thread, int count)
|
||||
+{
|
||||
+ int i, j, k;
|
||||
+ int ret;
|
||||
+ struct pathgroup *pgp;
|
||||
+ struct path *pp;
|
||||
+ struct config *conf;
|
||||
+
|
||||
+ for (i = 0; i < count; i++) {
|
||||
+ if (thread[i].param.status != MPATH_PR_RETRYABLE_ERROR)
|
||||
+ continue;
|
||||
+ vector_foreach_slot (mpp->pg, pgp, j) {
|
||||
+ vector_foreach_slot (pgp->paths, pp, k) {
|
||||
+ if (strncmp(pp->dev, thread[i].param.dev,
|
||||
+ FILE_NAME_SIZE) == 0)
|
||||
+ goto match;
|
||||
+ }
|
||||
+ }
|
||||
+ /* no match. This shouldn't ever happen. */
|
||||
+ condlog(0, "%s: Error: can't find path %s", mpp->wwid,
|
||||
+ thread[i].param.dev);
|
||||
+ continue;
|
||||
+ match:
|
||||
+ conf = get_multipath_config();
|
||||
+ ret = pathinfo(pp, conf, DI_CHECKER);
|
||||
+ put_multipath_config(conf);
|
||||
+ /* If pathinfo fails, or if the path is active, return error */
|
||||
+ if (ret != PATHINFO_OK || pp->state == PATH_UP ||
|
||||
+ pp->state == PATH_GHOST)
|
||||
+ return MPATH_PR_OTHER;
|
||||
+ }
|
||||
+ return MPATH_PR_SUCCESS;
|
||||
+}
|
||||
+
|
||||
static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type,
|
||||
struct prout_param_descriptor * paramp, int noisy)
|
||||
@@ -345,8 +387,9 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int i, j, k;
|
||||
struct pathgroup *pgp = NULL;
|
||||
struct path *pp = NULL;
|
||||
- bool can_retry = false;
|
||||
+ bool had_success = false;
|
||||
bool need_retry = false;
|
||||
+ bool retryable_error = false;
|
||||
int active_pathcount=0;
|
||||
int rc;
|
||||
int count=0;
|
||||
@@ -450,16 +493,21 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
*/
|
||||
if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
|
||||
need_retry = true;
|
||||
+ else if (thread[i].param.status == MPATH_PR_RETRYABLE_ERROR)
|
||||
+ retryable_error = true;
|
||||
else if (thread[i].param.status == MPATH_PR_SUCCESS)
|
||||
- can_retry = true;
|
||||
+ had_success = true;
|
||||
else if (status == MPATH_PR_SUCCESS)
|
||||
status = thread[i].param.status;
|
||||
}
|
||||
- if (need_retry && can_retry && rq_servact == MPATH_PROUT_REG_SA &&
|
||||
+ if (need_retry && had_success && rq_servact == MPATH_PROUT_REG_SA &&
|
||||
status == MPATH_PR_SUCCESS) {
|
||||
condlog(3, "%s: ERROR: initiating pr out retry", mpp->wwid);
|
||||
+ retryable_error = false;
|
||||
for (i = 0; i < count; i++) {
|
||||
- if (thread[i].param.status != MPATH_PR_RESERV_CONFLICT) {
|
||||
+ /* retry retryable errors and conflicts */
|
||||
+ if (thread[i].param.status != MPATH_PR_RESERV_CONFLICT &&
|
||||
+ thread[i].param.status != MPATH_PR_RETRYABLE_ERROR) {
|
||||
thread[i].param.status = MPATH_PR_SKIP;
|
||||
continue;
|
||||
}
|
||||
@@ -486,7 +534,10 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
condlog(3, "%s: failed to join thread while retrying %d",
|
||||
mpp->wwid, i);
|
||||
}
|
||||
- if (status == MPATH_PR_SUCCESS)
|
||||
+ if (thread[i].param.status ==
|
||||
+ MPATH_PR_RETRYABLE_ERROR)
|
||||
+ retryable_error = true;
|
||||
+ else if (status == MPATH_PR_SUCCESS)
|
||||
status = thread[i].param.status;
|
||||
}
|
||||
}
|
||||
@@ -495,10 +546,17 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
if (need_retry)
|
||||
- status = MPATH_PR_RESERV_CONFLICT;
|
||||
+ return MPATH_PR_RESERV_CONFLICT;
|
||||
+ if (status != MPATH_PR_SUCCESS)
|
||||
+ return status;
|
||||
+ /* If you had retryable errors on all paths, fail the registration */
|
||||
+ if (!had_success)
|
||||
+ return MPATH_PR_OTHER;
|
||||
+ if (retryable_error)
|
||||
+ status = check_failed_paths(mpp, thread, count);
|
||||
if (status == MPATH_PR_SUCCESS)
|
||||
preempt_missing_path(mpp, paramp->key, paramp->sa_key, noisy);
|
||||
- return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
+ return status;
|
||||
}
|
||||
|
||||
static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
@ -0,0 +1,46 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 25 Aug 2025 14:09:29 -0400
|
||||
Subject: [PATCH] libmpathpersist: Don't try release workaround for invalid
|
||||
type
|
||||
|
||||
When trying to release a reservation, if the user specified the wrong
|
||||
reservation type, libmpathpersist would try to preempt the reservation,
|
||||
because the reservation key matched the device key, but it was not
|
||||
removed. In this case, the preemption would also fail because it also
|
||||
requires a matching type.
|
||||
|
||||
Check if the reservation type matches, to avoid attempting the
|
||||
workaround in this case.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index de757c09..e5ae0836 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -576,6 +576,7 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
uint16_t udev_flags = (mpp->skip_kpartx) ? MPATH_UDEV_NO_KPARTX_FLAG : 0;
|
||||
bool did_resume = false;
|
||||
bool all_threads_failed;
|
||||
+ unsigned int scope_type;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -671,6 +672,13 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
|
||||
+ scope_type = resp.prin_descriptor.prin_readresv.scope_type;
|
||||
+ if ((scope_type & MPATH_PR_TYPE_MASK) != rq_type) {
|
||||
+ condlog(2, "%s: --prout_type %u doesn't match reservation %u",
|
||||
+ mpp->wwid, rq_type, scope_type & MPATH_PR_TYPE_MASK);
|
||||
+ return MPATH_PR_RESERV_CONFLICT;
|
||||
+ }
|
||||
+
|
||||
condlog (2, "%s: Path holding reservation is not available.", mpp->wwid);
|
||||
/*
|
||||
* Cannot free the reservation because the path that is holding it
|
@ -0,0 +1,43 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 4 Sep 2025 16:33:27 -0400
|
||||
Subject: [PATCH] libmpathpersist: Don't fail RESERVE commands unnecessarily
|
||||
|
||||
If you issue a RESERVE to a regular SCSI device that already holds the
|
||||
reservation, it succeeds (and does nothing). If you issue a RESERVE to a
|
||||
multipath device that already holds the reservation, it can fail with
|
||||
a reservation conflict error if you issue the RESERVE to a path that isn't
|
||||
holding the reservation. Instead, it should try all paths and
|
||||
succeed if the reservation command succeeds on any of them.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 13 ++++++++++++-
|
||||
1 file changed, 12 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index e5ae0836..45ba68c0 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -238,9 +238,20 @@ mpath_prout_common(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
* it may have just come back up, and multipathd
|
||||
* may not have had time to update the key. Allow
|
||||
* reservation conflicts.
|
||||
+ *
|
||||
+ * If you issue a RESERVE to a regular scsi device
|
||||
+ * that already holds the reservation, it succeeds
|
||||
+ * (and does nothing). A multipath device that
|
||||
+ * holds the reservation should not return a
|
||||
+ * reservation conflict on a RESERVE command, just
|
||||
+ * because it issued the RESERVE to a path that
|
||||
+ * isn't holding the reservation. It should instead
|
||||
+ * keep trying to see if it succeeds on another
|
||||
+ * path.
|
||||
*/
|
||||
if (ret == MPATH_PR_RESERV_CONFLICT &&
|
||||
- pp->dmstate == PSTATE_FAILED) {
|
||||
+ (pp->dmstate == PSTATE_FAILED ||
|
||||
+ rq_servact == MPATH_PROUT_RES_SA)) {
|
||||
conflict = true;
|
||||
continue;
|
||||
}
|
193
0069-libmpathpersist-reregister-keys-when-self-preempting.patch
Normal file
193
0069-libmpathpersist-reregister-keys-when-self-preempting.patch
Normal file
@ -0,0 +1,193 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 5 Sep 2025 14:04:58 -0400
|
||||
Subject: [PATCH] libmpathpersist: reregister keys when self preempting
|
||||
|
||||
When a SCSI device preempts its own reservation key, it will remove the
|
||||
registered keys from all other devices with that reservation key, but
|
||||
retain its registered key (and possibly acquire the reservation). If a
|
||||
multipath device preempts its own reservation key, it will also remove
|
||||
the registered keys from all its paths except the one issuing the
|
||||
reservation. This means that IO to the device can fail if it goes to one
|
||||
of these unregistered paths.
|
||||
|
||||
To avoid this, whenever a multipath device preempts itself, it must
|
||||
first suspend, then do the preemption and reregister the removed keys,
|
||||
and finally resume the device. This is already what libmpathpersist does
|
||||
if a release fails because the path holding the reservation is currently
|
||||
unavailable, with the addition of releasing the reservation after
|
||||
preempting it. This commit refactors that code into a separate function,
|
||||
makes the release optional, and calls the new function, preempt_self(),
|
||||
whenever a device preempts itself.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 133 ++++++++++++++--------------
|
||||
1 file changed, 68 insertions(+), 65 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 45ba68c0..da8a0d04 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -570,6 +570,65 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return status;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Called to make a multipath device preempt its own reservation (and
|
||||
+ * optionally release the reservation). Doing this causes the reservation
|
||||
+ * keys to be removed from all the device paths except that path used to issue
|
||||
+ * the preempt, so they need to be restored. To avoid the chance that IO
|
||||
+ * goes to these paths when they don't have a registered key, the device
|
||||
+ * is suspended before issuing the preemption, and the keys are reregistered
|
||||
+ * before resuming it.
|
||||
+ */
|
||||
+static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
+ unsigned int rq_type, int noisy, bool do_release)
|
||||
+{
|
||||
+ int status, rel_status = MPATH_PR_SUCCESS;
|
||||
+ struct path *pp = NULL;
|
||||
+ struct prout_param_descriptor paramp = {.sa_flags = 0};
|
||||
+ uint16_t udev_flags = (mpp->skip_kpartx) ? MPATH_UDEV_NO_KPARTX_FLAG : 0;
|
||||
+
|
||||
+ if (!dm_simplecmd_noflush(DM_DEVICE_SUSPEND, mpp->alias, 0)) {
|
||||
+ condlog(0, "%s: self preempt failed to suspend device.", mpp->wwid);
|
||||
+ return MPATH_PR_OTHER;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(paramp.key, &mpp->reservation_key, 8);
|
||||
+ memcpy(paramp.sa_key, &mpp->reservation_key, 8);
|
||||
+ status = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
+ ¶mp, noisy, &pp);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: self preempt command failed.", mpp->wwid);
|
||||
+ goto fail_resume;
|
||||
+ }
|
||||
+
|
||||
+ if (do_release) {
|
||||
+ memset(¶mp, 0, sizeof(paramp));
|
||||
+ memcpy(paramp.key, &mpp->reservation_key, 8);
|
||||
+ rel_status = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REL_SA,
|
||||
+ rq_scope, rq_type, ¶mp, noisy);
|
||||
+ if (rel_status != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: release on alternate path failed.",
|
||||
+ mpp->wwid);
|
||||
+ }
|
||||
+
|
||||
+ memset(¶mp, 0, sizeof(paramp));
|
||||
+ memcpy(paramp.sa_key, &mpp->reservation_key, 8);
|
||||
+ status = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope,
|
||||
+ rq_type, ¶mp, noisy);
|
||||
+ if (status != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: self preempt failed to reregister paths.",
|
||||
+ mpp->wwid);
|
||||
+
|
||||
+fail_resume:
|
||||
+ if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
+ condlog(0, "%s: self preempt failed to resume device.", mpp->wwid);
|
||||
+ if (status == MPATH_PR_SUCCESS)
|
||||
+ status = MPATH_PR_OTHER;
|
||||
+ }
|
||||
+ /* return the first error we encountered */
|
||||
+ return (rel_status != MPATH_PR_SUCCESS) ? rel_status : status;
|
||||
+}
|
||||
+
|
||||
static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type,
|
||||
struct prout_param_descriptor * paramp, int noisy)
|
||||
@@ -584,8 +643,6 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int count = 0;
|
||||
int status = MPATH_PR_SUCCESS;
|
||||
struct prin_resp resp = {{{.prgeneration = 0}}};
|
||||
- uint16_t udev_flags = (mpp->skip_kpartx) ? MPATH_UDEV_NO_KPARTX_FLAG : 0;
|
||||
- bool did_resume = false;
|
||||
bool all_threads_failed;
|
||||
unsigned int scope_type;
|
||||
|
||||
@@ -700,70 +757,10 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
* preempting one. Since the device is suspended, no IO can
|
||||
* go to these unregistered paths and fail).
|
||||
* 3. Releasing the reservation on the path that now holds it.
|
||||
- * 4. Resuming the device (since it no longer matters that most of
|
||||
- * that paths no longer have a registered key)
|
||||
- * 5. Reregistering keys on all the paths
|
||||
+ * 4. Reregistering keys on all the paths
|
||||
+ * 5. Resuming the device
|
||||
*/
|
||||
-
|
||||
- if (!dm_simplecmd_noflush(DM_DEVICE_SUSPEND, mpp->alias, 0)) {
|
||||
- condlog(0, "%s: release: failed to suspend dm device.", mpp->wwid);
|
||||
- return MPATH_PR_OTHER;
|
||||
- }
|
||||
-
|
||||
- memset(paramp, 0, sizeof(*paramp));
|
||||
- memcpy(paramp->key, &mpp->reservation_key, 8);
|
||||
- memcpy(paramp->sa_key, &mpp->reservation_key, 8);
|
||||
- status = mpath_prout_common(mpp, MPATH_PROUT_PREE_SA, rq_scope,
|
||||
- rq_type, paramp, noisy, &pp);
|
||||
- if (status != MPATH_PR_SUCCESS) {
|
||||
- condlog(0, "%s: release: pr preempt command failed.", mpp->wwid);
|
||||
- goto fail_resume;
|
||||
- }
|
||||
-
|
||||
- memset(paramp, 0, sizeof(*paramp));
|
||||
- memcpy(paramp->key, &mpp->reservation_key, 8);
|
||||
- status = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REL_SA, rq_scope,
|
||||
- rq_type, paramp, noisy);
|
||||
- if (status != MPATH_PR_SUCCESS) {
|
||||
- condlog(0, "%s: release on alternate path failed.", mpp->wwid);
|
||||
- goto out_reregister;
|
||||
- }
|
||||
-
|
||||
- if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
- condlog(0, "%s release: failed to resume dm device.", mpp->wwid);
|
||||
- /*
|
||||
- * leave status set to MPATH_PR_SUCCESS, we will have another
|
||||
- * chance to resume the device.
|
||||
- */
|
||||
- goto out_reregister;
|
||||
- }
|
||||
- did_resume = true;
|
||||
-
|
||||
-out_reregister:
|
||||
- memset(paramp, 0, sizeof(*paramp));
|
||||
- memcpy(paramp->sa_key, &mpp->reservation_key, 8);
|
||||
- rc = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope, rq_type,
|
||||
- paramp, noisy);
|
||||
- if (rc != MPATH_PR_SUCCESS)
|
||||
- condlog(0, "%s: release: failed to reregister paths.", mpp->wwid);
|
||||
-
|
||||
- /*
|
||||
- * If we failed releasing the reservation or resuming earlier
|
||||
- * try resuming now. Otherwise, return with the reregistering status
|
||||
- * This means we will report failure, even though the resevation
|
||||
- * has been released, since the keys were not reregistered.
|
||||
- */
|
||||
- if (did_resume)
|
||||
- return rc;
|
||||
- else if (status == MPATH_PR_SUCCESS)
|
||||
- status = rc;
|
||||
-fail_resume:
|
||||
- if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
- condlog(0, "%s: release: failed to resume dm device.", mpp->wwid);
|
||||
- if (status == MPATH_PR_SUCCESS)
|
||||
- status = MPATH_PR_OTHER;
|
||||
- }
|
||||
- return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
+ return preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type, noisy, true);
|
||||
}
|
||||
|
||||
static int reservation_key_matches(struct multipath *mpp, uint8_t *key, int noisy)
|
||||
@@ -909,6 +906,12 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
case MPATH_PROUT_PREE_AB_SA:
|
||||
if (reservation_key_matches(mpp, paramp->sa_key, noisy) == YNU_YES)
|
||||
preempting_reservation = true;
|
||||
+ /* if we are preempting ourself */
|
||||
+ if (memcmp(paramp->sa_key, paramp->key, 8) == 0) {
|
||||
+ ret = preempt_self(mpp, rq_servact, rq_scope, rq_type,
|
||||
+ noisy, false);
|
||||
+ break;
|
||||
+ }
|
||||
/* fallthrough */
|
||||
case MPATH_PROUT_RES_SA:
|
||||
case MPATH_PROUT_CLEAR_SA:
|
108
0070-libmpathpersist-handle-updating-key-race-condition.patch
Normal file
108
0070-libmpathpersist-handle-updating-key-race-condition.patch
Normal file
@ -0,0 +1,108 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 9 Sep 2025 18:55:49 -0400
|
||||
Subject: [PATCH] libmpathpersist: handle updating key race condition
|
||||
|
||||
If a multipath device's registered key is changed, mpathpersist needs
|
||||
to update the key in multipathd before it registers the new key on the
|
||||
paths. This means that there is a time when multipathd thinks the paths
|
||||
should be using the new key, but none of them are. If a path is
|
||||
restored after mpathpersist checks which paths are usable to set the
|
||||
key on, but before it sets the key on any path, multipathd will see
|
||||
that the new key is not registered on any paths, and think that the
|
||||
key has been preempted or cleared. This will leave the path without
|
||||
a key, and possibly make multipathd think the device does not hold
|
||||
the reservation, even if it does.
|
||||
|
||||
To avoid this, multipathd will now remember the old key when registering
|
||||
a new one. Once the registration is finished, and (un)setprstatus is
|
||||
called, multipathd will forget the old key. Until then, multipathd will
|
||||
check for either key when it looks to see if there is an existing key.
|
||||
If the registration fails and the key get reverted, multipathd will
|
||||
also forget the old key.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/prkey.c | 16 ++++++++++++++--
|
||||
libmultipath/structs.h | 1 +
|
||||
multipathd/main.c | 12 +++++++++++-
|
||||
3 files changed, 26 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/prkey.c b/libmultipath/prkey.c
|
||||
index c66d293b..4fbde5ad 100644
|
||||
--- a/libmultipath/prkey.c
|
||||
+++ b/libmultipath/prkey.c
|
||||
@@ -222,10 +222,22 @@ int set_prkey(struct config *conf, struct multipath *mpp, uint64_t prkey,
|
||||
}
|
||||
else
|
||||
ret = do_prkey(fd, mpp->wwid, NULL, PRKEY_WRITE);
|
||||
- if (ret == 0)
|
||||
+ if (ret == 0) {
|
||||
+ /*
|
||||
+ * If you are reverting back to the old key, because you
|
||||
+ * did not successfully set a new key, don't remember the
|
||||
+ * key you never successfully set.
|
||||
+ */
|
||||
+ if (get_be64(mpp->old_pr_key) == prkey)
|
||||
+ memset(&mpp->old_pr_key, 0, 8);
|
||||
+ else
|
||||
+ memcpy(&mpp->old_pr_key, &mpp->reservation_key, 8);
|
||||
select_reservation_key(conf, mpp);
|
||||
- if (get_be64(mpp->reservation_key) != prkey)
|
||||
+ }
|
||||
+ if (get_be64(mpp->reservation_key) != prkey) {
|
||||
+ memset(&mpp->old_pr_key, 0, 8);
|
||||
ret = 1;
|
||||
+ }
|
||||
out_file:
|
||||
close(fd);
|
||||
out:
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index 90127641..2ff195f3 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -487,6 +487,7 @@ struct multipath {
|
||||
/* persistent management data*/
|
||||
int prkey_source;
|
||||
struct be64 reservation_key;
|
||||
+ struct be64 old_pr_key;
|
||||
uint8_t sa_flags;
|
||||
int prflag;
|
||||
int prhold;
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 484c8ac1..3b53d140 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -3967,6 +3967,7 @@ void set_pr(struct multipath *mpp)
|
||||
{
|
||||
mpp->ever_registered_pr = true;
|
||||
mpp->prflag = PR_SET;
|
||||
+ memset(&mpp->old_pr_key, 0, 8);
|
||||
}
|
||||
|
||||
void unset_pr(struct multipath *mpp)
|
||||
@@ -3974,6 +3975,7 @@ void unset_pr(struct multipath *mpp)
|
||||
mpp->prflag = PR_UNSET;
|
||||
mpp->prhold = PR_UNSET;
|
||||
mpp->sa_flags = 0;
|
||||
+ memset(&mpp->old_pr_key, 0, 8);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4026,7 +4028,15 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
dumpHex((char *)keyp, 8, 1);
|
||||
}
|
||||
|
||||
- if (!memcmp(&mpp->reservation_key, keyp, 8))
|
||||
+ /*
|
||||
+ * If you are in the middle of updating a key (old_pr_key
|
||||
+ * is set) check for either the new key or the old key,
|
||||
+ * since you might be checking before any paths have
|
||||
+ * updated their keys.
|
||||
+ */
|
||||
+ if (!memcmp(&mpp->reservation_key, keyp, 8) ||
|
||||
+ (get_be64(mpp->old_pr_key) &&
|
||||
+ !memcmp(&mpp->old_pr_key, keyp, 8)))
|
||||
isFound = 1;
|
||||
}
|
||||
|
@ -0,0 +1,82 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 10 Sep 2025 17:52:12 -0400
|
||||
Subject: [PATCH] libmpathpersist: handle preempting all registrants
|
||||
reservations
|
||||
|
||||
All Registrants reservations (types 7 and 8) are held by key 0x0. When
|
||||
preempting one, all registrations are cleared, except for the one on the
|
||||
path that issued the PREEMPT. libmpathpersist needs to handle this just
|
||||
like the other cases of self-preemption, so that all the paths of the
|
||||
preempting multipath device have their registrations restored while the
|
||||
device is suspended.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 31 +++++++++++++++++++++++++----
|
||||
1 file changed, 27 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index da8a0d04..87d7cb6b 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -579,8 +579,9 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
* is suspended before issuing the preemption, and the keys are reregistered
|
||||
* before resuming it.
|
||||
*/
|
||||
-static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, int noisy, bool do_release)
|
||||
+static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
+ int rq_servact, int rq_scope, unsigned int rq_type,
|
||||
+ int noisy, bool do_release)
|
||||
{
|
||||
int status, rel_status = MPATH_PR_SUCCESS;
|
||||
struct path *pp = NULL;
|
||||
@@ -593,7 +594,7 @@ static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
}
|
||||
|
||||
memcpy(paramp.key, &mpp->reservation_key, 8);
|
||||
- memcpy(paramp.sa_key, &mpp->reservation_key, 8);
|
||||
+ memcpy(paramp.sa_key, &sa_key, 8);
|
||||
status = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
¶mp, noisy, &pp);
|
||||
if (status != MPATH_PR_SUCCESS) {
|
||||
@@ -629,6 +630,21 @@ fail_resume:
|
||||
return (rel_status != MPATH_PR_SUCCESS) ? rel_status : status;
|
||||
}
|
||||
|
||||
+static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
+ unsigned int rq_type, int noisy, bool do_release)
|
||||
+{
|
||||
+ return do_preempt_self(mpp, mpp->reservation_key, rq_servact, rq_scope,
|
||||
+ rq_type, noisy, do_release);
|
||||
+}
|
||||
+
|
||||
+static int preempt_all(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
+ unsigned int rq_type, int noisy)
|
||||
+{
|
||||
+ struct be64 zerokey = {0};
|
||||
+ return do_preempt_self(mpp, zerokey, rq_servact, rq_scope, rq_type,
|
||||
+ noisy, false);
|
||||
+}
|
||||
+
|
||||
static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type,
|
||||
struct prout_param_descriptor * paramp, int noisy)
|
||||
@@ -904,8 +920,15 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
break;
|
||||
case MPATH_PROUT_PREE_SA:
|
||||
case MPATH_PROUT_PREE_AB_SA:
|
||||
- if (reservation_key_matches(mpp, paramp->sa_key, noisy) == YNU_YES)
|
||||
+ if (reservation_key_matches(mpp, paramp->sa_key, noisy) == YNU_YES) {
|
||||
preempting_reservation = true;
|
||||
+ if (memcmp(paramp->sa_key, &zerokey, 8) == 0) {
|
||||
+ /* all registrants case */
|
||||
+ ret = preempt_all(mpp, rq_servact, rq_scope,
|
||||
+ rq_type, noisy);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
/* if we are preempting ourself */
|
||||
if (memcmp(paramp->sa_key, paramp->key, 8) == 0) {
|
||||
ret = preempt_self(mpp, rq_servact, rq_scope, rq_type,
|
@ -0,0 +1,73 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 18 Sep 2025 18:12:07 -0400
|
||||
Subject: [PATCH] libmpathpersist: Fix REGISTER AND IGNORE while holding a
|
||||
reservation
|
||||
|
||||
If a device that is holding a reservation changes its registered key,
|
||||
but the path holding the reservation is unavailable, libmpathpersist
|
||||
must preempt the old key to update the reservation. If the key is
|
||||
changed using REGISTER AND IGNORE, set_ignored_key() determines the old
|
||||
key to preempt. Unfortunately, commit 165427dda broke it, by comparing
|
||||
the wrong key against the actual reservation key. Then commit cf0eea85
|
||||
broke it more, by using mpp->reservation_key after it had been updated,
|
||||
so it was no longer the old key. Fix this by correctly comparing the old
|
||||
key against the actual reservation key.
|
||||
|
||||
Fixes: 165427dda ("libmpathpersist: Add safety check for preempting on key change")
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 13 +++++++------
|
||||
1 file changed, 7 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 87d7cb6b..e3514137 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -801,16 +801,17 @@ static int reservation_key_matches(struct multipath *mpp, uint8_t *key, int nois
|
||||
* currently registered key for use in preempt_missing_path(), but only if
|
||||
* the key is holding the reservation.
|
||||
*/
|
||||
-static void set_ignored_key(struct multipath *mpp, uint8_t *key)
|
||||
+static void set_ignored_key(struct multipath *mpp, uint8_t *curr_key,
|
||||
+ uint8_t *key)
|
||||
{
|
||||
memset(key, 0, 8);
|
||||
- if (!get_be64(mpp->reservation_key))
|
||||
+ if (memcmp(curr_key, key, 8) == 0)
|
||||
return;
|
||||
if (get_prhold(mpp->alias) == PR_UNSET)
|
||||
return;
|
||||
- if (reservation_key_matches(mpp, key, 0) == YNU_NO)
|
||||
+ if (reservation_key_matches(mpp, curr_key, 0) == YNU_NO)
|
||||
return;
|
||||
- memcpy(key, &mpp->reservation_key, 8);
|
||||
+ memcpy(key, curr_key, 8);
|
||||
}
|
||||
|
||||
int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
@@ -834,6 +835,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
select_reservation_key(conf, mpp);
|
||||
put_multipath_config(conf);
|
||||
|
||||
+ memcpy(&oldkey, &mpp->reservation_key, 8);
|
||||
unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
|
||||
if (mpp->prkey_source == PRKEY_SOURCE_FILE &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
@@ -842,7 +844,6 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
memcmp(paramp->key, &zerokey, 8) == 0 ||
|
||||
memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) {
|
||||
updated_prkey = true;
|
||||
- memcpy(&oldkey, &mpp->reservation_key, 8);
|
||||
memcpy(&mpp->reservation_key, paramp->sa_key, 8);
|
||||
if (update_prkey_flags(alias, get_be64(mpp->reservation_key),
|
||||
paramp->sa_flags)) {
|
||||
@@ -910,7 +911,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
put_multipath_config(conf);
|
||||
|
||||
if (rq_servact == MPATH_PROUT_REG_IGN_SA)
|
||||
- set_ignored_key(mpp, paramp->key);
|
||||
+ set_ignored_key(mpp, (uint8_t *)&oldkey, paramp->key);
|
||||
|
||||
switch(rq_servact)
|
||||
{
|
159
0073-libmpathpersist-Handle-RESERVE-with-reservation-held.patch
Normal file
159
0073-libmpathpersist-Handle-RESERVE-with-reservation-held.patch
Normal file
@ -0,0 +1,159 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 18 Sep 2025 19:29:08 -0400
|
||||
Subject: [PATCH] libmpathpersist: Handle RESERVE with reservation held by
|
||||
failed path
|
||||
|
||||
Issuing a RESERVE on a device that already holds the reservation should
|
||||
succeed, as long as the type is the same. But if the path that holds the
|
||||
reservation is unavailable, mpathpersist fails, since it gets a
|
||||
reservation conflict on all available paths. To deal with this, if the
|
||||
multipath device has failed paths, and the key holding the reservation
|
||||
matches the multipath device's key, and multipathd says that it is
|
||||
holding the reservation, assume the reservation is held by a failed path
|
||||
and claim the RESERVE succeeded, even though none of the actual scsi
|
||||
commands did
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 47 +++++++++++++++++++++++------
|
||||
1 file changed, 37 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index e3514137..0cb08f88 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -210,7 +210,7 @@ static void *mpath_prout_pthread_fn(void *p)
|
||||
static int
|
||||
mpath_prout_common(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor *paramp,
|
||||
- int noisy, struct path **pptr)
|
||||
+ int noisy, struct path **pptr, bool *failed_paths)
|
||||
{
|
||||
int i, j, ret;
|
||||
struct pathgroup *pgp = NULL;
|
||||
@@ -223,6 +223,8 @@ mpath_prout_common(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))) {
|
||||
condlog(1, "%s: %s path not up. Skip",
|
||||
mpp->wwid, pp->dev);
|
||||
+ if (failed_paths)
|
||||
+ *failed_paths = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -257,6 +259,8 @@ mpath_prout_common(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
}
|
||||
if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
return ret;
|
||||
+ if (failed_paths)
|
||||
+ *failed_paths = true;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
@@ -343,7 +347,7 @@ void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
memcpy(paramp.key, sa_key, 8);
|
||||
memcpy(paramp.sa_key, key, 8);
|
||||
status = mpath_prout_common(mpp, MPATH_PROUT_PREE_SA, rq_scope,
|
||||
- rq_type, ¶mp, noisy, NULL);
|
||||
+ rq_type, ¶mp, noisy, NULL, NULL);
|
||||
if (status != MPATH_PR_SUCCESS)
|
||||
condlog(0, "%s: register: pr preempt command failed.", mpp->wwid);
|
||||
}
|
||||
@@ -596,7 +600,7 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
memcpy(paramp.key, &mpp->reservation_key, 8);
|
||||
memcpy(paramp.sa_key, &sa_key, 8);
|
||||
status = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
- ¶mp, noisy, &pp);
|
||||
+ ¶mp, noisy, &pp, NULL);
|
||||
if (status != MPATH_PR_SUCCESS) {
|
||||
condlog(0, "%s: self preempt command failed.", mpp->wwid);
|
||||
goto fail_resume;
|
||||
@@ -779,20 +783,25 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type, noisy, true);
|
||||
}
|
||||
|
||||
-static int reservation_key_matches(struct multipath *mpp, uint8_t *key, int noisy)
|
||||
+static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
|
||||
+ unsigned int *type)
|
||||
{
|
||||
struct prin_resp resp = {{{.prgeneration = 0}}};
|
||||
int status;
|
||||
|
||||
- status = mpath_prin_activepath(mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
+ status = mpath_prin_activepath(mpp, MPATH_PRIN_RRES_SA, &resp, 0);
|
||||
if (status != MPATH_PR_SUCCESS) {
|
||||
condlog(0, "%s: pr in read reservation command failed.", mpp->wwid);
|
||||
return YNU_UNDEF;
|
||||
}
|
||||
if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
return YNU_NO;
|
||||
- if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) == 0)
|
||||
+ if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) == 0) {
|
||||
+ if (type)
|
||||
+ *type = resp.prin_descriptor.prin_readresv.scope_type &
|
||||
+ MPATH_PR_TYPE_MASK;
|
||||
return YNU_YES;
|
||||
+ }
|
||||
return YNU_NO;
|
||||
}
|
||||
|
||||
@@ -809,11 +818,20 @@ static void set_ignored_key(struct multipath *mpp, uint8_t *curr_key,
|
||||
return;
|
||||
if (get_prhold(mpp->alias) == PR_UNSET)
|
||||
return;
|
||||
- if (reservation_key_matches(mpp, curr_key, 0) == YNU_NO)
|
||||
+ if (reservation_key_matches(mpp, curr_key, NULL) == YNU_NO)
|
||||
return;
|
||||
memcpy(key, curr_key, 8);
|
||||
}
|
||||
|
||||
+static bool check_holding_reservation(struct multipath *mpp, unsigned int *type)
|
||||
+{
|
||||
+ if (get_be64(mpp->reservation_key) &&
|
||||
+ get_prhold(mpp->alias) == PR_SET &&
|
||||
+ reservation_key_matches(mpp, (uint8_t *)&mpp->reservation_key, type) == YNU_YES)
|
||||
+ return true;
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
int rq_servact, int rq_scope, unsigned int rq_type,
|
||||
struct prout_param_descriptor *paramp, int noisy)
|
||||
@@ -826,6 +844,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
struct config *conf;
|
||||
bool unregistering, preempting_reservation = false;
|
||||
bool updated_prkey = false;
|
||||
+ bool failed_paths = false;
|
||||
|
||||
ret = mpath_get_map(curmp, fd, &alias, &mpp);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
@@ -921,7 +940,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
break;
|
||||
case MPATH_PROUT_PREE_SA:
|
||||
case MPATH_PROUT_PREE_AB_SA:
|
||||
- if (reservation_key_matches(mpp, paramp->sa_key, noisy) == YNU_YES) {
|
||||
+ if (reservation_key_matches(mpp, paramp->sa_key, NULL) == YNU_YES) {
|
||||
preempting_reservation = true;
|
||||
if (memcmp(paramp->sa_key, &zerokey, 8) == 0) {
|
||||
/* all registrants case */
|
||||
@@ -938,10 +957,18 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
}
|
||||
/* fallthrough */
|
||||
case MPATH_PROUT_RES_SA:
|
||||
- case MPATH_PROUT_CLEAR_SA:
|
||||
+ case MPATH_PROUT_CLEAR_SA: {
|
||||
+ unsigned int res_type;
|
||||
ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
- paramp, noisy, NULL);
|
||||
+ paramp, noisy, NULL, &failed_paths);
|
||||
+ if (rq_servact == MPATH_PROUT_RES_SA &&
|
||||
+ ret != MPATH_PR_SUCCESS && failed_paths &&
|
||||
+ check_holding_reservation(mpp, &res_type) &&
|
||||
+ res_type == rq_type)
|
||||
+ /* The reserve failed, but multipathd says we hold it */
|
||||
+ ret = MPATH_PR_SUCCESS;
|
||||
break;
|
||||
+ }
|
||||
case MPATH_PROUT_REL_SA:
|
||||
ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
break;
|
149
0074-libmpathpersist-use-check_holding_reservation-in-mpa.patch
Normal file
149
0074-libmpathpersist-use-check_holding_reservation-in-mpa.patch
Normal file
@ -0,0 +1,149 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 25 Sep 2025 16:48:49 -0400
|
||||
Subject: [PATCH] libmpathpersist: use check_holding_reservation in
|
||||
mpath_prout_rel
|
||||
|
||||
Instead of open-coding mostly the same work, just make mpath_prout_rel()
|
||||
call check_holding_reservation().
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist_int.c | 86 ++++++++++++-----------------
|
||||
1 file changed, 35 insertions(+), 51 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 0cb08f88..0eb7041e 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -649,12 +649,42 @@ static int preempt_all(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
noisy, false);
|
||||
}
|
||||
|
||||
+static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
|
||||
+ unsigned int *type)
|
||||
+{
|
||||
+ struct prin_resp resp = {{{.prgeneration = 0}}};
|
||||
+ int status;
|
||||
+
|
||||
+ status = mpath_prin_activepath(mpp, MPATH_PRIN_RRES_SA, &resp, 0);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: pr in read reservation command failed.", mpp->wwid);
|
||||
+ return YNU_UNDEF;
|
||||
+ }
|
||||
+ if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
+ return YNU_NO;
|
||||
+ if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) == 0) {
|
||||
+ if (type)
|
||||
+ *type = resp.prin_descriptor.prin_readresv.scope_type &
|
||||
+ MPATH_PR_TYPE_MASK;
|
||||
+ return YNU_YES;
|
||||
+ }
|
||||
+ return YNU_NO;
|
||||
+}
|
||||
+
|
||||
+static bool check_holding_reservation(struct multipath *mpp, unsigned int *type)
|
||||
+{
|
||||
+ if (get_be64(mpp->reservation_key) &&
|
||||
+ get_prhold(mpp->alias) == PR_SET &&
|
||||
+ reservation_key_matches(mpp, (uint8_t *)&mpp->reservation_key, type) == YNU_YES)
|
||||
+ return true;
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type,
|
||||
struct prout_param_descriptor * paramp, int noisy)
|
||||
{
|
||||
int i, j;
|
||||
- int num = 0;
|
||||
struct pathgroup *pgp = NULL;
|
||||
struct path *pp = NULL;
|
||||
int active_pathcount = 0;
|
||||
@@ -662,9 +692,8 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int rc;
|
||||
int count = 0;
|
||||
int status = MPATH_PR_SUCCESS;
|
||||
- struct prin_resp resp = {{{.prgeneration = 0}}};
|
||||
bool all_threads_failed;
|
||||
- unsigned int scope_type;
|
||||
+ unsigned int res_type;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -743,27 +772,13 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return status;
|
||||
}
|
||||
|
||||
- status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
- if (status != MPATH_PR_SUCCESS){
|
||||
- condlog (0, "%s: pr in read reservation command failed.", mpp->wwid);
|
||||
- return MPATH_PR_OTHER;
|
||||
- }
|
||||
-
|
||||
- num = resp.prin_descriptor.prin_readresv.additional_length / 8;
|
||||
- if (num == 0){
|
||||
- condlog (2, "%s: Path holding reservation is released.", mpp->wwid);
|
||||
- return MPATH_PR_SUCCESS;
|
||||
- }
|
||||
- if (!get_be64(mpp->reservation_key) ||
|
||||
- memcmp(&mpp->reservation_key, resp.prin_descriptor.prin_readresv.key, 8)) {
|
||||
+ if (!check_holding_reservation(mpp, &res_type)) {
|
||||
condlog(2, "%s: Releasing key not holding reservation.", mpp->wwid);
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
-
|
||||
- scope_type = resp.prin_descriptor.prin_readresv.scope_type;
|
||||
- if ((scope_type & MPATH_PR_TYPE_MASK) != rq_type) {
|
||||
+ if (res_type != rq_type) {
|
||||
condlog(2, "%s: --prout_type %u doesn't match reservation %u",
|
||||
- mpp->wwid, rq_type, scope_type & MPATH_PR_TYPE_MASK);
|
||||
+ mpp->wwid, rq_type, res_type);
|
||||
return MPATH_PR_RESERV_CONFLICT;
|
||||
}
|
||||
|
||||
@@ -783,28 +798,6 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type, noisy, true);
|
||||
}
|
||||
|
||||
-static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
|
||||
- unsigned int *type)
|
||||
-{
|
||||
- struct prin_resp resp = {{{.prgeneration = 0}}};
|
||||
- int status;
|
||||
-
|
||||
- status = mpath_prin_activepath(mpp, MPATH_PRIN_RRES_SA, &resp, 0);
|
||||
- if (status != MPATH_PR_SUCCESS) {
|
||||
- condlog(0, "%s: pr in read reservation command failed.", mpp->wwid);
|
||||
- return YNU_UNDEF;
|
||||
- }
|
||||
- if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
- return YNU_NO;
|
||||
- if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) == 0) {
|
||||
- if (type)
|
||||
- *type = resp.prin_descriptor.prin_readresv.scope_type &
|
||||
- MPATH_PR_TYPE_MASK;
|
||||
- return YNU_YES;
|
||||
- }
|
||||
- return YNU_NO;
|
||||
-}
|
||||
-
|
||||
/*
|
||||
* for MPATH_PROUT_REG_IGN_SA, we use the ignored paramp->key to store the
|
||||
* currently registered key for use in preempt_missing_path(), but only if
|
||||
@@ -823,15 +816,6 @@ static void set_ignored_key(struct multipath *mpp, uint8_t *curr_key,
|
||||
memcpy(key, curr_key, 8);
|
||||
}
|
||||
|
||||
-static bool check_holding_reservation(struct multipath *mpp, unsigned int *type)
|
||||
-{
|
||||
- if (get_be64(mpp->reservation_key) &&
|
||||
- get_prhold(mpp->alias) == PR_SET &&
|
||||
- reservation_key_matches(mpp, (uint8_t *)&mpp->reservation_key, type) == YNU_YES)
|
||||
- return true;
|
||||
- return false;
|
||||
-}
|
||||
-
|
||||
int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
int rq_servact, int rq_scope, unsigned int rq_type,
|
||||
struct prout_param_descriptor *paramp, int noisy)
|
262
0075-libmpathpersist-Fix-unregistering-while-holding-the-.patch
Normal file
262
0075-libmpathpersist-Fix-unregistering-while-holding-the-.patch
Normal file
@ -0,0 +1,262 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 19 Sep 2025 18:17:20 -0400
|
||||
Subject: [PATCH] libmpathpersist: Fix unregistering while holding the
|
||||
reservation
|
||||
|
||||
There were two problems with how libmpathpersist handled unregistering
|
||||
a key while holding the reseravation (which should also release the
|
||||
reservation).
|
||||
1. If the path holding the reservation is not unregistered first, there
|
||||
will be unregistered paths, while a reservation is still held, which
|
||||
would cause IO to those paths to fail, when it shouldn't.
|
||||
2. If the path that holds the reservation is down, libmpathpersist was
|
||||
not clearing the reservation, since the there were no registered keys
|
||||
it could use for the PREEMPT command workaround
|
||||
|
||||
To fix these, libmpathpersist now releases the reservation first when
|
||||
trying to unregister a key that is holding the reservation.
|
||||
mpath_prout_rel() has a new option so that if it needs to self preempt
|
||||
to clear the reservation, it won't re-register the paths when called
|
||||
as part of unregistering a key. Also, instead of checking if the device
|
||||
is currently holding a reservation using mpp->reservation_key in
|
||||
check_holding_reservation() (which will already be set to 0 when called
|
||||
as part of unregistering a key), pass in the key to check.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.h | 3 +
|
||||
libmpathpersist/mpath_persist_int.c | 108 ++++++++++++++++++++--------
|
||||
2 files changed, 80 insertions(+), 31 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h
|
||||
index b83fc3bd..22c1d4ac 100644
|
||||
--- a/libmpathpersist/mpath_persist.h
|
||||
+++ b/libmpathpersist/mpath_persist.h
|
||||
@@ -66,6 +66,9 @@ extern "C" {
|
||||
#define MPATH_PR_RETRYABLE_ERROR 16 /* error that might be succeed
|
||||
down another path. Internal
|
||||
only. */
|
||||
+#define MPATH_PR_SUCCESS_UNREGISTER 17 /* Success, and additionally, all
|
||||
+ paths were unregistered.
|
||||
+ Internal only. */
|
||||
|
||||
/* PR MASK */
|
||||
#define MPATH_F_APTPL_MASK 0x01 /* APTPL MASK*/
|
||||
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
||||
index 0eb7041e..00334a1a 100644
|
||||
--- a/libmpathpersist/mpath_persist_int.c
|
||||
+++ b/libmpathpersist/mpath_persist_int.c
|
||||
@@ -574,18 +574,23 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return status;
|
||||
}
|
||||
|
||||
+enum preempt_work {
|
||||
+ PREE_WORK_NONE,
|
||||
+ PREE_WORK_REL,
|
||||
+ PREE_WORK_REL_UNREG,
|
||||
+};
|
||||
/*
|
||||
* Called to make a multipath device preempt its own reservation (and
|
||||
- * optionally release the reservation). Doing this causes the reservation
|
||||
- * keys to be removed from all the device paths except that path used to issue
|
||||
- * the preempt, so they need to be restored. To avoid the chance that IO
|
||||
- * goes to these paths when they don't have a registered key, the device
|
||||
- * is suspended before issuing the preemption, and the keys are reregistered
|
||||
- * before resuming it.
|
||||
+ * optional extra work). Doing this causes the reservation keys to be removed
|
||||
+ * from all the device paths except that path used to issue the preempt, so
|
||||
+ * they may need to be restored. To avoid the chance that IO goes to these
|
||||
+ * paths when they don't have a registered key and a reservation exists, the
|
||||
+ * device is suspended before issuing the preemption, and the keys are
|
||||
+ * reregistered (or the reservation is released) before resuming it.
|
||||
*/
|
||||
static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
int rq_servact, int rq_scope, unsigned int rq_type,
|
||||
- int noisy, bool do_release)
|
||||
+ int noisy, enum preempt_work work)
|
||||
{
|
||||
int status, rel_status = MPATH_PR_SUCCESS;
|
||||
struct path *pp = NULL;
|
||||
@@ -606,7 +611,7 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
goto fail_resume;
|
||||
}
|
||||
|
||||
- if (do_release) {
|
||||
+ if (work != PREE_WORK_NONE) {
|
||||
memset(¶mp, 0, sizeof(paramp));
|
||||
memcpy(paramp.key, &mpp->reservation_key, 8);
|
||||
rel_status = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REL_SA,
|
||||
@@ -614,15 +619,26 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
if (rel_status != MPATH_PR_SUCCESS)
|
||||
condlog(0, "%s: release on alternate path failed.",
|
||||
mpp->wwid);
|
||||
+ else if (work == PREE_WORK_REL_UNREG) {
|
||||
+ /* unregister the last path */
|
||||
+ rel_status = prout_do_scsi_ioctl(pp->dev,
|
||||
+ MPATH_PROUT_REG_IGN_SA,
|
||||
+ rq_scope, rq_type,
|
||||
+ ¶mp, noisy);
|
||||
+ if (rel_status != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: final self preempt unregister failed,",
|
||||
+ mpp->wwid);
|
||||
+ }
|
||||
+ }
|
||||
+ if (work != PREE_WORK_REL_UNREG) {
|
||||
+ memset(¶mp, 0, sizeof(paramp));
|
||||
+ memcpy(paramp.sa_key, &mpp->reservation_key, 8);
|
||||
+ status = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope,
|
||||
+ rq_type, ¶mp, noisy);
|
||||
+ if (status != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: self preempt failed to reregister paths.",
|
||||
+ mpp->wwid);
|
||||
}
|
||||
-
|
||||
- memset(¶mp, 0, sizeof(paramp));
|
||||
- memcpy(paramp.sa_key, &mpp->reservation_key, 8);
|
||||
- status = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope,
|
||||
- rq_type, ¶mp, noisy);
|
||||
- if (status != MPATH_PR_SUCCESS)
|
||||
- condlog(0, "%s: self preempt failed to reregister paths.",
|
||||
- mpp->wwid);
|
||||
|
||||
fail_resume:
|
||||
if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
@@ -635,10 +651,10 @@ fail_resume:
|
||||
}
|
||||
|
||||
static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, int noisy, bool do_release)
|
||||
+ unsigned int rq_type, int noisy, enum preempt_work work)
|
||||
{
|
||||
return do_preempt_self(mpp, mpp->reservation_key, rq_servact, rq_scope,
|
||||
- rq_type, noisy, do_release);
|
||||
+ rq_type, noisy, work);
|
||||
}
|
||||
|
||||
static int preempt_all(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
@@ -646,7 +662,7 @@ static int preempt_all(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
{
|
||||
struct be64 zerokey = {0};
|
||||
return do_preempt_self(mpp, zerokey, rq_servact, rq_scope, rq_type,
|
||||
- noisy, false);
|
||||
+ noisy, PREE_WORK_NONE);
|
||||
}
|
||||
|
||||
static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
|
||||
@@ -671,18 +687,21 @@ static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
|
||||
return YNU_NO;
|
||||
}
|
||||
|
||||
-static bool check_holding_reservation(struct multipath *mpp, unsigned int *type)
|
||||
+static bool check_holding_reservation(struct multipath *mpp, uint8_t *curr_key,
|
||||
+ unsigned int *type)
|
||||
{
|
||||
- if (get_be64(mpp->reservation_key) &&
|
||||
+ uint64_t zerokey = 0;
|
||||
+ if (memcmp(curr_key, &zerokey, 8) != 0 &&
|
||||
get_prhold(mpp->alias) == PR_SET &&
|
||||
- reservation_key_matches(mpp, (uint8_t *)&mpp->reservation_key, type) == YNU_YES)
|
||||
+ reservation_key_matches(mpp, curr_key, type) == YNU_YES)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
-static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
+static int mpath_prout_rel(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
unsigned int rq_type,
|
||||
- struct prout_param_descriptor * paramp, int noisy)
|
||||
+ struct prout_param_descriptor *paramp, int noisy,
|
||||
+ bool unregister)
|
||||
{
|
||||
int i, j;
|
||||
struct pathgroup *pgp = NULL;
|
||||
@@ -772,7 +791,8 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return status;
|
||||
}
|
||||
|
||||
- if (!check_holding_reservation(mpp, &res_type)) {
|
||||
+ if (!check_holding_reservation(mpp, (uint8_t *)&mpp->reservation_key,
|
||||
+ &res_type)) {
|
||||
condlog(2, "%s: Releasing key not holding reservation.", mpp->wwid);
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
@@ -795,7 +815,13 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
* 4. Reregistering keys on all the paths
|
||||
* 5. Resuming the device
|
||||
*/
|
||||
- return preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type, noisy, true);
|
||||
+ status = preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type,
|
||||
+ noisy,
|
||||
+ unregister ? PREE_WORK_REL_UNREG : PREE_WORK_REL);
|
||||
+ if (status == MPATH_PR_SUCCESS && unregister)
|
||||
+ return MPATH_PR_SUCCESS_UNREGISTER;
|
||||
+ return status;
|
||||
+
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -838,7 +864,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
select_reservation_key(conf, mpp);
|
||||
put_multipath_config(conf);
|
||||
|
||||
- memcpy(&oldkey, &mpp->reservation_key, 8);
|
||||
+ oldkey = mpp->reservation_key;
|
||||
unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
|
||||
if (mpp->prkey_source == PRKEY_SOURCE_FILE &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
@@ -920,7 +946,27 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
{
|
||||
case MPATH_PROUT_REG_SA:
|
||||
case MPATH_PROUT_REG_IGN_SA:
|
||||
- ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
+ if (unregistering && check_holding_reservation(mpp, (uint8_t *)&oldkey, &rq_type)) {
|
||||
+ struct be64 newkey = mpp->reservation_key;
|
||||
+ /* temporarily restore reservation key */
|
||||
+ mpp->reservation_key = oldkey;
|
||||
+ ret = mpath_prout_rel(mpp, MPATH_PROUT_REL_SA, rq_scope,
|
||||
+ rq_type, paramp, noisy, true);
|
||||
+ mpp->reservation_key = newkey;
|
||||
+ if (ret == MPATH_PR_SUCCESS)
|
||||
+ /*
|
||||
+ * Since unregistering it true, paramp->sa_key
|
||||
+ * must be zero here. So this command will
|
||||
+ * unregister the key.
|
||||
+ */
|
||||
+ ret = mpath_prout_reg(mpp, rq_servact, rq_scope,
|
||||
+ rq_type, paramp, noisy);
|
||||
+ else if (ret == MPATH_PR_SUCCESS_UNREGISTER)
|
||||
+ /* We already unregistered the key */
|
||||
+ ret = MPATH_PR_SUCCESS;
|
||||
+ } else
|
||||
+ ret = mpath_prout_reg(mpp, rq_servact, rq_scope,
|
||||
+ rq_type, paramp, noisy);
|
||||
break;
|
||||
case MPATH_PROUT_PREE_SA:
|
||||
case MPATH_PROUT_PREE_AB_SA:
|
||||
@@ -936,7 +982,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
/* if we are preempting ourself */
|
||||
if (memcmp(paramp->sa_key, paramp->key, 8) == 0) {
|
||||
ret = preempt_self(mpp, rq_servact, rq_scope, rq_type,
|
||||
- noisy, false);
|
||||
+ noisy, PREE_WORK_NONE);
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
@@ -947,14 +993,14 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
paramp, noisy, NULL, &failed_paths);
|
||||
if (rq_servact == MPATH_PROUT_RES_SA &&
|
||||
ret != MPATH_PR_SUCCESS && failed_paths &&
|
||||
- check_holding_reservation(mpp, &res_type) &&
|
||||
+ check_holding_reservation(mpp, paramp->key, &res_type) &&
|
||||
res_type == rq_type)
|
||||
/* The reserve failed, but multipathd says we hold it */
|
||||
ret = MPATH_PR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
case MPATH_PROUT_REL_SA:
|
||||
- ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
+ ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy, false);
|
||||
break;
|
||||
default:
|
||||
ret = MPATH_PR_OTHER;
|
214
0076-libmpathpersist-Fix-race-between-restoring-a-path-an.patch
Normal file
214
0076-libmpathpersist-Fix-race-between-restoring-a-path-an.patch
Normal file
@ -0,0 +1,214 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 30 Sep 2025 19:36:36 -0400
|
||||
Subject: [PATCH] libmpathpersist: Fix race between restoring a path and
|
||||
preemption
|
||||
|
||||
If a multipath device gets preempted while a path is being restored, the
|
||||
path could end up getting the old key registered on it anyways. This
|
||||
happens by:
|
||||
1. multipathd calling update_map_pr() in mpath_pr_event_handle() and
|
||||
seeing that there are matching keys.
|
||||
2. Those matching keys get preempted.
|
||||
3. multipathd registering the preempted key on the path.
|
||||
|
||||
Since there is no way to guarantee that the key won't get preempted
|
||||
after multipathd checks for it, mpath_pr_event_handle() now calls
|
||||
update_map_pr() to check the registered keys again after registering the
|
||||
key. There must be at least as many keys registered after registering
|
||||
the key on the restored path (which may already have a key registered on
|
||||
it, so it's possible that the number of registered keys doesn't change).
|
||||
|
||||
pr_register_active_paths() calls mpath_pr_event_handle() for all working
|
||||
paths on a device. In order to avoid calling update_map_pr() twice for
|
||||
every path, mpath_pr_event_handle() now takes the number of keys to
|
||||
expect, and skips the initial call to update_map_pr() if it already
|
||||
knows how many keys are registered before trying to register the new
|
||||
path.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/main.c | 77 ++++++++++++++++++++++++++++++++---------------
|
||||
1 file changed, 52 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 3b53d140..06ff6858 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -89,7 +89,8 @@
|
||||
#define CMDSIZE 160
|
||||
#define MSG_SIZE 32
|
||||
|
||||
-static void mpath_pr_event_handle(struct path *pp);
|
||||
+static unsigned int
|
||||
+mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed);
|
||||
|
||||
#define LOG_MSG(lvl, pp) \
|
||||
do { \
|
||||
@@ -638,7 +639,7 @@ flush_map_nopaths(struct multipath *mpp, struct vectors *vecs) {
|
||||
static void
|
||||
pr_register_active_paths(struct multipath *mpp)
|
||||
{
|
||||
- unsigned int i, j;
|
||||
+ unsigned int i, j, nr_keys = 0;
|
||||
struct path *pp;
|
||||
struct pathgroup *pgp;
|
||||
|
||||
@@ -647,7 +648,7 @@ pr_register_active_paths(struct multipath *mpp)
|
||||
if (mpp->prflag == PR_UNSET)
|
||||
return;
|
||||
if ((pp->state == PATH_UP) || (pp->state == PATH_GHOST))
|
||||
- mpath_pr_event_handle(pp);
|
||||
+ nr_keys = mpath_pr_event_handle(pp, nr_keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1298,7 +1299,7 @@ rescan:
|
||||
verify_paths(mpp);
|
||||
mpp->action = ACT_RELOAD;
|
||||
prflag = mpp->prflag;
|
||||
- mpath_pr_event_handle(pp);
|
||||
+ mpath_pr_event_handle(pp, 0);
|
||||
} else {
|
||||
if (!should_multipath(pp, vecs->pathvec, vecs->mpvec)) {
|
||||
orphan_path(pp, "only one path");
|
||||
@@ -2652,7 +2653,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
*/
|
||||
condlog(2, "%s: checking persistent "
|
||||
"reservation registration", pp->dev);
|
||||
- mpath_pr_event_handle(pp);
|
||||
+ mpath_pr_event_handle(pp, 0);
|
||||
if (pp->mpp->prflag == PR_SET &&
|
||||
prflag != PR_SET)
|
||||
pr_register_active_paths(pp->mpp);
|
||||
@@ -3982,12 +3983,16 @@ void unset_pr(struct multipath *mpp)
|
||||
* Returns MPATH_PR_SUCCESS unless if fails to read the PR keys. If
|
||||
* MPATH_PR_SUCCESS is returned, mpp->prflag will be either PR_SET or
|
||||
* PR_UNSET.
|
||||
+ *
|
||||
+ * The number of found keys must be at least as large as *nr_keys,
|
||||
+ * and if MPATH_PR_SUCCESS is returned and mpp->prflag is PR_SET after
|
||||
+ * the call, *nr_keys will be set to the number of found keys.
|
||||
*/
|
||||
-static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
+static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *nr_keys)
|
||||
{
|
||||
struct prin_resp resp;
|
||||
- unsigned int i;
|
||||
- int ret, isFound;
|
||||
+ unsigned int i, nr_found = 0;
|
||||
+ int ret;
|
||||
bool was_set = (mpp->prflag == PR_SET);
|
||||
|
||||
/* If pr is explicitly unset, it must be manually set */
|
||||
@@ -4017,7 +4022,6 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
condlog(4, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
get_be64(mpp->reservation_key));
|
||||
|
||||
- isFound = 0;
|
||||
for (i = 0;
|
||||
i < resp.prin_descriptor.prin_readkeys.additional_length / 8; i++) {
|
||||
uint8_t *keyp = &resp.prin_descriptor.prin_readkeys.key_list[i * 8];
|
||||
@@ -4037,41 +4041,57 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
if (!memcmp(&mpp->reservation_key, keyp, 8) ||
|
||||
(get_be64(mpp->old_pr_key) &&
|
||||
!memcmp(&mpp->old_pr_key, keyp, 8)))
|
||||
- isFound = 1;
|
||||
+ nr_found++;
|
||||
}
|
||||
|
||||
- if (isFound) {
|
||||
+ if (nr_found >= *nr_keys) {
|
||||
set_pr(mpp);
|
||||
- condlog(was_set ? 3 : 2, "%s: key found. prflag set.", mpp->alias);
|
||||
+ condlog(was_set ? 3 : 2, "%s: %u keys found. prflag set.",
|
||||
+ mpp->alias, nr_found);
|
||||
+ *nr_keys = nr_found;
|
||||
} else {
|
||||
unset_pr(mpp);
|
||||
- condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
- mpp->alias);
|
||||
+ condlog(was_set ? 1 : 3,
|
||||
+ "%s: %u keys found. needed %u. prflag unset.",
|
||||
+ mpp->alias, nr_found, *nr_keys);
|
||||
}
|
||||
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
|
||||
-static void mpath_pr_event_handle(struct path *pp)
|
||||
+/*
|
||||
+ * This function is called with the number of registered keys that should be
|
||||
+ * seen for this device to know that the key has not been preempted while the
|
||||
+ * path was getting registered. If 0 is passed in, update_mpath_pr is called
|
||||
+ * before registering the key to figure out the number, assuming that at
|
||||
+ * least one key must exist.
|
||||
+ *
|
||||
+ * The function returns the number of keys that are registered or 0 if
|
||||
+ * it's unknown.
|
||||
+ */
|
||||
+static unsigned int mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed)
|
||||
{
|
||||
struct multipath *mpp = pp->mpp;
|
||||
int ret;
|
||||
- struct prout_param_descriptor param;
|
||||
+ struct prout_param_descriptor param = {.sa_flags = 0};
|
||||
bool clear_reg = false;
|
||||
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
unset_pr(mpp);
|
||||
- return;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
- if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS)
|
||||
- return;
|
||||
+ if (nr_keys_needed == 0) {
|
||||
+ nr_keys_needed = 1;
|
||||
+ if (update_map_pr(mpp, pp, &nr_keys_needed) != MPATH_PR_SUCCESS)
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
check_prhold(mpp, pp);
|
||||
|
||||
if (mpp->prflag != PR_SET) {
|
||||
if (!mpp->ever_registered_pr)
|
||||
- return;
|
||||
+ return 0;
|
||||
/*
|
||||
* This path may have been unusable and either the
|
||||
* registration was cleared or the registered
|
||||
@@ -4084,21 +4104,28 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
clear_reg = true;
|
||||
}
|
||||
|
||||
- memset(¶m, 0, sizeof(param));
|
||||
-
|
||||
if (!clear_reg) {
|
||||
param.sa_flags = mpp->sa_flags;
|
||||
memcpy(param.sa_key, &mpp->reservation_key, 8);
|
||||
param.num_transportid = 0;
|
||||
}
|
||||
-
|
||||
+retry:
|
||||
condlog(3, "%s registration for device %s:%s",
|
||||
clear_reg ? "Clearing" : "Setting", pp->dev, pp->mpp->wwid);
|
||||
|
||||
ret = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REG_IGN_SA, 0, 0, ¶m, 0);
|
||||
- if (ret != MPATH_PR_SUCCESS )
|
||||
- {
|
||||
+ if (ret != MPATH_PR_SUCCESS) {
|
||||
condlog(0, "%s: %s reservation registration failed. Error: %d",
|
||||
clear_reg ? "Clearing" : "Setting", pp->dev, ret);
|
||||
+ } else if (!clear_reg) {
|
||||
+ if (update_map_pr(mpp, pp, &nr_keys_needed) != MPATH_PR_SUCCESS)
|
||||
+ return 0;
|
||||
+ if (mpp->prflag != PR_SET) {
|
||||
+ memset(¶m, 0, sizeof(param));
|
||||
+ clear_reg = true;
|
||||
+ goto retry;
|
||||
+ }
|
||||
+ return nr_keys_needed;
|
||||
}
|
||||
+ return 0;
|
||||
}
|
49
0077-multipathd-Fix-tracking-of-old-PR-key.patch
Normal file
49
0077-multipathd-Fix-tracking-of-old-PR-key.patch
Normal file
@ -0,0 +1,49 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 30 Sep 2025 23:32:11 -0400
|
||||
Subject: [PATCH] multipathd: Fix tracking of old PR key
|
||||
|
||||
When libmpathpersist is in the process of changing a registered key,
|
||||
multipathd needs to remember both the old and new values of the key to
|
||||
deal with a race between limpathpersist updating the key and multipathd
|
||||
restoring a failed path. It was supposed to stop remembering the old
|
||||
value when libmpathpersist was done changing the key and issued a
|
||||
"setprstatus" command. However, clearing the old key was done in
|
||||
set_pr(), which only gets called by cli_setprstatus() when registering a
|
||||
new device, not when changing the key on a registered device. Also,
|
||||
set_pr() is called by update_map_pr(). This means that multipathd was
|
||||
forgetting the key when it shouldn't and not when it should. Fix this
|
||||
to only forget the key when cli_setprstatus() is called, and always
|
||||
then.
|
||||
|
||||
Fixes: 1aeffa9e ("libmpathpersist: handle updating key race condition")
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/cli_handlers.c | 1 +
|
||||
multipathd/main.c | 1 -
|
||||
2 files changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||||
index ee2764b9..1696dbd4 100644
|
||||
--- a/multipathd/cli_handlers.c
|
||||
+++ b/multipathd/cli_handlers.c
|
||||
@@ -1283,6 +1283,7 @@ cli_setprstatus(void * v, struct strbuf *reply, void * data)
|
||||
set_pr(mpp);
|
||||
condlog(2, "%s: prflag set", param);
|
||||
}
|
||||
+ memset(&mpp->old_pr_key, 0, 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 06ff6858..e17a3355 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -3968,7 +3968,6 @@ void set_pr(struct multipath *mpp)
|
||||
{
|
||||
mpp->ever_registered_pr = true;
|
||||
mpp->prflag = PR_SET;
|
||||
- memset(&mpp->old_pr_key, 0, 8);
|
||||
}
|
||||
|
||||
void unset_pr(struct multipath *mpp)
|
@ -1,42 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 17 Mar 2020 17:28:24 -0500
|
||||
Subject: [PATCH] libmultipath: assign variable to make gcc happy
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
There is nothing wrong with is_queueing not being set at the start
|
||||
of __set_no_path_retry(), it will always get set before it is accessed,
|
||||
but gcc 8.2.1 is failing with
|
||||
|
||||
structs_vec.c: In function ‘__set_no_path_retry’:
|
||||
structs_vec.c:339:7: error: ‘is_queueing’ may be used uninitialized in
|
||||
this function [-Werror=maybe-uninitialized]
|
||||
bool is_queueing;
|
||||
^~~~~~~~~~~
|
||||
|
||||
so, assign a value to make it happy.
|
||||
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/structs_vec.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
|
||||
index 3dbbaa0f..077f2e42 100644
|
||||
--- a/libmultipath/structs_vec.c
|
||||
+++ b/libmultipath/structs_vec.c
|
||||
@@ -336,7 +336,7 @@ static void leave_recovery_mode(struct multipath *mpp)
|
||||
|
||||
void __set_no_path_retry(struct multipath *mpp, bool check_features)
|
||||
{
|
||||
- bool is_queueing;
|
||||
+ bool is_queueing = false; /* assign a value to make gcc happy */
|
||||
|
||||
check_features = check_features && mpp->features != NULL;
|
||||
if (check_features)
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,66 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Sat, 21 Mar 2020 23:49:59 -0500
|
||||
Subject: [PATCH] libmutipath: don't close fd on dm_lib_release
|
||||
|
||||
If dm_hold_control_open() isn't set, when dm_lib_release() is called, it
|
||||
will close the control fd. The control fd will get re-opened on the next
|
||||
dm_task_run() call, but if there is a dm_task_run() call already
|
||||
in progress in another thread, it can fail. Since many of the
|
||||
device-mapper callouts happen with the vecs lock held, this wasn't too
|
||||
noticeable, but there is code that calls dm_task_run() without the
|
||||
vecs lock held, notably the dmevent waiter code.
|
||||
|
||||
Since, as Martin pointed out, dm_hold_control_open() hasn't always
|
||||
existed in libdevmapper, check if it's supported on compilation,
|
||||
and update the version requirements if so.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/Makefile | 4 ++++
|
||||
libmultipath/devmapper.c | 7 ++++++-
|
||||
2 files changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
|
||||
index e5651e49..ad690a49 100644
|
||||
--- a/libmultipath/Makefile
|
||||
+++ b/libmultipath/Makefile
|
||||
@@ -36,6 +36,10 @@ ifneq ($(call check_func,dm_task_deferred_remove,/usr/include/libdevmapper.h),0)
|
||||
CFLAGS += -DLIBDM_API_DEFERRED
|
||||
endif
|
||||
|
||||
+ifneq ($(call check_func,dm_hold_control_dev,/usr/include/libdevmapper.h),0)
|
||||
+ CFLAGS += -DLIBDM_API_HOLD_CONTROL
|
||||
+endif
|
||||
+
|
||||
OBJS = memory.o parser.o vector.o devmapper.o callout.o \
|
||||
hwtable.o blacklist.o util.o dmparser.o config.o \
|
||||
structs.o discovery.o propsel.o dict.o \
|
||||
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
|
||||
index bed8ddc6..13a1cf53 100644
|
||||
--- a/libmultipath/devmapper.c
|
||||
+++ b/libmultipath/devmapper.c
|
||||
@@ -108,7 +108,9 @@ dm_lib_prereq (void)
|
||||
{
|
||||
char version[64];
|
||||
int v[3];
|
||||
-#if defined(LIBDM_API_DEFERRED)
|
||||
+#if defined(LIBDM_API_HOLD_CONTROL)
|
||||
+ int minv[3] = {1, 2, 111};
|
||||
+#elif defined(LIBDM_API_DEFERRED)
|
||||
int minv[3] = {1, 2, 89};
|
||||
#elif defined(DM_SUBSYSTEM_UDEV_FLAG0)
|
||||
int minv[3] = {1, 2, 82};
|
||||
@@ -254,6 +256,9 @@ void libmp_dm_init(void)
|
||||
memcpy(conf->version, version, sizeof(version));
|
||||
put_multipath_config(conf);
|
||||
dm_init(verbosity);
|
||||
+#ifdef LIBDM_API_HOLD_CONTROL
|
||||
+ dm_hold_control_dev(1);
|
||||
+#endif
|
||||
dm_udev_set_sync_support(libmp_dm_udev_sync);
|
||||
}
|
||||
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,64 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 19 Mar 2020 22:17:51 -0500
|
||||
Subject: [PATCH] libmultipath: allow force reload with no active paths
|
||||
|
||||
If the partition information has changed on multipath devices (say,
|
||||
because it was updated on another node that has access to the same
|
||||
storage), users expect that running "multipathd reconfigure" will update
|
||||
that. However, if the checkers for the multipath device are pending for
|
||||
too long when the the device is reconfigured, multipathd will give up
|
||||
waiting for them, and refuse to reload the device, since there are no
|
||||
active paths. This means that no kpartx update will be triggered.
|
||||
|
||||
Multipath is fully capable of reloading a multipath device that has no
|
||||
active paths. This has been possible for years. If multipath is supposed
|
||||
to reload the device, it should do so, even if there are no active paths.
|
||||
|
||||
Generally, when multipath is force reloaded, kpartx will be updated.
|
||||
However when a device is reloaded with no paths, the udev rules won't
|
||||
run kpartx. But they also weren't running kpartx when the first valid
|
||||
path appeared, even though the dm activation rules get run in this case.
|
||||
This changes 11-dm-mpath.rules to run kpartx when a device goes from no
|
||||
usable paths to having usable paths.
|
||||
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/configure.c | 6 ------
|
||||
multipath/11-dm-mpath.rules | 2 +-
|
||||
2 files changed, 1 insertion(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||||
index c95848a0..96c79610 100644
|
||||
--- a/libmultipath/configure.c
|
||||
+++ b/libmultipath/configure.c
|
||||
@@ -710,12 +710,6 @@ select_action (struct multipath * mpp, vector curmp, int force_reload)
|
||||
return;
|
||||
}
|
||||
|
||||
- if (pathcount(mpp, PATH_UP) == 0) {
|
||||
- mpp->action = ACT_IMPOSSIBLE;
|
||||
- condlog(3, "%s: set ACT_IMPOSSIBLE (no usable path)",
|
||||
- mpp->alias);
|
||||
- return;
|
||||
- }
|
||||
if (force_reload) {
|
||||
mpp->force_udev_reload = 1;
|
||||
mpp->action = ACT_RELOAD;
|
||||
diff --git a/multipath/11-dm-mpath.rules b/multipath/11-dm-mpath.rules
|
||||
index 07320a14..cd522e8c 100644
|
||||
--- a/multipath/11-dm-mpath.rules
|
||||
+++ b/multipath/11-dm-mpath.rules
|
||||
@@ -75,7 +75,7 @@ ENV{MPATH_DEVICE_READY}=="0", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1"
|
||||
ENV{MPATH_DEVICE_READY}!="0", ENV{.MPATH_DEVICE_READY_OLD}=="0",\
|
||||
ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="$env{DM_DISABLE_OTHER_RULES_FLAG_OLD}",\
|
||||
ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="",\
|
||||
- ENV{DM_ACTIVATION}="1"
|
||||
+ ENV{DM_ACTIVATION}="1", ENV{MPATH_UNCHANGED}="0"
|
||||
|
||||
# The code to check multipath state ends here. We need to set
|
||||
# properties and symlinks regardless whether the map is usable or
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,31 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hesse <mail@eworm.de>
|
||||
Date: Wed, 6 May 2020 09:35:47 +0200
|
||||
Subject: [PATCH] libmpathpersist: depend on libmultipath
|
||||
|
||||
Without this the build fails with:
|
||||
|
||||
/usr/bin/ld: cannot find -lmultipath
|
||||
|
||||
Signed-off-by: Christian Hesse <mail@eworm.de>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 1dee3680..ba1d73ba 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -28,7 +28,7 @@ all: $(BUILDDIRS)
|
||||
$(BUILDDIRS):
|
||||
$(MAKE) -C $@
|
||||
|
||||
-multipath multipathd mpathpersist: libmultipath
|
||||
+libmpathpersist multipath multipathd mpathpersist: libmultipath
|
||||
mpathpersist: libmpathpersist
|
||||
|
||||
$(BUILDDIRS.clean):
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,34 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Tue, 12 May 2020 00:39:21 +0200
|
||||
Subject: [PATCH] multipath-tools: Makefile: more dependency fixes for parallel
|
||||
build
|
||||
|
||||
Extend the late fixes from Christian.
|
||||
|
||||
Cc: Christian Hesse <mail@eworm.de>
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index ba1d73ba..fec3b73b 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -28,8 +28,9 @@ all: $(BUILDDIRS)
|
||||
$(BUILDDIRS):
|
||||
$(MAKE) -C $@
|
||||
|
||||
-libmpathpersist multipath multipathd mpathpersist: libmultipath
|
||||
-mpathpersist: libmpathpersist
|
||||
+libmultipath libdmmp: libmpathcmd
|
||||
+libmpathpersist multipath multipathd: libmultipath
|
||||
+mpathpersist multipathd: libmpathpersist
|
||||
|
||||
$(BUILDDIRS.clean):
|
||||
$(MAKE) -C ${@:.clean=} clean
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,33 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Tue, 12 May 2020 00:39:24 +0200
|
||||
Subject: [PATCH] multipath-tools: Makefile.inc: set -Wno-error=clobbered
|
||||
|
||||
We need to ignore -Wclobbered because gcc has trouble dealing with glibc's
|
||||
implementation of pthread_cleanup_push().
|
||||
|
||||
For some variants of gcc, -Wno-clobbered alone isn't enough if -Werror is also
|
||||
set. Compilation with -Wno-error=clobbered works, though.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile.inc | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/Makefile.inc b/Makefile.inc
|
||||
index d4d1e0dd..9060ac9b 100644
|
||||
--- a/Makefile.inc
|
||||
+++ b/Makefile.inc
|
||||
@@ -91,7 +91,7 @@ TEST_CC_OPTION = $(shell \
|
||||
|
||||
STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
|
||||
ERROR_DISCARDED_QUALIFIERS := $(call TEST_CC_OPTION,-Werror=discarded-qualifiers,)
|
||||
-WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered,)
|
||||
+WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered -Wno-error=clobbered,)
|
||||
|
||||
OPTFLAGS = -O2 -g -pipe -Werror -Wall -Wextra -Wformat=2 -Werror=implicit-int \
|
||||
-Werror=implicit-function-declaration -Werror=format-security \
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,91 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Tue, 12 May 2020 00:39:25 +0200
|
||||
Subject: [PATCH] libmultipath: discovery.c: use %z qualifier for size_t
|
||||
|
||||
Otherwise compilation for 32bit targets spits out warnings.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/discovery.c | 16 ++++++++--------
|
||||
1 file changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
||||
index ee3290cd..ffec5162 100644
|
||||
--- a/libmultipath/discovery.c
|
||||
+++ b/libmultipath/discovery.c
|
||||
@@ -986,7 +986,7 @@ parse_vpd_pg80(const unsigned char *in, char *out, size_t out_len)
|
||||
}
|
||||
|
||||
if (len >= out_len) {
|
||||
- condlog(2, "vpd pg80 overflow, %lu/%lu bytes required",
|
||||
+ condlog(2, "vpd pg80 overflow, %zu/%zu bytes required",
|
||||
len + 1, out_len);
|
||||
len = out_len - 1;
|
||||
}
|
||||
@@ -1087,7 +1087,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
|
||||
|
||||
len = sprintf(out, "%d", vpd_type);
|
||||
if (2 * vpd_len >= out_len - len) {
|
||||
- condlog(1, "%s: WWID overflow, type %d, %lu/%lu bytes required",
|
||||
+ condlog(1, "%s: WWID overflow, type %d, %zu/%zu bytes required",
|
||||
__func__, vpd_type,
|
||||
2 * vpd_len + len + 1, out_len);
|
||||
vpd_len = (out_len - len - 1) / 2;
|
||||
@@ -1096,7 +1096,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
|
||||
len += sprintf(out + len,
|
||||
"%02x", vpd[i]);
|
||||
} else if (vpd_type == 0x8 && vpd_len < 4) {
|
||||
- condlog(1, "%s: VPD length %lu too small for designator type 8",
|
||||
+ condlog(1, "%s: VPD length %zu too small for designator type 8",
|
||||
__func__, vpd_len);
|
||||
return -EINVAL;
|
||||
} else if (vpd_type == 0x8) {
|
||||
@@ -1112,7 +1112,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
|
||||
while (len > 2 && vpd[len - 2] == '\0')
|
||||
--len;
|
||||
if (len > out_len - 1) {
|
||||
- condlog(1, "%s: WWID overflow, type 8/%c, %lu/%lu bytes required",
|
||||
+ condlog(1, "%s: WWID overflow, type 8/%c, %zu/%zu bytes required",
|
||||
__func__, out[0], len + 1, out_len);
|
||||
len = out_len - 1;
|
||||
}
|
||||
@@ -1136,7 +1136,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
|
||||
while ((p = memchr(vpd, ' ', vpd_len))) {
|
||||
p_len = p - vpd;
|
||||
if (len + p_len > out_len - 1) {
|
||||
- condlog(1, "%s: WWID overflow, type 1, %lu/%lu bytes required",
|
||||
+ condlog(1, "%s: WWID overflow, type 1, %zu/%zu bytes required",
|
||||
__func__, len + p_len, out_len);
|
||||
p_len = out_len - len - 1;
|
||||
}
|
||||
@@ -1162,7 +1162,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
|
||||
p_len = vpd_len;
|
||||
if (p_len > 0 && len < out_len - 1) {
|
||||
if (len + p_len > out_len - 1) {
|
||||
- condlog(1, "%s: WWID overflow, type 1, %lu/%lu bytes required",
|
||||
+ condlog(1, "%s: WWID overflow, type 1, %zu/%zu bytes required",
|
||||
__func__, len + p_len + 1, out_len);
|
||||
p_len = out_len - len - 1;
|
||||
}
|
||||
@@ -1186,14 +1186,14 @@ parse_vpd_c0_hp3par(const unsigned char *in, size_t in_len,
|
||||
|
||||
memset(out, 0x0, out_len);
|
||||
if (in_len <= 4 || (in[4] > 3 && in_len < 44)) {
|
||||
- condlog(3, "HP/3PAR vendor specific VPD page length too short: %lu", in_len);
|
||||
+ condlog(3, "HP/3PAR vendor specific VPD page length too short: %zu", in_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (in[4] <= 3) /* revision must be > 3 to have Vomlume Name */
|
||||
return -ENODATA;
|
||||
len = get_unaligned_be32(&in[40]);
|
||||
if (len > out_len || len + 44 > in_len) {
|
||||
- condlog(3, "HP/3PAR vendor specific Volume name too long: %lu",
|
||||
+ condlog(3, "HP/3PAR vendor specific Volume name too long: %zu",
|
||||
len);
|
||||
return -EINVAL;
|
||||
}
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,185 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Tue, 12 May 2020 00:39:26 +0200
|
||||
Subject: [PATCH] libmultipath: eliminate more signed/unsigned comparisons
|
||||
|
||||
Fix some more compiler warnings about signed/unsigned comparison.
|
||||
I've observed these only on 32bit builds, therefore they went unnoticed
|
||||
before.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/print.c | 12 ++++++------
|
||||
libmultipath/prioritizers/alua_spc3.h | 2 +-
|
||||
multipathd/cli_handlers.c | 20 ++++++++++----------
|
||||
multipathd/main.c | 2 +-
|
||||
4 files changed, 18 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/print.c b/libmultipath/print.c
|
||||
index b944ef32..298b3764 100644
|
||||
--- a/libmultipath/print.c
|
||||
+++ b/libmultipath/print.c
|
||||
@@ -1958,25 +1958,25 @@ char *snprint_config(const struct config *conf, int *len,
|
||||
}
|
||||
|
||||
c = reply + snprint_defaults(conf, reply, maxlen);
|
||||
- if ((c - reply) == maxlen)
|
||||
+ if (c == reply + maxlen)
|
||||
continue;
|
||||
|
||||
c += snprint_blacklist(conf, c, reply + maxlen - c);
|
||||
- if ((c - reply) == maxlen)
|
||||
+ if (c == reply + maxlen)
|
||||
continue;
|
||||
|
||||
c += snprint_blacklist_except(conf, c, reply + maxlen - c);
|
||||
- if ((c - reply) == maxlen)
|
||||
+ if (c == reply + maxlen)
|
||||
continue;
|
||||
|
||||
c += snprint_hwtable(conf, c, reply + maxlen - c,
|
||||
hwtable ? hwtable : conf->hwtable);
|
||||
- if ((c - reply) == maxlen)
|
||||
+ if (c == reply + maxlen)
|
||||
continue;
|
||||
|
||||
c += snprint_overrides(conf, c, reply + maxlen - c,
|
||||
conf->overrides);
|
||||
- if ((c - reply) == maxlen)
|
||||
+ if (c == reply + maxlen)
|
||||
continue;
|
||||
|
||||
if (VECTOR_SIZE(conf->mptable) > 0 ||
|
||||
@@ -1984,7 +1984,7 @@ char *snprint_config(const struct config *conf, int *len,
|
||||
c += snprint_mptable(conf, c, reply + maxlen - c,
|
||||
mpvec);
|
||||
|
||||
- if ((c - reply) < maxlen) {
|
||||
+ if (c < reply + maxlen) {
|
||||
if (len)
|
||||
*len = c - reply;
|
||||
return reply;
|
||||
diff --git a/libmultipath/prioritizers/alua_spc3.h b/libmultipath/prioritizers/alua_spc3.h
|
||||
index 18b495ef..7ba2cf4c 100644
|
||||
--- a/libmultipath/prioritizers/alua_spc3.h
|
||||
+++ b/libmultipath/prioritizers/alua_spc3.h
|
||||
@@ -284,7 +284,7 @@ struct rtpg_data {
|
||||
#define RTPG_FOR_EACH_PORT_GROUP(p, g) \
|
||||
for( \
|
||||
g = &(p->data[0]); \
|
||||
- (((char *) g) - ((char *) p)) < get_unaligned_be32(p->length); \
|
||||
+ ((char *) g) < ((char *) p) + get_unaligned_be32(p->length); \
|
||||
g = (struct rtpg_tpg_dscr *) ( \
|
||||
((char *) g) + \
|
||||
sizeof(struct rtpg_tpg_dscr) + \
|
||||
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||||
index 7d878c88..31c3d9fd 100644
|
||||
--- a/multipathd/cli_handlers.c
|
||||
+++ b/multipathd/cli_handlers.c
|
||||
@@ -66,7 +66,7 @@ show_paths (char ** r, int * len, struct vectors * vecs, char * style,
|
||||
c += snprint_foreign_paths(c, reply + maxlen - c,
|
||||
style, pretty);
|
||||
|
||||
- again = ((c - reply) == (maxlen - 1));
|
||||
+ again = (c == reply + maxlen - 1);
|
||||
|
||||
REALLOC_REPLY(reply, again, maxlen);
|
||||
}
|
||||
@@ -102,7 +102,7 @@ show_path (char ** r, int * len, struct vectors * vecs, struct path *pp,
|
||||
|
||||
c += snprint_path(c, reply + maxlen - c, style, pp, 0);
|
||||
|
||||
- again = ((c - reply) == (maxlen - 1));
|
||||
+ again = (c == reply + maxlen - 1);
|
||||
|
||||
REALLOC_REPLY(reply, again, maxlen);
|
||||
}
|
||||
@@ -131,7 +131,7 @@ show_map_topology (char ** r, int * len, struct multipath * mpp,
|
||||
c = reply;
|
||||
|
||||
c += snprint_multipath_topology(c, reply + maxlen - c, mpp, 2);
|
||||
- again = ((c - reply) == (maxlen - 1));
|
||||
+ again = (c == reply + maxlen - 1);
|
||||
|
||||
REALLOC_REPLY(reply, again, maxlen);
|
||||
}
|
||||
@@ -171,7 +171,7 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs)
|
||||
}
|
||||
c += snprint_foreign_topology(c, reply + maxlen - c, 2);
|
||||
|
||||
- again = ((c - reply) == (maxlen - 1));
|
||||
+ again = (c == reply + maxlen - 1);
|
||||
|
||||
REALLOC_REPLY(reply, again, maxlen);
|
||||
}
|
||||
@@ -209,7 +209,7 @@ show_maps_json (char ** r, int * len, struct vectors * vecs)
|
||||
c = reply;
|
||||
|
||||
c += snprint_multipath_topology_json(c, maxlen, vecs);
|
||||
- again = ((c - reply) == maxlen);
|
||||
+ again = (c == reply + maxlen);
|
||||
|
||||
REALLOC_REPLY(reply, again, maxlen);
|
||||
}
|
||||
@@ -238,7 +238,7 @@ show_map_json (char ** r, int * len, struct multipath * mpp,
|
||||
c = reply;
|
||||
|
||||
c += snprint_multipath_map_json(c, maxlen, mpp);
|
||||
- again = ((c - reply) == maxlen);
|
||||
+ again = (c == reply + maxlen);
|
||||
|
||||
REALLOC_REPLY(reply, again, maxlen);
|
||||
}
|
||||
@@ -487,7 +487,7 @@ show_map (char ** r, int *len, struct multipath * mpp, char * style,
|
||||
c += snprint_multipath(c, reply + maxlen - c, style,
|
||||
mpp, pretty);
|
||||
|
||||
- again = ((c - reply) == (maxlen - 1));
|
||||
+ again = (c == reply + maxlen - 1);
|
||||
|
||||
REALLOC_REPLY(reply, again, maxlen);
|
||||
}
|
||||
@@ -533,7 +533,7 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style,
|
||||
}
|
||||
c += snprint_foreign_multipaths(c, reply + maxlen - c,
|
||||
style, pretty);
|
||||
- again = ((c - reply) == (maxlen - 1));
|
||||
+ again = (c == reply + maxlen - 1);
|
||||
|
||||
REALLOC_REPLY(reply, again, maxlen);
|
||||
}
|
||||
@@ -1297,7 +1297,7 @@ show_blacklist (char ** r, int * len)
|
||||
|
||||
c = reply;
|
||||
c += snprint_blacklist_report(conf, c, maxlen);
|
||||
- again = ((c - reply) == maxlen);
|
||||
+ again = (c == reply + maxlen);
|
||||
REALLOC_REPLY(reply, again, maxlen);
|
||||
}
|
||||
pthread_cleanup_pop(1);
|
||||
@@ -1339,7 +1339,7 @@ show_devices (char ** r, int * len, struct vectors *vecs)
|
||||
|
||||
c = reply;
|
||||
c += snprint_devices(conf, c, maxlen, vecs);
|
||||
- again = ((c - reply) == maxlen);
|
||||
+ again = (c == reply + maxlen);
|
||||
REALLOC_REPLY(reply, again, maxlen);
|
||||
}
|
||||
pthread_cleanup_pop(1);
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 8baf9abe..6b7db2c0 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -2374,7 +2374,7 @@ checkerloop (void *ap)
|
||||
conf = get_multipath_config();
|
||||
max_checkint = conf->max_checkint;
|
||||
put_multipath_config(conf);
|
||||
- if (diff_time.tv_sec > max_checkint)
|
||||
+ if (diff_time.tv_sec > (time_t)max_checkint)
|
||||
condlog(1, "path checkers took longer "
|
||||
"than %lu seconds, consider "
|
||||
"increasing max_polling_interval",
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,49 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Tue, 12 May 2020 00:39:27 +0200
|
||||
Subject: [PATCH] libmultipath: set_uint: fix parsing for 32bit
|
||||
|
||||
On architectures where sizeof(long) == sizeof(int), the code wouldn't
|
||||
work as intended. Use strtoul instead. As strtoul happily parses
|
||||
negative numbers as input, require the number to begin with a digit.
|
||||
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/dict.c | 11 +++++++----
|
||||
1 file changed, 7 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
|
||||
index 3e25e74f..0e9ea387 100644
|
||||
--- a/libmultipath/dict.c
|
||||
+++ b/libmultipath/dict.c
|
||||
@@ -60,19 +60,22 @@ static int
|
||||
set_uint(vector strvec, void *ptr)
|
||||
{
|
||||
unsigned int *uint_ptr = (unsigned int *)ptr;
|
||||
- char *buff, *eptr;
|
||||
- long res;
|
||||
+ char *buff, *eptr, *p;
|
||||
+ unsigned long res;
|
||||
int rc;
|
||||
|
||||
buff = set_value(strvec);
|
||||
if (!buff)
|
||||
return 1;
|
||||
|
||||
- res = strtol(buff, &eptr, 10);
|
||||
+ p = buff;
|
||||
+ while (isspace(*p))
|
||||
+ p++;
|
||||
+ res = strtoul(p, &eptr, 10);
|
||||
if (eptr > buff)
|
||||
while (isspace(*eptr))
|
||||
eptr++;
|
||||
- if (*buff == '\0' || *eptr != '\0' || res < 0 || res > UINT_MAX) {
|
||||
+ if (*buff == '\0' || *eptr != '\0' || !isdigit(*p) || res > UINT_MAX) {
|
||||
condlog(1, "%s: invalid value for %s: \"%s\"",
|
||||
__func__, (char*)VECTOR_SLOT(strvec, 0), buff);
|
||||
rc = 1;
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,33 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Tue, 12 May 2020 22:38:22 +0200
|
||||
Subject: [PATCH] multipath-tools Makefile: add install dependency
|
||||
|
||||
$(libdir) must exist before running "make install" on prioritizer, checker,
|
||||
and foreign libraries.
|
||||
|
||||
Cc: Christian Hesse <mail@eworm.de>
|
||||
Signed-off-by: Martin Wilck <mwilck@suse.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index fec3b73b..8bcaba66 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -32,6 +32,10 @@ libmultipath libdmmp: libmpathcmd
|
||||
libmpathpersist multipath multipathd: libmultipath
|
||||
mpathpersist multipathd: libmpathpersist
|
||||
|
||||
+libmultipath/checkers.install \
|
||||
+ libmultipath/prioritizers.install \
|
||||
+ libmultipath/foreign.install: libmultipath.install
|
||||
+
|
||||
$(BUILDDIRS.clean):
|
||||
$(MAKE) -C ${@:.clean=} clean
|
||||
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,66 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 13 Apr 2017 07:22:23 -0500
|
||||
Subject: [PATCH] RH: fixup udev rules for redhat
|
||||
|
||||
The multipath rules need to run after scsi_id is run. This means moving
|
||||
them after 60-persistent-storage.rules for redhat. Redhat also uses a
|
||||
different naming scheme for partitions than SuSE.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile.inc | 2 +-
|
||||
kpartx/kpartx.rules | 2 +-
|
||||
multipath/Makefile | 4 ++--
|
||||
3 files changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/Makefile.inc b/Makefile.inc
|
||||
index 9060ac9b..034752d9 100644
|
||||
--- a/Makefile.inc
|
||||
+++ b/Makefile.inc
|
||||
@@ -53,7 +53,7 @@ endif
|
||||
prefix =
|
||||
exec_prefix = $(prefix)
|
||||
usr_prefix = $(prefix)
|
||||
-bindir = $(exec_prefix)/sbin
|
||||
+bindir = $(exec_prefix)/usr/sbin
|
||||
libudevdir = $(prefix)/$(SYSTEMDPATH)/udev
|
||||
udevrulesdir = $(libudevdir)/rules.d
|
||||
multipathdir = $(TOPDIR)/libmultipath
|
||||
diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules
|
||||
index 8f990494..8a3a1718 100644
|
||||
--- a/kpartx/kpartx.rules
|
||||
+++ b/kpartx/kpartx.rules
|
||||
@@ -32,6 +32,6 @@ LABEL="mpath_kpartx_end"
|
||||
GOTO="kpartx_end"
|
||||
|
||||
LABEL="run_kpartx"
|
||||
-RUN+="/sbin/kpartx -un -p -part /dev/$name"
|
||||
+RUN+="/sbin/kpartx -un /dev/$name"
|
||||
|
||||
LABEL="kpartx_end"
|
||||
diff --git a/multipath/Makefile b/multipath/Makefile
|
||||
index 0828a8f7..b9bbb3cf 100644
|
||||
--- a/multipath/Makefile
|
||||
+++ b/multipath/Makefile
|
||||
@@ -24,7 +24,7 @@ install:
|
||||
$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
||||
$(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/56-multipath.rules
|
||||
+ $(INSTALL_PROGRAM) -m 644 $(EXEC).rules $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules
|
||||
$(INSTALL_PROGRAM) -d $(DESTDIR)$(man8dir)
|
||||
$(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir)
|
||||
$(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir)
|
||||
@@ -33,7 +33,7 @@ install:
|
||||
uninstall:
|
||||
$(RM) $(DESTDIR)$(bindir)/$(EXEC)
|
||||
$(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules
|
||||
- $(RM) $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules
|
||||
+ $(RM) $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules
|
||||
$(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz
|
||||
$(RM) $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz
|
||||
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,106 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 15 Oct 2014 10:39:30 -0500
|
||||
Subject: [PATCH] RH: don't start without a config file
|
||||
|
||||
If /etc/multipath.conf doesn't exist, don't start multipathd and blacklist
|
||||
all devices when running multipath. A completely blank configuration file
|
||||
is almost never what users want. Also, people may have the multipath
|
||||
packages installed but don't want to use them. This patch provides a
|
||||
simple way to disable multipath. Simply removing or renaming
|
||||
/etc/multipath.conf will keep multipath from doing anything.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/config.c | 15 +++++++++++++++
|
||||
libmultipath/config.h | 1 +
|
||||
multipath/multipath.rules | 1 +
|
||||
multipathd/multipathd.8 | 2 ++
|
||||
multipathd/multipathd.service | 1 +
|
||||
5 files changed, 20 insertions(+)
|
||||
|
||||
diff --git a/libmultipath/config.c b/libmultipath/config.c
|
||||
index b4d87689..b36778b0 100644
|
||||
--- a/libmultipath/config.c
|
||||
+++ b/libmultipath/config.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "devmapper.h"
|
||||
#include "mpath_cmd.h"
|
||||
#include "propsel.h"
|
||||
+#include "version.h"
|
||||
|
||||
static int
|
||||
hwe_strmatch (const struct hwentry *hwe1, const struct hwentry *hwe2)
|
||||
@@ -778,6 +779,20 @@ load_config (char * file)
|
||||
goto out;
|
||||
}
|
||||
factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
|
||||
+ } else {
|
||||
+ condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
|
||||
+ if (conf->blist_devnode == NULL) {
|
||||
+ conf->blist_devnode = vector_alloc();
|
||||
+ if (!conf->blist_devnode) {
|
||||
+ condlog(0, "cannot allocate blacklist\n");
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+ if (store_ble(conf->blist_devnode, strdup(".*"),
|
||||
+ ORIGIN_NO_CONFIG)) {
|
||||
+ condlog(0, "cannot store default no-config blacklist\n");
|
||||
+ goto out;
|
||||
+ }
|
||||
}
|
||||
|
||||
conf->processed_main_config = 1;
|
||||
diff --git a/libmultipath/config.h b/libmultipath/config.h
|
||||
index ceecff2d..3368d8c9 100644
|
||||
--- a/libmultipath/config.h
|
||||
+++ b/libmultipath/config.h
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#define ORIGIN_DEFAULT 0
|
||||
#define ORIGIN_CONFIG 1
|
||||
+#define ORIGIN_NO_CONFIG 2
|
||||
|
||||
/*
|
||||
* In kernel, fast_io_fail == 0 means immediate failure on rport delete.
|
||||
diff --git a/multipath/multipath.rules b/multipath/multipath.rules
|
||||
index 9df11a95..0486bf70 100644
|
||||
--- a/multipath/multipath.rules
|
||||
+++ b/multipath/multipath.rules
|
||||
@@ -9,6 +9,7 @@ IMPORT{cmdline}="nompath"
|
||||
ENV{nompath}=="?*", GOTO="end_mpath"
|
||||
IMPORT{cmdline}="multipath"
|
||||
ENV{multipath}=="off", GOTO="end_mpath"
|
||||
+TEST!="/etc/multipath.conf", GOTO="end_mpath"
|
||||
|
||||
ENV{DEVTYPE}!="partition", GOTO="test_dev"
|
||||
IMPORT{parent}="DM_MULTIPATH_DEVICE_PATH"
|
||||
diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8
|
||||
index 048a838d..8bd47a80 100644
|
||||
--- a/multipathd/multipathd.8
|
||||
+++ b/multipathd/multipathd.8
|
||||
@@ -39,6 +39,8 @@ map regains its maximum performance and redundancy.
|
||||
This daemon executes the external \fBmultipath\fR tool when events occur.
|
||||
In turn, the multipath tool signals the multipathd daemon when it is done with
|
||||
devmap reconfiguration, so that it can refresh its failed path list.
|
||||
+
|
||||
+In this Linux distribution, multipathd does not run unless a /etc/multipath.conf file exists.
|
||||
.
|
||||
.
|
||||
.\" ----------------------------------------------------------------------------
|
||||
diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service
|
||||
index ba24983e..17434cef 100644
|
||||
--- a/multipathd/multipathd.service
|
||||
+++ b/multipathd/multipathd.service
|
||||
@@ -4,6 +4,7 @@ Wants=systemd-udev-trigger.service systemd-udev-settle.service
|
||||
Before=iscsi.service iscsid.service lvm2-activation-early.service
|
||||
Before=local-fs-pre.target blk-availability.service
|
||||
After=multipathd.socket systemd-udev-trigger.service systemd-udev-settle.service
|
||||
+ConditionPathExists=/etc/multipath.conf
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
ConditionKernelCommandLine=!nompath
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,64 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 19 Apr 2017 06:10:01 -0500
|
||||
Subject: [PATCH] RH: use rpm optflags if present
|
||||
|
||||
Use the passed in optflags when compiling as an RPM, and keep the
|
||||
default flags as close as possible to the current fedora flags, while
|
||||
still being generic.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
Makefile.inc | 29 +++++++++++++++++++++--------
|
||||
1 file changed, 21 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/Makefile.inc b/Makefile.inc
|
||||
index 034752d9..c2abd301 100644
|
||||
--- a/Makefile.inc
|
||||
+++ b/Makefile.inc
|
||||
@@ -89,16 +89,29 @@ TEST_CC_OPTION = $(shell \
|
||||
echo "$(2)"; \
|
||||
fi)
|
||||
|
||||
-STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
|
||||
ERROR_DISCARDED_QUALIFIERS := $(call TEST_CC_OPTION,-Werror=discarded-qualifiers,)
|
||||
WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered -Wno-error=clobbered,)
|
||||
+ifndef RPM_OPT_FLAGS
|
||||
+ STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
|
||||
+ OPTFLAGS = -O2 -g -pipe -Wall -Werror=format-security \
|
||||
+ -Wp,-D_FORTIFY_SOURCE=2 -fexceptions \
|
||||
+ $(STACKPROT) -grecord-gcc-switches \
|
||||
+ -fasynchronous-unwind-tables
|
||||
+ ifeq ($(shell test -f /usr/lib/rpm/redhat/redhat-hardened-cc1 && echo 1),1)
|
||||
+ OPTFLAGS += -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1
|
||||
+ endif
|
||||
+ ifeq ($(shell test -f /usr/lib/rpm/redhat/redhat-annobin-cc1 && echo 1),1)
|
||||
+ OPTFLAGS += -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1
|
||||
+ endif
|
||||
+else
|
||||
+ OPTFLAGS = $(RPM_OPT_FLAGS)
|
||||
+endif
|
||||
+OPTFLAGS += -Werror -Wextra -Wstrict-prototypes -Wformat=2 \
|
||||
+ -Werror=implicit-int -Werror=implicit-function-declaration \
|
||||
+ $(WNOCLOBBERED) \
|
||||
+ -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) \
|
||||
+ --param=ssp-buffer-size=4
|
||||
|
||||
-OPTFLAGS = -O2 -g -pipe -Werror -Wall -Wextra -Wformat=2 -Werror=implicit-int \
|
||||
- -Werror=implicit-function-declaration -Werror=format-security \
|
||||
- $(WNOCLOBBERED) \
|
||||
- -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) \
|
||||
- $(STACKPROT) --param=ssp-buffer-size=4
|
||||
-CPPFLAGS := -Wp,-D_FORTIFY_SOURCE=2
|
||||
CFLAGS := $(OPTFLAGS) -DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
|
||||
-MMD -MP $(CFLAGS)
|
||||
BIN_CFLAGS = -fPIE -DPIE
|
||||
@@ -135,4 +148,4 @@ check_file = $(shell \
|
||||
|
||||
%.o: %.c
|
||||
@echo building $@ because of $?
|
||||
- $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
+ $(CC) $(CFLAGS) -c -o $@ $<
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,121 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 6 Nov 2017 21:39:28 -0600
|
||||
Subject: [PATCH] RH: warn on invalid regex instead of failing
|
||||
|
||||
multipath.conf used to allow "*" as a match everything regular expression,
|
||||
instead of requiring ".*". Instead of erroring when the old style
|
||||
regular expressions are used, it should print a warning and convert
|
||||
them.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/dict.c | 27 +++++++++++++++++++++------
|
||||
libmultipath/parser.c | 13 +++++++++++++
|
||||
libmultipath/parser.h | 1 +
|
||||
3 files changed, 35 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
|
||||
index 0e9ea387..184d4b22 100644
|
||||
--- a/libmultipath/dict.c
|
||||
+++ b/libmultipath/dict.c
|
||||
@@ -103,6 +103,21 @@ set_str(vector strvec, void *ptr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int
|
||||
+set_regex(vector strvec, void *ptr)
|
||||
+{
|
||||
+ char **str_ptr = (char **)ptr;
|
||||
+
|
||||
+ if (*str_ptr)
|
||||
+ FREE(*str_ptr);
|
||||
+ *str_ptr = set_regex_value(strvec);
|
||||
+
|
||||
+ if (!*str_ptr)
|
||||
+ return 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
set_yes_no(vector strvec, void *ptr)
|
||||
{
|
||||
@@ -1504,7 +1519,7 @@ ble_ ## option ## _handler (struct config *conf, vector strvec) \
|
||||
if (!conf->option) \
|
||||
return 1; \
|
||||
\
|
||||
- buff = set_value(strvec); \
|
||||
+ buff = set_regex_value(strvec); \
|
||||
if (!buff) \
|
||||
return 1; \
|
||||
\
|
||||
@@ -1520,7 +1535,7 @@ ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \
|
||||
if (!conf->option) \
|
||||
return 1; \
|
||||
\
|
||||
- buff = set_value(strvec); \
|
||||
+ buff = set_regex_value(strvec); \
|
||||
if (!buff) \
|
||||
return 1; \
|
||||
\
|
||||
@@ -1623,16 +1638,16 @@ device_handler(struct config *conf, vector strvec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-declare_hw_handler(vendor, set_str)
|
||||
+declare_hw_handler(vendor, set_regex)
|
||||
declare_hw_snprint(vendor, print_str)
|
||||
|
||||
-declare_hw_handler(product, set_str)
|
||||
+declare_hw_handler(product, set_regex)
|
||||
declare_hw_snprint(product, print_str)
|
||||
|
||||
-declare_hw_handler(revision, set_str)
|
||||
+declare_hw_handler(revision, set_regex)
|
||||
declare_hw_snprint(revision, print_str)
|
||||
|
||||
-declare_hw_handler(bl_product, set_str)
|
||||
+declare_hw_handler(bl_product, set_regex)
|
||||
declare_hw_snprint(bl_product, print_str)
|
||||
|
||||
declare_hw_handler(hwhandler, set_str)
|
||||
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
|
||||
index d478b177..a184511b 100644
|
||||
--- a/libmultipath/parser.c
|
||||
+++ b/libmultipath/parser.c
|
||||
@@ -382,6 +382,19 @@ oom:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+void *
|
||||
+set_regex_value(vector strvec)
|
||||
+{
|
||||
+ char *buff = set_value(strvec);
|
||||
+
|
||||
+ if (buff && strcmp("*", buff) == 0) {
|
||||
+ condlog(0, "Invalid regular expression \"*\" in multipath.conf. Using \".*\"");
|
||||
+ FREE(buff);
|
||||
+ return strdup(".*");
|
||||
+ }
|
||||
+ return buff;
|
||||
+}
|
||||
+
|
||||
/* non-recursive configuration stream handler */
|
||||
static int kw_level = 0;
|
||||
|
||||
diff --git a/libmultipath/parser.h b/libmultipath/parser.h
|
||||
index 62906e98..b7917052 100644
|
||||
--- a/libmultipath/parser.h
|
||||
+++ b/libmultipath/parser.h
|
||||
@@ -77,6 +77,7 @@ extern void dump_keywords(vector keydump, int level);
|
||||
extern void free_keywords(vector keywords);
|
||||
extern vector alloc_strvec(char *string);
|
||||
extern void *set_value(vector strvec);
|
||||
+extern void *set_regex_value(vector strvec);
|
||||
extern int process_file(struct config *conf, char *conf_file);
|
||||
extern struct keyword * find_keyword(vector keywords, vector v, char * name);
|
||||
int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,139 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 8 Jun 2020 14:27:51 -0500
|
||||
Subject: [PATCH] libmultipath: remove _blacklist_exceptions functions
|
||||
|
||||
_blacklist_exceptions() and _blacklist_exceptions_device() are exactly
|
||||
the same as _blacklist() and _blacklist_device(), so remove them, and
|
||||
give the remaining functions to a more general name.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/blacklist.c | 62 ++++++++++------------------------------
|
||||
1 file changed, 15 insertions(+), 47 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
|
||||
index d9691b17..04d3adb9 100644
|
||||
--- a/libmultipath/blacklist.c
|
||||
+++ b/libmultipath/blacklist.c
|
||||
@@ -101,21 +101,8 @@ int set_ble_device(vector blist, char * vendor, char * product, int origin)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int
|
||||
-_blacklist_exceptions (vector elist, const char * str)
|
||||
-{
|
||||
- int i;
|
||||
- struct blentry * ele;
|
||||
-
|
||||
- vector_foreach_slot (elist, ele, i) {
|
||||
- if (!regexec(&ele->regex, str, 0, NULL, 0))
|
||||
- return 1;
|
||||
- }
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-int
|
||||
-_blacklist (vector blist, const char * str)
|
||||
+static int
|
||||
+match_reglist (vector blist, const char * str)
|
||||
{
|
||||
int i;
|
||||
struct blentry * ble;
|
||||
@@ -127,28 +114,9 @@ _blacklist (vector blist, const char * str)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int
|
||||
-_blacklist_exceptions_device(const struct _vector *elist, const char * vendor,
|
||||
- const char * product)
|
||||
-{
|
||||
- int i;
|
||||
- struct blentry_device * ble;
|
||||
-
|
||||
- vector_foreach_slot (elist, ble, i) {
|
||||
- if (!ble->vendor && !ble->product)
|
||||
- continue;
|
||||
- if ((!ble->vendor ||
|
||||
- !regexec(&ble->vendor_reg, vendor, 0, NULL, 0)) &&
|
||||
- (!ble->product ||
|
||||
- !regexec(&ble->product_reg, product, 0, NULL, 0)))
|
||||
- return 1;
|
||||
- }
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-int
|
||||
-_blacklist_device (const struct _vector *blist, const char * vendor,
|
||||
- const char * product)
|
||||
+static int
|
||||
+match_reglist_device (const struct _vector *blist, const char * vendor,
|
||||
+ const char * product)
|
||||
{
|
||||
int i;
|
||||
struct blentry_device * ble;
|
||||
@@ -294,9 +262,9 @@ filter_device (vector blist, vector elist, char * vendor, char * product,
|
||||
int r = MATCH_NOTHING;
|
||||
|
||||
if (vendor && product) {
|
||||
- if (_blacklist_exceptions_device(elist, vendor, product))
|
||||
+ if (match_reglist_device(elist, vendor, product))
|
||||
r = MATCH_DEVICE_BLIST_EXCEPT;
|
||||
- else if (_blacklist_device(blist, vendor, product))
|
||||
+ else if (match_reglist_device(blist, vendor, product))
|
||||
r = MATCH_DEVICE_BLIST;
|
||||
}
|
||||
|
||||
@@ -310,9 +278,9 @@ filter_devnode (vector blist, vector elist, char * dev)
|
||||
int r = MATCH_NOTHING;
|
||||
|
||||
if (dev) {
|
||||
- if (_blacklist_exceptions(elist, dev))
|
||||
+ if (match_reglist(elist, dev))
|
||||
r = MATCH_DEVNODE_BLIST_EXCEPT;
|
||||
- else if (_blacklist(blist, dev))
|
||||
+ else if (match_reglist(blist, dev))
|
||||
r = MATCH_DEVNODE_BLIST;
|
||||
}
|
||||
|
||||
@@ -326,9 +294,9 @@ filter_wwid (vector blist, vector elist, char * wwid, char * dev)
|
||||
int r = MATCH_NOTHING;
|
||||
|
||||
if (wwid) {
|
||||
- if (_blacklist_exceptions(elist, wwid))
|
||||
+ if (match_reglist(elist, wwid))
|
||||
r = MATCH_WWID_BLIST_EXCEPT;
|
||||
- else if (_blacklist(blist, wwid))
|
||||
+ else if (match_reglist(blist, wwid))
|
||||
r = MATCH_WWID_BLIST;
|
||||
}
|
||||
|
||||
@@ -345,9 +313,9 @@ filter_protocol(vector blist, vector elist, struct path * pp)
|
||||
if (pp) {
|
||||
snprint_path_protocol(buf, sizeof(buf), pp);
|
||||
|
||||
- if (_blacklist_exceptions(elist, buf))
|
||||
+ if (match_reglist(elist, buf))
|
||||
r = MATCH_PROTOCOL_BLIST_EXCEPT;
|
||||
- else if (_blacklist(blist, buf))
|
||||
+ else if (match_reglist(blist, buf))
|
||||
r = MATCH_PROTOCOL_BLIST;
|
||||
}
|
||||
|
||||
@@ -417,11 +385,11 @@ filter_property(struct config *conf, struct udev_device *udev, int lvl,
|
||||
if (check_missing_prop && !strcmp(env, uid_attribute))
|
||||
uid_attr_seen = true;
|
||||
|
||||
- if (_blacklist_exceptions(conf->elist_property, env)) {
|
||||
+ if (match_reglist(conf->elist_property, env)) {
|
||||
r = MATCH_PROPERTY_BLIST_EXCEPT;
|
||||
break;
|
||||
}
|
||||
- if (_blacklist(conf->blist_property, env)) {
|
||||
+ if (match_reglist(conf->blist_property, env)) {
|
||||
r = MATCH_PROPERTY_BLIST;
|
||||
break;
|
||||
}
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,95 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 8 Jun 2020 20:23:56 -0500
|
||||
Subject: [PATCH] libmultipath: fix parser issue with comments in strings
|
||||
|
||||
If a quoted string starts with '#' or '!', the parser will stop
|
||||
parsing the line, thinking that it's a comment. It should only
|
||||
be checking for comments outside of quoted strings. Fixed this and
|
||||
added unit tests to verify it.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/parser.c | 4 +++-
|
||||
tests/parser.c | 42 ++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 45 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
|
||||
index a184511b..a7285a35 100644
|
||||
--- a/libmultipath/parser.c
|
||||
+++ b/libmultipath/parser.c
|
||||
@@ -300,8 +300,10 @@ alloc_strvec(char *string)
|
||||
(isspace((int) *cp) || !isascii((int) *cp)))
|
||||
&& *cp != '\0')
|
||||
cp++;
|
||||
- if (*cp == '\0' || *cp == '!' || *cp == '#')
|
||||
+ if (*cp == '\0' ||
|
||||
+ (!in_string && (*cp == '!' || *cp == '#'))) {
|
||||
return strvec;
|
||||
+ }
|
||||
}
|
||||
out:
|
||||
vector_free(strvec);
|
||||
diff --git a/tests/parser.c b/tests/parser.c
|
||||
index 29859dac..5772391e 100644
|
||||
--- a/tests/parser.c
|
||||
+++ b/tests/parser.c
|
||||
@@ -440,6 +440,46 @@ static void test18(void **state)
|
||||
free_strvec(v);
|
||||
}
|
||||
|
||||
+static void test19(void **state)
|
||||
+{
|
||||
+#define QUOTED19 "!value"
|
||||
+ vector v = alloc_strvec("key \"" QUOTED19 "\"");
|
||||
+ char *val;
|
||||
+
|
||||
+ assert_int_equal(VECTOR_SIZE(v), 4);
|
||||
+ assert_string_equal(VECTOR_SLOT(v, 0), "key");
|
||||
+ assert_true(is_quote(VECTOR_SLOT(v, 1)));
|
||||
+ assert_string_equal(VECTOR_SLOT(v, 2), QUOTED19);
|
||||
+ assert_true(is_quote(VECTOR_SLOT(v, 3)));
|
||||
+ assert_int_equal(validate_config_strvec(v, test_file), 0);
|
||||
+
|
||||
+ val = set_value(v);
|
||||
+ assert_string_equal(val, QUOTED19);
|
||||
+
|
||||
+ free(val);
|
||||
+ free_strvec(v);
|
||||
+}
|
||||
+
|
||||
+static void test20(void **state)
|
||||
+{
|
||||
+#define QUOTED20 "#value"
|
||||
+ vector v = alloc_strvec("key \"" QUOTED20 "\"");
|
||||
+ char *val;
|
||||
+
|
||||
+ assert_int_equal(VECTOR_SIZE(v), 4);
|
||||
+ assert_string_equal(VECTOR_SLOT(v, 0), "key");
|
||||
+ assert_true(is_quote(VECTOR_SLOT(v, 1)));
|
||||
+ assert_string_equal(VECTOR_SLOT(v, 2), QUOTED20);
|
||||
+ assert_true(is_quote(VECTOR_SLOT(v, 3)));
|
||||
+ assert_int_equal(validate_config_strvec(v, test_file), 0);
|
||||
+
|
||||
+ val = set_value(v);
|
||||
+ assert_string_equal(val, QUOTED20);
|
||||
+
|
||||
+ free(val);
|
||||
+ free_strvec(v);
|
||||
+}
|
||||
+
|
||||
int test_config_parser(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
@@ -461,6 +501,8 @@ int test_config_parser(void)
|
||||
cmocka_unit_test(test16),
|
||||
cmocka_unit_test(test17),
|
||||
cmocka_unit_test(test18),
|
||||
+ cmocka_unit_test(test19),
|
||||
+ cmocka_unit_test(test20),
|
||||
};
|
||||
return cmocka_run_group_tests(tests, setup, teardown);
|
||||
}
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,435 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 8 Jun 2020 13:40:16 -0500
|
||||
Subject: [PATCH] libmultipath: invert regexes that start with exclamation
|
||||
point
|
||||
|
||||
The number of devices that multipath needs to blacklist keeps growing,
|
||||
and the udev rules already have
|
||||
|
||||
KERNEL!="sd*|dasd*|nvme*", GOTO="end_mpath"
|
||||
|
||||
so they only work correctly with these device types. Instead of
|
||||
individually blacklisting every type of device that can't be
|
||||
multipathed, multipath's default blacklist should work like the udev
|
||||
rule, and blacklist all devices that aren't scsi, dasd, or nvme.
|
||||
Unfortunately, the c regex library doesn't support negative lookahead.
|
||||
Instead, multipath should treat "!" at the beginning of
|
||||
blacklist/exceptions regexes as inverse matching the rest of the regex.
|
||||
If users need to match a literal '!' as the first character of their
|
||||
regex, they can use "\!" instead. This allows multipath to change the
|
||||
default devnode blacklist regex to "!^(sd[a-z]|dasd[a-z]|nvme[0-9])".
|
||||
|
||||
Extra tests have been added to the blacklist unit tests to verify the
|
||||
inverse matching code and the new default blacklist.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/blacklist.c | 41 +++++++++-----
|
||||
libmultipath/blacklist.h | 3 +
|
||||
multipath/multipath.conf.5 | 17 ++++--
|
||||
tests/blacklist.c | 110 +++++++++++++++++++++++++++++++++++++
|
||||
tests/test-lib.c | 2 +-
|
||||
5 files changed, 155 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
|
||||
index 04d3adb9..0c58aa32 100644
|
||||
--- a/libmultipath/blacklist.c
|
||||
+++ b/libmultipath/blacklist.c
|
||||
@@ -15,9 +15,24 @@
|
||||
#include "structs_vec.h"
|
||||
#include "print.h"
|
||||
|
||||
+char *check_invert(char *str, bool *invert)
|
||||
+{
|
||||
+ if (str[0] == '!') {
|
||||
+ *invert = true;
|
||||
+ return str + 1;
|
||||
+ }
|
||||
+ if (str[0] == '\\' && str[1] == '!') {
|
||||
+ *invert = false;
|
||||
+ return str + 1;
|
||||
+ }
|
||||
+ *invert = false;
|
||||
+ return str;
|
||||
+}
|
||||
+
|
||||
int store_ble(vector blist, char * str, int origin)
|
||||
{
|
||||
struct blentry * ble;
|
||||
+ char *regex_str;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
@@ -30,7 +45,8 @@ int store_ble(vector blist, char * str, int origin)
|
||||
if (!ble)
|
||||
goto out;
|
||||
|
||||
- if (regcomp(&ble->regex, str, REG_EXTENDED|REG_NOSUB))
|
||||
+ regex_str = check_invert(str, &ble->invert);
|
||||
+ if (regcomp(&ble->regex, regex_str, REG_EXTENDED|REG_NOSUB))
|
||||
goto out1;
|
||||
|
||||
if (!vector_alloc_slot(blist))
|
||||
@@ -66,6 +82,7 @@ int alloc_ble_device(vector blist)
|
||||
int set_ble_device(vector blist, char * vendor, char * product, int origin)
|
||||
{
|
||||
struct blentry_device * ble;
|
||||
+ char *regex_str;
|
||||
|
||||
if (!blist)
|
||||
return 1;
|
||||
@@ -76,7 +93,8 @@ int set_ble_device(vector blist, char * vendor, char * product, int origin)
|
||||
return 1;
|
||||
|
||||
if (vendor) {
|
||||
- if (regcomp(&ble->vendor_reg, vendor,
|
||||
+ regex_str = check_invert(vendor, &ble->vendor_invert);
|
||||
+ if (regcomp(&ble->vendor_reg, regex_str,
|
||||
REG_EXTENDED|REG_NOSUB)) {
|
||||
FREE(vendor);
|
||||
if (product)
|
||||
@@ -86,7 +104,8 @@ int set_ble_device(vector blist, char * vendor, char * product, int origin)
|
||||
ble->vendor = vendor;
|
||||
}
|
||||
if (product) {
|
||||
- if (regcomp(&ble->product_reg, product,
|
||||
+ regex_str = check_invert(product, &ble->product_invert);
|
||||
+ if (regcomp(&ble->product_reg, regex_str,
|
||||
REG_EXTENDED|REG_NOSUB)) {
|
||||
FREE(product);
|
||||
if (vendor) {
|
||||
@@ -108,7 +127,7 @@ match_reglist (vector blist, const char * str)
|
||||
struct blentry * ble;
|
||||
|
||||
vector_foreach_slot (blist, ble, i) {
|
||||
- if (!regexec(&ble->regex, str, 0, NULL, 0))
|
||||
+ if (!!regexec(&ble->regex, str, 0, NULL, 0) == ble->invert)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -125,9 +144,11 @@ match_reglist_device (const struct _vector *blist, const char * vendor,
|
||||
if (!ble->vendor && !ble->product)
|
||||
continue;
|
||||
if ((!ble->vendor ||
|
||||
- !regexec(&ble->vendor_reg, vendor, 0, NULL, 0)) &&
|
||||
+ !!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) ==
|
||||
+ ble->vendor_invert) &&
|
||||
(!ble->product ||
|
||||
- !regexec(&ble->product_reg, product, 0, NULL, 0)))
|
||||
+ !!regexec(&ble->product_reg, product, 0, NULL, 0) ==
|
||||
+ ble->product_invert))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -160,13 +181,7 @@ setup_default_blist (struct config * conf)
|
||||
char * str;
|
||||
int i;
|
||||
|
||||
- str = STRDUP("^(ram|zram|raw|loop|fd|md|dm-|sr|scd|st|dcssblk)[0-9]");
|
||||
- if (!str)
|
||||
- return 1;
|
||||
- if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
|
||||
- return 1;
|
||||
-
|
||||
- str = STRDUP("^(td|hd|vd)[a-z]");
|
||||
+ str = STRDUP("!^(sd[a-z]|dasd[a-z]|nvme[0-9])");
|
||||
if (!str)
|
||||
return 1;
|
||||
if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
|
||||
diff --git a/libmultipath/blacklist.h b/libmultipath/blacklist.h
|
||||
index 2d721f60..4305857d 100644
|
||||
--- a/libmultipath/blacklist.h
|
||||
+++ b/libmultipath/blacklist.h
|
||||
@@ -20,6 +20,7 @@
|
||||
struct blentry {
|
||||
char * str;
|
||||
regex_t regex;
|
||||
+ bool invert;
|
||||
int origin;
|
||||
};
|
||||
|
||||
@@ -28,6 +29,8 @@ struct blentry_device {
|
||||
char * product;
|
||||
regex_t vendor_reg;
|
||||
regex_t product_reg;
|
||||
+ bool vendor_invert;
|
||||
+ bool product_invert;
|
||||
int origin;
|
||||
};
|
||||
|
||||
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
||||
index 3455b1cc..6dc26f10 100644
|
||||
--- a/multipath/multipath.conf.5
|
||||
+++ b/multipath/multipath.conf.5
|
||||
@@ -1248,6 +1248,16 @@ being handled by multipath-tools.
|
||||
.LP
|
||||
.
|
||||
.
|
||||
+In the \fIblacklist\fR and \fIblacklist_exceptions\fR sections, starting a
|
||||
+quoted value with an exclamation mark \fB"!"\fR will invert the matching
|
||||
+of the rest of the regular expression. For instance, \fB"!^sd[a-z]"\fR will
|
||||
+match all values that do not start with \fB"sd[a-z]"\fR. The exclamation mark
|
||||
+can be escaped \fB"\\!"\fR to match a literal \fB!\fR at the start of a
|
||||
+regular expression. \fBNote:\fR The exclamation mark must be inside quotes,
|
||||
+otherwise it will be treated as starting a comment.
|
||||
+.LP
|
||||
+.
|
||||
+.
|
||||
The \fIblacklist_exceptions\fR section is used to revert the actions of the
|
||||
\fIblacklist\fR section. This allows one to selectively include ("whitelist") devices which
|
||||
would normally be excluded via the \fIblacklist\fR section. A common usage is
|
||||
@@ -1264,10 +1274,9 @@ unless explicitly stated.
|
||||
Regular expression matching the device nodes to be excluded/included.
|
||||
.RS
|
||||
.PP
|
||||
-The default \fIblacklist\fR consists of the regular expressions
|
||||
-"^(ram|zram|raw|loop|fd|md|dm-|sr|scd|st|dcssblk)[0-9]" and
|
||||
-"^(td|hd|vd)[a-z]". This causes virtual devices, non-disk devices, and some other
|
||||
-device types to be excluded from multipath handling by default.
|
||||
+The default \fIblacklist\fR consists of the regular expression
|
||||
+\fB"!^(sd[a-z]|dasd[a-z]|nvme[0-9])"\fR. This causes all device types other
|
||||
+than scsi, dasd, and nvme to be excluded from multipath handling by default.
|
||||
.RE
|
||||
.TP
|
||||
.B wwid
|
||||
diff --git a/tests/blacklist.c b/tests/blacklist.c
|
||||
index cc8a9a4a..d20e97af 100644
|
||||
--- a/tests/blacklist.c
|
||||
+++ b/tests/blacklist.c
|
||||
@@ -60,20 +60,46 @@ __wrap_udev_list_entry_get_name(struct udev_list_entry *list_entry)
|
||||
return *(const char **)list_entry;
|
||||
}
|
||||
|
||||
+vector elist_property_default;
|
||||
+vector blist_devnode_default;
|
||||
vector blist_devnode_sdb;
|
||||
+vector blist_devnode_sdb_inv;
|
||||
vector blist_all;
|
||||
vector blist_device_foo_bar;
|
||||
+vector blist_device_foo_inv_bar;
|
||||
+vector blist_device_foo_bar_inv;
|
||||
vector blist_device_all;
|
||||
vector blist_wwid_xyzzy;
|
||||
+vector blist_wwid_xyzzy_inv;
|
||||
vector blist_protocol_fcp;
|
||||
+vector blist_protocol_fcp_inv;
|
||||
vector blist_property_wwn;
|
||||
+vector blist_property_wwn_inv;
|
||||
|
||||
static int setup(void **state)
|
||||
{
|
||||
+ struct config conf;
|
||||
+
|
||||
+ memset(&conf, 0, sizeof(conf));
|
||||
+ conf.blist_devnode = vector_alloc();
|
||||
+ if (!conf.blist_devnode)
|
||||
+ return -1;
|
||||
+ conf.elist_property = vector_alloc();
|
||||
+ if (!conf.elist_property)
|
||||
+ return -1;
|
||||
+ if (setup_default_blist(&conf) != 0)
|
||||
+ return -1;
|
||||
+ elist_property_default = conf.elist_property;
|
||||
+ blist_devnode_default = conf.blist_devnode;
|
||||
+
|
||||
blist_devnode_sdb = vector_alloc();
|
||||
if (!blist_devnode_sdb ||
|
||||
store_ble(blist_devnode_sdb, strdup("sdb"), ORIGIN_CONFIG))
|
||||
return -1;
|
||||
+ blist_devnode_sdb_inv = vector_alloc();
|
||||
+ if (!blist_devnode_sdb_inv ||
|
||||
+ store_ble(blist_devnode_sdb_inv, strdup("!sdb"), ORIGIN_CONFIG))
|
||||
+ return -1;
|
||||
|
||||
blist_all = vector_alloc();
|
||||
if (!blist_all || store_ble(blist_all, strdup(".*"), ORIGIN_CONFIG))
|
||||
@@ -84,6 +110,18 @@ static int setup(void **state)
|
||||
set_ble_device(blist_device_foo_bar, strdup("foo"), strdup("bar"),
|
||||
ORIGIN_CONFIG))
|
||||
return -1;
|
||||
+ blist_device_foo_inv_bar = vector_alloc();
|
||||
+ if (!blist_device_foo_inv_bar ||
|
||||
+ alloc_ble_device(blist_device_foo_inv_bar) ||
|
||||
+ set_ble_device(blist_device_foo_inv_bar, strdup("!foo"),
|
||||
+ strdup("bar"), ORIGIN_CONFIG))
|
||||
+ return -1;
|
||||
+ blist_device_foo_bar_inv = vector_alloc();
|
||||
+ if (!blist_device_foo_bar_inv ||
|
||||
+ alloc_ble_device(blist_device_foo_bar_inv) ||
|
||||
+ set_ble_device(blist_device_foo_bar_inv, strdup("foo"),
|
||||
+ strdup("!bar"), ORIGIN_CONFIG))
|
||||
+ return -1;
|
||||
|
||||
blist_device_all = vector_alloc();
|
||||
if (!blist_device_all || alloc_ble_device(blist_device_all) ||
|
||||
@@ -95,29 +133,50 @@ static int setup(void **state)
|
||||
if (!blist_wwid_xyzzy ||
|
||||
store_ble(blist_wwid_xyzzy, strdup("xyzzy"), ORIGIN_CONFIG))
|
||||
return -1;
|
||||
+ blist_wwid_xyzzy_inv = vector_alloc();
|
||||
+ if (!blist_wwid_xyzzy_inv ||
|
||||
+ store_ble(blist_wwid_xyzzy_inv, strdup("!xyzzy"), ORIGIN_CONFIG))
|
||||
+ return -1;
|
||||
|
||||
blist_protocol_fcp = vector_alloc();
|
||||
if (!blist_protocol_fcp ||
|
||||
store_ble(blist_protocol_fcp, strdup("scsi:fcp"), ORIGIN_CONFIG))
|
||||
return -1;
|
||||
+ blist_protocol_fcp_inv = vector_alloc();
|
||||
+ if (!blist_protocol_fcp_inv ||
|
||||
+ store_ble(blist_protocol_fcp_inv, strdup("!scsi:fcp"),
|
||||
+ ORIGIN_CONFIG))
|
||||
+ return -1;
|
||||
|
||||
blist_property_wwn = vector_alloc();
|
||||
if (!blist_property_wwn ||
|
||||
store_ble(blist_property_wwn, strdup("ID_WWN"), ORIGIN_CONFIG))
|
||||
return -1;
|
||||
+ blist_property_wwn_inv = vector_alloc();
|
||||
+ if (!blist_property_wwn_inv ||
|
||||
+ store_ble(blist_property_wwn_inv, strdup("!ID_WWN"), ORIGIN_CONFIG))
|
||||
+ return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int teardown(void **state)
|
||||
{
|
||||
+ free_blacklist(elist_property_default);
|
||||
+ free_blacklist(blist_devnode_default);
|
||||
free_blacklist(blist_devnode_sdb);
|
||||
+ free_blacklist(blist_devnode_sdb_inv);
|
||||
free_blacklist(blist_all);
|
||||
free_blacklist_device(blist_device_foo_bar);
|
||||
+ free_blacklist_device(blist_device_foo_inv_bar);
|
||||
+ free_blacklist_device(blist_device_foo_bar_inv);
|
||||
free_blacklist_device(blist_device_all);
|
||||
free_blacklist(blist_wwid_xyzzy);
|
||||
+ free_blacklist(blist_wwid_xyzzy_inv);
|
||||
free_blacklist(blist_protocol_fcp);
|
||||
+ free_blacklist(blist_protocol_fcp_inv);
|
||||
free_blacklist(blist_property_wwn);
|
||||
+ free_blacklist(blist_property_wwn_inv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -141,6 +200,11 @@ static void test_devnode_blacklist(void **state)
|
||||
expect_condlog(3, "sdb: device node name blacklisted\n");
|
||||
assert_int_equal(filter_devnode(blist_devnode_sdb, NULL, "sdb"),
|
||||
MATCH_DEVNODE_BLIST);
|
||||
+ assert_int_equal(filter_devnode(blist_devnode_sdb_inv, NULL, "sdb"),
|
||||
+ MATCH_NOTHING);
|
||||
+ expect_condlog(3, "sdc: device node name blacklisted\n");
|
||||
+ assert_int_equal(filter_devnode(blist_devnode_sdb_inv, NULL, "sdc"),
|
||||
+ MATCH_DEVNODE_BLIST);
|
||||
}
|
||||
|
||||
static void test_devnode_whitelist(void **state)
|
||||
@@ -159,12 +223,39 @@ static void test_devnode_missing(void **state)
|
||||
MATCH_NOTHING);
|
||||
}
|
||||
|
||||
+static void test_devnode_default(void **state)
|
||||
+{
|
||||
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "sdaa"),
|
||||
+ MATCH_NOTHING);
|
||||
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "nvme0n1"),
|
||||
+ MATCH_NOTHING);
|
||||
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "dasda"),
|
||||
+ MATCH_NOTHING);
|
||||
+ expect_condlog(3, "hda: device node name blacklisted\n");
|
||||
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "hda"),
|
||||
+ MATCH_DEVNODE_BLIST);
|
||||
+}
|
||||
+
|
||||
static void test_device_blacklist(void **state)
|
||||
{
|
||||
expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n");
|
||||
assert_int_equal(filter_device(blist_device_foo_bar, NULL, "foo",
|
||||
"bar", "sdb"),
|
||||
MATCH_DEVICE_BLIST);
|
||||
+ assert_int_equal(filter_device(blist_device_foo_inv_bar, NULL, "foo",
|
||||
+ "bar", "sdb"),
|
||||
+ MATCH_NOTHING);
|
||||
+ assert_int_equal(filter_device(blist_device_foo_bar_inv, NULL, "foo",
|
||||
+ "bar", "sdb"),
|
||||
+ MATCH_NOTHING);
|
||||
+ expect_condlog(3, "sdb: (baz:bar) vendor/product blacklisted\n");
|
||||
+ assert_int_equal(filter_device(blist_device_foo_inv_bar, NULL, "baz",
|
||||
+ "bar", "sdb"),
|
||||
+ MATCH_DEVICE_BLIST);
|
||||
+ expect_condlog(3, "sdb: (foo:baz) vendor/product blacklisted\n");
|
||||
+ assert_int_equal(filter_device(blist_device_foo_bar_inv, NULL, "foo",
|
||||
+ "baz", "sdb"),
|
||||
+ MATCH_DEVICE_BLIST);
|
||||
}
|
||||
|
||||
static void test_device_whitelist(void **state)
|
||||
@@ -191,6 +282,11 @@ static void test_wwid_blacklist(void **state)
|
||||
expect_condlog(3, "sdb: wwid xyzzy blacklisted\n");
|
||||
assert_int_equal(filter_wwid(blist_wwid_xyzzy, NULL, "xyzzy", "sdb"),
|
||||
MATCH_WWID_BLIST);
|
||||
+ assert_int_equal(filter_wwid(blist_wwid_xyzzy_inv, NULL, "xyzzy",
|
||||
+ "sdb"), MATCH_NOTHING);
|
||||
+ expect_condlog(3, "sdb: wwid plugh blacklisted\n");
|
||||
+ assert_int_equal(filter_wwid(blist_wwid_xyzzy_inv, NULL, "plugh",
|
||||
+ "sdb"), MATCH_WWID_BLIST);
|
||||
}
|
||||
|
||||
static void test_wwid_whitelist(void **state)
|
||||
@@ -218,6 +314,12 @@ static void test_protocol_blacklist(void **state)
|
||||
expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n");
|
||||
assert_int_equal(filter_protocol(blist_protocol_fcp, NULL, &pp),
|
||||
MATCH_PROTOCOL_BLIST);
|
||||
+ assert_int_equal(filter_protocol(blist_protocol_fcp_inv, NULL, &pp),
|
||||
+ MATCH_NOTHING);
|
||||
+ pp.sg_id.proto_id = SCSI_PROTOCOL_ATA;
|
||||
+ expect_condlog(3, "sdb: protocol scsi:ata blacklisted\n");
|
||||
+ assert_int_equal(filter_protocol(blist_protocol_fcp_inv, NULL, &pp),
|
||||
+ MATCH_PROTOCOL_BLIST);
|
||||
}
|
||||
|
||||
static void test_protocol_whitelist(void **state)
|
||||
@@ -245,10 +347,17 @@ static void test_protocol_missing(void **state)
|
||||
static void test_property_blacklist(void **state)
|
||||
{
|
||||
static struct udev_device udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } };
|
||||
+ static struct udev_device udev_inv = { "sdb", { "ID_WWN", NULL } };
|
||||
conf.blist_property = blist_property_wwn;
|
||||
expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n");
|
||||
assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
|
||||
MATCH_PROPERTY_BLIST);
|
||||
+ conf.blist_property = blist_property_wwn_inv;
|
||||
+ expect_condlog(3, "sdb: udev property ID_FOO blacklisted\n");
|
||||
+ assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
|
||||
+ MATCH_PROPERTY_BLIST);
|
||||
+ assert_int_equal(filter_property(&conf, &udev_inv, 3, "ID_SERIAL"),
|
||||
+ MATCH_NOTHING);
|
||||
}
|
||||
|
||||
/* the property check works different in that you check all the property
|
||||
@@ -482,6 +591,7 @@ int test_blacklist(void)
|
||||
cmocka_unit_test(test_devnode_blacklist),
|
||||
cmocka_unit_test(test_devnode_whitelist),
|
||||
cmocka_unit_test(test_devnode_missing),
|
||||
+ cmocka_unit_test(test_devnode_default),
|
||||
cmocka_unit_test(test_device_blacklist),
|
||||
cmocka_unit_test(test_device_whitelist),
|
||||
cmocka_unit_test(test_device_missing),
|
||||
diff --git a/tests/test-lib.c b/tests/test-lib.c
|
||||
index 59275163..08ff2d8d 100644
|
||||
--- a/tests/test-lib.c
|
||||
+++ b/tests/test-lib.c
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "test-lib.h"
|
||||
|
||||
const int default_mask = (DI_SYSFS|DI_BLACKLIST|DI_WWID|DI_CHECKER|DI_PRIO);
|
||||
-const char default_devnode[] = "sdTEST";
|
||||
+const char default_devnode[] = "sdxTEST";
|
||||
const char default_wwid[] = "TEST-WWID";
|
||||
/* default_wwid should be a substring of default_wwid_1! */
|
||||
const char default_wwid_1[] = "TEST-WWID-1";
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,322 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 23 Jun 2020 22:17:31 -0500
|
||||
Subject: [PATCH] libmultipath: make dm_get_map/status return codes symbolic
|
||||
|
||||
dm_get_map() and dm_get_status() now use symbolic return codes. They
|
||||
also differentiate between failing to get information from device-mapper
|
||||
and not finding the requested device. These symboilc return codes are
|
||||
also used by update_multipath_* functions.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/devmapper.c | 51 +++++++++++++++++++++++++-------------
|
||||
libmultipath/devmapper.h | 6 +++++
|
||||
libmultipath/structs_vec.c | 45 +++++++++++++++++++--------------
|
||||
multipathd/main.c | 12 ++++-----
|
||||
4 files changed, 72 insertions(+), 42 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
|
||||
index 13a1cf53..f6204e5f 100644
|
||||
--- a/libmultipath/devmapper.c
|
||||
+++ b/libmultipath/devmapper.c
|
||||
@@ -525,36 +525,43 @@ int dm_map_present(const char * str)
|
||||
|
||||
int dm_get_map(const char *name, unsigned long long *size, char *outparams)
|
||||
{
|
||||
- int r = 1;
|
||||
+ int r = DMP_ERR;
|
||||
struct dm_task *dmt;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params = NULL;
|
||||
|
||||
if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
|
||||
- return 1;
|
||||
+ return r;
|
||||
|
||||
if (!dm_task_set_name(dmt, name))
|
||||
goto out;
|
||||
|
||||
dm_task_no_open_count(dmt);
|
||||
|
||||
- if (!dm_task_run(dmt))
|
||||
+ errno = 0;
|
||||
+ if (!dm_task_run(dmt)) {
|
||||
+ if (dm_task_get_errno(dmt) == ENXIO)
|
||||
+ r = DMP_NOT_FOUND;
|
||||
goto out;
|
||||
+ }
|
||||
|
||||
+ r = DMP_NOT_FOUND;
|
||||
/* Fetch 1st target */
|
||||
- dm_get_next_target(dmt, NULL, &start, &length,
|
||||
- &target_type, ¶ms);
|
||||
+ if (dm_get_next_target(dmt, NULL, &start, &length,
|
||||
+ &target_type, ¶ms) != NULL)
|
||||
+ /* more than one target */
|
||||
+ goto out;
|
||||
|
||||
if (size)
|
||||
*size = length;
|
||||
|
||||
if (!outparams) {
|
||||
- r = 0;
|
||||
+ r = DMP_OK;
|
||||
goto out;
|
||||
}
|
||||
if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
|
||||
- r = 0;
|
||||
+ r = DMP_OK;
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
@@ -628,35 +635,45 @@ is_mpath_part(const char *part_name, const char *map_name)
|
||||
|
||||
int dm_get_status(const char *name, char *outstatus)
|
||||
{
|
||||
- int r = 1;
|
||||
+ int r = DMP_ERR;
|
||||
struct dm_task *dmt;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *status = NULL;
|
||||
|
||||
if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS)))
|
||||
- return 1;
|
||||
+ return r;
|
||||
|
||||
if (!dm_task_set_name(dmt, name))
|
||||
goto out;
|
||||
|
||||
dm_task_no_open_count(dmt);
|
||||
|
||||
- if (!dm_task_run(dmt))
|
||||
+ errno = 0;
|
||||
+ if (!dm_task_run(dmt)) {
|
||||
+ if (dm_task_get_errno(dmt) == ENXIO)
|
||||
+ r = DMP_NOT_FOUND;
|
||||
goto out;
|
||||
+ }
|
||||
|
||||
+ r = DMP_NOT_FOUND;
|
||||
/* Fetch 1st target */
|
||||
- dm_get_next_target(dmt, NULL, &start, &length,
|
||||
- &target_type, &status);
|
||||
+ if (dm_get_next_target(dmt, NULL, &start, &length,
|
||||
+ &target_type, &status) != NULL)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
|
||||
+ goto out;
|
||||
+
|
||||
if (!status) {
|
||||
condlog(2, "get null status.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
|
||||
- r = 0;
|
||||
+ r = DMP_OK;
|
||||
out:
|
||||
- if (r)
|
||||
+ if (r != DMP_OK)
|
||||
condlog(0, "%s: error getting map status string", name);
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
@@ -866,7 +883,7 @@ int _dm_flush_map (const char * mapname, int need_sync, int deferred_remove,
|
||||
return 1;
|
||||
|
||||
if (need_suspend &&
|
||||
- !dm_get_map(mapname, &mapsize, params) &&
|
||||
+ dm_get_map(mapname, &mapsize, params) == DMP_OK &&
|
||||
strstr(params, "queue_if_no_path")) {
|
||||
if (!dm_queue_if_no_path(mapname, 0))
|
||||
queue_if_no_path = 1;
|
||||
@@ -1075,7 +1092,7 @@ struct multipath *dm_get_multipath(const char *name)
|
||||
if (!mpp->alias)
|
||||
goto out;
|
||||
|
||||
- if (dm_get_map(name, &mpp->size, NULL))
|
||||
+ if (dm_get_map(name, &mpp->size, NULL) != DMP_OK)
|
||||
goto out;
|
||||
|
||||
dm_get_uuid(name, mpp->wwid, WWID_SIZE);
|
||||
@@ -1259,7 +1276,7 @@ do_foreach_partmaps (const char * mapname,
|
||||
/*
|
||||
* and we can fetch the map table from the kernel
|
||||
*/
|
||||
- !dm_get_map(names->name, &size, ¶ms[0]) &&
|
||||
+ dm_get_map(names->name, &size, ¶ms[0]) == DMP_OK &&
|
||||
|
||||
/*
|
||||
* and the table maps over the multipath map
|
||||
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
|
||||
index 7557a86b..adb55000 100644
|
||||
--- a/libmultipath/devmapper.h
|
||||
+++ b/libmultipath/devmapper.h
|
||||
@@ -27,6 +27,12 @@
|
||||
#define UUID_PREFIX "mpath-"
|
||||
#define UUID_PREFIX_LEN (sizeof(UUID_PREFIX) - 1)
|
||||
|
||||
+enum {
|
||||
+ DMP_ERR,
|
||||
+ DMP_OK,
|
||||
+ DMP_NOT_FOUND,
|
||||
+};
|
||||
+
|
||||
void dm_init(int verbosity);
|
||||
void libmp_dm_init(void);
|
||||
void libmp_udev_set_sync_support(int on);
|
||||
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
|
||||
index 077f2e42..8137ea21 100644
|
||||
--- a/libmultipath/structs_vec.c
|
||||
+++ b/libmultipath/structs_vec.c
|
||||
@@ -196,43 +196,47 @@ extract_hwe_from_path(struct multipath * mpp)
|
||||
int
|
||||
update_multipath_table (struct multipath *mpp, vector pathvec, int is_daemon)
|
||||
{
|
||||
+ int r = DMP_ERR;
|
||||
char params[PARAMS_SIZE] = {0};
|
||||
|
||||
if (!mpp)
|
||||
- return 1;
|
||||
+ return r;
|
||||
|
||||
- if (dm_get_map(mpp->alias, &mpp->size, params)) {
|
||||
- condlog(3, "%s: cannot get map", mpp->alias);
|
||||
- return 1;
|
||||
+ r = dm_get_map(mpp->alias, &mpp->size, params);
|
||||
+ if (r != DMP_OK) {
|
||||
+ condlog(3, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting table" : "map not present");
|
||||
+ return r;
|
||||
}
|
||||
|
||||
if (disassemble_map(pathvec, params, mpp, is_daemon)) {
|
||||
condlog(3, "%s: cannot disassemble map", mpp->alias);
|
||||
- return 1;
|
||||
+ return DMP_ERR;
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ return DMP_OK;
|
||||
}
|
||||
|
||||
int
|
||||
update_multipath_status (struct multipath *mpp)
|
||||
{
|
||||
+ int r = DMP_ERR;
|
||||
char status[PARAMS_SIZE] = {0};
|
||||
|
||||
if (!mpp)
|
||||
- return 1;
|
||||
+ return r;
|
||||
|
||||
- if (dm_get_status(mpp->alias, status)) {
|
||||
- condlog(3, "%s: cannot get status", mpp->alias);
|
||||
- return 1;
|
||||
+ r = dm_get_status(mpp->alias, status);
|
||||
+ if (r != DMP_OK) {
|
||||
+ condlog(3, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting status" : "map not present");
|
||||
+ return r;
|
||||
}
|
||||
|
||||
if (disassemble_status(status, mpp)) {
|
||||
condlog(3, "%s: cannot disassemble status", mpp->alias);
|
||||
- return 1;
|
||||
+ return DMP_ERR;
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ return DMP_OK;
|
||||
}
|
||||
|
||||
void sync_paths(struct multipath *mpp, vector pathvec)
|
||||
@@ -264,10 +268,10 @@ int
|
||||
update_multipath_strings(struct multipath *mpp, vector pathvec, int is_daemon)
|
||||
{
|
||||
struct pathgroup *pgp;
|
||||
- int i;
|
||||
+ int i, r = DMP_ERR;
|
||||
|
||||
if (!mpp)
|
||||
- return 1;
|
||||
+ return r;
|
||||
|
||||
update_mpp_paths(mpp, pathvec);
|
||||
condlog(4, "%s: %s", mpp->alias, __FUNCTION__);
|
||||
@@ -276,18 +280,21 @@ update_multipath_strings(struct multipath *mpp, vector pathvec, int is_daemon)
|
||||
free_pgvec(mpp->pg, KEEP_PATHS);
|
||||
mpp->pg = NULL;
|
||||
|
||||
- if (update_multipath_table(mpp, pathvec, is_daemon))
|
||||
- return 1;
|
||||
+ r = update_multipath_table(mpp, pathvec, is_daemon);
|
||||
+ if (r != DMP_OK)
|
||||
+ return r;
|
||||
+
|
||||
sync_paths(mpp, pathvec);
|
||||
|
||||
- if (update_multipath_status(mpp))
|
||||
- return 1;
|
||||
+ r = update_multipath_status(mpp);
|
||||
+ if (r != DMP_OK)
|
||||
+ return r;
|
||||
|
||||
vector_foreach_slot(mpp->pg, pgp, i)
|
||||
if (pgp->paths)
|
||||
path_group_prio_update(pgp);
|
||||
|
||||
- return 0;
|
||||
+ return DMP_OK;
|
||||
}
|
||||
|
||||
static void enter_recovery_mode(struct multipath *mpp)
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 6b7db2c0..e3427d3d 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -414,7 +414,7 @@ int __setup_multipath(struct vectors *vecs, struct multipath *mpp,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (update_multipath_strings(mpp, vecs->pathvec, 1)) {
|
||||
+ if (update_multipath_strings(mpp, vecs->pathvec, 1) != DMP_OK) {
|
||||
condlog(0, "%s: failed to setup multipath", mpp->alias);
|
||||
goto out;
|
||||
}
|
||||
@@ -553,9 +553,9 @@ add_map_without_path (struct vectors *vecs, const char *alias)
|
||||
mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
|
||||
put_multipath_config(conf);
|
||||
|
||||
- if (update_multipath_table(mpp, vecs->pathvec, 1))
|
||||
+ if (update_multipath_table(mpp, vecs->pathvec, 1) != DMP_OK)
|
||||
goto out;
|
||||
- if (update_multipath_status(mpp))
|
||||
+ if (update_multipath_status(mpp) != DMP_OK)
|
||||
goto out;
|
||||
|
||||
if (!vector_alloc_slot(vecs->mpvec))
|
||||
@@ -1346,8 +1346,8 @@ map_discovery (struct vectors * vecs)
|
||||
return 1;
|
||||
|
||||
vector_foreach_slot (vecs->mpvec, mpp, i)
|
||||
- if (update_multipath_table(mpp, vecs->pathvec, 1) ||
|
||||
- update_multipath_status(mpp)) {
|
||||
+ if (update_multipath_table(mpp, vecs->pathvec, 1) != DMP_OK ||
|
||||
+ update_multipath_status(mpp) != DMP_OK) {
|
||||
remove_map(mpp, vecs, 1);
|
||||
i--;
|
||||
}
|
||||
@@ -2087,7 +2087,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
/*
|
||||
* Synchronize with kernel state
|
||||
*/
|
||||
- if (update_multipath_strings(pp->mpp, vecs->pathvec, 1)) {
|
||||
+ if (update_multipath_strings(pp->mpp, vecs->pathvec, 1) != DMP_OK) {
|
||||
condlog(1, "%s: Could not synchronize with kernel state",
|
||||
pp->dev);
|
||||
pp->dmstate = PSTATE_UNDEF;
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,116 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 11 Jun 2020 15:41:18 -0500
|
||||
Subject: [PATCH] multipathd: fix check_path errors with removed map
|
||||
|
||||
If a multipath device is removed during, or immediately before the call
|
||||
to check_path(), multipathd can behave incorrectly. A missing multpath
|
||||
device will cause update_multipath_strings() to fail, setting
|
||||
pp->dmstate to PSTATE_UNDEF. If the path is up, this state will cause
|
||||
reinstate_path() to be called, which will also fail. This will trigger
|
||||
a reload, restoring the recently removed device.
|
||||
|
||||
If update_multipath_strings() fails because there is no multipath
|
||||
device, check_path should just quit, since the remove dmevent and uevent
|
||||
are likely already queued up. Also, I don't see any reason to reload the
|
||||
multipath device if reinstate fails. This code was added by
|
||||
fac68d7a99ef17d496079538a5c6836acd7911ab, which clamined that reinstate
|
||||
could fail if the path was disabled. Looking through the current kernel
|
||||
code, I can't see any reason why a reinstate would fail, where a reload
|
||||
would help. If the path was missing from the multipath device,
|
||||
update_multipath_strings() would already catch that, and quit
|
||||
check_path() early, which make more sense to me than reloading does.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/main.c | 44 +++++++++++++++++++-------------------------
|
||||
1 file changed, 19 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index e3427d3d..1d9ce7f7 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -1611,22 +1611,18 @@ fail_path (struct path * pp, int del_active)
|
||||
/*
|
||||
* caller must have locked the path list before calling that function
|
||||
*/
|
||||
-static int
|
||||
+static void
|
||||
reinstate_path (struct path * pp)
|
||||
{
|
||||
- int ret = 0;
|
||||
-
|
||||
if (!pp->mpp)
|
||||
- return 0;
|
||||
+ return;
|
||||
|
||||
- if (dm_reinstate_path(pp->mpp->alias, pp->dev_t)) {
|
||||
+ if (dm_reinstate_path(pp->mpp->alias, pp->dev_t))
|
||||
condlog(0, "%s: reinstate failed", pp->dev_t);
|
||||
- ret = 1;
|
||||
- } else {
|
||||
+ else {
|
||||
condlog(2, "%s: reinstated", pp->dev_t);
|
||||
update_queue_mode_add_path(pp->mpp);
|
||||
}
|
||||
- return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2087,9 +2083,16 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
/*
|
||||
* Synchronize with kernel state
|
||||
*/
|
||||
- if (update_multipath_strings(pp->mpp, vecs->pathvec, 1) != DMP_OK) {
|
||||
- condlog(1, "%s: Could not synchronize with kernel state",
|
||||
- pp->dev);
|
||||
+ ret = update_multipath_strings(pp->mpp, vecs->pathvec, 1);
|
||||
+ if (ret != DMP_OK) {
|
||||
+ if (ret == DMP_NOT_FOUND) {
|
||||
+ /* multipath device missing. Likely removed */
|
||||
+ condlog(1, "%s: multipath device '%s' not found",
|
||||
+ pp->dev, pp->mpp->alias);
|
||||
+ return 0;
|
||||
+ } else
|
||||
+ condlog(1, "%s: Couldn't synchronize with kernel state",
|
||||
+ pp->dev);
|
||||
pp->dmstate = PSTATE_UNDEF;
|
||||
}
|
||||
/* if update_multipath_strings orphaned the path, quit early */
|
||||
@@ -2179,12 +2182,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
/*
|
||||
* reinstate this path
|
||||
*/
|
||||
- if (!disable_reinstate && reinstate_path(pp)) {
|
||||
- condlog(3, "%s: reload map", pp->dev);
|
||||
- ev_add_path(pp, vecs, 1);
|
||||
- pp->tick = 1;
|
||||
- return 0;
|
||||
- }
|
||||
+ if (!disable_reinstate)
|
||||
+ reinstate_path(pp);
|
||||
new_path_up = 1;
|
||||
|
||||
if (oldchkrstate != PATH_UP && oldchkrstate != PATH_GHOST)
|
||||
@@ -2200,15 +2199,10 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
else if (newstate == PATH_UP || newstate == PATH_GHOST) {
|
||||
if ((pp->dmstate == PSTATE_FAILED ||
|
||||
pp->dmstate == PSTATE_UNDEF) &&
|
||||
- !disable_reinstate) {
|
||||
+ !disable_reinstate)
|
||||
/* Clear IO errors */
|
||||
- if (reinstate_path(pp)) {
|
||||
- condlog(3, "%s: reload map", pp->dev);
|
||||
- ev_add_path(pp, vecs, 1);
|
||||
- pp->tick = 1;
|
||||
- return 0;
|
||||
- }
|
||||
- } else {
|
||||
+ reinstate_path(pp);
|
||||
+ else {
|
||||
LOG_MSG(4, verbosity, pp);
|
||||
if (pp->checkint != max_checkint) {
|
||||
/*
|
||||
--
|
||||
2.17.2
|
||||
|
@ -1,45 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 17 Jun 2020 13:31:37 -0500
|
||||
Subject: [PATCH] libmultipath: make dm_flush_maps only return 0 on success
|
||||
|
||||
dm_flush_maps() returned both 0 and 1 on error, depending on which part
|
||||
of the function it was in, but the caller was always treating 0 as a
|
||||
success. Make dm_flush_maps() always return 1 on error and 0 on success.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/devmapper.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
|
||||
index f6204e5f..cda83ce4 100644
|
||||
--- a/libmultipath/devmapper.c
|
||||
+++ b/libmultipath/devmapper.c
|
||||
@@ -953,13 +953,13 @@ dm_flush_map_nopaths(const char * mapname, int deferred_remove)
|
||||
|
||||
int dm_flush_maps (int retries)
|
||||
{
|
||||
- int r = 0;
|
||||
+ int r = 1;
|
||||
struct dm_task *dmt;
|
||||
struct dm_names *names;
|
||||
unsigned next = 0;
|
||||
|
||||
if (!(dmt = libmp_dm_task_create (DM_DEVICE_LIST)))
|
||||
- return 0;
|
||||
+ return r;
|
||||
|
||||
dm_task_no_open_count(dmt);
|
||||
|
||||
@@ -972,6 +972,7 @@ int dm_flush_maps (int retries)
|
||||
if (!names->dev)
|
||||
goto out;
|
||||
|
||||
+ r = 0;
|
||||
do {
|
||||
r |= dm_suspend_and_flush_map(names->name, retries);
|
||||
next = names->next;
|
||||
--
|
||||
2.17.2
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user