diff --git a/.gitignore b/.gitignore index c297b30..befbabe 100644 --- a/.gitignore +++ b/.gitignore @@ -21,17 +21,3 @@ multipath-tools-091027.tar.gz /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.8.tgz -/multipath-tools-0.9.9.tgz -/multipath-tools-0.10.0.tgz -/multipath-tools-0.11.1.tgz -/multipath-tools-0.13.0.tgz diff --git a/0001-Change-the-multipath.conf-manpage-uxsock_timeout-def.patch b/0001-Change-the-multipath.conf-manpage-uxsock_timeout-def.patch new file mode 100644 index 0000000..02b2e18 --- /dev/null +++ b/0001-Change-the-multipath.conf-manpage-uxsock_timeout-def.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christophe Varoqui +Date: Mon, 14 Dec 2020 11:05:24 +0100 +Subject: [PATCH] Change the multipath.conf manpage uxsock_timeout default + value + +Fixes: 7db0c44 ("multipathd: Set CLI timeout correctly") + +Reviewed-by: Martin Wilck +Signed-off-by: Benjamin Marzinski +--- + multipath/multipath.conf.5 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 +index d2101ed6..7242d39b 100644 +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -1153,7 +1153,7 @@ In these cases it is recommended to increase the CLI timeout to avoid + those issues. + .RS + .TP +-The default is: \fB1000\fR ++The default is: \fB4000\fR + .RE + . + . +-- +2.17.2 + diff --git a/0001-RH-fixup-udev-rules-for-redhat.patch b/0001-RH-fixup-udev-rules-for-redhat.patch deleted file mode 100644 index ed5b7e9..0000000 --- a/0001-RH-fixup-udev-rules-for-redhat.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 64a07df23affd21842fdc604887276e62e5b41de Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - Makefile.inc | 2 +- - kpartx/kpartx.rules.in | 2 +- - multipath/Makefile | 4 ++-- - 3 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/Makefile.inc b/Makefile.inc -index 9e3dc466..ead89030 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.in b/kpartx/kpartx.rules.in -index 9d879609..2049eb8f 100644 ---- a/kpartx/kpartx.rules.in -+++ b/kpartx/kpartx.rules.in -@@ -39,6 +39,6 @@ LABEL="mpath_kpartx_end" - GOTO="kpartx_end" - - LABEL="run_kpartx" --RUN+="@BINDIR@/kpartx -un -p -part /dev/$name" -+RUN+="@BINDIR@/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 diff --git a/0002-libmultipath-find_mpe-don-t-match-with-empty-WWID.patch b/0002-libmultipath-find_mpe-don-t-match-with-empty-WWID.patch new file mode 100644 index 0000000..2d38590 --- /dev/null +++ b/0002-libmultipath-find_mpe-don-t-match-with-empty-WWID.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 21:59:11 +0200 +Subject: [PATCH] libmultipath: find_mpe(): don't match with empty WWID + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index b9bdbdbc..df0f8f45 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -147,7 +147,7 @@ struct mpentry *find_mpe(vector mptable, char *wwid) + int i; + struct mpentry * mpe; + +- if (!wwid) ++ if (!wwid || !*wwid) + return NULL; + + vector_foreach_slot (mptable, mpe, i) +-- +2.17.2 + diff --git a/0003-RH-don-t-start-without-a-config-file.patch b/0003-RH-don-t-start-without-a-config-file.patch deleted file mode 100644 index 05d4e7a..0000000 --- a/0003-RH-don-t-start-without-a-config-file.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 5613e07ce9cabf2fdc402f6f102cc54bd1059800 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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.in | 1 + - 7 files changed, 25 insertions(+) - -diff --git a/libmultipath/config.c b/libmultipath/config.c -index 8b424d18..b8317f4d 100644 ---- a/libmultipath/config.c -+++ b/libmultipath/config.c -@@ -937,6 +937,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 5b4ebf8c..2302eacc 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 f2adcdeb..31012874 100644 ---- a/multipath/main.c -+++ b/multipath/main.c -@@ -834,11 +834,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)) -@@ -1092,6 +1095,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 2ac1972f..cc248231 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 8815e099..342e363e 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 eb58943c..ab166435 100644 ---- a/multipathd/multipathd.service.in -+++ b/multipathd/multipathd.service.in -@@ -6,6 +6,7 @@ Wants=systemd-udevd-kernel.socket multipathd-queueing.service @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.in b/multipathd/multipathd.socket.in -index 11002fce..5ed24757 100644 ---- a/multipathd/multipathd.socket.in -+++ b/multipathd/multipathd.socket.in -@@ -1,6 +1,7 @@ - [Unit] - Description=multipathd control socket - DefaultDependencies=no -+ConditionPathExists=/etc/multipath.conf - ConditionKernelCommandLine=!nompath - ConditionKernelCommandLine=!multipath=off - ConditionVirtualization=!container diff --git a/0003-libmultipath-copy-mpp-hwe-from-pp-hwe.patch b/0003-libmultipath-copy-mpp-hwe-from-pp-hwe.patch new file mode 100644 index 0000000..63ff6a5 --- /dev/null +++ b/0003-libmultipath-copy-mpp-hwe-from-pp-hwe.patch @@ -0,0 +1,260 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 22:22:36 +0200 +Subject: [PATCH] libmultipath: copy mpp->hwe from pp->hwe + +Since f0462f0 ("libmultipath: use vector for for pp->hwe and mp->hwe"), +we've been trying to fix issues caused by paths getting freed and mpp->hwe +dangling. This approach couldn't work because we need mpp->hwe to persist, +even if all paths are removed from the map. Before f0462f0, a simple +assignment worked, because the lifetime of the hwe wasn't bound to the +path. But now, we need to copy the vector. It turns out that we need to set +mpp->hwe only in two places, add_map_with_path() and setup_map(), and +that the code is simplified overall. + +Even now, it can happen that a map is added with add_map_without_paths(), +and has no paths. In that case, calling do_set_from_hwe() with a NULL +pointer is not a bug, so remove the message. + +Fixes: f0462f0 ("libmultipath: use vector for for pp->hwe and mp->hwe") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 7 +++++ + libmultipath/propsel.c | 4 +-- + libmultipath/structs.c | 15 +++++++++++ + libmultipath/structs.h | 1 + + libmultipath/structs_vec.c | 54 ++++++++++++++++---------------------- + multipathd/main.c | 10 ------- + 6 files changed, 46 insertions(+), 45 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 6fb477fc..d7afc915 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -311,6 +311,13 @@ int setup_map(struct multipath *mpp, char *params, int params_size, + if (mpp->disable_queueing && VECTOR_SIZE(mpp->paths) != 0) + mpp->disable_queueing = 0; + ++ /* ++ * If this map was created with add_map_without_path(), ++ * mpp->hwe might not be set yet. ++ */ ++ if (!mpp->hwe) ++ extract_hwe_from_path(mpp); ++ + /* + * properties selectors + * +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index 7e6e0d68..40201344 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -65,9 +65,7 @@ do { \ + __do_set_from_vec(struct hwentry, var, (src)->hwe, dest) + + #define do_set_from_hwe(var, src, dest, msg) \ +- if (!src->hwe) { \ +- condlog(0, "BUG: do_set_from_hwe called with hwe == NULL"); \ +- } else if (__do_set_from_hwe(var, src, dest)) { \ ++ if (src->hwe && __do_set_from_hwe(var, src, dest)) { \ + origin = msg; \ + goto out; \ + } +diff --git a/libmultipath/structs.c b/libmultipath/structs.c +index 464596fc..2efad6f0 100644 +--- a/libmultipath/structs.c ++++ b/libmultipath/structs.c +@@ -234,6 +234,17 @@ alloc_multipath (void) + return mpp; + } + ++void *set_mpp_hwe(struct multipath *mpp, const struct path *pp) ++{ ++ if (!mpp || !pp || !pp->hwe) ++ return NULL; ++ if (mpp->hwe) ++ return mpp->hwe; ++ mpp->hwe = vector_convert(NULL, pp->hwe, ++ struct hwentry, identity); ++ return mpp->hwe; ++} ++ + void free_multipath_attributes(struct multipath *mpp) + { + if (!mpp) +@@ -290,6 +301,10 @@ free_multipath (struct multipath * mpp, enum free_path_mode free_paths) + + free_pathvec(mpp->paths, free_paths); + free_pgvec(mpp->pg, free_paths); ++ if (mpp->hwe) { ++ vector_free(mpp->hwe); ++ mpp->hwe = NULL; ++ } + FREE_PTR(mpp->mpcontext); + FREE(mpp); + } +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index 7de93d6c..4ce30551 100644 +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -422,6 +422,7 @@ struct host_group { + struct path * alloc_path (void); + struct pathgroup * alloc_pathgroup (void); + struct multipath * alloc_multipath (void); ++void *set_mpp_hwe(struct multipath *mpp, const struct path *pp); + void uninitialize_path(struct path *pp); + void free_path (struct path *); + void free_pathvec (vector vec, enum free_path_mode free_paths); +diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c +index 8895fa77..f7f45f11 100644 +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -294,11 +294,6 @@ err: + void orphan_path(struct path *pp, const char *reason) + { + condlog(3, "%s: orphan path, %s", pp->dev, reason); +- if (pp->mpp && pp->hwe && pp->mpp->hwe == pp->hwe) { +- condlog(0, "BUG: orphaning path %s that holds hwe of %s", +- pp->dev, pp->mpp->alias); +- pp->mpp->hwe = NULL; +- } + pp->mpp = NULL; + uninitialize_path(pp); + } +@@ -308,8 +303,6 @@ void orphan_paths(vector pathvec, struct multipath *mpp, const char *reason) + int i; + struct path * pp; + +- /* Avoid BUG message from orphan_path() */ +- mpp->hwe = NULL; + vector_foreach_slot (pathvec, pp, i) { + if (pp->mpp == mpp) { + if (pp->initialized == INIT_REMOVED) { +@@ -397,24 +390,26 @@ extract_hwe_from_path(struct multipath * mpp) + if (mpp->hwe || !mpp->paths) + return; + +- condlog(3, "%s: searching paths for valid hwe", mpp->alias); ++ condlog(4, "%s: searching paths for valid hwe", mpp->alias); + /* doing this in two passes seems like paranoia to me */ + vector_foreach_slot(mpp->paths, pp, i) { +- if (pp->state != PATH_UP) +- continue; +- if (pp->hwe) { +- mpp->hwe = pp->hwe; +- return; +- } ++ if (pp->state == PATH_UP && ++ pp->initialized != INIT_REMOVED && pp->hwe) ++ goto done; + } + vector_foreach_slot(mpp->paths, pp, i) { +- if (pp->state == PATH_UP) +- continue; +- if (pp->hwe) { +- mpp->hwe = pp->hwe; +- return; +- } ++ if (pp->state != PATH_UP && ++ pp->initialized != INIT_REMOVED && pp->hwe) ++ goto done; + } ++done: ++ if (i < VECTOR_SIZE(mpp->paths)) ++ (void)set_mpp_hwe(mpp, pp); ++ ++ if (mpp->hwe) ++ condlog(3, "%s: got hwe from path %s", mpp->alias, pp->dev); ++ else ++ condlog(2, "%s: no hwe found", mpp->alias); + } + + int +@@ -514,8 +509,6 @@ void sync_paths(struct multipath *mpp, vector pathvec) + } + if (!found) { + condlog(3, "%s dropped path %s", mpp->alias, pp->dev); +- if (mpp->hwe == pp->hwe) +- mpp->hwe = NULL; + vector_del_slot(mpp->paths, i--); + orphan_path(pp, "path removed externally"); + } +@@ -524,8 +517,6 @@ void sync_paths(struct multipath *mpp, vector pathvec) + update_mpp_paths(mpp, pathvec); + vector_foreach_slot (mpp->paths, pp, i) + pp->mpp = mpp; +- if (mpp->hwe == NULL) +- extract_hwe_from_path(mpp); + } + + int +@@ -701,9 +692,15 @@ struct multipath *add_map_with_path(struct vectors *vecs, struct path *pp, + + conf = get_multipath_config(); + mpp->mpe = find_mpe(conf->mptable, pp->wwid); +- mpp->hwe = pp->hwe; + put_multipath_config(conf); + ++ /* ++ * We need to call this before select_alias(), ++ * because that accesses hwe properties. ++ */ ++ if (pp->hwe && !set_mpp_hwe(mpp, pp)) ++ goto out; ++ + strcpy(mpp->wwid, pp->wwid); + find_existing_alias(mpp, vecs); + if (select_alias(conf, mpp)) +@@ -754,12 +751,6 @@ int verify_paths(struct multipath *mpp) + vector_del_slot(mpp->paths, i); + i--; + +- /* Make sure mpp->hwe doesn't point to freed memory. +- * We call extract_hwe_from_path() below to restore +- * mpp->hwe +- */ +- if (mpp->hwe == pp->hwe) +- mpp->hwe = NULL; + /* + * Don't delete path from pathvec yet. We'll do this + * after the path has been removed from the map, in +@@ -771,7 +762,6 @@ int verify_paths(struct multipath *mpp) + mpp->alias, pp->dev, pp->dev_t); + } + } +- extract_hwe_from_path(mpp); + return count; + } + +diff --git a/multipathd/main.c b/multipathd/main.c +index a4abbb27..eedc6c10 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1153,13 +1153,6 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map) + if (i != -1) + vector_del_slot(mpp->paths, i); + +- /* +- * Make sure mpp->hwe doesn't point to freed memory +- * We call extract_hwe_from_path() below to restore mpp->hwe +- */ +- if (mpp->hwe == pp->hwe) +- mpp->hwe = NULL; +- + /* + * remove the map IF removing the last path + */ +@@ -1191,9 +1184,6 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map) + */ + } + +- if (mpp->hwe == NULL) +- extract_hwe_from_path(mpp); +- + if (setup_map(mpp, params, PARAMS_SIZE, vecs)) { + condlog(0, "%s: failed to setup map for" + " removal of path %s", mpp->alias, pp->dev); +-- +2.17.2 + diff --git a/0004-libmultipath-dm_map_present_by_uuid-fix-dm_task_crea.patch b/0004-libmultipath-dm_map_present_by_uuid-fix-dm_task_crea.patch new file mode 100644 index 0000000..c3a0a18 --- /dev/null +++ b/0004-libmultipath-dm_map_present_by_uuid-fix-dm_task_crea.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Sep 2020 14:24:41 +0200 +Subject: [PATCH] libmultipath: dm_map_present_by_uuid(): fix dm_task_create() + call + +libmultipath shouldn't call dm_task_create() directly any more. + +Fixes: 90535a3 ("multipath: centralize validation code") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/devmapper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 7f093617..0bc1d16e 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -836,7 +836,7 @@ dm_map_present_by_uuid(const char *uuid) + if (safe_sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid)) + goto out; + +- if (!(dmt = dm_task_create(DM_DEVICE_INFO))) ++ if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO))) + goto out; + + dm_task_no_open_count(dmt); +-- +2.17.2 + diff --git a/0005-RH-use-rpm-optflags-if-present.patch b/0005-RH-use-rpm-optflags-if-present.patch deleted file mode 100644 index 7a6f57f..0000000 --- a/0005-RH-use-rpm-optflags-if-present.patch +++ /dev/null @@ -1,67 +0,0 @@ -From bf46f8029998498045bb055415ba3ff515c79eaa Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - Makefile.inc | 25 ++++++++++++++++++------- - 1 file changed, 18 insertions(+), 7 deletions(-) - -diff --git a/Makefile.inc b/Makefile.inc -index ead89030..03aee175 100644 ---- a/Makefile.inc -+++ b/Makefile.inc -@@ -102,17 +102,29 @@ 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 -+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 - - # Set WARN_ONLY=1 to avoid compilation erroring out due to warnings. Useful during development. - WARN_ONLY := - ERROR := $(if $(WARN_ONLY),,error=) - WERROR := $(if $(WARN_ONLY),,-Werror) --WARNFLAGS := $(WERROR) -Wall -Wextra -Wformat=2 $(WFORMATOVERFLOW) -W$(ERROR)implicit-int \ -+WARNFLAGS := $(WERROR) -Wextra -Wformat=2 $(WFORMATOVERFLOW) -W$(ERROR)implicit-int \ - -W$(ERROR)implicit-function-declaration -W$(ERROR)format-security \ -- $(WNOCLOBBERED) -W$(ERROR)cast-qual $(ERROR_DISCARDED_QUALIFIERS) $(W_URCU_TYPE_LIMITS) -+ $(WNOCLOBBERED) -W$(ERROR)cast-qual $(ERROR_DISCARDED_QUALIFIERS) $(W_URCU_TYPE_LIMITS) -Wstrict-prototypes - --CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) \ -+CPPFLAGS := $(CPPFLAGS) $(D_URCU_VERSION) \ - -D_FILE_OFFSET_BITS=64 \ - -DBIN_DIR=\"$(bindir)\" -DMULTIPATH_DIR=\"$(TGTDIR)$(plugindir)\" \ - -DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(TGTDIR)$(configdir)\" \ -@@ -121,12 +133,11 @@ CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) \ - -DABSTRACT_SOCKET=\"$(abstract_socket)\" -DPATHNAME_SOCKET=\"$(pathname_socket)\" \ - -DWSTRINGOP_TRUNCATION=$(if $(WSTRINGOP_TRUNCATION),1,0) \ - -MMD -MP --CFLAGS := -std=$(C_STD) $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \ -- -fexceptions -+CFLAGS := -std=$(C_STD) $(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. diff --git a/0005-libdmmp-tests-fix-compilation.patch b/0005-libdmmp-tests-fix-compilation.patch new file mode 100644 index 0000000..d1d9955 --- /dev/null +++ b/0005-libdmmp-tests-fix-compilation.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Sep 2020 12:10:35 +0200 +Subject: [PATCH] libdmmp tests: fix compilation + +These tests don't compile with -Werror=unused-parameter. Fix it. +Reviewed-by: Benjamin Marzinski + +Signed-off-by: Benjamin Marzinski +--- + libdmmp/test/libdmmp_speed_test.c | 2 +- + libdmmp/test/libdmmp_test.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libdmmp/test/libdmmp_speed_test.c b/libdmmp/test/libdmmp_speed_test.c +index 372cd390..d91ba50a 100644 +--- a/libdmmp/test/libdmmp_speed_test.c ++++ b/libdmmp/test/libdmmp_speed_test.c +@@ -27,7 +27,7 @@ + + #include + +-int main(int argc, char *argv[]) ++int main(void) + { + struct dmmp_context *ctx = NULL; + struct dmmp_mpath **dmmp_mps = NULL; +diff --git a/libdmmp/test/libdmmp_test.c b/libdmmp/test/libdmmp_test.c +index d944e1e3..a940b576 100644 +--- a/libdmmp/test/libdmmp_test.c ++++ b/libdmmp/test/libdmmp_test.c +@@ -102,7 +102,7 @@ out: + return rc; + } + +-int main(int argc, char *argv[]) ++int main(void) + { + struct dmmp_context *ctx = NULL; + struct dmmp_mpath **dmmp_mps = NULL; +-- +2.17.2 + diff --git a/0006-libmultipath-prio-constify-some-function-parameters.patch b/0006-libmultipath-prio-constify-some-function-parameters.patch new file mode 100644 index 0000000..80771ea --- /dev/null +++ b/0006-libmultipath-prio-constify-some-function-parameters.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Sep 2020 23:57:22 +0200 +Subject: [PATCH] libmultipath: prio: constify some function parameters + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/prio.c | 4 ++-- + libmultipath/prio.h | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libmultipath/prio.c b/libmultipath/prio.c +index 194563c4..3a718ba5 100644 +--- a/libmultipath/prio.c ++++ b/libmultipath/prio.c +@@ -18,7 +18,7 @@ unsigned int get_prio_timeout(unsigned int timeout_ms, + return default_timeout; + } + +-int init_prio (char *multipath_dir) ++int init_prio (const char *multipath_dir) + { + if (!add_prio(multipath_dir, DEFAULT_PRIO)) + return 1; +@@ -87,7 +87,7 @@ int prio_set_args (struct prio * p, const char * args) + return snprintf(p->args, PRIO_ARGS_LEN, "%s", args); + } + +-struct prio * add_prio (char *multipath_dir, char * name) ++struct prio * add_prio (const char *multipath_dir, const char * name) + { + char libname[LIB_PRIO_NAMELEN]; + struct stat stbuf; +diff --git a/libmultipath/prio.h b/libmultipath/prio.h +index 599d1d88..26754f78 100644 +--- a/libmultipath/prio.h ++++ b/libmultipath/prio.h +@@ -55,9 +55,9 @@ struct prio { + + unsigned int get_prio_timeout(unsigned int checker_timeout, + unsigned int default_timeout); +-int init_prio (char *); ++int init_prio (const char *); + void cleanup_prio (void); +-struct prio * add_prio (char *, char *); ++struct prio * add_prio (const char *, const char *); + int prio_getprio (struct prio *, struct path *, unsigned int); + void prio_get (char *, struct prio *, char *, char *); + void prio_put (struct prio *); +-- +2.17.2 + diff --git a/0007-libmultipath-checkers-prio-allow-non-lazy-.so-loadin.patch b/0007-libmultipath-checkers-prio-allow-non-lazy-.so-loadin.patch new file mode 100644 index 0000000..90a2f25 --- /dev/null +++ b/0007-libmultipath-checkers-prio-allow-non-lazy-.so-loadin.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Sep 2020 23:58:15 +0200 +Subject: [PATCH] libmultipath: checkers/prio: allow non-lazy .so loading + +If compiled with -DLOAD_ALL_SHARED_LIBS, all known prioritizers +and checkers will be loaded immediately on startup. This is useful +for determining symbol usage (start executables with LD_BIND_NOW=1). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/checkers.c | 17 +++++++++++++++++ + libmultipath/prio.c | 22 ++++++++++++++++++++++ + 2 files changed, 39 insertions(+) + +diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c +index f7ddd536..18b1f5eb 100644 +--- a/libmultipath/checkers.c ++++ b/libmultipath/checkers.c +@@ -7,6 +7,7 @@ + #include "debug.h" + #include "checkers.h" + #include "vector.h" ++#include "util.h" + + struct checker_class { + struct list_head node; +@@ -375,7 +376,23 @@ void checker_get(const char *multipath_dir, struct checker *dst, + + int init_checkers(const char *multipath_dir) + { ++#ifdef LOAD_ALL_SHARED_LIBS ++ static const char *const all_checkers[] = { ++ DIRECTIO, ++ TUR, ++ HP_SW, ++ RDAC, ++ EMC_CLARIION, ++ READSECTOR0, ++ CCISS_TUR, ++ }; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(all_checkers); i++) ++ add_checker_class(multipath_dir, all_checkers[i]); ++#else + if (!add_checker_class(multipath_dir, DEFAULT_CHECKER)) + return 1; ++#endif + return 0; + } +diff --git a/libmultipath/prio.c b/libmultipath/prio.c +index 3a718ba5..c92bde7f 100644 +--- a/libmultipath/prio.c ++++ b/libmultipath/prio.c +@@ -20,8 +20,30 @@ unsigned int get_prio_timeout(unsigned int timeout_ms, + + int init_prio (const char *multipath_dir) + { ++#ifdef LOAD_ALL_SHARED_LIBS ++ static const char *const all_prios[] = { ++ PRIO_ALUA, ++ PRIO_CONST, ++ PRIO_DATACORE, ++ PRIO_EMC, ++ PRIO_HDS, ++ PRIO_HP_SW, ++ PRIO_ONTAP, ++ PRIO_RANDOM, ++ PRIO_RDAC, ++ PRIO_WEIGHTED_PATH, ++ PRIO_SYSFS, ++ PRIO_PATH_LATENCY, ++ PRIO_ANA, ++ }; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(all_prios); i++) ++ add_prio(multipath_dir, all_prios[i]); ++#else + if (!add_prio(multipath_dir, DEFAULT_PRIO)) + return 1; ++#endif + return 0; + } + +-- +2.17.2 + diff --git a/0008-multipath-tools-Makefiles-separate-rules-for-.so-and.patch b/0008-multipath-tools-Makefiles-separate-rules-for-.so-and.patch new file mode 100644 index 0000000..edc3e66 --- /dev/null +++ b/0008-multipath-tools-Makefiles-separate-rules-for-.so-and.patch @@ -0,0 +1,96 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Sep 2020 12:52:49 +0200 +Subject: [PATCH] multipath-tools Makefiles: separate rules for .so and man + pages + +Rely more on "make" functionality than on sequential command execution. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathcmd/Makefile | 8 +++++--- + libmpathpersist/Makefile | 10 +++++++--- + libmultipath/Makefile | 8 +++++--- + 3 files changed, 17 insertions(+), 9 deletions(-) + +diff --git a/libmpathcmd/Makefile b/libmpathcmd/Makefile +index 0f6b8166..08ccb811 100644 +--- a/libmpathcmd/Makefile ++++ b/libmpathcmd/Makefile +@@ -8,13 +8,15 @@ CFLAGS += $(LIB_CFLAGS) + + OBJS = mpath_cmd.o + +-all: $(LIBS) ++all: $(DEVLIB) + + $(LIBS): $(OBJS) + $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) +- $(LN) $@ $(DEVLIB) + +-install: $(LIBS) ++$(DEVLIB): $(LIBS) ++ $(LN) $(LIBS) $@ ++ ++install: all + $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) + $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) +diff --git a/libmpathpersist/Makefile b/libmpathpersist/Makefile +index 21fdad80..9e869fdc 100644 +--- a/libmpathpersist/Makefile ++++ b/libmpathpersist/Makefile +@@ -11,15 +11,19 @@ LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \ + + OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o + +-all: $(LIBS) ++all: $(DEVLIB) man + + $(LIBS): $(OBJS) + $(CC) $(LDFLAGS) $(SHARED_FLAGS) $(LIBDEPS) -Wl,-soname=$@ -o $@ $(OBJS) +- $(LN) $(LIBS) $(DEVLIB) ++ ++$(DEVLIB): $(LIBS) ++ $(LN) $(LIBS) $@ ++ ++man: + $(GZIP) mpath_persistent_reserve_in.3 > mpath_persistent_reserve_in.3.gz + $(GZIP) mpath_persistent_reserve_out.3 > mpath_persistent_reserve_out.3.gz + +-install: $(LIBS) ++install: all + $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) + $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir) +diff --git a/libmultipath/Makefile b/libmultipath/Makefile +index 62ba16e8..40028556 100644 +--- a/libmultipath/Makefile ++++ b/libmultipath/Makefile +@@ -54,7 +54,7 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.o \ + io_err_stat.o dm-generic.o generic.o foreign.o nvme-lib.o \ + libsg.o valid.o + +-all: $(LIBS) ++all: $(DEVLIB) + + nvme-lib.o: nvme-lib.c nvme-ioctl.c nvme-ioctl.h + $(CC) $(CFLAGS) -Wno-unused-function -c -o $@ $< +@@ -74,9 +74,11 @@ nvme-ioctl.h: nvme/nvme-ioctl.h + + $(LIBS): $(OBJS) + $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) +- $(LN) $@ $(DEVLIB) + +-install: ++$(DEVLIB): $(LIBS) ++ $(LN) $(LIBS) $@ ++ ++install: all + $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) + $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(libdir) +-- +2.17.2 + diff --git a/0009-libmultipath-create-separate-.so-for-unit-tests.patch b/0009-libmultipath-create-separate-.so-for-unit-tests.patch new file mode 100644 index 0000000..38a01d7 --- /dev/null +++ b/0009-libmultipath-create-separate-.so-for-unit-tests.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 19 Sep 2020 00:29:45 +0200 +Subject: [PATCH] libmultipath: create separate .so for unit tests + +The unit tests use a lot of internal symbols that we don't want +to add to the ABI if we don't have to. As long as we don't +have to make incompatible changes to functions, we can work around +that by simply using a non-versioned library for the unit tests. +Therefore we add a seperate rule here. Do this before actually +adding a version script, to avoid breakage during bisection. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/Makefile | 7 +++++++ + tests/Makefile | 10 ++++++---- + 2 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/libmultipath/Makefile b/libmultipath/Makefile +index 40028556..12bf6300 100644 +--- a/libmultipath/Makefile ++++ b/libmultipath/Makefile +@@ -78,6 +78,13 @@ $(LIBS): $(OBJS) + $(DEVLIB): $(LIBS) + $(LN) $(LIBS) $@ + ++../tests/$(LIBS): $(OBJS) $(VERSION_SCRIPT) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=`basename $@` \ ++ -o $@ $(OBJS) $(LIBDEPS) ++ $(LN) $@ ${@:.so.0=.so} ++ ++test-lib: ../tests/$(LIBS) ++ + install: all + $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) +diff --git a/tests/Makefile b/tests/Makefile +index d26b3ce7..9658c9fd 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -10,7 +10,7 @@ W_MISSING_INITIALIZERS := $(call TEST_MISSING_INITIALIZERS) + + CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) \ + -Wno-unused-parameter $(W_MISSING_INITIALIZERS) +-LIBDEPS += -L$(multipathdir) -L$(mpathcmddir) -lmultipath -lmpathcmd -lcmocka ++LIBDEPS += -L. -L$(mpathcmddir) -lmultipath -lmpathcmd -lcmocka + + TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \ + alias directio valid devt +@@ -68,7 +68,7 @@ lib/libchecktur.so: + + %.out: %-test lib/libchecktur.so + @echo == running $< == +- @LD_LIBRARY_PATH=$(multipathdir):$(mpathcmddir) ./$< >$@ ++ @LD_LIBRARY_PATH=.:$(mpathcmddir) ./$< >$@ + + %.vgr: %-test lib/libchecktur.so + @echo == running valgrind for $< == +@@ -78,7 +78,7 @@ lib/libchecktur.so: + OBJS = $(TESTS:%=%.o) $(HELPERS) + + test_clean: +- $(RM) $(TESTS:%=%.out) $(TESTS:%=%.vgr) ++ $(RM) $(TESTS:%=%.out) $(TESTS:%=%.vgr) *.so* + + valgrind_clean: + $(RM) $(TESTS:%=%.vgr) +@@ -98,12 +98,14 @@ dep_clean: + @sed -n 's/^.*__wrap_\([a-zA-Z0-9_]*\).*$$/-Wl,--wrap=\1/p' $< | \ + sort -u | tr '\n' ' ' >$@ + ++libmultipath.so.0: ++ $(MAKE) -C $(multipathdir) test-lib + + # COLON will get expanded during second expansion below + COLON:=: + .SECONDEXPANSION: + %-test: %.o %.o.wrap $$($$@_OBJDEPS) $$($$@_TESTDEPS) $$($$@_TESTDEPS$$(COLON).o=.o.wrap) \ +- $(multipathdir)/libmultipath.so Makefile ++ libmultipath.so.0 Makefile + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) $< $($@_TESTDEPS) $($@_OBJDEPS) \ + $(LIBDEPS) $($@_LIBDEPS) \ + $(shell cat $<.wrap) $(foreach dep,$($@_TESTDEPS),$(shell cat $(dep).wrap)) +-- +2.17.2 + diff --git a/0010-RH-make-parse_vpd_pg83-match-scsi_id-output.patch b/0010-RH-make-parse_vpd_pg83-match-scsi_id-output.patch deleted file mode 100644 index f7bca92..0000000 --- a/0010-RH-make-parse_vpd_pg83-match-scsi_id-output.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 137c96d16b6bb03d8a52854e152db4ee36b7d9e4 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 31db8758..21cfcc73 100644 ---- a/libmultipath/discovery.c -+++ b/libmultipath/discovery.c -@@ -1225,13 +1225,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: -@@ -1249,10 +1245,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); - } diff --git a/0010-libmultipath-add-linker-version-script.patch b/0010-libmultipath-add-linker-version-script.patch new file mode 100644 index 0000000..ed6ad7f --- /dev/null +++ b/0010-libmultipath-add-linker-version-script.patch @@ -0,0 +1,303 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 19 Sep 2020 00:00:18 +0200 +Subject: [PATCH] libmultipath: add linker version script + +This version script documents the current ABI of libmultipath, +as used by multipath, multipathd, (lib)mpathpersist, and the +dynamically loaded libraries (prioritizers, checkers, and foreign). +The initial version string is set to "LIBMULTIPATH_1.0.0". + +This reduces the amount of exported symbols of libmultipath.so.0 +by more than a half (199 vs. 434). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/Makefile | 7 +- + libmultipath/libmultipath.version | 248 ++++++++++++++++++++++++++++++ + 2 files changed, 253 insertions(+), 2 deletions(-) + create mode 100644 libmultipath/libmultipath.version + +diff --git a/libmultipath/Makefile b/libmultipath/Makefile +index 12bf6300..e7254f39 100644 +--- a/libmultipath/Makefile ++++ b/libmultipath/Makefile +@@ -6,6 +6,7 @@ include ../Makefile.inc + SONAME = 0 + DEVLIB = libmultipath.so + LIBS = $(DEVLIB).$(SONAME) ++VERSION_SCRIPT := libmultipath.version + + CFLAGS += $(LIB_CFLAGS) -I$(mpathcmddir) -I$(mpathpersistdir) -I$(nvmedir) + +@@ -72,8 +73,10 @@ nvme-ioctl.c: nvme/nvme-ioctl.c + nvme-ioctl.h: nvme/nvme-ioctl.h + $(call make_static,$<,$@) + +-$(LIBS): $(OBJS) +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) ++ ++$(LIBS): $(OBJS) $(VERSION_SCRIPT) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \ ++ -Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS) + + $(DEVLIB): $(LIBS) + $(LN) $(LIBS) $@ +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +new file mode 100644 +index 00000000..a6bf8218 +--- /dev/null ++++ b/libmultipath/libmultipath.version +@@ -0,0 +1,248 @@ ++/* ++ * Copyright (c) 2020 SUSE LLC ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * ++ * libmultipath ABI ++ * ++ * libmultipath doesn't have a stable ABI in the usual sense. In particular, ++ * the library does not attempt to ship different versions of the same symbol ++ * for backward compatibility. ++ * ++ * The ABI versioning only serves to avoid linking with a non-matching ABI, to ++ * cut down the set of exported symbols, and to describe it. ++ * The version string is LIBMULTIPATH_$MAJOR.$MINOR.$REL. ++ * ++ * Policy: ++ * ++ * * Bump $MAJOR for incompatible changes, like: ++ * - symbols removed ++ * - parameter list or return values changed for existing functions ++ * - externally visible data structures changed in incompatible ways ++ * (like offsets of previously existing struct members) ++ * In this case, the new version doesn't inherit the previous versions, ++ * because the new library doesn't provide the full previous ABI any more. ++ * All predecessors are merged into the new version. ++ * ++ * * Bump $MINOR for compatible changes, like adding symbols. ++ * The new version inherits the previous ones. ++ * ++ * * Bump $REL to describe deviations from upstream, e.g. in ++ * multipath-tools packages shipped by distributions. ++ * The new version inherits the previous ones. ++ */ ++ ++LIBMULTIPATH_1.0.0 { ++global: ++ /* symbols referenced by multipath and multipathd */ ++ add_foreign; ++ add_map_with_path; ++ adopt_paths; ++ alloc_multipath; ++ alloc_path; ++ alloc_path_with_pathinfo; ++ alloc_strvec; ++ change_foreign; ++ check_alias_settings; ++ checker_clear_message; ++ checker_disable; ++ checker_enable; ++ checker_is_sync; ++ checker_message; ++ checker_name; ++ checker_state_name; ++ check_foreign; ++ cleanup_checkers; ++ cleanup_foreign; ++ cleanup_lock; ++ cleanup_prio; ++ close_fd; ++ coalesce_paths; ++ convert_dev; ++ count_active_paths; ++ delete_all_foreign; ++ delete_foreign; ++ disassemble_map; ++ disassemble_status; ++ dlog; ++ dm_cancel_deferred_remove; ++ dm_drv_version; ++ dm_enablegroup; ++ dm_fail_path; ++ _dm_flush_map; ++ dm_flush_map_nopaths; ++ dm_flush_maps; ++ dm_geteventnr; ++ dm_get_info; ++ dm_get_major_minor; ++ dm_get_map; ++ dm_get_maps; ++ dm_get_multipath; ++ dm_get_status; ++ dm_get_uuid; ++ dm_is_mpath; ++ dm_mapname; ++ dm_map_present; ++ dm_queue_if_no_path; ++ dm_reassign; ++ dm_reinstate_path; ++ dm_simplecmd_noflush; ++ dm_switchgroup; ++ dm_tgt_version; ++ domap; ++ ensure_directories_exist; ++ extract_hwe_from_path; ++ filter_devnode; ++ filter_path; ++ filter_wwid; ++ find_mp_by_alias; ++ find_mp_by_minor; ++ find_mp_by_str; ++ find_mp_by_wwid; ++ find_mpe; ++ find_path_by_dev; ++ find_path_by_devt; ++ find_slot; ++ foreign_multipath_layout; ++ foreign_path_layout; ++ free_config; ++ free_multipath; ++ free_multipathvec; ++ free_path; ++ free_pathvec; ++ free_strvec; ++ get_monotonic_time; ++ get_multipath_layout; ++ get_path_layout; ++ get_pgpolicy_id; ++ get_refwwid; ++ get_state; ++ get_udev_device; ++ get_uid; ++ get_used_hwes; ++ group_by_prio; ++ init_checkers; ++ init_foreign; ++ init_prio; ++ io_err_stat_attr; ++ io_err_stat_handle_pathfail; ++ is_path_valid; ++ is_quote; ++ libmp_dm_task_create; ++ libmp_udev_set_sync_support; ++ load_config; ++ log_thread_reset; ++ log_thread_start; ++ log_thread_stop; ++ need_io_err_check; ++ normalize_timespec; ++ orphan_path; ++ orphan_paths; ++ parse_prkey_flags; ++ pathcount; ++ path_discovery; ++ path_get_tpgs; ++ pathinfo; ++ path_offline; ++ print_all_paths; ++ print_foreign_topology; ++ _print_multipath_topology; ++ pthread_cond_init_mono; ++ recv_packet; ++ recv_packet_from_client; ++ reinstate_paths; ++ remember_wwid; ++ remove_map; ++ remove_map_by_alias; ++ remove_maps; ++ remove_wwid; ++ replace_wwids; ++ reset_checker_classes; ++ select_all_tg_pt; ++ select_action; ++ select_find_multipaths_timeout; ++ select_no_path_retry; ++ select_path_group; ++ select_reservation_key; ++ send_packet; ++ set_max_fds; ++ __set_no_path_retry; ++ set_path_removed; ++ set_prkey; ++ setup_map; ++ setup_thread_attr; ++ should_multipath; ++ snprint_blacklist_report; ++ snprint_config; ++ snprint_devices; ++ snprint_foreign_multipaths; ++ snprint_foreign_paths; ++ snprint_foreign_topology; ++ _snprint_multipath; ++ snprint_multipath_header; ++ snprint_multipath_map_json; ++ _snprint_multipath_topology; ++ snprint_multipath_topology_json; ++ _snprint_path; ++ snprint_path_header; ++ snprint_status; ++ snprint_wildcards; ++ stop_io_err_stat_thread; ++ store_path; ++ store_pathinfo; ++ strchop; ++ strlcpy; ++ sync_map_state; ++ sysfs_attr_set_value; ++ sysfs_get_size; ++ sysfs_is_multipathed; ++ timespecsub; ++ trigger_paths_udev_change; ++ uevent_dispatch; ++ uevent_get_dm_str; ++ uevent_get_env_positive_int; ++ uevent_is_mpath; ++ uevent_listen; ++ update_mpp_paths; ++ update_multipath_status; ++ update_multipath_strings; ++ update_multipath_table; ++ update_pathvec_from_dm; ++ update_queue_mode_add_path; ++ update_queue_mode_del_path; ++ ux_socket_listen; ++ valid_alias; ++ vector_alloc; ++ vector_alloc_slot; ++ vector_del_slot; ++ vector_free; ++ vector_reset; ++ vector_set_slot; ++ verify_paths; ++ ++ /* checkers */ ++ sg_read; ++ ++ /* prioritizers */ ++ get_asymmetric_access_state; ++ get_prio_timeout; ++ get_target_port_group; ++ get_target_port_group_support; ++ libmp_nvme_ana_log; ++ libmp_nvme_get_nsid; ++ libmp_nvme_identify_ns; ++ log_nvme_errcode; ++ nvme_id_ctrl_ana; ++ snprint_host_wwnn; ++ snprint_host_wwpn; ++ snprint_path_serial; ++ snprint_tgt_wwnn; ++ snprint_tgt_wwpn; ++ sysfs_get_asymmetric_access_state; ++ ++ /* foreign */ ++ free_scandir_result; ++ sysfs_attr_get_value; ++ ++local: ++ *; ++}; +-- +2.17.2 + diff --git a/0011-RH-add-scsi-device-handlers-to-modules-load.d.patch b/0011-RH-add-scsi-device-handlers-to-modules-load.d.patch deleted file mode 100644 index 3fe7c25..0000000 --- a/0011-RH-add-scsi-device-handlers-to-modules-load.d.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 374755791536be4870ab2e93ae36549cbaaeb800 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - Makefile.inc | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Makefile.inc b/Makefile.inc -index 03aee175..936a622f 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}) - diff --git a/0011-libmpathpersist-add-linker-version-script.patch b/0011-libmpathpersist-add-linker-version-script.patch new file mode 100644 index 0000000..916c4f3 --- /dev/null +++ b/0011-libmpathpersist-add-linker-version-script.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 19 Sep 2020 00:02:16 +0200 +Subject: [PATCH] libmpathpersist: add linker version script + +This defines the ABI of libmpathpersist in the current state. +The initial version is set to "LIBMPATHPERSIST_1.0.0". + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathpersist/Makefile | 6 +++-- + libmpathpersist/libmpathpersist.version | 32 +++++++++++++++++++++++++ + 2 files changed, 36 insertions(+), 2 deletions(-) + create mode 100644 libmpathpersist/libmpathpersist.version + +diff --git a/libmpathpersist/Makefile b/libmpathpersist/Makefile +index 9e869fdc..456ce4cf 100644 +--- a/libmpathpersist/Makefile ++++ b/libmpathpersist/Makefile +@@ -3,6 +3,7 @@ include ../Makefile.inc + SONAME = 0 + DEVLIB = libmpathpersist.so + LIBS = $(DEVLIB).$(SONAME) ++VERSION_SCRIPT := libmpathpersist.version + + CFLAGS += $(LIB_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir) + +@@ -13,8 +14,9 @@ OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o + + all: $(DEVLIB) man + +-$(LIBS): $(OBJS) +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) $(LIBDEPS) -Wl,-soname=$@ -o $@ $(OBJS) ++$(LIBS): $(OBJS) $(VERSION_SCRIPT) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) $(LIBDEPS) -Wl,-soname=$@ \ ++ -Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) + + $(DEVLIB): $(LIBS) + $(LN) $(LIBS) $@ +diff --git a/libmpathpersist/libmpathpersist.version b/libmpathpersist/libmpathpersist.version +new file mode 100644 +index 00000000..dc648ce6 +--- /dev/null ++++ b/libmpathpersist/libmpathpersist.version +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2020 SUSE LLC ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * ++ * libmpathpersist ABI ++ * ++ * The ABI of libmpathpersist is supposed to remain stable. Removing symbols ++ * or altering existing symbols' semantics is not allowed. When changing a ++ * a symbol, either use a new name, or explicit symver directives. ++ * ++ * See libmultipath.version for general policy about version numbers. ++ */ ++LIBMPATHPERSIST_1.0.0 { ++global: ++ ++ __mpath_persistent_reserve_in; ++ __mpath_persistent_reserve_out; ++ dumpHex; ++ mpath_alloc_prin_response; ++ mpath_lib_exit; ++ mpath_lib_init; ++ mpath_mx_alloc_len; ++ mpath_persistent_reserve_in; ++ mpath_persistent_reserve_init_vecs; ++ mpath_persistent_reserve_out; ++ mpath_persistent_reserve_free_vecs; ++ prin_do_scsi_ioctl; ++ prout_do_scsi_ioctl; ++ update_map_pr; ++ ++local: *; ++}; +-- +2.17.2 + diff --git a/0012-RH-compile-with-libreadline-support.patch b/0012-RH-compile-with-libreadline-support.patch deleted file mode 100644 index 0964c42..0000000 --- a/0012-RH-compile-with-libreadline-support.patch +++ /dev/null @@ -1,26 +0,0 @@ -From cc15379130e8aa068e97c64afd46be212b456d4f Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - Makefile.inc | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Makefile.inc b/Makefile.inc -index 936a622f..f475f70f 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 diff --git a/0012-libmpathcmd-add-linker-version-script.patch b/0012-libmpathcmd-add-linker-version-script.patch new file mode 100644 index 0000000..454c3b7 --- /dev/null +++ b/0012-libmpathcmd-add-linker-version-script.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Sep 2020 12:54:20 +0200 +Subject: [PATCH] libmpathcmd: add linker version script + +For completeness, this isn't really necessary. +The version string is set to "LIBMPATHCMD_1.0.0". + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathcmd/Makefile | 6 ++++-- + libmpathcmd/libmpathcmd.version | 25 +++++++++++++++++++++++++ + 2 files changed, 29 insertions(+), 2 deletions(-) + create mode 100644 libmpathcmd/libmpathcmd.version + +diff --git a/libmpathcmd/Makefile b/libmpathcmd/Makefile +index 08ccb811..25910194 100644 +--- a/libmpathcmd/Makefile ++++ b/libmpathcmd/Makefile +@@ -3,6 +3,7 @@ include ../Makefile.inc + SONAME = 0 + DEVLIB = libmpathcmd.so + LIBS = $(DEVLIB).$(SONAME) ++VERSION_SCRIPT := libmpathcmd.version + + CFLAGS += $(LIB_CFLAGS) + +@@ -10,8 +11,9 @@ OBJS = mpath_cmd.o + + all: $(DEVLIB) + +-$(LIBS): $(OBJS) +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) ++$(LIBS): $(OBJS) $(VERSION_SCRIPT) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \ ++ -Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS) + + $(DEVLIB): $(LIBS) + $(LN) $(LIBS) $@ +diff --git a/libmpathcmd/libmpathcmd.version b/libmpathcmd/libmpathcmd.version +new file mode 100644 +index 00000000..f1006280 +--- /dev/null ++++ b/libmpathcmd/libmpathcmd.version +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (c) 2020 SUSE LLC ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * ++ * libmpathcmd ABI ++ * ++ * The ABI of libmpathcmd is supposed to remain stable. Removing symbols ++ * or altering existing symbols' semantics is not allowed. When changing a ++ * a symbol, either use a new name, or explicit symver directives. ++ * ++ * See libmultipath.version for general policy about version numbers. ++ */ ++LIBMPATHCMD_1.0.0 { ++global: ++ __mpath_connect; ++ mpath_connect; ++ mpath_disconnect; ++ mpath_process_cmd; ++ mpath_recv_reply; ++ mpath_recv_reply_len; ++ mpath_recv_reply_data; ++ mpath_send_cmd; ++local: ++ *; ++}; +-- +2.17.2 + diff --git a/0013-RH-Add-mpathcleanup.patch b/0013-RH-Add-mpathcleanup.patch deleted file mode 100644 index d1a8e84..0000000 --- a/0013-RH-Add-mpathcleanup.patch +++ /dev/null @@ -1,186 +0,0 @@ -From 2ef5bd86052ba0b22f4d3a16e69cdf268d90a53a Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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] " -+ 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 diff --git a/0013-libmpathpersist-initialize-mpp-hwe-in-get_mpvec.patch b/0013-libmpathpersist-initialize-mpp-hwe-in-get_mpvec.patch new file mode 100644 index 0000000..a04673d --- /dev/null +++ b/0013-libmpathpersist-initialize-mpp-hwe-in-get_mpvec.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 25 Sep 2020 21:37:16 +0200 +Subject: [PATCH] libmpathpersist: initialize mpp->hwe in get_mpvec() + +In __mpath_persistent_reserve_out, we call select_all_tg_pt(), +which requires mpp->hwe to be set. Initialize it in get_mpvec(). + +Fixes: 5b54e77 ("mpathpersist: add all_tg_pt option") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathpersist/mpath_persist.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 1f9817ed..4b3f3e0d 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -341,11 +341,13 @@ get_mpvec (vector curmp, vector pathvec, char * refwwid) + continue; + + if (update_multipath_table(mpp, pathvec, DI_CHECKER) != DMP_OK || +- update_multipath_status(mpp) != DMP_OK) { ++ update_multipath_status(mpp) != DMP_OK || ++ update_mpp_paths(mpp, pathvec)) { + condlog(1, "error parsing map %s", mpp->wwid); + remove_map(mpp, pathvec, curmp, PURGE_VEC); + i--; +- } ++ } else ++ extract_hwe_from_path(mpp); + } + return MPATH_PR_SUCCESS ; + } +-- +2.17.2 + diff --git a/0014-multipathd-allow-shutdown-during-configure.patch b/0014-multipathd-allow-shutdown-during-configure.patch new file mode 100644 index 0000000..2cbfecf --- /dev/null +++ b/0014-multipathd-allow-shutdown-during-configure.patch @@ -0,0 +1,140 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 4 Jan 2019 16:59:49 +0100 +Subject: [PATCH] multipathd: allow shutdown during configure() + +reconfigure() can be a long-running operation; both initial path +discovery and initial map setup can take a long time. Allow +the main program to indicate that the process should be +interrupted if a shutdown signal was received. + +We take advantage of the dynamic linker's symbol lookup ordering +here. The default implementation of should_exit never returns +true, but callers (like multipathd) can override it. + +Cc: Chongyun Wu +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 6 ++++++ + libmultipath/discovery.c | 3 +++ + libmultipath/util.c | 5 +++++ + libmultipath/util.h | 1 + + multipathd/main.c | 17 +++++++++++++++++ + 5 files changed, 32 insertions(+) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index d7afc915..1c8aac08 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -1173,6 +1173,12 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + + vector_foreach_slot (pathvec, pp1, k) { + int invalid; ++ ++ if (should_exit()) { ++ ret = CP_FAIL; ++ goto out; ++ } ++ + /* skip this path for some reason */ + + /* 1. if path has no unique id or wwid blacklisted */ +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index c2e1754c..e7084664 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -200,6 +200,9 @@ path_discovery (vector pathvec, int flag) + const char *devtype; + const char *devpath; + ++ if (should_exit()) ++ break; ++ + devpath = udev_list_entry_get_name(entry); + condlog(4, "Discover device %s", devpath); + udevice = udev_device_new_from_syspath(udev, devpath); +diff --git a/libmultipath/util.c b/libmultipath/util.c +index 1748eafe..1f977792 100644 +--- a/libmultipath/util.c ++++ b/libmultipath/util.c +@@ -445,3 +445,8 @@ void _log_bitfield_overflow(const char *f, unsigned int bit, unsigned int len) + { + condlog(0, "%s: bitfield overflow: %u >= %u", f, bit, len); + } ++ ++int should_exit(void) ++{ ++ return 0; ++} +diff --git a/libmultipath/util.h b/libmultipath/util.h +index 2b9703ac..ac19473e 100644 +--- a/libmultipath/util.h ++++ b/libmultipath/util.h +@@ -27,6 +27,7 @@ int parse_prkey(const char *ptr, uint64_t *prkey); + int parse_prkey_flags(const char *ptr, uint64_t *prkey, uint8_t *flags); + int safe_write(int fd, const void *buf, size_t count); + void set_max_fds(rlim_t max_fds); ++int should_exit(void); + + #define KERNEL_VERSION(maj, min, ptc) ((((maj) * 256) + (min)) * 256 + (ptc)) + #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) +diff --git a/multipathd/main.c b/multipathd/main.c +index eedc6c10..fa53e963 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -141,6 +141,11 @@ static inline enum daemon_status get_running_state(void) + return st; + } + ++int should_exit(void) ++{ ++ return get_running_state() == DAEMON_SHUTDOWN; ++} ++ + /* + * global copy of vecs for use in sig handlers + */ +@@ -2570,6 +2575,9 @@ configure (struct vectors * vecs) + goto fail; + } + ++ if (should_exit()) ++ goto fail; ++ + conf = get_multipath_config(); + pthread_cleanup_push(put_multipath_config, conf); + vector_foreach_slot (vecs->pathvec, pp, i){ +@@ -2586,6 +2594,9 @@ configure (struct vectors * vecs) + goto fail; + } + ++ if (should_exit()) ++ goto fail; ++ + /* + * create new set of maps & push changed ones into dm + * In the first call, use FORCE_RELOAD_WEAK to avoid making +@@ -2600,6 +2611,9 @@ configure (struct vectors * vecs) + goto fail; + } + ++ if (should_exit()) ++ goto fail; ++ + /* + * may need to remove some maps which are no longer relevant + * e.g., due to blacklist changes in conf file +@@ -2611,6 +2625,9 @@ configure (struct vectors * vecs) + + dm_lib_release(); + ++ if (should_exit()) ++ goto fail; ++ + sync_maps_state(mpvec); + vector_foreach_slot(mpvec, mpp, i){ + if (remember_wwid(mpp->wwid) == 1) +-- +2.17.2 + diff --git a/0015-multipathd-avoid-sending-READY-1-to-systemd-on-early.patch b/0015-multipathd-avoid-sending-READY-1-to-systemd-on-early.patch new file mode 100644 index 0000000..c2d1475 --- /dev/null +++ b/0015-multipathd-avoid-sending-READY-1-to-systemd-on-early.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 10:23:05 +0200 +Subject: [PATCH] multipathd: avoid sending "READY=1" to systemd on early + shutdown + +If multipathd gets a shutdown request during initial reconfigure(), +it shouldn't send "READY=1" to systemd. Ensure this by sending +"READY=1" via post_config_state(). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index fa53e963..53a22a43 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -189,6 +189,8 @@ static void do_sd_notify(enum daemon_status old_state, + { + char notify_msg[MSG_SIZE]; + const char *msg; ++ static bool startup_done = false; ++ + /* + * Checkerloop switches back and forth between idle and running state. + * No need to tell systemd each time. +@@ -205,6 +207,11 @@ static void do_sd_notify(enum daemon_status old_state, + + if (msg && !safe_sprintf(notify_msg, "STATUS=%s", msg)) + sd_notify(0, notify_msg); ++ ++ if (new_state == DAEMON_IDLE && !startup_done) { ++ sd_notify(0, "READY=1"); ++ startup_done = true; ++ } + } + #endif + +@@ -2903,9 +2910,6 @@ child (__attribute__((unused)) void *param) + struct vectors * vecs; + struct multipath * mpp; + int i; +-#ifdef USE_SYSTEMD +- int startup_done = 0; +-#endif + int rc; + int pid_fd = -1; + struct config *conf; +@@ -3065,12 +3069,6 @@ child (__attribute__((unused)) void *param) + } + lock_cleanup_pop(vecs->lock); + post_config_state(DAEMON_IDLE); +-#ifdef USE_SYSTEMD +- if (!startup_done) { +- sd_notify(0, "READY=1"); +- startup_done = 1; +- } +-#endif + } + } + +-- +2.17.2 + diff --git a/0016-multipathd-send-STOPPING-1-to-systemd-on-shutdown.patch b/0016-multipathd-send-STOPPING-1-to-systemd-on-shutdown.patch new file mode 100644 index 0000000..b38cf2f --- /dev/null +++ b/0016-multipathd-send-STOPPING-1-to-systemd-on-shutdown.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 10:47:52 +0200 +Subject: [PATCH] multipathd: send "STOPPING=1" to systemd on shutdown + +Inform systemd that the daemon is shutting down. See sd_notify(3). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 53a22a43..c264351c 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -208,7 +208,9 @@ static void do_sd_notify(enum daemon_status old_state, + if (msg && !safe_sprintf(notify_msg, "STATUS=%s", msg)) + sd_notify(0, notify_msg); + +- if (new_state == DAEMON_IDLE && !startup_done) { ++ if (new_state == DAEMON_SHUTDOWN) ++ sd_notify(0, "STOPPING=1"); ++ else if (new_state == DAEMON_IDLE && !startup_done) { + sd_notify(0, "READY=1"); + startup_done = true; + } +-- +2.17.2 + diff --git a/0017-multipathd-send-RELOADING-1-to-systemd-on-DAEMON_CON.patch b/0017-multipathd-send-RELOADING-1-to-systemd-on-DAEMON_CON.patch new file mode 100644 index 0000000..76894d0 --- /dev/null +++ b/0017-multipathd-send-RELOADING-1-to-systemd-on-DAEMON_CON.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 10:57:22 +0200 +Subject: [PATCH] multipathd: send "RELOADING=1" to systemd on DAEMON_CONFIGURE + state + +The logic is as follows: child() sets DAEMON_IDLE status after +DAEMON_CONFIGURE when reconfigure() has finished. The only other state change +that can race with that is DAEMON_SHUTDOWN. Other state changes will wait for +DAEMON_IDLE first (see set_config_state()). When DAEMON_CONFIGURE is entered, +and we are not just starting up, send a "RELOADING=1" message to +systemd. After that, we must send "READY=1" when we're done reloading. Also +do that on startup, when DAEMON_IDLE is set for the first time. +See sd_notify(3). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index c264351c..e3f2328d 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -210,10 +210,11 @@ static void do_sd_notify(enum daemon_status old_state, + + if (new_state == DAEMON_SHUTDOWN) + sd_notify(0, "STOPPING=1"); +- else if (new_state == DAEMON_IDLE && !startup_done) { ++ else if (new_state == DAEMON_IDLE && old_state == DAEMON_CONFIGURE) { + sd_notify(0, "READY=1"); + startup_done = true; +- } ++ } else if (new_state == DAEMON_CONFIGURE && startup_done) ++ sd_notify(0, "RELOADING=1"); + } + #endif + +-- +2.17.2 + diff --git a/0018-multipathd-use-volatile-qualifier-for-running_state.patch b/0018-multipathd-use-volatile-qualifier-for-running_state.patch new file mode 100644 index 0000000..400298e --- /dev/null +++ b/0018-multipathd-use-volatile-qualifier-for-running_state.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 12:44:59 +0200 +Subject: [PATCH] multipathd: use volatile qualifier for running_state + +While we access running_state only under the config_lock, +we sometimes do in a loop. Use the volatile qualifier to make +sure compilers can't optimize away the loads. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index e3f2328d..d081b3e9 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -126,7 +126,7 @@ int poll_dmevents = 0; + int poll_dmevents = 1; + #endif + /* Don't access this variable without holding config_lock */ +-enum daemon_status running_state = DAEMON_INIT; ++volatile enum daemon_status running_state = DAEMON_INIT; + pid_t daemon_pid; + pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t config_cond; +-- +2.17.2 + diff --git a/0019-multipathd-generalize-and-fix-wait_for_state_change_.patch b/0019-multipathd-generalize-and-fix-wait_for_state_change_.patch new file mode 100644 index 0000000..73f99ec --- /dev/null +++ b/0019-multipathd-generalize-and-fix-wait_for_state_change_.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 12:46:36 +0200 +Subject: [PATCH] multipathd: generalize and fix wait_for_state_change_if() + +It's unlikely but not impossible that other threads change the state +while we're waiting, and if we grab the lock again, it's still not +what we wanted. We need to continue waiting until either the condition +is met, or time timeout expired. + +Moreover, generalize this code so that it can also be used in +set_config_state(). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index d081b3e9..1fb0ee62 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -223,6 +223,23 @@ static void config_cleanup(__attribute__((unused)) void *arg) + pthread_mutex_unlock(&config_lock); + } + ++#define __wait_for_state_change(condition, ms) \ ++ ({ \ ++ struct timespec tmo; \ ++ int rc = 0; \ ++ \ ++ if (condition) { \ ++ get_monotonic_time(&tmo); \ ++ tmo.tv_nsec += (ms) * 1000 * 1000; \ ++ normalize_timespec(&tmo); \ ++ do \ ++ rc = pthread_cond_timedwait( \ ++ &config_cond, &config_lock, &tmo); \ ++ while (rc == 0 && (condition)); \ ++ } \ ++ rc; \ ++ }) ++ + /* + * If the current status is @oldstate, wait for at most @ms milliseconds + * for the state to change, and return the new state, which may still be +@@ -232,20 +249,14 @@ enum daemon_status wait_for_state_change_if(enum daemon_status oldstate, + unsigned long ms) + { + enum daemon_status st; +- struct timespec tmo; + + if (oldstate == DAEMON_SHUTDOWN) + return DAEMON_SHUTDOWN; + + pthread_mutex_lock(&config_lock); + pthread_cleanup_push(config_cleanup, NULL); ++ __wait_for_state_change(running_state == oldstate, ms); + st = running_state; +- if (st == oldstate && clock_gettime(CLOCK_MONOTONIC, &tmo) == 0) { +- tmo.tv_nsec += ms * 1000 * 1000; +- normalize_timespec(&tmo); +- (void)pthread_cond_timedwait(&config_cond, &config_lock, &tmo); +- st = running_state; +- } + pthread_cleanup_pop(1); + return st; + } +-- +2.17.2 + diff --git a/0020-multipathd-set_config_state-avoid-code-duplication.patch b/0020-multipathd-set_config_state-avoid-code-duplication.patch new file mode 100644 index 0000000..a5310f3 --- /dev/null +++ b/0020-multipathd-set_config_state-avoid-code-duplication.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 12:48:55 +0200 +Subject: [PATCH] multipathd: set_config_state(): avoid code duplication + +Use __post_config_state() and __wait_for_state_change(). This +way __post_config_state() is the only place where running_state +is ever changed, and we avoid code duplication. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 23 +++++------------------ + 1 file changed, 5 insertions(+), 18 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 1fb0ee62..39aea4ad 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -292,27 +292,14 @@ int set_config_state(enum daemon_status state) + pthread_cleanup_push(config_cleanup, NULL); + pthread_mutex_lock(&config_lock); + if (running_state != state) { +-#ifdef USE_SYSTEMD +- enum daemon_status old_state = running_state; +-#endif + + if (running_state == DAEMON_SHUTDOWN) + rc = EINVAL; +- else if (running_state != DAEMON_IDLE) { +- struct timespec ts; +- +- get_monotonic_time(&ts); +- ts.tv_sec += 1; +- rc = pthread_cond_timedwait(&config_cond, +- &config_lock, &ts); +- } +- if (!rc && (running_state != DAEMON_SHUTDOWN)) { +- running_state = state; +- pthread_cond_broadcast(&config_cond); +-#ifdef USE_SYSTEMD +- do_sd_notify(old_state, state); +-#endif +- } ++ else ++ rc = __wait_for_state_change( ++ running_state != DAEMON_IDLE, 1000); ++ if (!rc) ++ __post_config_state(state); + } + pthread_cleanup_pop(1); + return rc; +-- +2.17.2 + diff --git a/0021-multipathd-cancel-threads-early-during-shutdown.patch b/0021-multipathd-cancel-threads-early-during-shutdown.patch new file mode 100644 index 0000000..cc51513 --- /dev/null +++ b/0021-multipathd-cancel-threads-early-during-shutdown.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 4 Jan 2019 17:10:25 +0100 +Subject: [PATCH] multipathd: cancel threads early during shutdown + +Cancel the other threads before taking vecs->lock. This avoids +delays during shutdown caused e.g. by the checker thread holding +the vecs lock. + +Note: this makes it possible that cancelled threads leak memory, +because they can now be cancelled before having released the vecs +lock. I believe this is acceptable, as only threads are affected +that are cancelled during multipathd shutdown. + +Cc: Chongyun Wu +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 39aea4ad..d1f8cc1b 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3073,23 +3073,24 @@ child (__attribute__((unused)) void *param) + } + } + +- lock(&vecs->lock); ++ pthread_cancel(check_thr); ++ pthread_cancel(uevent_thr); ++ pthread_cancel(uxlsnr_thr); ++ pthread_cancel(uevq_thr); ++ if (poll_dmevents) ++ pthread_cancel(dmevent_thr); ++ + conf = get_multipath_config(); + queue_without_daemon = conf->queue_without_daemon; + put_multipath_config(conf); ++ ++ lock(&vecs->lock); + if (queue_without_daemon == QUE_NO_DAEMON_OFF) + vector_foreach_slot(vecs->mpvec, mpp, i) + dm_queue_if_no_path(mpp->alias, 0); + remove_maps_and_stop_waiters(vecs); + unlock(&vecs->lock); + +- pthread_cancel(check_thr); +- pthread_cancel(uevent_thr); +- pthread_cancel(uxlsnr_thr); +- pthread_cancel(uevq_thr); +- if (poll_dmevents) +- pthread_cancel(dmevent_thr); +- + pthread_join(check_thr, NULL); + pthread_join(uevent_thr, NULL); + pthread_join(uxlsnr_thr, NULL); +-- +2.17.2 + diff --git a/0022-multipath-tools-don-t-call-dm_lib_release-any-more.patch b/0022-multipath-tools-don-t-call-dm_lib_release-any-more.patch new file mode 100644 index 0000000..fe32b1a --- /dev/null +++ b/0022-multipath-tools-don-t-call-dm_lib_release-any-more.patch @@ -0,0 +1,165 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 17:57:16 +0200 +Subject: [PATCH] multipath-tools: don't call dm_lib_release() any more + +The purpose of dm_lib_release() is to release stacked device node +operations in libdevmapper. This is functionality we don't need and +use any more, as we rely on udev to set up device nodes and symlinks. + +We always set DM_UDEV_DISABLE_LIBRARY_FALLBACK when we run dm tasks. +In the standard CREATE and REMOVE cases, libdevmapper doesn't +stack any operations if this flag is set. The only exceptions are + + a) RESUME operations with DM_ADD_NODE_ON_RESUME set. This happens +implicity when we create new maps + b) RENAME operations + +In both cases, we call dm_udev_wait() after the libdm operation, which +calls update_devs() and thus has the same effect as dm_lib_release(), +cleaning out stacked operations. + +OTOH, dm_lib_releases() accesses static variables in libdevmapper, so +calling it might be racy. + +Drop the calls to dm_lib_release(). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + kpartx/kpartx.c | 1 - + libmpathpersist/mpath_persist.c | 1 - + multipath/main.c | 1 - + multipathd/cli_handlers.c | 2 -- + multipathd/main.c | 15 ++------------- + 5 files changed, 2 insertions(+), 18 deletions(-) + +diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c +index 4a0aae93..6a7933fa 100644 +--- a/kpartx/kpartx.c ++++ b/kpartx/kpartx.c +@@ -681,7 +681,6 @@ main(int argc, char **argv){ + } + + end: +- dm_lib_release(); + dm_lib_exit(); + + return r; +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 4b3f3e0d..cc4a088d 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -56,7 +56,6 @@ mpath_lib_init (void) + int + mpath_lib_exit (struct config *conf) + { +- dm_lib_release(); + dm_lib_exit(); + cleanup_prio(); + cleanup_checkers(); +diff --git a/multipath/main.c b/multipath/main.c +index 9e920d89..dc4974b9 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -1063,7 +1063,6 @@ main (int argc, char *argv[]) + condlog(3, "restart multipath configuration process"); + + out: +- dm_lib_release(); + dm_lib_exit(); + + cleanup_foreign(); +diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c +index 235e2a2e..54635738 100644 +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -860,7 +860,6 @@ cli_add_map (void * v, char ** reply, int * len, void * data) + != CP_OK) + condlog(2, "%s: coalesce_paths failed", + param); +- dm_lib_release(); + FREE(refwwid); + } + } /*we attempt to create device only once*/ +@@ -1032,7 +1031,6 @@ cli_resize(void *v, char **reply, int *len, void *data) + if (resize_map(mpp, size, vecs) != 0) + return 1; + +- dm_lib_release(); + if (setup_multipath(vecs, mpp) != 0) + return 1; + sync_map_state(mpp); +diff --git a/multipathd/main.c b/multipathd/main.c +index d1f8cc1b..5cc34357 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -510,7 +510,6 @@ retry: + sleep(1); + goto retry; + } +- dm_lib_release(); + + fail: + if (new_map && (retries < 0 || wait_for_events(mpp, vecs))) { +@@ -611,10 +610,8 @@ coalesce_maps(struct vectors *vecs, vector nmpv) + vector_del_slot(ompv, i); + i--; + } +- else { +- dm_lib_release(); ++ else + condlog(2, "%s devmap removed", ompp->alias); +- } + } else if (reassign_maps) { + condlog(3, "%s: Reassign existing device-mapper" + " devices", ompp->alias); +@@ -660,10 +657,8 @@ flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths) + } + return r; + } +- else { +- dm_lib_release(); ++ else + condlog(2, "%s: map flushed", mpp->alias); +- } + + orphan_paths(vecs->pathvec, mpp, "map flushed"); + remove_map_and_stop_waiter(mpp, vecs); +@@ -1080,7 +1075,6 @@ rescan: + else + goto fail_map; + } +- dm_lib_release(); + + if ((mpp->action == ACT_CREATE || + (mpp->action == ACT_NOTHING && start_waiter && !mpp->waiter)) && +@@ -1947,8 +1941,6 @@ int reload_and_sync_map(struct multipath *mpp, + { + if (reload_map(vecs, mpp, refresh, 1)) + return 1; +- +- dm_lib_release(); + if (setup_multipath(vecs, mpp) != 0) + return 2; + sync_map_state(mpp); +@@ -2631,8 +2623,6 @@ configure (struct vectors * vecs) + goto fail; + } + +- dm_lib_release(); +- + if (should_exit()) + goto fail; + +@@ -3115,7 +3105,6 @@ child (__attribute__((unused)) void *param) + if (poll_dmevents) + cleanup_dmevent_waiter(); + +- dm_lib_release(); + dm_lib_exit(); + + /* We're done here */ +-- +2.17.2 + diff --git a/0023-libmultipath-devmapper-refactor-libdm-version-determ.patch b/0023-libmultipath-devmapper-refactor-libdm-version-determ.patch new file mode 100644 index 0000000..b5e96b2 --- /dev/null +++ b/0023-libmultipath-devmapper-refactor-libdm-version-determ.patch @@ -0,0 +1,506 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 23:12:15 +0200 +Subject: [PATCH] libmultipath: devmapper: refactor libdm version determination + +As one step towards bundling all possibly racy libdm init calls into a single +function, split the code for determining and checking versions of +libdm and kernel components. Provide a generic helper +libmp_get_version() that makes sure the versions are "lazily" initialized. + +External callers may use dm_prereq(), like before. +Minor API change: dm_prereq() does not nullify the argument any more +if an error is encountered. + +Remove the conf->version field, which isn't needed any more after this +change. This makes it necessary to fixup the hwtable test. Also, it +represents an incompatible ABI change as offsets in "struct config" are +changed, and two symbols removed. Bump the ABI major version to 2. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.h | 1 - + libmultipath/devmapper.c | 162 ++++++++++++++++++++---------- + libmultipath/devmapper.h | 10 +- + libmultipath/libmultipath.version | 5 +- + libmultipath/propsel.c | 10 +- + multipathd/dmevents.c | 2 +- + multipathd/main.c | 1 - + tests/Makefile | 2 +- + tests/hwtable.c | 3 - + tests/test-lib.c | 13 +++ + 10 files changed, 141 insertions(+), 68 deletions(-) + +diff --git a/libmultipath/config.h b/libmultipath/config.h +index 290aea58..7af19844 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -192,7 +192,6 @@ struct config { + int find_multipaths_timeout; + int marginal_pathgroups; + int skip_delegate; +- unsigned int version[3]; + unsigned int sequence_nr; + + char * multipath_dir; +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 0bc1d16e..3e36129b 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -26,6 +26,7 @@ + #include "sysfs.h" + #include "config.h" + #include "wwids.h" ++#include "version.h" + + #include "log_pthread.h" + #include +@@ -34,7 +35,13 @@ + #define MAX_WAIT 5 + #define LOOPS_PER_SEC 5 + ++#define INVALID_VERSION ~0U ++static unsigned int dm_library_version[3] = { INVALID_VERSION, }; ++static unsigned int dm_kernel_version[3] = { INVALID_VERSION, }; ++static unsigned int dm_mpath_target_version[3] = { INVALID_VERSION, }; ++ + static pthread_once_t dm_initialized = PTHREAD_ONCE_INIT; ++static pthread_once_t versions_initialized = PTHREAD_ONCE_INIT; + + static int dm_conf_verbosity; + +@@ -102,7 +109,7 @@ dm_write_log (int level, const char *file, int line, const char *f, ...) + return; + } + +-void dm_init(int v) ++static void dm_init(int v) + { + /* + * This maps libdm's standard loglevel _LOG_WARN (= 4), which is rather +@@ -112,61 +119,68 @@ void dm_init(int v) + dm_log_init(&dm_write_log); + } + ++static void init_dm_library_version(void) ++{ ++ char version[64]; ++ unsigned int v[3]; ++ ++ dm_get_library_version(version, sizeof(version)); ++ if (sscanf(version, "%u.%u.%u ", &v[0], &v[1], &v[2]) != 3) { ++ condlog(0, "invalid libdevmapper version %s", version); ++ return; ++ } ++ memcpy(dm_library_version, v, sizeof(dm_library_version)); ++ condlog(3, "libdevmapper version %u.%.2u.%.2u", ++ dm_library_version[0], dm_library_version[1], ++ dm_library_version[2]); ++} ++ + static int + dm_lib_prereq (void) + { +- char version[64]; +- int v[3]; ++ + #if defined(LIBDM_API_HOLD_CONTROL) +- int minv[3] = {1, 2, 111}; ++ unsigned int minv[3] = {1, 2, 111}; + #elif defined(LIBDM_API_GET_ERRNO) +- int minv[3] = {1, 2, 99}; ++ unsigned int minv[3] = {1, 2, 99}; + #elif defined(LIBDM_API_DEFERRED) +- int minv[3] = {1, 2, 89}; ++ unsigned int minv[3] = {1, 2, 89}; + #elif defined(DM_SUBSYSTEM_UDEV_FLAG0) +- int minv[3] = {1, 2, 82}; ++ unsigned int minv[3] = {1, 2, 82}; + #elif defined(LIBDM_API_COOKIE) +- int minv[3] = {1, 2, 38}; ++ unsigned int minv[3] = {1, 2, 38}; + #else +- int minv[3] = {1, 2, 8}; ++ unsigned int minv[3] = {1, 2, 8}; + #endif + +- dm_get_library_version(version, sizeof(version)); +- condlog(3, "libdevmapper version %s", version); +- if (sscanf(version, "%d.%d.%d ", &v[0], &v[1], &v[2]) != 3) { +- condlog(0, "invalid libdevmapper version %s", version); +- return 1; +- } +- +- if VERSION_GE(v, minv) ++ if (VERSION_GE(dm_library_version, minv)) + return 0; +- condlog(0, "libdevmapper version must be >= %d.%.2d.%.2d", ++ condlog(0, "libdevmapper version must be >= %u.%.2u.%.2u", + minv[0], minv[1], minv[2]); + return 1; + } + +-int +-dm_drv_version(unsigned int *v) ++static void init_dm_drv_version(void) + { + char buff[64]; +- +- v[0] = 0; +- v[1] = 0; +- v[2] = 0; ++ unsigned int v[3]; + + if (!dm_driver_version(buff, sizeof(buff))) { + condlog(0, "cannot get kernel dm version"); +- return 1; ++ return; + } + if (sscanf(buff, "%u.%u.%u ", &v[0], &v[1], &v[2]) != 3) { + condlog(0, "invalid kernel dm version '%s'", buff); +- return 1; ++ return; + } +- return 0; ++ memcpy(dm_kernel_version, v, sizeof(dm_library_version)); ++ condlog(3, "kernel device mapper v%u.%u.%u", ++ dm_kernel_version[0], ++ dm_kernel_version[1], ++ dm_kernel_version[2]); + } + +-int +-dm_tgt_version (unsigned int * version, char * str) ++static int dm_tgt_version (unsigned int *version, char *str) + { + int r = 2; + struct dm_task *dmt; +@@ -174,10 +188,11 @@ dm_tgt_version (unsigned int * version, char * str) + struct dm_versions *last_target; + unsigned int *v; + +- version[0] = 0; +- version[1] = 0; +- version[2] = 0; +- ++ /* ++ * We have to call dm_task_create() and not libmp_dm_task_create() ++ * here to avoid a recursive invocation of ++ * pthread_once(&dm_initialized), which would cause a deadlock. ++ */ + if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) + return 1; + +@@ -213,26 +228,25 @@ out: + return r; + } + +-static int +-dm_tgt_prereq (unsigned int *ver) ++static void init_dm_mpath_version(void) + { +- unsigned int minv[3] = {1, 0, 3}; +- unsigned int version[3] = {0, 0, 0}; +- unsigned int * v = version; +- +- if (dm_tgt_version(v, TGT_MPATH)) { +- /* in doubt return not capable */ +- return 1; +- } ++ if (!dm_tgt_version(dm_mpath_target_version, TGT_MPATH)) ++ condlog(3, "DM multipath kernel driver v%u.%u.%u", ++ dm_mpath_target_version[0], ++ dm_mpath_target_version[1], ++ dm_mpath_target_version[2]); ++} + +- /* test request based multipath capability */ +- condlog(3, "DM multipath kernel driver v%u.%u.%u", +- v[0], v[1], v[2]); ++static int dm_tgt_prereq (unsigned int *ver) ++{ ++ unsigned int minv[3] = {1, 0, 3}; + +- if (VERSION_GE(v, minv)) { +- ver[0] = v[0]; +- ver[1] = v[1]; +- ver[2] = v[2]; ++ if (VERSION_GE(dm_mpath_target_version, minv)) { ++ if (ver) { ++ ver[0] = dm_mpath_target_version[0]; ++ ver[1] = dm_mpath_target_version[1]; ++ ver[2] = dm_mpath_target_version[2]; ++ } + return 0; + } + +@@ -241,13 +255,60 @@ dm_tgt_prereq (unsigned int *ver) + return 1; + } + ++static void _init_versions(void) ++{ ++ dlog(logsink, 3, VERSION_STRING); ++ init_dm_library_version(); ++ init_dm_drv_version(); ++ init_dm_mpath_version(); ++} ++ ++static int init_versions(void) { ++ pthread_once(&versions_initialized, _init_versions); ++ return (dm_library_version[0] == INVALID_VERSION || ++ dm_kernel_version[0] == INVALID_VERSION || ++ dm_mpath_target_version[0] == INVALID_VERSION); ++} ++ + int dm_prereq(unsigned int *v) + { ++ if (init_versions()) ++ return 1; + if (dm_lib_prereq()) + return 1; + return dm_tgt_prereq(v); + } + ++int libmp_get_version(int which, unsigned int version[3]) ++{ ++ unsigned int *src_version; ++ ++ init_versions(); ++ switch (which) { ++ case DM_LIBRARY_VERSION: ++ src_version = dm_library_version; ++ break; ++ case DM_KERNEL_VERSION: ++ src_version = dm_kernel_version; ++ break; ++ case DM_MPATH_TARGET_VERSION: ++ src_version = dm_mpath_target_version; ++ break; ++ case MULTIPATH_VERSION: ++ version[0] = (VERSION_CODE >> 16) & 0xff; ++ version[1] = (VERSION_CODE >> 8) & 0xff; ++ version[2] = VERSION_CODE & 0xff; ++ return 0; ++ default: ++ condlog(0, "%s: invalid value for 'which'", __func__); ++ return 1; ++ } ++ if (src_version[0] == INVALID_VERSION) ++ return 1; ++ memcpy(version, src_version, 3 * sizeof(*version)); ++ return 0; ++} ++ + static int libmp_dm_udev_sync = 0; + + void libmp_udev_set_sync_support(int on) +@@ -265,7 +326,6 @@ static void libmp_dm_init(void) + exit(1); + conf = get_multipath_config(); + verbosity = conf->verbosity; +- memcpy(conf->version, version, sizeof(version)); + put_multipath_config(conf); + dm_init(verbosity); + #ifdef LIBDM_API_HOLD_CONTROL +diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h +index f469c98a..a0bcd137 100644 +--- a/libmultipath/devmapper.h ++++ b/libmultipath/devmapper.h +@@ -33,13 +33,10 @@ enum { + DMP_NOT_FOUND, + }; + +-void dm_init(int verbosity); + int dm_prereq(unsigned int *v); + void skip_libmp_dm_init(void); + void libmp_udev_set_sync_support(int on); + struct dm_task *libmp_dm_task_create(int task); +-int dm_drv_version (unsigned int * version); +-int dm_tgt_version (unsigned int * version, char * str); + int dm_simplecmd_flush (int, const char *, uint16_t); + int dm_simplecmd_noflush (int, const char *, uint16_t); + int dm_addmap_create (struct multipath *mpp, char *params); +@@ -89,6 +86,13 @@ struct multipath *dm_get_multipath(const char *name); + #include + #define dm_task_get_errno(x) errno + #endif ++enum { ++ DM_LIBRARY_VERSION, ++ DM_KERNEL_VERSION, ++ DM_MPATH_TARGET_VERSION, ++ MULTIPATH_VERSION ++}; ++int libmp_get_version(int which, unsigned int version[3]); + + #define dm_log_error(lvl, cmd, dmt) \ + condlog(lvl, "%s: libdm task=%d error: %s", __func__, \ +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index a6bf8218..ab5bb0ad 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -31,7 +31,7 @@ + * The new version inherits the previous ones. + */ + +-LIBMULTIPATH_1.0.0 { ++LIBMULTIPATH_2.0.0 { + global: + /* symbols referenced by multipath and multipathd */ + add_foreign; +@@ -65,7 +65,6 @@ global: + disassemble_status; + dlog; + dm_cancel_deferred_remove; +- dm_drv_version; + dm_enablegroup; + dm_fail_path; + _dm_flush_map; +@@ -87,7 +86,6 @@ global: + dm_reinstate_path; + dm_simplecmd_noflush; + dm_switchgroup; +- dm_tgt_version; + domap; + ensure_directories_exist; + extract_hwe_from_path; +@@ -128,6 +126,7 @@ global: + is_path_valid; + is_quote; + libmp_dm_task_create; ++ libmp_get_version; + libmp_udev_set_sync_support; + load_config; + log_thread_reset; +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index 40201344..3f2c2cfa 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -735,9 +735,10 @@ out: + + int select_minio(struct config *conf, struct multipath *mp) + { +- unsigned int minv_dmrq[3] = {1, 1, 0}; ++ unsigned int minv_dmrq[3] = {1, 1, 0}, version[3]; + +- if (VERSION_GE(conf->version, minv_dmrq)) ++ if (!libmp_get_version(DM_MPATH_TARGET_VERSION, version) ++ && VERSION_GE(version, minv_dmrq)) + return select_minio_rq(conf, mp); + else + return select_minio_bio(conf, mp); +@@ -820,9 +821,10 @@ out: + int select_retain_hwhandler(struct config *conf, struct multipath *mp) + { + const char *origin; +- unsigned int minv_dm_retain[3] = {1, 5, 0}; ++ unsigned int minv_dm_retain[3] = {1, 5, 0}, version[3]; + +- if (!VERSION_GE(conf->version, minv_dm_retain)) { ++ if (!libmp_get_version(DM_MPATH_TARGET_VERSION, version) && ++ !VERSION_GE(version, minv_dm_retain)) { + mp->retain_hwhandler = RETAIN_HWHANDLER_OFF; + origin = "(setting: WARNING, requires kernel dm-mpath version >= 1.5.0)"; + goto out; +diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c +index 5f2d210d..fc97c8a2 100644 +--- a/multipathd/dmevents.c ++++ b/multipathd/dmevents.c +@@ -60,7 +60,7 @@ int dmevent_poll_supported(void) + { + unsigned int v[3]; + +- if (dm_drv_version(v)) ++ if (libmp_get_version(DM_KERNEL_VERSION, v)) + return 0; + + if (VERSION_GE(v, DM_VERSION_FOR_ARM_POLL)) +diff --git a/multipathd/main.c b/multipathd/main.c +index 5cc34357..00b66ba4 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2709,7 +2709,6 @@ reconfigure (struct vectors * vecs) + /* Re-read any timezone changes */ + tzset(); + +- dm_tgt_version(conf->version, TGT_MPATH); + if (verbosity) + conf->verbosity = verbosity; + if (bindings_read_only) +diff --git a/tests/Makefile b/tests/Makefile +index 9658c9fd..78777bec 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -43,7 +43,7 @@ endif + dmevents-test_LIBDEPS = -lpthread -ldevmapper -lurcu + hwtable-test_TESTDEPS := test-lib.o + hwtable-test_OBJDEPS := ../libmultipath/discovery.o ../libmultipath/blacklist.o \ +- ../libmultipath/structs.o ++ ../libmultipath/structs.o ../libmultipath/propsel.o + hwtable-test_LIBDEPS := -ludev -lpthread -ldl + blacklist-test_TESTDEPS := test-log.o + blacklist-test_OBJDEPS := ../libmultipath/blacklist.o +diff --git a/tests/hwtable.c b/tests/hwtable.c +index 12660da2..57f832b7 100644 +--- a/tests/hwtable.c ++++ b/tests/hwtable.c +@@ -30,8 +30,6 @@ + #define N_CONF_FILES 2 + + static const char tmplate[] = "/tmp/hwtable-XXXXXX"; +-/* pretend new dm, use minio_rq */ +-static const unsigned int dm_tgt_version[3] = { 1, 1, 1 }; + + struct key_value { + const char *key; +@@ -360,7 +358,6 @@ static void write_device(FILE *ff, int nkv, const struct key_value *kv) + assert_ptr_not_equal(__cf, NULL); \ + assert_ptr_not_equal(__cf->hwtable, NULL); \ + __cf->verbosity = VERBOSITY; \ +- memcpy(&__cf->version, dm_tgt_version, sizeof(__cf->version)); \ + __cf; }) + + #define FREE_CONFIG(conf) do { \ +diff --git a/tests/test-lib.c b/tests/test-lib.c +index b7c09cc2..e7663f9a 100644 +--- a/tests/test-lib.c ++++ b/tests/test-lib.c +@@ -56,6 +56,15 @@ int __wrap_execute_program(char *path, char *value, int len) + return 0; + } + ++int __wrap_libmp_get_version(int which, unsigned int version[3]) ++{ ++ unsigned int *vers = mock_ptr_type(unsigned int *); ++ ++ condlog(4, "%s: %d", __func__, which); ++ memcpy(version, vers, 3 * sizeof(unsigned int)); ++ return 0; ++} ++ + struct udev_list_entry + *__wrap_udev_device_get_properties_list_entry(struct udev_device *ud) + { +@@ -339,6 +348,8 @@ struct multipath *__mock_multipath(struct vectors *vecs, struct path *pp) + struct multipath *mp; + struct config *conf; + struct mocked_path mop; ++ /* pretend new dm, use minio_rq, */ ++ static const unsigned int fake_dm_tgt_version[3] = { 1, 1, 1 }; + + mocked_path_from_path(&mop, pp); + /* pathinfo() call in adopt_paths */ +@@ -351,7 +362,9 @@ struct multipath *__mock_multipath(struct vectors *vecs, struct path *pp) + conf = get_multipath_config(); + select_pgpolicy(conf, mp); + select_no_path_retry(conf, mp); ++ will_return(__wrap_libmp_get_version, fake_dm_tgt_version); + select_retain_hwhandler(conf, mp); ++ will_return(__wrap_libmp_get_version, fake_dm_tgt_version); + select_minio(conf, mp); + put_multipath_config(conf); + +-- +2.17.2 + diff --git a/0024-libmultipath-protect-racy-libdevmapper-calls-with-a-.patch b/0024-libmultipath-protect-racy-libdevmapper-calls-with-a-.patch new file mode 100644 index 0000000..026dd7c --- /dev/null +++ b/0024-libmultipath-protect-racy-libdevmapper-calls-with-a-.patch @@ -0,0 +1,437 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 23:38:48 +0200 +Subject: [PATCH] libmultipath: protect racy libdevmapper calls with a mutex + +dm_udev_wait() and dm_task_run() may access global / static state +in libdevmapper. They need to be protected by a lock in in our +multithreaded library. + +The modified call sequence requires fixing the dmevents test: +devmapper.c must be added to dmevents-test_OBJDEPS to catch calls +to dm_task_run(). Also, the call to dmevent_poll_supported() in +setup() will cause init_versions() to be called, which requires +bypassing the wrappers in the test setup phase. + +Cc: lixiaokeng@huawei.com + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/devmapper.c | 73 +++++++++++++++++++------------ + libmultipath/devmapper.h | 2 + + libmultipath/libmultipath.version | 6 +++ + libmultipath/util.c | 5 +++ + libmultipath/util.h | 1 + + multipathd/dmevents.c | 2 +- + multipathd/waiter.c | 2 +- + tests/Makefile | 1 + + tests/dmevents.c | 12 +++++ + 9 files changed, 75 insertions(+), 29 deletions(-) + +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 3e36129b..4eb6f539 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -42,6 +42,7 @@ static unsigned int dm_mpath_target_version[3] = { INVALID_VERSION, }; + + static pthread_once_t dm_initialized = PTHREAD_ONCE_INIT; + static pthread_once_t versions_initialized = PTHREAD_ONCE_INIT; ++static pthread_mutex_t libmp_dm_lock = PTHREAD_MUTEX_INITIALIZER; + + static int dm_conf_verbosity; + +@@ -59,16 +60,34 @@ static inline int dm_task_set_cookie(struct dm_task *dmt, uint32_t *c, int a) + return 1; + } + +-void dm_udev_wait(unsigned int c) ++static void libmp_udev_wait(unsigned int c) + { + } + +-void dm_udev_set_sync_support(int c) ++static void dm_udev_set_sync_support(int c) + { + } +- ++#else ++static void libmp_udev_wait(unsigned int c) ++{ ++ pthread_mutex_lock(&libmp_dm_lock); ++ pthread_cleanup_push(cleanup_mutex, &libmp_dm_lock); ++ dm_udev_wait(c); ++ pthread_cleanup_pop(1); ++} + #endif + ++int libmp_dm_task_run(struct dm_task *dmt) ++{ ++ int r; ++ ++ pthread_mutex_lock(&libmp_dm_lock); ++ pthread_cleanup_push(cleanup_mutex, &libmp_dm_lock); ++ r = dm_task_run(dmt); ++ pthread_cleanup_pop(1); ++ return r; ++} ++ + __attribute__((format(printf, 4, 5))) static void + dm_write_log (int level, const char *file, int line, const char *f, ...) + { +@@ -198,7 +217,7 @@ static int dm_tgt_version (unsigned int *version, char *str) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(2, DM_DEVICE_LIST_VERSIONS, dmt); + condlog(0, "Can not communicate with kernel DM"); + goto out; +@@ -382,12 +401,12 @@ dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t + DM_UDEV_DISABLE_LIBRARY_FALLBACK | udev_flags)) + goto out; + +- r = dm_task_run (dmt); ++ r = libmp_dm_task_run (dmt); + if (!r) + dm_log_error(2, task, dmt); + + if (udev_wait_flag) +- dm_udev_wait(cookie); ++ libmp_udev_wait(cookie); + out: + dm_task_destroy (dmt); + return r; +@@ -474,12 +493,12 @@ dm_addmap (int task, const char *target, struct multipath *mpp, + !dm_task_set_cookie(dmt, &cookie, udev_flags)) + goto freeout; + +- r = dm_task_run (dmt); ++ r = libmp_dm_task_run (dmt); + if (!r) + dm_log_error(2, task, dmt); + + if (task == DM_DEVICE_CREATE) +- dm_udev_wait(cookie); ++ libmp_udev_wait(cookie); + freeout: + if (prefixed_uuid) + FREE(prefixed_uuid); +@@ -589,7 +608,7 @@ do_get_info(const char *name, struct dm_info *info) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_INFO, dmt); + goto out; + } +@@ -630,7 +649,7 @@ int dm_get_map(const char *name, unsigned long long *size, char *outparams) + dm_task_no_open_count(dmt); + + errno = 0; +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_TABLE, dmt); + if (dm_task_get_errno(dmt) == ENXIO) + r = DMP_NOT_FOUND; +@@ -672,7 +691,7 @@ dm_get_prefixed_uuid(const char *name, char *uuid, int uuid_len) + if (!dm_task_set_name (dmt, name)) + goto uuidout; + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_INFO, dmt); + goto uuidout; + } +@@ -743,7 +762,7 @@ int dm_get_status(const char *name, char *outstatus) + dm_task_no_open_count(dmt); + + errno = 0; +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_STATUS, dmt); + if (dm_task_get_errno(dmt) == ENXIO) + r = DMP_NOT_FOUND; +@@ -796,7 +815,7 @@ int dm_type(const char *name, char *type) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_TABLE, dmt); + goto out; + } +@@ -840,7 +859,7 @@ int dm_is_mpath(const char *name) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_TABLE, dmt); + goto out_task; + } +@@ -904,7 +923,7 @@ dm_map_present_by_uuid(const char *uuid) + if (!dm_task_set_uuid(dmt, prefixed_uuid)) + goto out_task; + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_INFO, dmt); + goto out_task; + } +@@ -950,7 +969,7 @@ dm_get_opencount (const char * mapname) + if (!dm_task_set_name(dmt, mapname)) + goto out; + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_INFO, dmt); + goto out; + } +@@ -1110,7 +1129,7 @@ int dm_flush_maps (int need_suspend, int retries) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run (dmt)) { ++ if (!libmp_dm_task_run (dmt)) { + dm_log_error(3, DM_DEVICE_LIST, dmt); + goto out; + } +@@ -1156,7 +1175,7 @@ dm_message(const char * mapname, char * message) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(2, DM_DEVICE_TARGET_MSG, dmt); + goto out; + } +@@ -1276,7 +1295,7 @@ dm_get_maps (vector mp) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_LIST, dmt); + goto out; + } +@@ -1361,7 +1380,7 @@ dm_mapname(int major, int minor) + * daemon uev_trigger -> uev_add_map + */ + while (--loop) { +- r = dm_task_run(dmt); ++ r = libmp_dm_task_run(dmt); + + if (r) + break; +@@ -1406,7 +1425,7 @@ do_foreach_partmaps (const char * mapname, + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_LIST, dmt); + goto out; + } +@@ -1641,11 +1660,11 @@ dm_rename (const char * old, char * new, char *delim, int skip_kpartx) + + if (!dm_task_set_cookie(dmt, &cookie, udev_flags)) + goto out; +- r = dm_task_run(dmt); ++ r = libmp_dm_task_run(dmt); + if (!r) + dm_log_error(2, DM_DEVICE_RENAME, dmt); + +- dm_udev_wait(cookie); ++ libmp_udev_wait(cookie); + + out: + dm_task_destroy(dmt); +@@ -1687,7 +1706,7 @@ int dm_reassign_table(const char *name, char *old, char *new) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_TABLE, dmt); + goto out; + } +@@ -1720,7 +1739,7 @@ int dm_reassign_table(const char *name, char *old, char *new) + if (modified) { + dm_task_no_open_count(reload_dmt); + +- if (!dm_task_run(reload_dmt)) { ++ if (!libmp_dm_task_run(reload_dmt)) { + dm_log_error(3, DM_DEVICE_RELOAD, reload_dmt); + condlog(3, "%s: failed to reassign targets", name); + goto out_reload; +@@ -1767,7 +1786,7 @@ int dm_reassign(const char *mapname) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_DEPS, dmt); + goto out; + } +@@ -1835,7 +1854,7 @@ int dm_setgeometry(struct multipath *mpp) + goto out; + } + +- r = dm_task_run(dmt); ++ r = libmp_dm_task_run(dmt); + if (!r) + dm_log_error(3, DM_DEVICE_SET_GEOMETRY, dmt); + out: +diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h +index a0bcd137..fa6b3c53 100644 +--- a/libmultipath/devmapper.h ++++ b/libmultipath/devmapper.h +@@ -93,6 +93,8 @@ enum { + MULTIPATH_VERSION + }; + int libmp_get_version(int which, unsigned int version[3]); ++struct dm_task; ++int libmp_dm_task_run(struct dm_task *dmt); + + #define dm_log_error(lvl, cmd, dmt) \ + condlog(lvl, "%s: libdm task=%d error: %s", __func__, \ +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index ab5bb0ad..97acdbb2 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -245,3 +245,9 @@ global: + local: + *; + }; ++ ++LIBMULTIPATH_2.1.0 { ++global: ++ libmp_dm_task_run; ++ cleanup_mutex; ++} LIBMULTIPATH_2.0.0; +diff --git a/libmultipath/util.c b/libmultipath/util.c +index 1f977792..0e37f3ff 100644 +--- a/libmultipath/util.c ++++ b/libmultipath/util.c +@@ -424,6 +424,11 @@ void cleanup_free_ptr(void *arg) + free(*p); + } + ++void cleanup_mutex(void *arg) ++{ ++ pthread_mutex_unlock(arg); ++} ++ + struct bitfield *alloc_bitfield(unsigned int maxbit) + { + unsigned int n; +diff --git a/libmultipath/util.h b/libmultipath/util.h +index ac19473e..e9b48f9f 100644 +--- a/libmultipath/util.h ++++ b/libmultipath/util.h +@@ -49,6 +49,7 @@ int should_exit(void); + + void close_fd(void *arg); + void cleanup_free_ptr(void *arg); ++void cleanup_mutex(void *arg); + + struct scandir_result { + struct dirent **di; +diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c +index fc97c8a2..b561cbfd 100644 +--- a/multipathd/dmevents.c ++++ b/multipathd/dmevents.c +@@ -156,7 +156,7 @@ static int dm_get_events(void) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_LIST, dmt); + goto fail; + } +diff --git a/multipathd/waiter.c b/multipathd/waiter.c +index 3bc69807..bbe6c2a1 100644 +--- a/multipathd/waiter.c ++++ b/multipathd/waiter.c +@@ -118,7 +118,7 @@ static int waiteventloop (struct event_thread *waiter) + pthread_sigmask(SIG_UNBLOCK, &set, &oldset); + + pthread_testcancel(); +- r = dm_task_run(waiter->dmt); ++ r = libmp_dm_task_run(waiter->dmt); + if (!r) + dm_log_error(2, DM_DEVICE_WAITEVENT, waiter->dmt); + pthread_testcancel(); +diff --git a/tests/Makefile b/tests/Makefile +index 78777bec..908407ea 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -40,6 +40,7 @@ endif + # linker input file). + # XYZ-test_LIBDEPS: Additional libs to link for this test + ++dmevents-test_OBJDEPS = ../libmultipath/devmapper.o + dmevents-test_LIBDEPS = -lpthread -ldevmapper -lurcu + hwtable-test_TESTDEPS := test-lib.o + hwtable-test_OBJDEPS := ../libmultipath/discovery.o ../libmultipath/blacklist.o \ +diff --git a/tests/dmevents.c b/tests/dmevents.c +index bee117ac..b7c5122b 100644 +--- a/tests/dmevents.c ++++ b/tests/dmevents.c +@@ -179,6 +179,8 @@ struct dm_names *build_dm_names(void) + return names; + } + ++static bool setup_done; ++ + static int setup(void **state) + { + if (dmevent_poll_supported()) { +@@ -186,6 +188,7 @@ static int setup(void **state) + *state = &data; + } else + *state = NULL; ++ setup_done = true; + return 0; + } + +@@ -262,14 +265,20 @@ struct dm_task *__wrap_libmp_dm_task_create(int task) + return mock_type(struct dm_task *); + } + ++int __real_dm_task_no_open_count(struct dm_task *dmt); + int __wrap_dm_task_no_open_count(struct dm_task *dmt) + { ++ if (!setup_done) ++ return __real_dm_task_no_open_count(dmt); + assert_ptr_equal((struct test_data *)dmt, &data); + return mock_type(int); + } + ++int __real_dm_task_run(struct dm_task *dmt); + int __wrap_dm_task_run(struct dm_task *dmt) + { ++ if (!setup_done) ++ return __real_dm_task_run(dmt); + assert_ptr_equal((struct test_data *)dmt, &data); + return mock_type(int); + } +@@ -291,8 +300,11 @@ struct dm_names * __wrap_dm_task_get_names(struct dm_task *dmt) + return data.names; + } + ++void __real_dm_task_destroy(struct dm_task *dmt); + void __wrap_dm_task_destroy(struct dm_task *dmt) + { ++ if (!setup_done) ++ return __real_dm_task_destroy(dmt); + assert_ptr_equal((struct test_data *)dmt, &data); + + if (data.names) { +-- +2.17.2 + diff --git a/0025-libmultipath-constify-file-argument-in-config-parser.patch b/0025-libmultipath-constify-file-argument-in-config-parser.patch new file mode 100644 index 0000000..9470cf4 --- /dev/null +++ b/0025-libmultipath-constify-file-argument-in-config-parser.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 12:02:01 +0200 +Subject: [PATCH] libmultipath: constify file argument in config parser + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 3 +-- + libmultipath/config.h | 2 +- + libmultipath/parser.c | 9 +++++---- + libmultipath/parser.h | 2 +- + 4 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index df0f8f45..5c91a09d 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -719,8 +719,7 @@ static void set_max_checkint_from_watchdog(struct config *conf) + } + #endif + +-struct config * +-load_config (char * file) ++struct config *load_config(const char *file) + { + struct config *conf = alloc_config(); + +diff --git a/libmultipath/config.h b/libmultipath/config.h +index 7af19844..ace403b8 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -251,7 +251,7 @@ void free_mptable (vector mptable); + + int store_hwe (vector hwtable, struct hwentry *); + +-struct config *load_config (char * file); ++struct config *load_config (const char *file); + struct config * alloc_config (void); + void free_config (struct config * conf); + extern struct config *get_multipath_config(void); +diff --git a/libmultipath/parser.c b/libmultipath/parser.c +index ed6d5d6d..163ffbc9 100644 +--- a/libmultipath/parser.c ++++ b/libmultipath/parser.c +@@ -390,7 +390,7 @@ oom: + /* non-recursive configuration stream handler */ + static int kw_level = 0; + +-int warn_on_duplicates(vector uniques, char *str, char *file) ++int warn_on_duplicates(vector uniques, char *str, const char *file) + { + char *tmp; + int i; +@@ -434,7 +434,7 @@ is_sublevel_keyword(char *str) + } + + int +-validate_config_strvec(vector strvec, char *file) ++validate_config_strvec(vector strvec, const char *file) + { + char *str = NULL; + int i; +@@ -499,7 +499,8 @@ validate_config_strvec(vector strvec, char *file) + } + + static int +-process_stream(struct config *conf, FILE *stream, vector keywords, char *file) ++process_stream(struct config *conf, FILE *stream, vector keywords, ++ const char *file) + { + int i; + int r = 0, t; +@@ -584,7 +585,7 @@ out: + + /* Data initialization */ + int +-process_file(struct config *conf, char *file) ++process_file(struct config *conf, const char *file) + { + int r; + FILE *stream; +diff --git a/libmultipath/parser.h b/libmultipath/parser.h +index 62906e98..06666ccf 100644 +--- a/libmultipath/parser.h ++++ b/libmultipath/parser.h +@@ -77,7 +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 int process_file(struct config *conf, char *conf_file); ++extern int process_file(struct config *conf, const 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, + const void *data); +-- +2.17.2 + diff --git a/0026-libmultipath-provide-defaults-for-get-put-_multipath.patch b/0026-libmultipath-provide-defaults-for-get-put-_multipath.patch new file mode 100644 index 0000000..e3375f0 --- /dev/null +++ b/0026-libmultipath-provide-defaults-for-get-put-_multipath.patch @@ -0,0 +1,204 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 12:06:56 +0200 +Subject: [PATCH] libmultipath: provide defaults for {get,put}_multipath_config + +Add an implementation of get_multipath_config() and put_multipath_config() +to libmultipath. The linker's symbol lookup rules will make sure that +applications can override these functions if they need to. Defining +these functions in libmultipath avoids the need to provide stubs +for these functions in every appliation linking to libmultipath. + +libmultipath's internal functions simply refer to a static "struct config". +It must be initialized with init_config() rather than load_config(), +which always allocates a new struct for backward compatibility, and must +be teared down using uninit_config(). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 75 ++++++++++++++++++++++++++----- + libmultipath/config.h | 21 +++++++-- + libmultipath/libmultipath.version | 10 +++++ + 3 files changed, 93 insertions(+), 13 deletions(-) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index 5c91a09d..01b77dfe 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -27,6 +27,26 @@ + #include "mpath_cmd.h" + #include "propsel.h" + ++static struct config __internal_config; ++struct config *libmp_get_multipath_config(void) ++{ ++ if (!__internal_config.hwtable) ++ /* not initialized */ ++ return NULL; ++ return &__internal_config; ++} ++ ++struct config *get_multipath_config(void) ++ __attribute__((weak, alias("libmp_get_multipath_config"))); ++ ++void libmp_put_multipath_config(void *conf __attribute__((unused))) ++{ ++ /* empty */ ++} ++ ++void put_multipath_config(void *conf) ++ __attribute__((weak, alias("libmp_put_multipath_config"))); ++ + static int + hwe_strmatch (const struct hwentry *hwe1, const struct hwentry *hwe2) + { +@@ -574,17 +594,15 @@ restart: + return; + } + +-struct config * +-alloc_config (void) ++static struct config *alloc_config (void) + { + return (struct config *)MALLOC(sizeof(struct config)); + } + +-void +-free_config (struct config * conf) ++static void _uninit_config(struct config *conf) + { + if (!conf) +- return; ++ conf = &__internal_config; + + if (conf->multipath_dir) + FREE(conf->multipath_dir); +@@ -650,7 +668,27 @@ free_config (struct config * conf) + free_hwtable(conf->hwtable); + free_hwe(conf->overrides); + free_keywords(conf->keywords); +- FREE(conf); ++ ++ memset(conf, 0, sizeof(*conf)); ++} ++ ++void uninit_config(void) ++{ ++ _uninit_config(&__internal_config); ++} ++ ++void free_config(struct config *conf) ++{ ++ if (!conf) ++ return; ++ else if (conf == &__internal_config) { ++ condlog(0, "ERROR: %s called for internal config. Use uninit_config() instead", ++ __func__); ++ return; ++ } ++ ++ _uninit_config(conf); ++ free(conf); + } + + /* if multipath fails to process the config directory, it should continue, +@@ -719,12 +757,29 @@ static void set_max_checkint_from_watchdog(struct config *conf) + } + #endif + ++static int _init_config (const char *file, struct config *conf); ++ ++int init_config(const char *file) ++{ ++ return _init_config(file, &__internal_config); ++} ++ + struct config *load_config(const char *file) + { + struct config *conf = alloc_config(); + ++ if (conf && !_init_config(file, conf)) ++ return conf; ++ ++ free(conf); ++ return NULL; ++} ++ ++int _init_config (const char *file, struct config *conf) ++{ ++ + if (!conf) +- return NULL; ++ conf = &__internal_config; + + /* + * internal defaults +@@ -896,10 +951,10 @@ struct config *load_config(const char *file) + !conf->wwids_file || !conf->prkeys_file) + goto out; + +- return conf; ++ return 0; + out: +- free_config(conf); +- return NULL; ++ _uninit_config(conf); ++ return 1; + } + + char *get_uid_attribute_by_attrs(struct config *conf, +diff --git a/libmultipath/config.h b/libmultipath/config.h +index ace403b8..0329de29 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -252,10 +252,25 @@ void free_mptable (vector mptable); + int store_hwe (vector hwtable, struct hwentry *); + + struct config *load_config (const char *file); +-struct config * alloc_config (void); + void free_config (struct config * conf); +-extern struct config *get_multipath_config(void); +-extern void put_multipath_config(void *); ++int init_config(const char *file); ++void uninit_config(void); ++ ++/* ++ * libmultipath provides default implementations of ++ * get_multipath_config() and put_multipath_config(). ++ * Applications using these should use init_config(file, NULL) ++ * to load the configuration, rather than load_config(file). ++ * Likewise, uninit_config() should be used for teardown, but ++ * using free_config() for that is supported, too. ++ * Applications can define their own {get,put}_multipath_config() ++ * functions, which override the library-internal ones, but ++ * could still call libmp_{get,put}_multipath_config(). ++ */ ++struct config *libmp_get_multipath_config(void); ++struct config *get_multipath_config(void); ++void libmp_put_multipath_config(void *); ++void put_multipath_config(void *); + + int parse_uid_attrs(char *uid_attrs, struct config *conf); + char *get_uid_attribute_by_attrs(struct config *conf, +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 97acdbb2..3e780fce 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -251,3 +251,13 @@ global: + libmp_dm_task_run; + cleanup_mutex; + } LIBMULTIPATH_2.0.0; ++ ++LIBMULTIPATH_2.2.0 { ++global: ++ libmp_get_multipath_config; ++ get_multipath_config; ++ libmp_put_multipath_config; ++ put_multipath_config; ++ init_config; ++ uninit_config; ++} LIBMULTIPATH_2.1.0; +-- +2.17.2 + diff --git a/0027-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch b/0027-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch new file mode 100644 index 0000000..def8896 --- /dev/null +++ b/0027-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 12:11:46 +0200 +Subject: [PATCH] libmpathpersist: allow using libmultipath + {get,put}_multipath_config + +Provide an alternative init function libmpathpersist_init() which +avoids allocating a new struct config, simply using libmultipath's +internal implementation. This causes a minor version bump for +libmpathpersist. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathpersist/libmpathpersist.version | 6 ++++ + libmpathpersist/mpath_persist.c | 42 +++++++++++++++++++++---- + libmpathpersist/mpath_persist.h | 28 +++++++++++++++++ + 3 files changed, 70 insertions(+), 6 deletions(-) + +diff --git a/libmpathpersist/libmpathpersist.version b/libmpathpersist/libmpathpersist.version +index dc648ce6..e0748138 100644 +--- a/libmpathpersist/libmpathpersist.version ++++ b/libmpathpersist/libmpathpersist.version +@@ -30,3 +30,9 @@ global: + + local: *; + }; ++ ++LIBMPATHPERSIST_1.1.0 { ++global: ++ libmpathpersist_init; ++ libmpathpersist_exit; ++} LIBMPATHPERSIST_1.0.0; +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index cc4a088d..febf4758 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -37,6 +37,27 @@ + + extern struct udev *udev; + ++static void adapt_config(struct config *conf) ++{ ++ conf->force_sync = 1; ++ set_max_fds(conf->max_fds); ++} ++ ++int libmpathpersist_init(void) ++{ ++ struct config *conf; ++ int rc = 0; ++ ++ if (init_config(DEFAULT_CONFIGFILE)) { ++ condlog(0, "Failed to initialize multipath config."); ++ return 1; ++ } ++ conf = libmp_get_multipath_config(); ++ adapt_config(conf); ++ libmp_put_multipath_config(conf); ++ return rc; ++} ++ + struct config * + mpath_lib_init (void) + { +@@ -47,20 +68,29 @@ mpath_lib_init (void) + condlog(0, "Failed to initialize multipath config."); + return NULL; + } +- conf->force_sync = 1; +- set_max_fds(conf->max_fds); +- ++ adapt_config(conf); + return conf; + } + +-int +-mpath_lib_exit (struct config *conf) ++static void libmpathpersist_cleanup(void) + { + dm_lib_exit(); + cleanup_prio(); + cleanup_checkers(); ++} ++ ++int ++mpath_lib_exit (struct config *conf) ++{ ++ libmpathpersist_cleanup(); + free_config(conf); +- conf = NULL; ++ return 0; ++} ++ ++int libmpathpersist_exit(void) ++{ ++ libmpathpersist_cleanup(); ++ uninit_config(); + return 0; + } + +diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h +index 7cf4faf9..91606efc 100644 +--- a/libmpathpersist/mpath_persist.h ++++ b/libmpathpersist/mpath_persist.h +@@ -175,6 +175,22 @@ struct prout_param_descriptor { /* PROUT parameter descriptor */ + * DESCRIPTION : + * Initialize device mapper multipath configuration. This function must be invoked first + * before performing reservation management functions. ++ * Either this function or mpath_lib_init() may be used. ++ * Use this function to work with libmultipath's internal "struct config". ++ * Call libmpathpersist_exit() for cleanup. ++ * RESTRICTIONS: ++ * ++ * RETURNS: 0->Success, 1->Failed. ++ */ ++extern int libmpathpersist_init (void); ++ ++/* ++ * DESCRIPTION : ++ * Initialize device mapper multipath configuration. This function must be invoked first ++ * before performing reservation management functions. ++ * Either this function or libmpathpersist_init() may be used. ++ * Use this function to work with an application-specific "struct config". ++ * Call mpath_lib_exit() for cleanup. + * RESTRICTIONS: + * + * RETURNS: struct config ->Success, NULL->Failed. +@@ -186,12 +202,24 @@ extern struct config * mpath_lib_init (void); + * DESCRIPTION : + * Release device mapper multipath configuration. This function must be invoked after + * performing reservation management functions. ++ * Use this after initialization with mpath_lib_init(). + * RESTRICTIONS: + * + * RETURNS: 0->Success, 1->Failed. + */ + extern int mpath_lib_exit (struct config *conf); + ++/* ++ * DESCRIPTION : ++ * Release device mapper multipath configuration. This function must be invoked after ++ * performing reservation management functions. ++ * Use this after initialization with libmpathpersist_init(). ++ * RESTRICTIONS: ++ * ++ * RETURNS: 0->Success, 1->Failed. ++ */ ++extern int libmpathpersist_exit (void); ++ + + /* + * DESCRIPTION : +-- +2.17.2 + diff --git a/0028-multipath-use-get_put-_multipath_config-from-libmult.patch b/0028-multipath-use-get_put-_multipath_config-from-libmult.patch new file mode 100644 index 0000000..762daea --- /dev/null +++ b/0028-multipath-use-get_put-_multipath_config-from-libmult.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 12:27:09 +0200 +Subject: [PATCH] multipath: use {get_put}_multipath_config from libmultipath + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipath/main.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/multipath/main.c b/multipath/main.c +index dc4974b9..4bbfce9a 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -68,7 +68,6 @@ + + int logsink; + struct udev *udev; +-struct config *multipath_conf; + + /* + * Return values of configure(), check_path_valid(), and main(). +@@ -79,16 +78,6 @@ enum { + RTVL_RETRY, /* returned by configure(), not by main() */ + }; + +-struct config *get_multipath_config(void) +-{ +- return multipath_conf; +-} +- +-void put_multipath_config(__attribute__((unused)) void *arg) +-{ +- /* Noop for now */ +-} +- + static int + dump_config (struct config *conf, vector hwes, vector mpvec) + { +@@ -823,10 +812,9 @@ main (int argc, char *argv[]) + + udev = udev_new(); + logsink = 0; +- conf = load_config(DEFAULT_CONFIGFILE); +- if (!conf) ++ if (init_config(DEFAULT_CONFIGFILE)) + exit(RTVL_FAIL); +- multipath_conf = conf; ++ conf = get_multipath_config(); + conf->retrigger_tries = 0; + conf->force_sync = 1; + while ((arg = getopt(argc, argv, ":adDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) { +@@ -1078,8 +1066,8 @@ out_free_config: + * the logging function (dm_write_log()), which is called there, + * references the config. + */ +- free_config(conf); +- conf = NULL; ++ put_multipath_config(conf); ++ uninit_config(); + udev_unref(udev); + if (dev) + FREE(dev); +-- +2.17.2 + diff --git a/0029-mpathpersist-use-get-put-_multipath_config-from-libm.patch b/0029-mpathpersist-use-get-put-_multipath_config-from-libm.patch new file mode 100644 index 0000000..6ab3c10 --- /dev/null +++ b/0029-mpathpersist-use-get-put-_multipath_config-from-libm.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 12:39:01 +0200 +Subject: [PATCH] mpathpersist: use {get,put}_multipath_config() from + libmultipath + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + mpathpersist/main.c | 16 ++-------------- + 1 file changed, 2 insertions(+), 14 deletions(-) + +diff --git a/mpathpersist/main.c b/mpathpersist/main.c +index a6a3bcf6..278e48f7 100644 +--- a/mpathpersist/main.c ++++ b/mpathpersist/main.c +@@ -43,17 +43,6 @@ void mpath_print_transport_id(struct prin_fulldescr *fdesc); + int construct_transportid(const char * inp, struct transportid transid[], int num_transportids); + + int logsink; +-struct config *multipath_conf; +- +-struct config *get_multipath_config(void) +-{ +- return multipath_conf; +-} +- +-void put_multipath_config(__attribute__((unused)) void * arg) +-{ +- /* Noop for now */ +-} + + void rcu_register_thread_memb(void) {} + +@@ -653,15 +642,14 @@ int main(int argc, char *argv[]) + } + + udev = udev_new(); +- multipath_conf = mpath_lib_init(); +- if(!multipath_conf) { ++ if (libmpathpersist_init()) { + udev_unref(udev); + exit(1); + } + + ret = handle_args(argc, argv, 0); + +- mpath_lib_exit(multipath_conf); ++ libmpathpersist_exit(); + udev_unref(udev); + + return (ret >= 0) ? ret : MPATH_PR_OTHER; +-- +2.17.2 + diff --git a/0030-libmultipath-add-udev-and-logsink-symbols.patch b/0030-libmultipath-add-udev-and-logsink-symbols.patch new file mode 100644 index 0000000..3bd9de0 --- /dev/null +++ b/0030-libmultipath-add-udev-and-logsink-symbols.patch @@ -0,0 +1,168 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 15:06:12 +0200 +Subject: [PATCH] libmultipath: add udev and logsink symbols + +With these symbols added, applications using libmultipath don't +need to define global variables "udev" and "logsink" any more. +This comes at the cost of having to call an init function. +Currently, libmultipath_init() does nothing but initialize +"udev". + +The linker's symbol lookup order still allows applications to use +their own "logsink" and "udev" variables, which will take precendence +over libmultipath's internal ones. In this case, calling +libmultipath_init() can be skipped, but like before, +udev should be initialized (using udev_new()) before making any +libmultipath calls. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 41 +++++++++++++++++++++++++++ + libmultipath/config.h | 46 ++++++++++++++++++++++++++++++- + libmultipath/debug.c | 2 ++ + libmultipath/libmultipath.version | 8 ++++++ + 4 files changed, 96 insertions(+), 1 deletion(-) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index 01b77dfe..f74417c6 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -27,6 +27,47 @@ + #include "mpath_cmd.h" + #include "propsel.h" + ++/* ++ * We don't support re-initialization after ++ * libmultipath_exit(). ++ */ ++static bool libmultipath_exit_called; ++static pthread_once_t _init_once = PTHREAD_ONCE_INIT; ++static pthread_once_t _exit_once = PTHREAD_ONCE_INIT; ++struct udev *udev; ++ ++static void _udev_init(void) ++{ ++ if (udev) ++ udev_ref(udev); ++ else ++ udev = udev_new(); ++ if (!udev) ++ condlog(0, "%s: failed to initialize udev", __func__); ++} ++ ++static bool _is_libmultipath_initialized(void) ++{ ++ return !libmultipath_exit_called && !!udev; ++} ++ ++int libmultipath_init(void) ++{ ++ pthread_once(&_init_once, _udev_init); ++ return !_is_libmultipath_initialized(); ++} ++ ++static void _libmultipath_exit(void) ++{ ++ libmultipath_exit_called = true; ++ udev_unref(udev); ++} ++ ++void libmultipath_exit(void) ++{ ++ pthread_once(&_exit_once, _libmultipath_exit); ++} ++ + static struct config __internal_config; + struct config *libmp_get_multipath_config(void) + { +diff --git a/libmultipath/config.h b/libmultipath/config.h +index 0329de29..f478df71 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -233,7 +233,51 @@ struct config { + char *enable_foreign; + }; + +-extern struct udev * udev; ++/** ++ * extern variable: udev ++ * ++ * A &struct udev instance used by libmultipath. libmultipath expects ++ * a valid, initialized &struct udev in this variable. ++ * An application can define this variable itself, in which case ++ * the applications's instance will take precedence. ++ * The application can initialize and destroy this variable by ++ * calling libmultipath_init() and libmultipath_exit(), respectively, ++ * whether or not it defines the variable itself. ++ * An application can initialize udev with udev_new() before calling ++ * libmultipath_init(), e.g. if it has to make libudev calls before ++ * libmultipath calls. If an application wants to keep using the ++ * udev variable after calling libmultipath_exit(), it should have taken ++ * an additional reference on it beforehand. This is the case e.g. ++ * after initiazing udev with udev_new(). ++ */ ++extern struct udev *udev; ++ ++/** ++ * libmultipath_init() - library initialization ++ * ++ * This function initializes libmultipath data structures. ++ * It is light-weight; some other initializations, like device-mapper ++ * initialization, are done lazily when the respective functionality ++ * is required. ++ * ++ * Clean up by libmultipath_exit() when the program terminates. ++ * It is an error to call libmultipath_init() after libmultipath_exit(). ++ * Return: 0 on success, 1 on failure. ++ */ ++int libmultipath_init(void); ++ ++/** ++ * libmultipath_exit() - library un-initialization ++ * ++ * This function un-initializes libmultipath data structures. ++ * It is recommended to call this function at program exit. ++ * ++ * Calls to libmultipath_init() after libmultipath_exit() will fail ++ * (in other words, libmultipath can't be re-initialized). ++ * Any other libmultipath calls after libmultipath_exit() may cause ++ * undefined behavior. ++ */ ++void libmultipath_exit(void); + + int find_hwe (const struct _vector *hwtable, + const char * vendor, const char * product, const char *revision, +diff --git a/libmultipath/debug.c b/libmultipath/debug.c +index 4128cb90..b3a1de9e 100644 +--- a/libmultipath/debug.c ++++ b/libmultipath/debug.c +@@ -15,6 +15,8 @@ + #include "defaults.h" + #include "debug.h" + ++int logsink; ++ + void dlog (int sink, int prio, const char * fmt, ...) + { + va_list ap; +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 3e780fce..0c300c81 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -261,3 +261,11 @@ global: + init_config; + uninit_config; + } LIBMULTIPATH_2.1.0; ++ ++LIBMULTIPATH_2.3.0 { ++global: ++ udev; ++ logsink; ++ libmultipath_init; ++ libmultipath_exit; ++} LIBMULTIPATH_2.2.0; +-- +2.17.2 + diff --git a/0031-multipath-remove-logsink-and-udev.patch b/0031-multipath-remove-logsink-and-udev.patch new file mode 100644 index 0000000..7ba8272 --- /dev/null +++ b/0031-multipath-remove-logsink-and-udev.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 16:06:17 +0200 +Subject: [PATCH] multipath: remove logsink and udev + +We can use libmultipath's symbols now. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipath/main.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/multipath/main.c b/multipath/main.c +index 4bbfce9a..9ae46ed5 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -66,9 +66,6 @@ + #include "valid.h" + #include "alias.h" + +-int logsink; +-struct udev *udev; +- + /* + * Return values of configure(), check_path_valid(), and main(). + */ +@@ -810,7 +807,7 @@ main (int argc, char *argv[]) + int retries = -1; + bool enable_foreign = false; + +- udev = udev_new(); ++ libmultipath_init(); + logsink = 0; + if (init_config(DEFAULT_CONFIGFILE)) + exit(RTVL_FAIL); +@@ -1068,7 +1065,7 @@ out_free_config: + */ + put_multipath_config(conf); + uninit_config(); +- udev_unref(udev); ++ libmultipath_exit(); + if (dev) + FREE(dev); + #ifdef _DEBUG_ +-- +2.17.2 + diff --git a/0032-libmpathpersist-call-libmultipath_-init-exit.patch b/0032-libmpathpersist-call-libmultipath_-init-exit.patch new file mode 100644 index 0000000..9c52f9f --- /dev/null +++ b/0032-libmpathpersist-call-libmultipath_-init-exit.patch @@ -0,0 +1,96 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Sep 2020 14:23:14 +0200 +Subject: [PATCH] libmpathpersist: call libmultipath_{init,exit}() + +Have libmpathpersist_{init,exit} do the udev initialization, too. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathpersist/mpath_persist.c | 11 ++++++++--- + libmpathpersist/mpath_persist.h | 9 ++++++--- + 2 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index febf4758..e1d1cb76 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -48,6 +48,10 @@ int libmpathpersist_init(void) + struct config *conf; + int rc = 0; + ++ if (libmultipath_init()) { ++ condlog(0, "Failed to initialize libmultipath."); ++ return 1; ++ } + if (init_config(DEFAULT_CONFIGFILE)) { + condlog(0, "Failed to initialize multipath config."); + return 1; +@@ -74,23 +78,24 @@ mpath_lib_init (void) + + static void libmpathpersist_cleanup(void) + { +- dm_lib_exit(); + cleanup_prio(); + cleanup_checkers(); ++ libmultipath_exit(); ++ dm_lib_exit(); + } + + int + mpath_lib_exit (struct config *conf) + { +- libmpathpersist_cleanup(); + free_config(conf); ++ libmpathpersist_cleanup(); + return 0; + } + + int libmpathpersist_exit(void) + { +- libmpathpersist_cleanup(); + uninit_config(); ++ libmpathpersist_cleanup(); + return 0; + } + +diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h +index 91606efc..5435eae4 100644 +--- a/libmpathpersist/mpath_persist.h ++++ b/libmpathpersist/mpath_persist.h +@@ -176,7 +176,8 @@ struct prout_param_descriptor { /* PROUT parameter descriptor */ + * Initialize device mapper multipath configuration. This function must be invoked first + * before performing reservation management functions. + * Either this function or mpath_lib_init() may be used. +- * Use this function to work with libmultipath's internal "struct config". ++ * Use this function to work with libmultipath's internal "struct config" ++ * and "struct udev". The latter will be initialized automatically. + * Call libmpathpersist_exit() for cleanup. + * RESTRICTIONS: + * +@@ -189,7 +190,8 @@ extern int libmpathpersist_init (void); + * Initialize device mapper multipath configuration. This function must be invoked first + * before performing reservation management functions. + * Either this function or libmpathpersist_init() may be used. +- * Use this function to work with an application-specific "struct config". ++ * Use this function to work with an application-specific "struct config" ++ * and "struct udev". The latter must be initialized by the application. + * Call mpath_lib_exit() for cleanup. + * RESTRICTIONS: + * +@@ -211,9 +213,10 @@ extern int mpath_lib_exit (struct config *conf); + + /* + * DESCRIPTION : +- * Release device mapper multipath configuration. This function must be invoked after ++ * Release device mapper multipath configuration a. This function must be invoked after + * performing reservation management functions. + * Use this after initialization with libmpathpersist_init(). ++ * Calling libmpathpersist_init() after libmpathpersist_exit() will fail. + * RESTRICTIONS: + * + * RETURNS: 0->Success, 1->Failed. +-- +2.17.2 + diff --git a/0033-mpathpersist-remove-logsink-and-udev.patch b/0033-mpathpersist-remove-logsink-and-udev.patch new file mode 100644 index 0000000..501f32f --- /dev/null +++ b/0033-mpathpersist-remove-logsink-and-udev.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 16:08:43 +0200 +Subject: [PATCH] mpathpersist: remove logsink and udev + +We can use libmultipath's internal symbols now. The libmultipath +initialization is taken care of by libmpathpersist_init(). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + mpathpersist/main.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/mpathpersist/main.c b/mpathpersist/main.c +index 278e48f7..3c2e6576 100644 +--- a/mpathpersist/main.c ++++ b/mpathpersist/main.c +@@ -42,13 +42,10 @@ 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); + +-int logsink; +- + void rcu_register_thread_memb(void) {} + + void rcu_unregister_thread_memb(void) {} + +-struct udev *udev; + + static int verbose, loglevel, noisy; + +@@ -641,16 +638,13 @@ int main(int argc, char *argv[]) + exit (1); + } + +- udev = udev_new(); + if (libmpathpersist_init()) { +- udev_unref(udev); + exit(1); + } + + ret = handle_args(argc, argv, 0); + + libmpathpersist_exit(); +- udev_unref(udev); + + return (ret >= 0) ? ret : MPATH_PR_OTHER; + } +-- +2.17.2 + diff --git a/0034-multipathd-remove-logsink-and-udev.patch b/0034-multipathd-remove-logsink-and-udev.patch new file mode 100644 index 0000000..25e929a --- /dev/null +++ b/0034-multipathd-remove-logsink-and-udev.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 11:28:22 +0200 +Subject: [PATCH] multipathd: remove logsink and udev + +We can use the symbols from libmultipath now. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 00b66ba4..c5c374b7 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -115,7 +115,6 @@ struct mpath_event_param + struct multipath *mpp; + }; + +-int logsink; + int uxsock_timeout; + int verbosity; + int bindings_read_only; +@@ -151,8 +150,6 @@ int should_exit(void) + */ + struct vectors * gvecs; + +-struct udev * udev; +- + struct config *multipath_conf; + + /* Local variables */ +@@ -3123,8 +3120,6 @@ child (__attribute__((unused)) void *param) + conf = rcu_dereference(multipath_conf); + rcu_assign_pointer(multipath_conf, NULL); + call_rcu(&conf->rcu, rcu_free_config); +- udev_unref(udev); +- udev = NULL; + pthread_attr_destroy(&waiter_attr); + pthread_attr_destroy(&io_err_stat_attr); + #ifdef _DEBUG_ +@@ -3228,7 +3223,9 @@ main (int argc, char *argv[]) + + pthread_cond_init_mono(&config_cond); + +- udev = udev_new(); ++ libmultipath_init(); ++ if (atexit(libmultipath_exit)) ++ condlog(3, "failed to register exit handler for libmultipath"); + libmp_udev_set_sync_support(0); + + while ((arg = getopt(argc, argv, ":dsv:k::Bniw")) != EOF ) { +-- +2.17.2 + diff --git a/0035-multipath-tools-add-Vexata-by-StorCentric-VX-arrays.patch b/0035-multipath-tools-add-Vexata-by-StorCentric-VX-arrays.patch new file mode 100644 index 0000000..c8fa5bb --- /dev/null +++ b/0035-multipath-tools-add-Vexata-by-StorCentric-VX-arrays.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Xose Vazquez Perez +Date: Wed, 16 Dec 2020 23:17:39 +0100 +Subject: [PATCH] multipath-tools: add Vexata(by StorCentric) VX arrays + +https://support.sas.com/resources/papers/performance-tuning-sas-vexata-systems.pdf + +Reviewed-by: Martin Wilck +Cc: Martin Wilck +Cc: Benjamin Marzinski +Cc: Christophe Varoqui +Cc: DM-DEVEL ML +Signed-off-by: Xose Vazquez Perez +Signed-off-by: Benjamin Marzinski +--- + libmultipath/hwtable.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c +index cd65afcc..c1d6f7ae 100644 +--- a/libmultipath/hwtable.c ++++ b/libmultipath/hwtable.c +@@ -1191,6 +1191,14 @@ static struct hwentry default_hw[] = { + .product = "Magnitude", + .pgpolicy = MULTIBUS, + .no_path_retry = 30, ++ }, ++ /* Vexata */ ++ { ++ /* VX */ ++ .vendor = "Vexata", ++ .product = "VX", ++ .pgpolicy = MULTIBUS, ++ .no_path_retry = 30, + }, + /* + * Promise Technology +-- +2.17.2 + diff --git a/0036-multipath-tools-Violin-and-Nexsan-were-bought-by-Sto.patch b/0036-multipath-tools-Violin-and-Nexsan-were-bought-by-Sto.patch new file mode 100644 index 0000000..006d74e --- /dev/null +++ b/0036-multipath-tools-Violin-and-Nexsan-were-bought-by-Sto.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Xose Vazquez Perez +Date: Wed, 16 Dec 2020 23:17:40 +0100 +Subject: [PATCH] multipath-tools: Violin and Nexsan were bought by StorCentric + +Reviewed-by: Martin Wilck +Cc: Martin Wilck +Cc: Benjamin Marzinski +Cc: Christophe Varoqui +Cc: DM-DEVEL ML +Signed-off-by: Xose Vazquez Perez +Signed-off-by: Benjamin Marzinski +--- + libmultipath/hwtable.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c +index c1d6f7ae..a54cc0a3 100644 +--- a/libmultipath/hwtable.c ++++ b/libmultipath/hwtable.c +@@ -1113,8 +1113,9 @@ static struct hwentry default_hw[] = { + .pgpolicy = MULTIBUS, + }, + /* +- * Imation/Nexsan ++ * StorCentric + */ ++ /* Nexsan */ + { + /* E-Series */ + .vendor = "NEXSAN", +@@ -1143,9 +1144,7 @@ static struct hwentry default_hw[] = { + .prio_name = PRIO_ALUA, + .no_path_retry = 30, + }, +- /* +- * Violin Systems +- */ ++ /* Violin Systems */ + { + /* 3000 / 6000 Series */ + .vendor = "VIOLIN", +-- +2.17.2 + diff --git a/0037-libmultipath-fix-memory-leaks-in-coalesce_paths.patch b/0037-libmultipath-fix-memory-leaks-in-coalesce_paths.patch new file mode 100644 index 0000000..0f67ead --- /dev/null +++ b/0037-libmultipath-fix-memory-leaks-in-coalesce_paths.patch @@ -0,0 +1,117 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: lixiaokeng +Date: Mon, 9 Nov 2020 12:32:05 +0800 +Subject: [PATCH] libmultipath: fix memory leaks in coalesce_paths + +When multipath -F are executed first and multipath -v2 or +-d are executed later, asan will warn memory leaks. The +reason is that the mpp allocated in coalesce_paths isn't +freed. Here we use newmp to store mpp. If newmp need not +be copied to mpvec, we free newmp at the end of the func. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Lixiaokeng +Signed-off-by: Zhiqiang Liu +Signed-off-by: Linfeilong +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 40 +++++++++++++++++++++++++++++----------- + 1 file changed, 29 insertions(+), 11 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 1c8aac08..d36f0d0d 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -1139,7 +1139,7 @@ out: + * FORCE_RELOAD_WEAK: existing maps are compared to the current conf and only + * reloaded in DM if there's a difference. This is useful during startup. + */ +-int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, ++int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, + int force_reload, enum mpath_cmds cmd) + { + int ret = CP_FAIL; +@@ -1151,6 +1151,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + struct path * pp2; + vector curmp = vecs->mpvec; + vector pathvec = vecs->pathvec; ++ vector newmp; + struct config *conf; + int allow_queueing; + struct bitfield *size_mismatch_seen; +@@ -1171,6 +1172,15 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + if (size_mismatch_seen == NULL) + return CP_FAIL; + ++ if (mpvec) ++ newmp = mpvec; ++ else ++ newmp = vector_alloc(); ++ if (!newmp) { ++ condlog(0, "can not allocate newmp"); ++ goto out; ++ } ++ + vector_foreach_slot (pathvec, pp1, k) { + int invalid; + +@@ -1283,8 +1293,14 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + goto out; + } + } +- if (r == DOMAP_DRY) ++ if (r == DOMAP_DRY) { ++ if (!vector_alloc_slot(newmp)) { ++ remove_map(mpp, vecs->pathvec, vecs->mpvec, KEEP_VEC); ++ goto out; ++ } ++ vector_set_slot(newmp, mpp); + continue; ++ } + + if (r == DOMAP_EXIST && mpp->action == ACT_NOTHING && + force_reload == FORCE_RELOAD_WEAK) +@@ -1320,22 +1336,22 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + print_multipath_topology(mpp, verbosity); + } + +- if (newmp) { +- if (mpp->action != ACT_REJECT) { +- if (!vector_alloc_slot(newmp)) +- goto out; +- vector_set_slot(newmp, mpp); ++ if (mpp->action != ACT_REJECT) { ++ if (!vector_alloc_slot(newmp)) { ++ remove_map(mpp, vecs->pathvec, vecs->mpvec, KEEP_VEC); ++ goto out; + } +- else +- remove_map(mpp, vecs->pathvec, vecs->mpvec, +- KEEP_VEC); ++ vector_set_slot(newmp, mpp); + } ++ else ++ remove_map(mpp, vecs->pathvec, vecs->mpvec, ++ KEEP_VEC); + } + /* + * Flush maps with only dead paths (ie not in sysfs) + * Keep maps with only failed paths + */ +- if (newmp) { ++ if (mpvec) { + vector_foreach_slot (newmp, mpp, i) { + char alias[WWID_SIZE]; + +@@ -1358,6 +1374,8 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + ret = CP_OK; + out: + free(size_mismatch_seen); ++ if (!mpvec) ++ free_multipathvec(newmp, KEEP_PATHS); + return ret; + } + +-- +2.17.2 + diff --git a/0038-multipath-tools-replace-hidden-tab-by-space-in-hwtab.patch b/0038-multipath-tools-replace-hidden-tab-by-space-in-hwtab.patch new file mode 100644 index 0000000..d51c502 --- /dev/null +++ b/0038-multipath-tools-replace-hidden-tab-by-space-in-hwtab.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Xose Vazquez Perez +Date: Thu, 17 Dec 2020 16:49:38 +0100 +Subject: [PATCH] multipath-tools: replace hidden tab by space in hwtable + +Cc: Martin Wilck +Cc: Benjamin Marzinski +Cc: Christophe Varoqui +Cc: DM-DEVEL ML +Signed-off-by: Xose Vazquez Perez +Signed-off-by: Benjamin Marzinski +--- + libmultipath/hwtable.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c +index a54cc0a3..921aadc5 100644 +--- a/libmultipath/hwtable.c ++++ b/libmultipath/hwtable.c +@@ -819,7 +819,7 @@ static struct hwentry default_hw[] = { + * + * The hwtable is searched backwards, so place this after "Generic NVMe" + */ +- .vendor = "NVME", ++ .vendor = "NVME", + .product = "^NetApp ONTAP Controller", + .pgpolicy = MULTIBUS, + .no_path_retry = NO_PATH_RETRY_QUEUE, +-- +2.17.2 + diff --git a/0039-multipathd-uxlsnr-avoid-deadlock-on-exit.patch b/0039-multipathd-uxlsnr-avoid-deadlock-on-exit.patch new file mode 100644 index 0000000..6f4fc00 --- /dev/null +++ b/0039-multipathd-uxlsnr-avoid-deadlock-on-exit.patch @@ -0,0 +1,105 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Sep 2020 20:59:25 +0200 +Subject: [PATCH] multipathd: uxlsnr: avoid deadlock on exit + +The uxlsnr wouldn't always release the client lock when cancelled, +causing a deadlock in uxsock_cleanup(). While this hasn't been +caused by commit 3d611a2, the deadlock seems to have become much +more likely after that patch. Solving this means that we have to +treat reallocation failure of the pollfd array differently. +We will now just ignore any clients above the last valid pfd index. +That's a minor problem, as we're in an OOM situation anyway. + +Moreover, client_lock is not a "struct lock", but a plain +pthread_mutex_t. + +Fixes: 3d611a2 ("multipathd: cancel threads early during shutdown") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/uxlsnr.c | 24 ++++++++++++++---------- + 1 file changed, 14 insertions(+), 10 deletions(-) + +diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c +index 1c5ce9d2..ce2b6800 100644 +--- a/multipathd/uxlsnr.c ++++ b/multipathd/uxlsnr.c +@@ -35,6 +35,7 @@ + #include "config.h" + #include "mpath_cmd.h" + #include "time-util.h" ++#include "util.h" + + #include "main.h" + #include "cli.h" +@@ -116,7 +117,7 @@ static void _dead_client(struct client *c) + + static void dead_client(struct client *c) + { +- pthread_cleanup_push(cleanup_lock, &client_lock); ++ pthread_cleanup_push(cleanup_mutex, &client_lock); + pthread_mutex_lock(&client_lock); + _dead_client(c); + pthread_cleanup_pop(1); +@@ -302,10 +303,11 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + sigdelset(&mask, SIGUSR1); + while (1) { + struct client *c, *tmp; +- int i, poll_count, num_clients; ++ int i, n_pfds, poll_count, num_clients; + + /* setup for a poll */ + pthread_mutex_lock(&client_lock); ++ pthread_cleanup_push(cleanup_mutex, &client_lock); + num_clients = 0; + list_for_each_entry(c, &clients, node) { + num_clients++; +@@ -322,14 +324,13 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + sizeof(struct pollfd)); + } + if (!new) { +- pthread_mutex_unlock(&client_lock); + condlog(0, "%s: failed to realloc %d poll fds", + "uxsock", 2 + num_clients); +- sched_yield(); +- continue; ++ num_clients = old_clients; ++ } else { ++ old_clients = num_clients; ++ polls = new; + } +- old_clients = num_clients; +- polls = new; + } + polls[0].fd = ux_sock; + polls[0].events = POLLIN; +@@ -347,11 +348,14 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + polls[i].fd = c->fd; + polls[i].events = POLLIN; + i++; ++ if (i >= 2 + num_clients) ++ break; + } +- pthread_mutex_unlock(&client_lock); ++ n_pfds = i; ++ pthread_cleanup_pop(1); + + /* most of our life is spent in this call */ +- poll_count = ppoll(polls, i, &sleep_time, &mask); ++ poll_count = ppoll(polls, n_pfds, &sleep_time, &mask); + + handle_signals(false); + if (poll_count == -1) { +@@ -384,7 +388,7 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + } + + /* see if a client wants to speak to us */ +- for (i = 2; i < num_clients + 2; i++) { ++ for (i = 2; i < n_pfds; i++) { + if (polls[i].revents & POLLIN) { + struct timespec start_time; + +-- +2.17.2 + diff --git a/0040-multipathd-Fix-liburcu-memory-leak.patch b/0040-multipathd-Fix-liburcu-memory-leak.patch new file mode 100644 index 0000000..8f04a66 --- /dev/null +++ b/0040-multipathd-Fix-liburcu-memory-leak.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 18:02:39 +0200 +Subject: [PATCH] multipathd: Fix liburcu memory leak + +Fix this leak in multipathd, reported by valgrind, that messes up +multipathd's otherwise clean leak report: + +==23823== 336 bytes in 1 blocks are possibly lost in loss record 3 of 3 +==23823== at 0x483AB65: calloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) +==23823== by 0x4012F16: _dl_allocate_tls (in /lib64/ld-2.31.so) +==23823== by 0x493BB8E: pthread_create@@GLIBC_2.2.5 (in /lib64/libpthread-2.31.so) +==23823== by 0x492A9A9: call_rcu_data_init (urcu-call-rcu-impl.h:437) +==23823== by 0x492AD2F: UnknownInlinedFun (urcu-call-rcu-impl.h:492) +==23823== by 0x492AD2F: create_call_rcu_data_memb (urcu-call-rcu-impl.h:504) +==23823== by 0x1164E3: child.constprop.0.isra.0 (main.c:2915) +==23823== by 0x10F50C: main (main.c:3335) +==23823== +==23823== LEAK SUMMARY: +==23823== definitely lost: 0 bytes in 0 blocks +==23823== indirectly lost: 0 bytes in 0 blocks +==23823== possibly lost: 336 bytes in 1 blocks + +The problem is caused by using liburcu's default RCU call handler, +which liburcu refuses to stop/join. See comments in the code. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 44 insertions(+), 1 deletion(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index c5c374b7..ce14bb66 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2889,6 +2889,48 @@ set_oom_adj (void) + condlog(0, "couldn't adjust oom score"); + } + ++/* ++ * Use a non-default call_rcu_data for child(). ++ * ++ * We do this to avoid a memory leak from liburcu. ++ * liburcu never frees the default rcu handler (see comments on ++ * call_rcu_data_free() in urcu-call-rcu-impl.h), its thread ++ * can't be joined with pthread_join(), leaving a memory leak. ++ * ++ * Therefore we create our own, which can be destroyed and joined. ++ */ ++static struct call_rcu_data *setup_rcu(void) ++{ ++ struct call_rcu_data *crdp; ++ ++ rcu_init(); ++ rcu_register_thread(); ++ crdp = create_call_rcu_data(0UL, -1); ++ if (crdp != NULL) ++ set_thread_call_rcu_data(crdp); ++ return crdp; ++} ++ ++static struct call_rcu_data *mp_rcu_data; ++ ++static void cleanup_rcu(void) ++{ ++ pthread_t rcu_thread; ++ ++ /* Wait for any pending RCU calls */ ++ rcu_barrier(); ++ if (mp_rcu_data != NULL) { ++ rcu_thread = get_call_rcu_thread(mp_rcu_data); ++ /* detach this thread from the RCU thread */ ++ set_thread_call_rcu_data(NULL); ++ synchronize_rcu(); ++ /* tell RCU thread to exit */ ++ call_rcu_data_free(mp_rcu_data); ++ pthread_join(rcu_thread, NULL); ++ } ++ rcu_unregister_thread(); ++} ++ + static int + child (__attribute__((unused)) void *param) + { +@@ -2906,7 +2948,8 @@ child (__attribute__((unused)) void *param) + + mlockall(MCL_CURRENT | MCL_FUTURE); + signal_init(); +- rcu_init(); ++ mp_rcu_data = setup_rcu(); ++ atexit(cleanup_rcu); + + setup_thread_attr(&misc_attr, 64 * 1024, 0); + setup_thread_attr(&uevent_attr, DEFAULT_UEVENT_STACKSIZE * 1024, 0); +-- +2.17.2 + diff --git a/0041-multipathd-move-handling-of-io_err_stat_attr-into-li.patch b/0041-multipathd-move-handling-of-io_err_stat_attr-into-li.patch new file mode 100644 index 0000000..329876d --- /dev/null +++ b/0041-multipathd-move-handling-of-io_err_stat_attr-into-li.patch @@ -0,0 +1,146 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 10:33:12 +0200 +Subject: [PATCH] multipathd: move handling of io_err_stat_attr into + libmultipath + +This thread attribute can be dynamically initialized and destroyed. +No need to carry it along in multipathd. Removal of the symbol +requires to bump the ABI version to 3. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/io_err_stat.c | 7 +++++-- + libmultipath/libmultipath.version | 23 ++++++++--------------- + multipathd/main.c | 2 -- + 3 files changed, 13 insertions(+), 19 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index 58bc1dd2..5363049d 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -34,6 +34,7 @@ + #include "lock.h" + #include "time-util.h" + #include "io_err_stat.h" ++#include "util.h" + + #define TIMEOUT_NO_IO_NSEC 10000000 /*10ms = 10000000ns*/ + #define FLAKY_PATHFAIL_THRESHOLD 2 +@@ -70,8 +71,7 @@ struct io_err_stat_path { + int err_rate_threshold; + }; + +-pthread_t io_err_stat_thr; +-pthread_attr_t io_err_stat_attr; ++static pthread_t io_err_stat_thr; + + static pthread_mutex_t io_err_thread_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_cond_t io_err_thread_cond = PTHREAD_COND_INITIALIZER; +@@ -727,6 +727,7 @@ static void *io_err_stat_loop(void *data) + int start_io_err_stat_thread(void *data) + { + int ret; ++ pthread_attr_t io_err_stat_attr; + + if (uatomic_read(&io_err_thread_running) == 1) + return 0; +@@ -739,6 +740,7 @@ int start_io_err_stat_thread(void *data) + if (!paths) + goto destroy_ctx; + ++ setup_thread_attr(&io_err_stat_attr, 32 * 1024, 0); + pthread_mutex_lock(&io_err_thread_lock); + pthread_cleanup_push(cleanup_unlock, &io_err_thread_lock); + +@@ -750,6 +752,7 @@ int start_io_err_stat_thread(void *data) + &io_err_thread_lock) == 0); + + pthread_cleanup_pop(1); ++ pthread_attr_destroy(&io_err_stat_attr); + + if (ret) { + io_err_stat_log(0, "cannot create io_error statistic thread"); +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 0c300c81..84beb7f0 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -31,7 +31,7 @@ + * The new version inherits the previous ones. + */ + +-LIBMULTIPATH_2.0.0 { ++LIBMULTIPATH_3.0.0 { + global: + /* symbols referenced by multipath and multipathd */ + add_foreign; +@@ -121,7 +121,6 @@ global: + init_checkers; + init_foreign; + init_prio; +- io_err_stat_attr; + io_err_stat_handle_pathfail; + is_path_valid; + is_quote; +@@ -242,30 +241,24 @@ global: + free_scandir_result; + sysfs_attr_get_value; + +-local: +- *; +-}; +- +-LIBMULTIPATH_2.1.0 { +-global: ++ /* added in 2.1.0 */ + libmp_dm_task_run; + cleanup_mutex; +-} LIBMULTIPATH_2.0.0; + +-LIBMULTIPATH_2.2.0 { +-global: ++ /* added in 2.2.0 */ + libmp_get_multipath_config; + get_multipath_config; + libmp_put_multipath_config; + put_multipath_config; + init_config; + uninit_config; +-} LIBMULTIPATH_2.1.0; + +-LIBMULTIPATH_2.3.0 { +-global: ++ /* added in 2.3.0 */ + udev; + logsink; + libmultipath_init; + libmultipath_exit; +-} LIBMULTIPATH_2.2.0; ++ ++local: ++ *; ++}; +diff --git a/multipathd/main.c b/multipathd/main.c +index ce14bb66..abc6a9f7 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2954,7 +2954,6 @@ child (__attribute__((unused)) void *param) + setup_thread_attr(&misc_attr, 64 * 1024, 0); + setup_thread_attr(&uevent_attr, DEFAULT_UEVENT_STACKSIZE * 1024, 0); + setup_thread_attr(&waiter_attr, 32 * 1024, 1); +- setup_thread_attr(&io_err_stat_attr, 32 * 1024, 0); + + if (logsink == 1) { + setup_thread_attr(&log_attr, 64 * 1024, 0); +@@ -3164,7 +3163,6 @@ child (__attribute__((unused)) void *param) + rcu_assign_pointer(multipath_conf, NULL); + call_rcu(&conf->rcu, rcu_free_config); + pthread_attr_destroy(&waiter_attr); +- pthread_attr_destroy(&io_err_stat_attr); + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +-- +2.17.2 + diff --git a/0042-multipathd-move-vecs-desctruction-into-cleanup-funct.patch b/0042-multipathd-move-vecs-desctruction-into-cleanup-funct.patch new file mode 100644 index 0000000..f65e6eb --- /dev/null +++ b/0042-multipathd-move-vecs-desctruction-into-cleanup-funct.patch @@ -0,0 +1,125 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 18:05:40 +0200 +Subject: [PATCH] multipathd: move vecs desctruction into cleanup function + +This will make it easer to move the stuff around later. +The only functional change is that map destuction now happens after +joining all threads, which should actually improve robustness. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 64 +++++++++++++++++++++++++++++------------------ + 1 file changed, 40 insertions(+), 24 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index abc6a9f7..3da0d7cc 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -148,7 +148,7 @@ int should_exit(void) + /* + * global copy of vecs for use in sig handlers + */ +-struct vectors * gvecs; ++static struct vectors * gvecs; + + struct config *multipath_conf; + +@@ -2889,6 +2889,44 @@ set_oom_adj (void) + condlog(0, "couldn't adjust oom score"); + } + ++static void cleanup_maps(struct vectors *vecs) ++{ ++ int queue_without_daemon, i; ++ struct multipath *mpp; ++ struct config *conf; ++ ++ conf = get_multipath_config(); ++ queue_without_daemon = conf->queue_without_daemon; ++ put_multipath_config(conf); ++ if (queue_without_daemon == QUE_NO_DAEMON_OFF) ++ vector_foreach_slot(vecs->mpvec, mpp, i) ++ dm_queue_if_no_path(mpp->alias, 0); ++ remove_maps_and_stop_waiters(vecs); ++ vecs->mpvec = NULL; ++} ++ ++static void cleanup_paths(struct vectors *vecs) ++{ ++ free_pathvec(vecs->pathvec, FREE_PATHS); ++ vecs->pathvec = NULL; ++} ++ ++static void cleanup_vecs(void) ++{ ++ if (!gvecs) ++ return; ++ /* ++ * We can't take the vecs lock here, because exit() may ++ * have been called from the child() thread, holding the lock already. ++ * Anyway, by the time we get here, all threads that might access ++ * vecs should have been joined already (in cleanup_threads). ++ */ ++ cleanup_maps(gvecs); ++ cleanup_paths(gvecs); ++ pthread_mutex_destroy(&gvecs->lock.mutex); ++ FREE(gvecs); ++} ++ + /* + * Use a non-default call_rcu_data for child(). + * +@@ -2937,13 +2975,10 @@ child (__attribute__((unused)) void *param) + pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr; + pthread_attr_t log_attr, misc_attr, uevent_attr; + struct vectors * vecs; +- struct multipath * mpp; +- int i; + int rc; + int pid_fd = -1; + struct config *conf; + char *envp; +- int queue_without_daemon; + enum daemon_status state; + + mlockall(MCL_CURRENT | MCL_FUTURE); +@@ -3108,17 +3143,6 @@ child (__attribute__((unused)) void *param) + if (poll_dmevents) + pthread_cancel(dmevent_thr); + +- conf = get_multipath_config(); +- queue_without_daemon = conf->queue_without_daemon; +- put_multipath_config(conf); +- +- lock(&vecs->lock); +- if (queue_without_daemon == QUE_NO_DAEMON_OFF) +- vector_foreach_slot(vecs->mpvec, mpp, i) +- dm_queue_if_no_path(mpp->alias, 0); +- remove_maps_and_stop_waiters(vecs); +- unlock(&vecs->lock); +- + pthread_join(check_thr, NULL); + pthread_join(uevent_thr, NULL); + pthread_join(uxlsnr_thr, NULL); +@@ -3128,15 +3152,7 @@ child (__attribute__((unused)) void *param) + + stop_io_err_stat_thread(); + +- lock(&vecs->lock); +- free_pathvec(vecs->pathvec, FREE_PATHS); +- vecs->pathvec = NULL; +- unlock(&vecs->lock); +- +- pthread_mutex_destroy(&vecs->lock.mutex); +- FREE(vecs); +- vecs = NULL; +- ++ cleanup_vecs(); + cleanup_foreign(); + cleanup_checkers(); + cleanup_prio(); +-- +2.17.2 + diff --git a/0043-multipathd-make-some-globals-static.patch b/0043-multipathd-make-some-globals-static.patch new file mode 100644 index 0000000..6ae5835 --- /dev/null +++ b/0043-multipathd-make-some-globals-static.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 11:18:02 +0200 +Subject: [PATCH] multipathd: make some globals static + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 3da0d7cc..eb760a71 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -116,19 +116,19 @@ struct mpath_event_param + }; + + int uxsock_timeout; +-int verbosity; +-int bindings_read_only; ++static int verbosity; ++static int bindings_read_only; + int ignore_new_devs; + #ifdef NO_DMEVENTS_POLL +-int poll_dmevents = 0; ++static int poll_dmevents = 0; + #else +-int poll_dmevents = 1; ++static int poll_dmevents = 1; + #endif + /* Don't access this variable without holding config_lock */ +-volatile enum daemon_status running_state = DAEMON_INIT; ++static volatile enum daemon_status running_state = DAEMON_INIT; + pid_t daemon_pid; +-pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER; +-pthread_cond_t config_cond; ++static pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER; ++static pthread_cond_t config_cond; + + static inline enum daemon_status get_running_state(void) + { +-- +2.17.2 + diff --git a/0044-multipathd-move-threads-destruction-into-separate-fu.patch b/0044-multipathd-move-threads-destruction-into-separate-fu.patch new file mode 100644 index 0000000..6c2251e --- /dev/null +++ b/0044-multipathd-move-threads-destruction-into-separate-fu.patch @@ -0,0 +1,164 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 11:18:44 +0200 +Subject: [PATCH] multipathd: move threads destruction into separate function + +Also, introduce booleans that indicate a certain thread has +been started successfully. Using these booleans, we can avoid +crashing by cancelling threads that have never been started. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 76 +++++++++++++++++++++++++++++++---------------- + 1 file changed, 51 insertions(+), 25 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index eb760a71..9eb658d4 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -129,6 +129,9 @@ static volatile enum daemon_status running_state = DAEMON_INIT; + pid_t daemon_pid; + static pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_cond_t config_cond; ++static pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr; ++static bool check_thr_started, uevent_thr_started, uxlsnr_thr_started, ++ uevq_thr_started, dmevent_thr_started; + + static inline enum daemon_status get_running_state(void) + { +@@ -2927,6 +2930,39 @@ static void cleanup_vecs(void) + FREE(gvecs); + } + ++static void cleanup_threads(void) ++{ ++ stop_io_err_stat_thread(); ++ ++ if (check_thr_started) ++ pthread_cancel(check_thr); ++ if (uevent_thr_started) ++ pthread_cancel(uevent_thr); ++ if (uxlsnr_thr_started) ++ pthread_cancel(uxlsnr_thr); ++ if (uevq_thr_started) ++ pthread_cancel(uevq_thr); ++ if (dmevent_thr_started) ++ pthread_cancel(dmevent_thr); ++ ++ if (check_thr_started) ++ pthread_join(check_thr, NULL); ++ if (uevent_thr_started) ++ pthread_join(uevent_thr, NULL); ++ if (uxlsnr_thr_started) ++ pthread_join(uxlsnr_thr, NULL); ++ if (uevq_thr_started) ++ pthread_join(uevq_thr, NULL); ++ if (dmevent_thr_started) ++ pthread_join(dmevent_thr, NULL); ++ ++ /* ++ * As all threads are joined now, and we're in DAEMON_SHUTDOWN ++ * state, no new waiter threads will be created any more. ++ */ ++ pthread_attr_destroy(&waiter_attr); ++} ++ + /* + * Use a non-default call_rcu_data for child(). + * +@@ -2972,7 +3008,6 @@ static void cleanup_rcu(void) + static int + child (__attribute__((unused)) void *param) + { +- pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr; + pthread_attr_t log_attr, misc_attr, uevent_attr; + struct vectors * vecs; + int rc; +@@ -3070,9 +3105,12 @@ child (__attribute__((unused)) void *param) + condlog(0, "failed to create cli listener: %d", rc); + goto failed; + } +- else if (state != DAEMON_CONFIGURE) { +- condlog(0, "cli listener failed to start"); +- goto failed; ++ else { ++ uxlsnr_thr_started = true; ++ if (state != DAEMON_CONFIGURE) { ++ condlog(0, "cli listener failed to start"); ++ goto failed; ++ } + } + + if (poll_dmevents) { +@@ -3085,7 +3123,8 @@ child (__attribute__((unused)) void *param) + condlog(0, "failed to create dmevent waiter thread: %d", + rc); + goto failed; +- } ++ } else ++ dmevent_thr_started = true; + } + + /* +@@ -3094,7 +3133,8 @@ child (__attribute__((unused)) void *param) + if ((rc = pthread_create(&uevent_thr, &uevent_attr, ueventloop, udev))) { + condlog(0, "failed to create uevent thread: %d", rc); + goto failed; +- } ++ } else ++ uevent_thr_started = true; + pthread_attr_destroy(&uevent_attr); + + /* +@@ -3103,11 +3143,13 @@ child (__attribute__((unused)) void *param) + if ((rc = pthread_create(&check_thr, &misc_attr, checkerloop, vecs))) { + condlog(0,"failed to create checker loop thread: %d", rc); + goto failed; +- } ++ } else ++ check_thr_started = true; + if ((rc = pthread_create(&uevq_thr, &misc_attr, uevqloop, vecs))) { + condlog(0, "failed to create uevent dispatcher: %d", rc); + goto failed; +- } ++ } else ++ uevq_thr_started = true; + pthread_attr_destroy(&misc_attr); + + while (1) { +@@ -3136,22 +3178,7 @@ child (__attribute__((unused)) void *param) + } + } + +- pthread_cancel(check_thr); +- pthread_cancel(uevent_thr); +- pthread_cancel(uxlsnr_thr); +- pthread_cancel(uevq_thr); +- if (poll_dmevents) +- pthread_cancel(dmevent_thr); +- +- pthread_join(check_thr, NULL); +- pthread_join(uevent_thr, NULL); +- pthread_join(uxlsnr_thr, NULL); +- pthread_join(uevq_thr, NULL); +- if (poll_dmevents) +- pthread_join(dmevent_thr, NULL); +- +- stop_io_err_stat_thread(); +- ++ cleanup_threads(); + cleanup_vecs(); + cleanup_foreign(); + cleanup_checkers(); +@@ -3178,7 +3205,6 @@ child (__attribute__((unused)) void *param) + conf = rcu_dereference(multipath_conf); + rcu_assign_pointer(multipath_conf, NULL); + call_rcu(&conf->rcu, rcu_free_config); +- pthread_attr_destroy(&waiter_attr); + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +-- +2.17.2 + diff --git a/0045-multipathd-move-conf-destruction-into-separate-funct.patch b/0045-multipathd-move-conf-destruction-into-separate-funct.patch new file mode 100644 index 0000000..97125dc --- /dev/null +++ b/0045-multipathd-move-conf-destruction-into-separate-funct.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 12:38:50 +0200 +Subject: [PATCH] multipathd: move conf destruction into separate function + +Also removing the comment about dlog() and dm_write_log(). +dlog() can cope with get_multipath_config() returning NULL, +and dm_write_log() hasn't accessed the configuration for a while. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 9eb658d4..07973e85 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2892,6 +2892,16 @@ set_oom_adj (void) + condlog(0, "couldn't adjust oom score"); + } + ++static void cleanup_conf(void) { ++ struct config *conf; ++ ++ conf = rcu_dereference(multipath_conf); ++ if (!conf) ++ return; ++ rcu_assign_pointer(multipath_conf, NULL); ++ call_rcu(&conf->rcu, rcu_free_config); ++} ++ + static void cleanup_maps(struct vectors *vecs) + { + int queue_without_daemon, i; +@@ -3196,15 +3206,7 @@ child (__attribute__((unused)) void *param) + + if (logsink == 1) + log_thread_stop(); +- +- /* +- * Freeing config must be done after condlog() and dm_lib_exit(), +- * because logging functions like dlog() and dm_write_log() +- * reference the config. +- */ +- conf = rcu_dereference(multipath_conf); +- rcu_assign_pointer(multipath_conf, NULL); +- call_rcu(&conf->rcu, rcu_free_config); ++ cleanup_conf(); + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +-- +2.17.2 + diff --git a/0046-multipathd-move-pid-destruction-into-separate-functi.patch b/0046-multipathd-move-pid-destruction-into-separate-functi.patch new file mode 100644 index 0000000..bbff859 --- /dev/null +++ b/0046-multipathd-move-pid-destruction-into-separate-functi.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 16:10:19 +0200 +Subject: [PATCH] multipathd: move pid destruction into separate function + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 07973e85..fc1f8d7f 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2892,6 +2892,12 @@ set_oom_adj (void) + condlog(0, "couldn't adjust oom score"); + } + ++static void cleanup_pidfile(void) ++{ ++ condlog(3, "unlink pidfile"); ++ unlink(DEFAULT_PIDFILE); ++} ++ + static void cleanup_conf(void) { + struct config *conf; + +@@ -3199,9 +3205,7 @@ child (__attribute__((unused)) void *param) + dm_lib_exit(); + + /* We're done here */ +- condlog(3, "unlink pidfile"); +- unlink(DEFAULT_PIDFILE); +- ++ cleanup_pidfile(); + condlog(2, "--------shut down-------"); + + if (logsink == 1) +-- +2.17.2 + diff --git a/0047-multipathd-close-pidfile-on-exit.patch b/0047-multipathd-close-pidfile-on-exit.patch new file mode 100644 index 0000000..6c9c1b1 --- /dev/null +++ b/0047-multipathd-close-pidfile-on-exit.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 16:27:33 +0200 +Subject: [PATCH] multipathd: close pidfile on exit + +It seems we've been doing this only in the failure case, for ages. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index fc1f8d7f..f6b80668 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -132,6 +132,7 @@ static pthread_cond_t config_cond; + static pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr; + static bool check_thr_started, uevent_thr_started, uxlsnr_thr_started, + uevq_thr_started, dmevent_thr_started; ++static int pid_fd = -1; + + static inline enum daemon_status get_running_state(void) + { +@@ -2894,6 +2895,8 @@ set_oom_adj (void) + + static void cleanup_pidfile(void) + { ++ if (pid_fd >= 0) ++ close(pid_fd); + condlog(3, "unlink pidfile"); + unlink(DEFAULT_PIDFILE); + } +@@ -3027,7 +3030,6 @@ child (__attribute__((unused)) void *param) + pthread_attr_t log_attr, misc_attr, uevent_attr; + struct vectors * vecs; + int rc; +- int pid_fd = -1; + struct config *conf; + char *envp; + enum daemon_status state; +-- +2.17.2 + diff --git a/0048-multipathd-add-helper-for-systemd-notification-at-ex.patch b/0048-multipathd-add-helper-for-systemd-notification-at-ex.patch new file mode 100644 index 0000000..bf3c462 --- /dev/null +++ b/0048-multipathd-add-helper-for-systemd-notification-at-ex.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 17:49:02 +0200 +Subject: [PATCH] multipathd: add helper for systemd notification at exit + +Add sd_notify_exit(). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 22 +++++++++++++--------- + 1 file changed, 13 insertions(+), 9 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index f6b80668..07068e4a 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3024,6 +3024,17 @@ static void cleanup_rcu(void) + rcu_unregister_thread(); + } + ++static int sd_notify_exit(int err) ++{ ++#ifdef USE_SYSTEMD ++ char msg[24]; ++ ++ snprintf(msg, sizeof(msg), "ERRNO=%d", err); ++ sd_notify(0, msg); ++#endif ++ return err; ++} ++ + static int + child (__attribute__((unused)) void *param) + { +@@ -3216,19 +3227,12 @@ child (__attribute__((unused)) void *param) + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +- +-#ifdef USE_SYSTEMD +- sd_notify(0, "ERRNO=0"); +-#endif +- exit(0); ++ exit(sd_notify_exit(0)); + + failed: +-#ifdef USE_SYSTEMD +- sd_notify(0, "ERRNO=1"); +-#endif + if (pid_fd >= 0) + close(pid_fd); +- exit(1); ++ exit(sd_notify_exit(1)); + } + + static int +-- +2.17.2 + diff --git a/0049-multipathd-child-call-cleanups-in-failure-case-too.patch b/0049-multipathd-child-call-cleanups-in-failure-case-too.patch new file mode 100644 index 0000000..fba8169 --- /dev/null +++ b/0049-multipathd-child-call-cleanups-in-failure-case-too.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 17:57:16 +0200 +Subject: [PATCH] multipathd: child(): call cleanups in failure case, too + +So far we haven't called any cleanup code if child() failed. +Fix it. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 07068e4a..6b9e323e 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3044,6 +3044,7 @@ child (__attribute__((unused)) void *param) + struct config *conf; + char *envp; + enum daemon_status state; ++ int exit_code = 1; + + mlockall(MCL_CURRENT | MCL_FUTURE); + signal_init(); +@@ -3207,6 +3208,8 @@ child (__attribute__((unused)) void *param) + } + } + ++ exit_code = 0; ++failed: + cleanup_threads(); + cleanup_vecs(); + cleanup_foreign(); +@@ -3227,12 +3230,7 @@ child (__attribute__((unused)) void *param) + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +- exit(sd_notify_exit(0)); +- +-failed: +- if (pid_fd >= 0) +- close(pid_fd); +- exit(sd_notify_exit(1)); ++ return sd_notify_exit(exit_code); + } + + static int +-- +2.17.2 + diff --git a/0050-multipathd-unwatch_all_dmevents-check-if-waiter-is-i.patch b/0050-multipathd-unwatch_all_dmevents-check-if-waiter-is-i.patch new file mode 100644 index 0000000..279109c --- /dev/null +++ b/0050-multipathd-unwatch_all_dmevents-check-if-waiter-is-i.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 18:45:30 +0200 +Subject: [PATCH] multipathd: unwatch_all_dmevents: check if waiter is + initialized + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/dmevents.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c +index b561cbfd..f52f5970 100644 +--- a/multipathd/dmevents.c ++++ b/multipathd/dmevents.c +@@ -257,6 +257,8 @@ void unwatch_all_dmevents(void) + struct dev_event *dev_evt; + int i; + ++ if (!waiter) ++ return; + pthread_mutex_lock(&waiter->events_lock); + vector_foreach_slot(waiter->events, dev_evt, i) + free(dev_evt); +-- +2.17.2 + diff --git a/0051-multipathd-print-error-message-if-config-can-t-be-lo.patch b/0051-multipathd-print-error-message-if-config-can-t-be-lo.patch new file mode 100644 index 0000000..9cf6182 --- /dev/null +++ b/0051-multipathd-print-error-message-if-config-can-t-be-lo.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 18:45:51 +0200 +Subject: [PATCH] multipathd: print error message if config can't be loaded + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 6b9e323e..7ab3eab8 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3074,8 +3074,10 @@ child (__attribute__((unused)) void *param) + condlog(2, "read " DEFAULT_CONFIGFILE); + + conf = load_config(DEFAULT_CONFIGFILE); +- if (!conf) ++ if (!conf) { ++ condlog(0, "failed to load configuration"); + goto failed; ++ } + + if (verbosity) + conf->verbosity = verbosity; +-- +2.17.2 + diff --git a/0052-libmultipath-add-libmp_dm_exit.patch b/0052-libmultipath-add-libmp_dm_exit.patch new file mode 100644 index 0000000..db24711 --- /dev/null +++ b/0052-libmultipath-add-libmp_dm_exit.patch @@ -0,0 +1,92 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 21:02:45 +0200 +Subject: [PATCH] libmultipath: add libmp_dm_exit() + +This function prepares for calling dm_lib_exit() on program exit. +It undoes changes to libdm internals done by libmultipath. +It doesn't call dm_lib_exit(), as the caller may want to keep +libdm active. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 1 + + libmultipath/config.h | 2 ++ + libmultipath/devmapper.c | 15 +++++++++++++++ + libmultipath/devmapper.h | 1 + + 4 files changed, 19 insertions(+) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index f74417c6..b9cb4131 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -60,6 +60,7 @@ int libmultipath_init(void) + static void _libmultipath_exit(void) + { + libmultipath_exit_called = true; ++ libmp_dm_exit(); + udev_unref(udev); + } + +diff --git a/libmultipath/config.h b/libmultipath/config.h +index f478df71..5d460359 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -271,6 +271,8 @@ int libmultipath_init(void); + * + * This function un-initializes libmultipath data structures. + * It is recommended to call this function at program exit. ++ * If the application also calls dm_lib_exit(), it should do so ++ * after libmultipath_exit(). + * + * Calls to libmultipath_init() after libmultipath_exit() will fail + * (in other words, libmultipath can't be re-initialized). +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 4eb6f539..e60ab493 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -335,6 +335,20 @@ void libmp_udev_set_sync_support(int on) + libmp_dm_udev_sync = !!on; + } + ++static bool libmp_dm_init_called; ++void libmp_dm_exit(void) ++{ ++ if (!libmp_dm_init_called) ++ return; ++ ++ /* switch back to default libdm logging */ ++ dm_log_init(NULL); ++#ifdef LIBDM_API_HOLD_CONTROL ++ /* make sure control fd is closed in dm_lib_release() */ ++ dm_hold_control_dev(0); ++#endif ++} ++ + static void libmp_dm_init(void) + { + struct config *conf; +@@ -351,6 +365,7 @@ static void libmp_dm_init(void) + dm_hold_control_dev(1); + #endif + dm_udev_set_sync_support(libmp_dm_udev_sync); ++ libmp_dm_init_called = true; + } + + static void _do_skip_libmp_dm_init(void) +diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h +index fa6b3c53..e29b4d41 100644 +--- a/libmultipath/devmapper.h ++++ b/libmultipath/devmapper.h +@@ -35,6 +35,7 @@ enum { + + int dm_prereq(unsigned int *v); + void skip_libmp_dm_init(void); ++void libmp_dm_exit(void); + void libmp_udev_set_sync_support(int on); + struct dm_task *libmp_dm_task_create(int task); + int dm_simplecmd_flush (int, const char *, uint16_t); +-- +2.17.2 + diff --git a/0053-multipathd-fixup-libdm-deinitialization.patch b/0053-multipathd-fixup-libdm-deinitialization.patch new file mode 100644 index 0000000..b57a8cd --- /dev/null +++ b/0053-multipathd-fixup-libdm-deinitialization.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 21:06:13 +0200 +Subject: [PATCH] multipathd: fixup libdm deinitialization + +With libmp_dm_exit() in place, we can make sure that the +calls are made in the right order. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 7ab3eab8..4c4e2eab 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3220,8 +3220,6 @@ failed: + if (poll_dmevents) + cleanup_dmevent_waiter(); + +- dm_lib_exit(); +- + /* We're done here */ + cleanup_pidfile(); + condlog(2, "--------shut down-------"); +@@ -3318,6 +3316,9 @@ main (int argc, char *argv[]) + + pthread_cond_init_mono(&config_cond); + ++ if (atexit(dm_lib_exit)) ++ condlog(3, "failed to register exit handler for libdm"); ++ + libmultipath_init(); + if (atexit(libmultipath_exit)) + condlog(3, "failed to register exit handler for libmultipath"); +-- +2.17.2 + diff --git a/0054-libmultipath-log_thread_stop-check-if-logarea-is-ini.patch b/0054-libmultipath-log_thread_stop-check-if-logarea-is-ini.patch new file mode 100644 index 0000000..004016c --- /dev/null +++ b/0054-libmultipath-log_thread_stop-check-if-logarea-is-ini.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 21:04:04 +0200 +Subject: [PATCH] libmultipath: log_thread_stop(): check if logarea is + initialized + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log_pthread.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c +index 15baef88..0c327ffc 100644 +--- a/libmultipath/log_pthread.c ++++ b/libmultipath/log_pthread.c +@@ -112,6 +112,9 @@ void log_thread_reset (void) + + void log_thread_stop (void) + { ++ if (!la) ++ return; ++ + logdbg(stderr,"enter log_thread_stop\n"); + + pthread_mutex_lock(&logev_lock); +-- +2.17.2 + diff --git a/0055-multipathd-add-cleanup_child-exit-handler.patch b/0055-multipathd-add-cleanup_child-exit-handler.patch new file mode 100644 index 0000000..8455a96 --- /dev/null +++ b/0055-multipathd-add-cleanup_child-exit-handler.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 21:08:19 +0200 +Subject: [PATCH] multipathd: add cleanup_child() exit handler + +cleanup_child() calls all cleanups in the right order, in an +exit handler. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 45 +++++++++++++++++++++++++-------------------- + 1 file changed, 25 insertions(+), 20 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 4c4e2eab..50cc3356 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3024,6 +3024,27 @@ static void cleanup_rcu(void) + rcu_unregister_thread(); + } + ++static void cleanup_child(void) ++{ ++ cleanup_threads(); ++ cleanup_vecs(); ++ cleanup_foreign(); ++ cleanup_checkers(); ++ cleanup_prio(); ++ if (poll_dmevents) ++ cleanup_dmevent_waiter(); ++ ++ cleanup_pidfile(); ++ if (logsink == 1) ++ log_thread_stop(); ++ ++ cleanup_conf(); ++ ++#ifdef _DEBUG_ ++ dbg_free_final(NULL); ++#endif ++} ++ + static int sd_notify_exit(int err) + { + #ifdef USE_SYSTEMD +@@ -3049,7 +3070,9 @@ child (__attribute__((unused)) void *param) + mlockall(MCL_CURRENT | MCL_FUTURE); + signal_init(); + mp_rcu_data = setup_rcu(); +- atexit(cleanup_rcu); ++ ++ if (atexit(cleanup_rcu) || atexit(cleanup_child)) ++ fprintf(stderr, "failed to register cleanup handlers\n"); + + setup_thread_attr(&misc_attr, 64 * 1024, 0); + setup_thread_attr(&uevent_attr, DEFAULT_UEVENT_STACKSIZE * 1024, 0); +@@ -3063,8 +3086,6 @@ child (__attribute__((unused)) void *param) + pid_fd = pidfile_create(DEFAULT_PIDFILE, daemon_pid); + if (pid_fd < 0) { + condlog(1, "failed to create pidfile"); +- if (logsink == 1) +- log_thread_stop(); + exit(1); + } + +@@ -3212,24 +3233,8 @@ child (__attribute__((unused)) void *param) + + exit_code = 0; + failed: +- cleanup_threads(); +- cleanup_vecs(); +- cleanup_foreign(); +- cleanup_checkers(); +- cleanup_prio(); +- if (poll_dmevents) +- cleanup_dmevent_waiter(); +- +- /* We're done here */ +- cleanup_pidfile(); + condlog(2, "--------shut down-------"); +- +- if (logsink == 1) +- log_thread_stop(); +- cleanup_conf(); +-#ifdef _DEBUG_ +- dbg_free_final(NULL); +-#endif ++ /* All cleanup is done in the cleanup_child() exit handler */ + return sd_notify_exit(exit_code); + } + +-- +2.17.2 + diff --git a/0056-libmultipath-fix-log_thread-startup-and-teardown.patch b/0056-libmultipath-fix-log_thread-startup-and-teardown.patch new file mode 100644 index 0000000..106f19a --- /dev/null +++ b/0056-libmultipath-fix-log_thread-startup-and-teardown.patch @@ -0,0 +1,148 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 26 Oct 2020 16:44:32 +0100 +Subject: [PATCH] libmultipath: fix log_thread startup and teardown + +This fixes several issues with the log_thread. First, the running flag +logq_running should be set by the thread itself, not by +log_thread_start()/_stop(). Second, the thread was both cancelled and +terminated via a flag (again, logq_running). It's sufficient to just cancel +and join it. Third, the locking wasn't cancel-safe in some places. Forth, +log_thread_start() didn't wait for startup properly. Fifth, using (pthread_t)0 +is wrong (pthread_t is opaque; there's no guarantee that 0 is not a valid +pthread_t value). Sixth, pthread_cancel() was called under logq_lock, which +doesn't make sense to me. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log_pthread.c | 62 +++++++++++++++++++++++++++----------- + 1 file changed, 45 insertions(+), 17 deletions(-) + +diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c +index 0c327ffc..3a2566ae 100644 +--- a/libmultipath/log_pthread.c ++++ b/libmultipath/log_pthread.c +@@ -13,6 +13,7 @@ + #include "log_pthread.h" + #include "log.h" + #include "lock.h" ++#include "util.h" + + static pthread_t log_thr; + +@@ -56,35 +57,52 @@ static void flush_logqueue (void) + } while (empty == 0); + } + ++static void cleanup_log_thread(__attribute((unused)) void *arg) ++{ ++ logdbg(stderr, "log thread exiting"); ++ pthread_mutex_lock(&logev_lock); ++ logq_running = 0; ++ pthread_mutex_unlock(&logev_lock); ++} ++ + static void * log_thread (__attribute__((unused)) void * et) + { + int running; + + pthread_mutex_lock(&logev_lock); +- logq_running = 1; ++ running = logq_running; ++ if (!running) ++ logq_running = 1; ++ pthread_cond_signal(&logev_cond); + pthread_mutex_unlock(&logev_lock); ++ if (running) ++ /* already started */ ++ return NULL; ++ pthread_cleanup_push(cleanup_log_thread, NULL); + + mlockall(MCL_CURRENT | MCL_FUTURE); + logdbg(stderr,"enter log_thread\n"); + + while (1) { + pthread_mutex_lock(&logev_lock); +- if (logq_running && !log_messages_pending) ++ pthread_cleanup_push(cleanup_mutex, &logev_lock); ++ while (!log_messages_pending) ++ /* this is a cancellation point */ + pthread_cond_wait(&logev_cond, &logev_lock); + log_messages_pending = 0; +- running = logq_running; +- pthread_mutex_unlock(&logev_lock); +- if (!running) +- break; ++ pthread_cleanup_pop(1); ++ + flush_logqueue(); + } ++ pthread_cleanup_pop(1); + return NULL; + } + + void log_thread_start (pthread_attr_t *attr) + { +- logdbg(stderr,"enter log_thread_start\n"); ++ int running = 0; + ++ logdbg(stderr,"enter log_thread_start\n"); + pthread_mutex_init(&logq_lock, NULL); + pthread_mutex_init(&logev_lock, NULL); + pthread_cond_init(&logev_cond, NULL); +@@ -93,7 +111,15 @@ void log_thread_start (pthread_attr_t *attr) + fprintf(stderr,"can't initialize log buffer\n"); + exit(1); + } +- if (pthread_create(&log_thr, attr, log_thread, NULL)) { ++ ++ pthread_mutex_lock(&logev_lock); ++ pthread_cleanup_push(cleanup_mutex, &logev_lock); ++ if (!pthread_create(&log_thr, attr, log_thread, NULL)) ++ while (!(running = logq_running)) ++ pthread_cond_wait(&logev_cond, &logev_lock); ++ pthread_cleanup_pop(1); ++ ++ if (!running) { + fprintf(stderr,"can't start log thread\n"); + exit(1); + } +@@ -112,23 +138,25 @@ void log_thread_reset (void) + + void log_thread_stop (void) + { ++ int running; ++ + if (!la) + return; + + logdbg(stderr,"enter log_thread_stop\n"); + + pthread_mutex_lock(&logev_lock); +- logq_running = 0; +- pthread_cond_signal(&logev_cond); +- pthread_mutex_unlock(&logev_lock); +- +- pthread_mutex_lock(&logq_lock); +- pthread_cancel(log_thr); +- pthread_mutex_unlock(&logq_lock); +- pthread_join(log_thr, NULL); +- log_thr = (pthread_t)0; ++ pthread_cleanup_push(cleanup_mutex, &logev_lock); ++ running = logq_running; ++ if (running) { ++ pthread_cancel(log_thr); ++ pthread_cond_signal(&logev_cond); ++ } ++ pthread_cleanup_pop(1); + + flush_logqueue(); ++ if (running) ++ pthread_join(log_thr, NULL); + + pthread_mutex_destroy(&logq_lock); + pthread_mutex_destroy(&logev_lock); +-- +2.17.2 + diff --git a/0057-multipathd-move-cleanup_-prio-checkers-foreign-to-li.patch b/0057-multipathd-move-cleanup_-prio-checkers-foreign-to-li.patch new file mode 100644 index 0000000..017034e --- /dev/null +++ b/0057-multipathd-move-cleanup_-prio-checkers-foreign-to-li.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 21:57:22 +0200 +Subject: [PATCH] multipathd: move cleanup_{prio,checkers,foreign} to + libmultipath_exit + +This requires another major ABI bump. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathpersist/mpath_persist.c | 2 -- + libmultipath/config.c | 4 ++++ + libmultipath/libmultipath.version | 5 +---- + multipathd/main.c | 3 --- + 4 files changed, 5 insertions(+), 9 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index e1d1cb76..9ebf91dd 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -78,8 +78,6 @@ mpath_lib_init (void) + + static void libmpathpersist_cleanup(void) + { +- cleanup_prio(); +- cleanup_checkers(); + libmultipath_exit(); + dm_lib_exit(); + } +diff --git a/libmultipath/config.c b/libmultipath/config.c +index b9cb4131..52b1447b 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -26,6 +26,7 @@ + #include "devmapper.h" + #include "mpath_cmd.h" + #include "propsel.h" ++#include "foreign.h" + + /* + * We don't support re-initialization after +@@ -60,6 +61,9 @@ int libmultipath_init(void) + static void _libmultipath_exit(void) + { + libmultipath_exit_called = true; ++ cleanup_foreign(); ++ cleanup_checkers(); ++ cleanup_prio(); + libmp_dm_exit(); + udev_unref(udev); + } +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 84beb7f0..800cff22 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -31,7 +31,7 @@ + * The new version inherits the previous ones. + */ + +-LIBMULTIPATH_3.0.0 { ++LIBMULTIPATH_4.0.0 { + global: + /* symbols referenced by multipath and multipathd */ + add_foreign; +@@ -51,10 +51,7 @@ global: + checker_name; + checker_state_name; + check_foreign; +- cleanup_checkers; +- cleanup_foreign; + cleanup_lock; +- cleanup_prio; + close_fd; + coalesce_paths; + convert_dev; +diff --git a/multipathd/main.c b/multipathd/main.c +index 50cc3356..4de0978e 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3028,9 +3028,6 @@ static void cleanup_child(void) + { + cleanup_threads(); + cleanup_vecs(); +- cleanup_foreign(); +- cleanup_checkers(); +- cleanup_prio(); + if (poll_dmevents) + cleanup_dmevent_waiter(); + +-- +2.17.2 + diff --git a/0058-multipath-use-atexit-for-cleanup-handlers.patch b/0058-multipath-use-atexit-for-cleanup-handlers.patch new file mode 100644 index 0000000..444a39d --- /dev/null +++ b/0058-multipath-use-atexit-for-cleanup-handlers.patch @@ -0,0 +1,110 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 00:30:02 +0200 +Subject: [PATCH] multipath: use atexit() for cleanup handlers + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipath/main.c | 37 ++++++++++++++++--------------------- + 1 file changed, 16 insertions(+), 21 deletions(-) + +diff --git a/multipath/main.c b/multipath/main.c +index 9ae46ed5..1949a1cd 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -452,13 +452,19 @@ static bool released_to_systemd(void) + return ret; + } + ++static struct vectors vecs; ++static void cleanup_vecs(void) ++{ ++ free_multipathvec(vecs.mpvec, KEEP_PATHS); ++ free_pathvec(vecs.pathvec, FREE_PATHS); ++} ++ + static int + configure (struct config *conf, enum mpath_cmds cmd, + enum devtypes dev_type, char *devpath) + { + vector curmp = NULL; + vector pathvec = NULL; +- struct vectors vecs; + int r = RTVL_FAIL, rc; + int di_flag = 0; + char * refwwid = NULL; +@@ -469,6 +475,7 @@ configure (struct config *conf, enum mpath_cmds cmd, + */ + curmp = vector_alloc(); + pathvec = vector_alloc(); ++ atexit(cleanup_vecs); + + if (!curmp || !pathvec) { + condlog(0, "can not allocate memory"); +@@ -580,9 +587,6 @@ out: + if (refwwid) + FREE(refwwid); + +- free_multipathvec(curmp, KEEP_PATHS); +- free_pathvec(pathvec, FREE_PATHS); +- + return r; + } + +@@ -808,9 +812,13 @@ main (int argc, char *argv[]) + bool enable_foreign = false; + + libmultipath_init(); ++ if (atexit(dm_lib_exit) || atexit(libmultipath_exit)) ++ condlog(1, "failed to register cleanup handler for libmultipath: %m"); + logsink = 0; + if (init_config(DEFAULT_CONFIGFILE)) + exit(RTVL_FAIL); ++ if (atexit(uninit_config)) ++ condlog(1, "failed to register cleanup handler for config: %m"); + conf = get_multipath_config(); + conf->retrigger_tries = 0; + conf->force_sync = 1; +@@ -887,7 +895,7 @@ main (int argc, char *argv[]) + break; + case 't': + r = dump_config(conf, NULL, NULL) ? RTVL_FAIL : RTVL_OK; +- goto out_free_config; ++ goto out; + case 'T': + cmd = CMD_DUMP_CONFIG; + break; +@@ -1048,26 +1056,13 @@ main (int argc, char *argv[]) + condlog(3, "restart multipath configuration process"); + + out: +- dm_lib_exit(); +- +- cleanup_foreign(); +- cleanup_prio(); +- cleanup_checkers(); ++ put_multipath_config(conf); ++ if (dev) ++ FREE(dev); + + if (dev_type == DEV_UEVENT) + closelog(); + +-out_free_config: +- /* +- * Freeing config must be done after dm_lib_exit(), because +- * the logging function (dm_write_log()), which is called there, +- * references the config. +- */ +- put_multipath_config(conf); +- uninit_config(); +- libmultipath_exit(); +- if (dev) +- FREE(dev); + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +-- +2.17.2 + diff --git a/0059-mpathpersist-use-atexit-for-cleanup-handlers.patch b/0059-mpathpersist-use-atexit-for-cleanup-handlers.patch new file mode 100644 index 0000000..7494b34 --- /dev/null +++ b/0059-mpathpersist-use-atexit-for-cleanup-handlers.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 00:32:48 +0200 +Subject: [PATCH] mpathpersist: use atexit() for cleanup handlers + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + mpathpersist/main.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/mpathpersist/main.c b/mpathpersist/main.c +index 3c2e6576..14245cc3 100644 +--- a/mpathpersist/main.c ++++ b/mpathpersist/main.c +@@ -641,11 +641,10 @@ int main(int argc, char *argv[]) + if (libmpathpersist_init()) { + exit(1); + } ++ if (atexit((void(*)(void))libmpathpersist_exit)) ++ fprintf(stderr, "failed to register cleanup handler for libmpathpersist: %m"); + + ret = handle_args(argc, argv, 0); +- +- libmpathpersist_exit(); +- + return (ret >= 0) ? ret : MPATH_PR_OTHER; + } + +-- +2.17.2 + diff --git a/0060-multipath-fix-leak-in-check_path_valid.patch b/0060-multipath-fix-leak-in-check_path_valid.patch new file mode 100644 index 0000000..c96f4cb --- /dev/null +++ b/0060-multipath-fix-leak-in-check_path_valid.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 23:30:50 +0200 +Subject: [PATCH] multipath: fix leak in check_path_valid() + +If path status was successfully determined before calling store_pathvec(), +free_path() wasn't called. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipath/main.c | 30 ++++++++++++++++++++---------- + 1 file changed, 20 insertions(+), 10 deletions(-) + +diff --git a/multipath/main.c b/multipath/main.c +index 1949a1cd..043d8fa7 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -93,7 +93,7 @@ void rcu_register_thread_memb(void) {} + void rcu_unregister_thread_memb(void) {} + + static int +-filter_pathvec (vector pathvec, char * refwwid) ++filter_pathvec (vector pathvec, const char *refwwid) + { + int i; + struct path * pp; +@@ -594,8 +594,9 @@ static int + check_path_valid(const char *name, struct config *conf, bool is_uevent) + { + int fd, r = PATH_IS_ERROR; +- struct path *pp = NULL; ++ struct path *pp; + vector pathvec = NULL; ++ const char *wwid; + + pp = alloc_path(); + if (!pp) +@@ -664,14 +665,19 @@ check_path_valid(const char *name, struct config *conf, bool is_uevent) + + if (store_path(pathvec, pp) != 0) { + free_path(pp); ++ pp = NULL; + goto fail; ++ } else { ++ /* make sure path isn't freed twice */ ++ wwid = pp->wwid; ++ pp = NULL; + } + + /* For find_multipaths = SMART, if there is more than one path + * matching the refwwid, then the path is valid */ + if (path_discovery(pathvec, DI_SYSFS | DI_WWID) < 0) + goto fail; +- filter_pathvec(pathvec, pp->wwid); ++ filter_pathvec(pathvec, wwid); + if (VECTOR_SIZE(pathvec) > 1) + r = PATH_IS_VALID; + else +@@ -679,21 +685,25 @@ check_path_valid(const char *name, struct config *conf, bool is_uevent) + + out: + r = print_cmd_valid(r, pathvec, conf); +- free_pathvec(pathvec, FREE_PATHS); + /* + * multipath -u must exit with status 0, otherwise udev won't + * import its output. + */ + if (!is_uevent && r == PATH_IS_NOT_VALID) +- return RTVL_FAIL; +- return RTVL_OK; ++ r = RTVL_FAIL; ++ else ++ r = RTVL_OK; ++ goto cleanup; + + fail: +- if (pathvec) +- free_pathvec(pathvec, FREE_PATHS); +- else ++ r = RTVL_FAIL; ++ ++cleanup: ++ if (pp != NULL) + free_path(pp); +- return RTVL_FAIL; ++ if (pathvec != NULL) ++ free_pathvec(pathvec, FREE_PATHS); ++ return r; + } + + static int +-- +2.17.2 + diff --git a/0061-multipath-tools-mpath-tools.supp-file-with-valgrind-.patch b/0061-multipath-tools-mpath-tools.supp-file-with-valgrind-.patch new file mode 100644 index 0000000..4228be6 --- /dev/null +++ b/0061-multipath-tools-mpath-tools.supp-file-with-valgrind-.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 24 Sep 2020 15:13:06 +0200 +Subject: [PATCH] multipath-tools: mpath-tools.supp: file with valgrind + suppressions + +These leaks are caused by other libraries (libsystemd, glibc, +libgcrypt) and should be ignored when debugging with valgrind + +Usage example: + +valgrind --suppressions=mpath-tools.supp \ + --leak-check=full --show-leak-kinds=all $COMMAND + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + third-party/valgrind/mpath-tools.supp | 32 +++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + create mode 100644 third-party/valgrind/mpath-tools.supp + +diff --git a/third-party/valgrind/mpath-tools.supp b/third-party/valgrind/mpath-tools.supp +new file mode 100644 +index 00000000..0537fd56 +--- /dev/null ++++ b/third-party/valgrind/mpath-tools.supp +@@ -0,0 +1,32 @@ ++{ ++ glibc _dlerror_run leak: https://stackoverflow.com/questions/1542457/memory-leak-reported-by-valgrind-in-dlopen ++ Memcheck:Leak ++ match-leak-kinds: reachable ++ fun:calloc ++ fun:_dlerror_run ++ fun:dlopen* ++} ++ ++{ ++ systemd mempools are never freed: https://bugzilla.redhat.com/show_bug.cgi?id=1215670 ++ Memcheck:Leak ++ match-leak-kinds: reachable ++ fun:malloc ++ fun:mempool_alloc_tile ++ fun:mempool_alloc0_tile ++ fun:hashmap_base_new ++ fun:hashmap_base_ensure_allocated ++} ++ ++{ ++ libgcrypt library initialization ++ Memcheck:Leak ++ match-leak-kinds: reachable ++ fun:malloc ++ ... ++ fun:_gcry_xmalloc ++ ... ++ fun:global_init.* ++ ... ++ fun:_dl_init ++} +-- +2.17.2 + diff --git a/0062-libmultipath-use-libmp_verbosity-to-track-verbosity.patch b/0062-libmultipath-use-libmp_verbosity-to-track-verbosity.patch new file mode 100644 index 0000000..042929d --- /dev/null +++ b/0062-libmultipath-use-libmp_verbosity-to-track-verbosity.patch @@ -0,0 +1,441 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 26 Sep 2020 00:04:53 +0200 +Subject: [PATCH] libmultipath: use libmp_verbosity to track verbosity + +Introduce a new global variable to set the verbosity of libmultipath. +This avoids accessing the configuration in every dlog() call. +When libmultipath reads its configuration in init_config() or +load_config(), it will use the current value of libmp_verbosity +for logging. Immediately before returning, libmp_verbosity will be +overwritten with the verbosity value from the configuration file, +if it was set there. An application is free to set libmp_verbosity +back to the previous value or not after that, depending on whether +command line options or configuration file settings should take +precedence. + +Replace internal access to conf->verbosity with the new variable. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathpersist/mpath_persist.c | 5 +--- + libmultipath/config.c | 9 +++++-- + libmultipath/configure.c | 16 +++---------- + libmultipath/debug.c | 10 ++------ + libmultipath/debug.h | 1 + + libmultipath/devmapper.c | 7 +----- + libmultipath/libmultipath.version | 5 ++++ + multipath/main.c | 21 ++++++---------- + multipathd/main.c | 40 ++++++++++++++++++------------- + tests/alias.c | 1 + + tests/blacklist.c | 2 ++ + 11 files changed, 53 insertions(+), 64 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 9ebf91dd..79322e86 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -170,10 +170,7 @@ void mpath_persistent_reserve_free_vecs(void) + + int mpath_persistent_reserve_init_vecs(int verbose) + { +- struct config *conf = get_multipath_config(); +- +- conf->verbosity = verbose; +- put_multipath_config(conf); ++ libmp_verbosity = verbose; + + if (curmp) + return MPATH_PR_SUCCESS; +diff --git a/libmultipath/config.c b/libmultipath/config.c +index 52b1447b..49e7fb81 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -828,10 +828,14 @@ int _init_config (const char *file, struct config *conf) + conf = &__internal_config; + + /* +- * internal defaults ++ * Processing the config file will overwrite conf->verbosity if set ++ * When we return, we'll copy the config value back + */ +- conf->verbosity = DEFAULT_VERBOSITY; ++ conf->verbosity = libmp_verbosity; + ++ /* ++ * internal defaults ++ */ + get_sys_max_fds(&conf->max_fds); + conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE); + conf->wwids_file = set_default(DEFAULT_WWIDS_FILE); +@@ -997,6 +1001,7 @@ int _init_config (const char *file, struct config *conf) + !conf->wwids_file || !conf->prkeys_file) + goto out; + ++ libmp_verbosity = conf->verbosity; + return 0; + out: + _uninit_config(conf); +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index d36f0d0d..20536e60 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -934,16 +934,12 @@ int domap(struct multipath *mpp, char *params, int is_daemon) + { + int r = DOMAP_FAIL; + struct config *conf; +- int verbosity; + + /* + * last chance to quit before touching the devmaps + */ + if (mpp->action == ACT_DRY_RUN) { +- conf = get_multipath_config(); +- verbosity = conf->verbosity; +- put_multipath_config(conf); +- print_multipath_topology(mpp, verbosity); ++ print_multipath_topology(mpp, libmp_verbosity); + return DOMAP_DRY; + } + +@@ -1327,14 +1323,8 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, + "queue_if_no_path"); + } + +- if (!is_daemon && mpp->action != ACT_NOTHING) { +- int verbosity; +- +- conf = get_multipath_config(); +- verbosity = conf->verbosity; +- put_multipath_config(conf); +- print_multipath_topology(mpp, verbosity); +- } ++ if (!is_daemon && mpp->action != ACT_NOTHING) ++ print_multipath_topology(mpp, libmp_verbosity); + + if (mpp->action != ACT_REJECT) { + if (!vector_alloc_slot(newmp)) { +diff --git a/libmultipath/debug.c b/libmultipath/debug.c +index b3a1de9e..a1713b95 100644 +--- a/libmultipath/debug.c ++++ b/libmultipath/debug.c +@@ -16,21 +16,15 @@ + #include "debug.h" + + int logsink; ++int libmp_verbosity = DEFAULT_VERBOSITY; + + void dlog (int sink, int prio, const char * fmt, ...) + { + va_list ap; +- int thres; +- struct config *conf; + + va_start(ap, fmt); +- conf = get_multipath_config(); +- ANNOTATE_IGNORE_READS_BEGIN(); +- thres = (conf) ? conf->verbosity : DEFAULT_VERBOSITY; +- ANNOTATE_IGNORE_READS_END(); +- put_multipath_config(conf); + +- if (prio <= thres) { ++ if (prio <= libmp_verbosity) { + if (sink < 1) { + if (sink == 0) { + time_t t = time(NULL); +diff --git a/libmultipath/debug.h b/libmultipath/debug.h +index c6120c1d..1f3bc8be 100644 +--- a/libmultipath/debug.h ++++ b/libmultipath/debug.h +@@ -8,6 +8,7 @@ void dlog (int sink, int prio, const char * fmt, ...) + #include "log_pthread.h" + + extern int logsink; ++extern int libmp_verbosity; + + #define condlog(prio, fmt, args...) \ + dlog(logsink, prio, fmt "\n", ##args) +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index e60ab493..dfe95d2f 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -351,16 +351,11 @@ void libmp_dm_exit(void) + + static void libmp_dm_init(void) + { +- struct config *conf; +- int verbosity; + unsigned int version[3]; + + if (dm_prereq(version)) + exit(1); +- conf = get_multipath_config(); +- verbosity = conf->verbosity; +- put_multipath_config(conf); +- dm_init(verbosity); ++ dm_init(libmp_verbosity); + #ifdef LIBDM_API_HOLD_CONTROL + dm_hold_control_dev(1); + #endif +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 800cff22..67a7379f 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -259,3 +259,8 @@ global: + local: + *; + }; ++ ++LIBMULTIPATH_4.1.0 { ++global: ++ libmp_verbosity; ++} LIBMULTIPATH_4.0.0; +diff --git a/multipath/main.c b/multipath/main.c +index 043d8fa7..98d93c58 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -208,22 +208,15 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid) + mpp->bestpg = select_path_group(mpp); + + if (cmd == CMD_LIST_SHORT || +- cmd == CMD_LIST_LONG) { +- struct config *conf = get_multipath_config(); +- print_multipath_topology(mpp, conf->verbosity); +- put_multipath_config(conf); +- } ++ cmd == CMD_LIST_LONG) ++ print_multipath_topology(mpp, libmp_verbosity); + + if (cmd == CMD_CREATE) + reinstate_paths(mpp); + } + +- if (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG) { +- struct config *conf = get_multipath_config(); +- +- print_foreign_topology(conf->verbosity); +- put_multipath_config(conf); +- } ++ if (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG) ++ print_foreign_topology(libmp_verbosity); + + return 0; + } +@@ -552,7 +545,7 @@ configure (struct config *conf, enum mpath_cmds cmd, + if (path_discovery(pathvec, di_flag) < 0) + goto out; + +- if (conf->verbosity > 2) ++ if (libmp_verbosity > 2) + print_all_paths(pathvec, 1); + + get_path_layout(pathvec, 0); +@@ -843,7 +836,7 @@ main (int argc, char *argv[]) + exit(RTVL_FAIL); + } + +- conf->verbosity = atoi(optarg); ++ libmp_verbosity = atoi(optarg); + break; + case 'b': + conf->bindings_file = strdup(optarg); +@@ -974,7 +967,7 @@ main (int argc, char *argv[]) + } + if (dev_type == DEV_UEVENT) { + openlog("multipath", 0, LOG_DAEMON); +- setlogmask(LOG_UPTO(conf->verbosity + 3)); ++ setlogmask(LOG_UPTO(libmp_verbosity + 3)); + logsink = 1; + } + +diff --git a/multipathd/main.c b/multipathd/main.c +index 4de0978e..ba257515 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -88,10 +88,10 @@ + #define CMDSIZE 160 + #define MSG_SIZE 32 + +-#define LOG_MSG(lvl, verb, pp) \ ++#define LOG_MSG(lvl, pp) \ + do { \ + if (pp->mpp && checker_selected(&pp->checker) && \ +- lvl <= verb) { \ ++ lvl <= libmp_verbosity) { \ + if (pp->offline) \ + condlog(lvl, "%s: %s - path offline", \ + pp->mpp->alias, pp->dev); \ +@@ -2070,7 +2070,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + int chkr_new_path_up = 0; + int disable_reinstate = 0; + int oldchkrstate = pp->chkrstate; +- int retrigger_tries, verbosity; ++ int retrigger_tries; + unsigned int checkint, max_checkint; + struct config *conf; + int marginal_pathgroups, marginal_changed = 0; +@@ -2090,7 +2090,6 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + retrigger_tries = conf->retrigger_tries; + checkint = conf->checkint; + max_checkint = conf->max_checkint; +- verbosity = conf->verbosity; + marginal_pathgroups = conf->marginal_pathgroups; + put_multipath_config(conf); + +@@ -2152,7 +2151,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + if (newstate == PATH_WILD || newstate == PATH_UNCHECKED) { + condlog(2, "%s: unusable path (%s) - checker failed", + pp->dev, checker_state_name(newstate)); +- LOG_MSG(2, verbosity, pp); ++ LOG_MSG(2, pp); + conf = get_multipath_config(); + pthread_cleanup_push(put_multipath_config, conf); + pathinfo(pp, conf, 0); +@@ -2257,7 +2256,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + int oldstate = pp->state; + pp->state = newstate; + +- LOG_MSG(1, verbosity, pp); ++ LOG_MSG(1, pp); + + /* + * upon state change, reset the checkint +@@ -2321,7 +2320,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + /* Clear IO errors */ + reinstate_path(pp); + else { +- LOG_MSG(4, verbosity, pp); ++ LOG_MSG(4, pp); + if (pp->checkint != max_checkint) { + /* + * double the next check delay. +@@ -2349,9 +2348,9 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + log_checker_err = conf->log_checker_err; + put_multipath_config(conf); + if (log_checker_err == LOG_CHKR_ERR_ONCE) +- LOG_MSG(3, verbosity, pp); ++ LOG_MSG(3, pp); + else +- LOG_MSG(2, verbosity, pp); ++ LOG_MSG(2, pp); + } + } + +@@ -2696,6 +2695,10 @@ reconfigure (struct vectors * vecs) + if (!conf) + return 1; + ++ if (verbosity) ++ libmp_verbosity = verbosity; ++ setlogmask(LOG_UPTO(libmp_verbosity + 3)); ++ + /* + * free old map and path vectors ... they use old conf state + */ +@@ -2710,8 +2713,6 @@ reconfigure (struct vectors * vecs) + /* Re-read any timezone changes */ + tzset(); + +- if (verbosity) +- conf->verbosity = verbosity; + if (bindings_read_only) + conf->bindings_read_only = bindings_read_only; + check_alias_settings(conf); +@@ -3091,14 +3092,18 @@ child (__attribute__((unused)) void *param) + condlog(2, "--------start up--------"); + condlog(2, "read " DEFAULT_CONFIGFILE); + ++ if (verbosity) ++ libmp_verbosity = verbosity; + conf = load_config(DEFAULT_CONFIGFILE); ++ if (verbosity) ++ libmp_verbosity = verbosity; ++ setlogmask(LOG_UPTO(libmp_verbosity + 3)); ++ + if (!conf) { + condlog(0, "failed to load configuration"); + goto failed; + } + +- if (verbosity) +- conf->verbosity = verbosity; + if (bindings_read_only) + conf->bindings_read_only = bindings_read_only; + uxsock_timeout = conf->uxsock_timeout; +@@ -3117,7 +3122,6 @@ child (__attribute__((unused)) void *param) + + if (poll_dmevents) + poll_dmevents = dmevent_poll_supported(); +- setlogmask(LOG_UPTO(conf->verbosity + 3)); + + envp = getenv("LimitNOFILE"); + +@@ -3339,7 +3343,7 @@ main (int argc, char *argv[]) + !isdigit(optarg[0])) + exit(1); + +- verbosity = atoi(optarg); ++ libmp_verbosity = verbosity = atoi(optarg); + break; + case 's': + logsink = -1; +@@ -3350,7 +3354,7 @@ main (int argc, char *argv[]) + if (!conf) + exit(1); + if (verbosity) +- conf->verbosity = verbosity; ++ libmp_verbosity = verbosity; + uxsock_timeout = conf->uxsock_timeout; + err = uxclnt(optarg, uxsock_timeout + 100); + free_config(conf); +@@ -3376,11 +3380,13 @@ main (int argc, char *argv[]) + char * c = s; + + logsink = 0; ++ if (verbosity) ++ libmp_verbosity = verbosity; + conf = load_config(DEFAULT_CONFIGFILE); + if (!conf) + exit(1); + if (verbosity) +- conf->verbosity = verbosity; ++ libmp_verbosity = verbosity; + uxsock_timeout = conf->uxsock_timeout; + memset(cmd, 0x0, CMDSIZE); + while (optind < argc) { +diff --git a/tests/alias.c b/tests/alias.c +index 7fda679d..0311faa6 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -735,6 +735,7 @@ static int test_allocate_binding(void) + int main(void) + { + int ret = 0; ++ libmp_verbosity = conf.verbosity; + + ret += test_format_devname(); + ret += test_scan_devname(); +diff --git a/tests/blacklist.c b/tests/blacklist.c +index 84a3ba2f..0b42e255 100644 +--- a/tests/blacklist.c ++++ b/tests/blacklist.c +@@ -22,6 +22,7 @@ + #include "globals.c" + #include "blacklist.h" + #include "test-log.h" ++#include "debug.h" + + struct udev_device { + const char *sysname; +@@ -152,6 +153,7 @@ static int setup(void **state) + store_ble(blist_property_wwn_inv, "!ID_WWN", ORIGIN_CONFIG)) + return -1; + ++ libmp_verbosity = conf.verbosity = 4; + return 0; + } + +-- +2.17.2 + diff --git a/0063-libmultipath-introduce-symbolic-values-for-logsink.patch b/0063-libmultipath-introduce-symbolic-values-for-logsink.patch new file mode 100644 index 0000000..24cf615 --- /dev/null +++ b/0063-libmultipath-introduce-symbolic-values-for-logsink.patch @@ -0,0 +1,185 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 26 Sep 2020 00:32:05 +0200 +Subject: [PATCH] libmultipath: introduce symbolic values for logsink + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/debug.c | 4 ++-- + libmultipath/debug.h | 6 ++++++ + libmultipath/devmapper.c | 4 ++-- + multipath/main.c | 4 ++-- + multipathd/main.c | 17 ++++++++--------- + tests/globals.c | 3 ++- + tests/hwtable.c | 2 +- + 7 files changed, 23 insertions(+), 17 deletions(-) + +diff --git a/libmultipath/debug.c b/libmultipath/debug.c +index a1713b95..f9b77552 100644 +--- a/libmultipath/debug.c ++++ b/libmultipath/debug.c +@@ -25,8 +25,8 @@ void dlog (int sink, int prio, const char * fmt, ...) + va_start(ap, fmt); + + if (prio <= libmp_verbosity) { +- if (sink < 1) { +- if (sink == 0) { ++ if (sink != LOGSINK_SYSLOG) { ++ if (sink == LOGSINK_STDERR_WITH_TIME) { + time_t t = time(NULL); + struct tm *tb = localtime(&t); + char buff[16]; +diff --git a/libmultipath/debug.h b/libmultipath/debug.h +index 1f3bc8be..b6ce70a7 100644 +--- a/libmultipath/debug.h ++++ b/libmultipath/debug.h +@@ -12,3 +12,9 @@ extern int libmp_verbosity; + + #define condlog(prio, fmt, args...) \ + dlog(logsink, prio, fmt "\n", ##args) ++ ++enum { ++ LOGSINK_STDERR_WITH_TIME = 0, ++ LOGSINK_STDERR_WITHOUT_TIME = -1, ++ LOGSINK_SYSLOG = 1, ++}; +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index dfe95d2f..f8b180e1 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -104,8 +104,8 @@ dm_write_log (int level, const char *file, int line, const char *f, ...) + return; + + va_start(ap, f); +- if (logsink < 1) { +- if (logsink == 0) { ++ if (logsink != LOGSINK_SYSLOG) { ++ if (logsink == LOGSINK_STDERR_WITH_TIME) { + time_t t = time(NULL); + struct tm *tb = localtime(&t); + char buff[16]; +diff --git a/multipath/main.c b/multipath/main.c +index 98d93c58..9ac42869 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -817,7 +817,7 @@ main (int argc, char *argv[]) + libmultipath_init(); + if (atexit(dm_lib_exit) || atexit(libmultipath_exit)) + condlog(1, "failed to register cleanup handler for libmultipath: %m"); +- logsink = 0; ++ logsink = LOGSINK_STDERR_WITH_TIME; + if (init_config(DEFAULT_CONFIGFILE)) + exit(RTVL_FAIL); + if (atexit(uninit_config)) +@@ -968,7 +968,7 @@ main (int argc, char *argv[]) + if (dev_type == DEV_UEVENT) { + openlog("multipath", 0, LOG_DAEMON); + setlogmask(LOG_UPTO(libmp_verbosity + 3)); +- logsink = 1; ++ logsink = LOGSINK_SYSLOG; + } + + set_max_fds(conf->max_fds); +diff --git a/multipathd/main.c b/multipathd/main.c +index ba257515..867f0f84 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2780,7 +2780,7 @@ handle_signals(bool nonfatal) + } + if (log_reset_sig) { + condlog(2, "reset log (signal)"); +- if (logsink == 1) ++ if (logsink == LOGSINK_SYSLOG) + log_thread_reset(); + } + reconfig_sig = 0; +@@ -3033,7 +3033,7 @@ static void cleanup_child(void) + cleanup_dmevent_waiter(); + + cleanup_pidfile(); +- if (logsink == 1) ++ if (logsink == LOGSINK_SYSLOG) + log_thread_stop(); + + cleanup_conf(); +@@ -3076,7 +3076,7 @@ child (__attribute__((unused)) void *param) + setup_thread_attr(&uevent_attr, DEFAULT_UEVENT_STACKSIZE * 1024, 0); + setup_thread_attr(&waiter_attr, 32 * 1024, 1); + +- if (logsink == 1) { ++ if (logsink == LOGSINK_SYSLOG) { + setup_thread_attr(&log_attr, 64 * 1024, 0); + log_thread_start(&log_attr); + pthread_attr_destroy(&log_attr); +@@ -3307,7 +3307,7 @@ main (int argc, char *argv[]) + ANNOTATE_BENIGN_RACE_SIZED(&uxsock_timeout, sizeof(uxsock_timeout), + "Suppress complaints about this scalar variable"); + +- logsink = 1; ++ logsink = LOGSINK_SYSLOG; + + if (getuid() != 0) { + fprintf(stderr, "need to be root\n"); +@@ -3334,9 +3334,8 @@ main (int argc, char *argv[]) + switch(arg) { + case 'd': + foreground = 1; +- if (logsink > 0) +- logsink = 0; +- //debug=1; /* ### comment me out ### */ ++ if (logsink == LOGSINK_SYSLOG) ++ logsink = LOGSINK_STDERR_WITH_TIME; + break; + case 'v': + if (sizeof(optarg) > sizeof(char *) || +@@ -3346,7 +3345,7 @@ main (int argc, char *argv[]) + libmp_verbosity = verbosity = atoi(optarg); + break; + case 's': +- logsink = -1; ++ logsink = LOGSINK_STDERR_WITHOUT_TIME; + break; + case 'k': + logsink = 0; +@@ -3379,7 +3378,7 @@ main (int argc, char *argv[]) + char * s = cmd; + char * c = s; + +- logsink = 0; ++ logsink = LOGSINK_STDERR_WITH_TIME; + if (verbosity) + libmp_verbosity = verbosity; + conf = load_config(DEFAULT_CONFIGFILE); +diff --git a/tests/globals.c b/tests/globals.c +index 8add5eb7..fc0c07ad 100644 +--- a/tests/globals.c ++++ b/tests/globals.c +@@ -1,9 +1,10 @@ + #include "structs.h" + #include "config.h" ++#include "debug.h" + + /* Required globals */ + struct udev *udev; +-int logsink = -1; ++int logsink = LOGSINK_STDERR_WITHOUT_TIME; + struct config conf = { + .verbosity = 4, + }; +diff --git a/tests/hwtable.c b/tests/hwtable.c +index 57f832b7..4dd0873b 100644 +--- a/tests/hwtable.c ++++ b/tests/hwtable.c +@@ -53,7 +53,7 @@ struct hwt_state { + + static struct config *_conf; + struct udev *udev; +-int logsink = -1; ++int logsink = LOGSINK_STDERR_WITHOUT_TIME; + + struct config *get_multipath_config(void) + { +-- +2.17.2 + diff --git a/0064-libmultipath-simplify-dlog.patch b/0064-libmultipath-simplify-dlog.patch new file mode 100644 index 0000000..af47833 --- /dev/null +++ b/0064-libmultipath-simplify-dlog.patch @@ -0,0 +1,152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 26 Sep 2020 00:39:22 +0200 +Subject: [PATCH] libmultipath: simplify dlog() + +By checking the log level in condlog() directly, we can simplify +dlog(). Also, it's now possible to limit the log level at compile +time by setting MAX_VERBOSITY, enabling the compiler to optimize +away log messages with higher loglevel. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/debug.c | 30 +++++++++++++----------------- + libmultipath/debug.h | 20 ++++++++++++++++---- + libmultipath/devmapper.c | 4 +++- + tests/test-log.c | 4 ++-- + tests/test-log.h | 3 ++- + 5 files changed, 36 insertions(+), 25 deletions(-) + +diff --git a/libmultipath/debug.c b/libmultipath/debug.c +index f9b77552..429f2699 100644 +--- a/libmultipath/debug.c ++++ b/libmultipath/debug.c +@@ -18,29 +18,25 @@ + int logsink; + int libmp_verbosity = DEFAULT_VERBOSITY; + +-void dlog (int sink, int prio, const char * fmt, ...) ++void dlog(int prio, const char * fmt, ...) + { + va_list ap; + + va_start(ap, fmt); ++ if (logsink != LOGSINK_SYSLOG) { ++ if (logsink == LOGSINK_STDERR_WITH_TIME) { ++ time_t t = time(NULL); ++ struct tm *tb = localtime(&t); ++ char buff[16]; + +- if (prio <= libmp_verbosity) { +- if (sink != LOGSINK_SYSLOG) { +- if (sink == LOGSINK_STDERR_WITH_TIME) { +- time_t t = time(NULL); +- struct tm *tb = localtime(&t); +- char buff[16]; +- +- strftime(buff, sizeof(buff), +- "%b %d %H:%M:%S", tb); +- buff[sizeof(buff)-1] = '\0'; +- +- fprintf(stderr, "%s | ", buff); +- } +- vfprintf(stderr, fmt, ap); ++ strftime(buff, sizeof(buff), ++ "%b %d %H:%M:%S", tb); ++ buff[sizeof(buff)-1] = '\0'; ++ fprintf(stderr, "%s | ", buff); + } +- else +- log_safe(prio + 3, fmt, ap); ++ vfprintf(stderr, fmt, ap); + } ++ else ++ log_safe(prio + 3, fmt, ap); + va_end(ap); + } +diff --git a/libmultipath/debug.h b/libmultipath/debug.h +index b6ce70a7..705a5d73 100644 +--- a/libmultipath/debug.h ++++ b/libmultipath/debug.h +@@ -1,5 +1,7 @@ +-void dlog (int sink, int prio, const char * fmt, ...) +- __attribute__((format(printf, 3, 4))); ++#ifndef _DEBUG_H ++#define _DEBUG_H ++void dlog (int prio, const char *fmt, ...) ++ __attribute__((format(printf, 2, 3))); + + + #include +@@ -10,11 +12,21 @@ void dlog (int sink, int prio, const char * fmt, ...) + extern int logsink; + extern int libmp_verbosity; + +-#define condlog(prio, fmt, args...) \ +- dlog(logsink, prio, fmt "\n", ##args) ++#ifndef MAX_VERBOSITY ++#define MAX_VERBOSITY 4 ++#endif + + enum { + LOGSINK_STDERR_WITH_TIME = 0, + LOGSINK_STDERR_WITHOUT_TIME = -1, + LOGSINK_SYSLOG = 1, + }; ++ ++#define condlog(prio, fmt, args...) \ ++ do { \ ++ int __p = (prio); \ ++ \ ++ if (__p <= MAX_VERBOSITY && __p <= libmp_verbosity) \ ++ dlog(__p, fmt "\n", ##args); \ ++ } while (0) ++#endif /* _DEBUG_H */ +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index f8b180e1..4977b311 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -276,7 +276,9 @@ static int dm_tgt_prereq (unsigned int *ver) + + static void _init_versions(void) + { +- dlog(logsink, 3, VERSION_STRING); ++ /* Can't use condlog here because of how VERSION_STRING is defined */ ++ if (3 <= libmp_verbosity) ++ dlog(3, VERSION_STRING); + init_dm_library_version(); + init_dm_drv_version(); + init_dm_mpath_version(); +diff --git a/tests/test-log.c b/tests/test-log.c +index 1c901cba..14f25b9b 100644 +--- a/tests/test-log.c ++++ b/tests/test-log.c +@@ -7,8 +7,8 @@ + #include "log.h" + #include "test-log.h" + +-__attribute__((format(printf, 3, 0))) +-void __wrap_dlog (int sink, int prio, const char * fmt, ...) ++__attribute__((format(printf, 2, 0))) ++void __wrap_dlog (int prio, const char * fmt, ...) + { + char buff[MAX_MSG_SIZE]; + va_list ap; +diff --git a/tests/test-log.h b/tests/test-log.h +index 2c878c63..6d22cd23 100644 +--- a/tests/test-log.h ++++ b/tests/test-log.h +@@ -1,7 +1,8 @@ + #ifndef _TEST_LOG_H + #define _TEST_LOG_H + +-void __wrap_dlog (int sink, int prio, const char * fmt, ...); ++__attribute__((format(printf, 2, 0))) ++void __wrap_dlog (int prio, const char * fmt, ...); + void expect_condlog(int prio, char *string); + + #endif +-- +2.17.2 + diff --git a/0065-multipathd-common-code-for-k-and-command-args.patch b/0065-multipathd-common-code-for-k-and-command-args.patch new file mode 100644 index 0000000..1fc5a75 --- /dev/null +++ b/0065-multipathd-common-code-for-k-and-command-args.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 26 Sep 2020 00:43:12 +0200 +Subject: [PATCH] multipathd: common code for "-k" and command args + +'multipathd -k"cmd"' and 'multipath cmd' are the same thing. +Treat it with common code. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 37 +++++++++++++++++++------------------ + 1 file changed, 19 insertions(+), 18 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 867f0f84..b6a5f5b7 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3301,6 +3301,8 @@ main (int argc, char *argv[]) + int err; + int foreground = 0; + struct config *conf; ++ char *opt_k_arg = NULL; ++ bool opt_k = false; + + ANNOTATE_BENIGN_RACE_SIZED(&multipath_conf, sizeof(multipath_conf), + "Manipulated through RCU"); +@@ -3348,16 +3350,9 @@ main (int argc, char *argv[]) + logsink = LOGSINK_STDERR_WITHOUT_TIME; + break; + case 'k': +- logsink = 0; +- conf = load_config(DEFAULT_CONFIGFILE); +- if (!conf) +- exit(1); +- if (verbosity) +- libmp_verbosity = verbosity; +- uxsock_timeout = conf->uxsock_timeout; +- err = uxclnt(optarg, uxsock_timeout + 100); +- free_config(conf); +- return err; ++ opt_k = true; ++ opt_k_arg = optarg; ++ break; + case 'B': + bindings_read_only = 1; + break; +@@ -3373,7 +3368,7 @@ main (int argc, char *argv[]) + exit(1); + } + } +- if (optind < argc) { ++ if (opt_k || optind < argc) { + char cmd[CMDSIZE]; + char * s = cmd; + char * c = s; +@@ -3388,14 +3383,20 @@ main (int argc, char *argv[]) + libmp_verbosity = verbosity; + uxsock_timeout = conf->uxsock_timeout; + memset(cmd, 0x0, CMDSIZE); +- while (optind < argc) { +- if (strchr(argv[optind], ' ')) +- c += snprintf(c, s + CMDSIZE - c, "\"%s\" ", argv[optind]); +- else +- c += snprintf(c, s + CMDSIZE - c, "%s ", argv[optind]); +- optind++; ++ if (opt_k) ++ s = opt_k_arg; ++ else { ++ while (optind < argc) { ++ if (strchr(argv[optind], ' ')) ++ c += snprintf(c, s + CMDSIZE - c, ++ "\"%s\" ", argv[optind]); ++ else ++ c += snprintf(c, s + CMDSIZE - c, ++ "%s ", argv[optind]); ++ optind++; ++ } ++ c += snprintf(c, s + CMDSIZE - c, "\n"); + } +- c += snprintf(c, s + CMDSIZE - c, "\n"); + err = uxclnt(s, uxsock_timeout + 100); + free_config(conf); + return err; +-- +2.17.2 + diff --git a/0066-multipathd-sanitize-uxsock_listen.patch b/0066-multipathd-sanitize-uxsock_listen.patch new file mode 100644 index 0000000..d7efc72 --- /dev/null +++ b/0066-multipathd-sanitize-uxsock_listen.patch @@ -0,0 +1,157 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 26 Sep 2020 15:22:34 +0200 +Subject: [PATCH] multipathd: sanitize uxsock_listen() + +We were allocating 1025 poll fds, which is weird. Change it to a power of two, +and make this more easily customizable in general. Use POLLFDS_BASE rather +than the hard-coded "2" for the number of fds we poll besides client +connections. Introduce a maximum number of clients that can connect. When +this number is reached, we simply stop polling the accept socket, so that new +connections aren't accepted any more. Don't attempt to realloc() the pollfd +array if the number of clients decreases. It's unlikely to ever be more than +one or two pages. Finally, there's no need to wake up every 5s. Our signal +handling is robust. Just sleep forever in ppoll() if nothing happens. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/uxlsnr.c | 70 ++++++++++++++++++++++++++++----------------- + 1 file changed, 43 insertions(+), 27 deletions(-) + +diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c +index ce2b6800..cd462b6d 100644 +--- a/multipathd/uxlsnr.c ++++ b/multipathd/uxlsnr.c +@@ -41,14 +41,25 @@ + #include "cli.h" + #include "uxlsnr.h" + +-static struct timespec sleep_time = {5, 0}; +- + struct client { + struct list_head node; + int fd; + }; + +-#define MIN_POLLS 1023 ++/* The number of fds we poll on, other than individual client connections */ ++#define POLLFDS_BASE 2 ++#define POLLFD_CHUNK (4096 / sizeof(struct pollfd)) ++/* Minimum mumber of pollfds to reserve for clients */ ++#define MIN_POLLS (POLLFD_CHUNK - POLLFDS_BASE) ++/* ++ * Max number of client connections allowed ++ * During coldplug, there may be a large number of "multipath -u" ++ * processes connecting. ++ */ ++#define MAX_CLIENTS (16384 - POLLFDS_BASE) ++ ++/* Compile-time error if POLLFD_CHUNK is too small */ ++static __attribute__((unused)) char ___a[-(MIN_POLLS <= 0)]; + + static LIST_HEAD(clients); + static pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER; +@@ -282,13 +293,13 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + char *inbuf; + char *reply; + sigset_t mask; +- int old_clients = MIN_POLLS; ++ int max_pfds = MIN_POLLS + POLLFDS_BASE; + /* 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 }; + + condlog(3, "uxsock: startup listener"); +- polls = (struct pollfd *)MALLOC((MIN_POLLS + 2) * sizeof(struct pollfd)); ++ polls = MALLOC(max_pfds * sizeof(*polls)); + if (!polls) { + condlog(0, "uxsock: failed to allocate poll fds"); + exit_daemon(); +@@ -312,28 +323,33 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + list_for_each_entry(c, &clients, node) { + num_clients++; + } +- if (num_clients != old_clients) { ++ if (num_clients + POLLFDS_BASE > max_pfds) { + struct pollfd *new; +- if (num_clients <= MIN_POLLS && old_clients > MIN_POLLS) { +- new = REALLOC(polls, (2 + MIN_POLLS) * +- sizeof(struct pollfd)); +- } else if (num_clients <= MIN_POLLS && old_clients <= MIN_POLLS) { +- new = polls; +- } else { +- new = REALLOC(polls, (2 + num_clients) * +- sizeof(struct pollfd)); +- } +- if (!new) { +- condlog(0, "%s: failed to realloc %d poll fds", +- "uxsock", 2 + num_clients); +- num_clients = old_clients; +- } else { +- old_clients = num_clients; ++ int n_new = max_pfds + POLLFD_CHUNK; ++ ++ new = REALLOC(polls, n_new * sizeof(*polls)); ++ if (new) { ++ max_pfds = n_new; + polls = new; ++ } else { ++ condlog(1, "%s: realloc failure, %d clients not served", ++ __func__, ++ num_clients + POLLFDS_BASE - max_pfds); ++ num_clients = max_pfds - POLLFDS_BASE; + } + } +- polls[0].fd = ux_sock; +- polls[0].events = POLLIN; ++ if (num_clients < MAX_CLIENTS) { ++ polls[0].fd = ux_sock; ++ polls[0].events = POLLIN; ++ } else { ++ /* ++ * New clients can't connect, num_clients won't grow ++ * to MAX_CLIENTS or higher ++ */ ++ condlog(1, "%s: max client connections reached, pausing polling", ++ __func__); ++ polls[0].fd = -1; ++ } + + reset_watch(notify_fd, &wds, &sequence_nr); + if (notify_fd == -1 || (wds.conf_wd == -1 && wds.dir_wd == -1)) +@@ -343,19 +359,19 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + polls[1].events = POLLIN; + + /* setup the clients */ +- i = 2; ++ i = POLLFDS_BASE; + list_for_each_entry(c, &clients, node) { + polls[i].fd = c->fd; + polls[i].events = POLLIN; + i++; +- if (i >= 2 + num_clients) ++ if (i >= max_pfds) + break; + } + n_pfds = i; + pthread_cleanup_pop(1); + + /* most of our life is spent in this call */ +- poll_count = ppoll(polls, n_pfds, &sleep_time, &mask); ++ poll_count = ppoll(polls, n_pfds, NULL, &mask); + + handle_signals(false); + if (poll_count == -1) { +@@ -388,7 +404,7 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + } + + /* see if a client wants to speak to us */ +- for (i = 2; i < n_pfds; i++) { ++ for (i = POLLFDS_BASE; i < n_pfds; i++) { + if (polls[i].revents & POLLIN) { + struct timespec start_time; + +-- +2.17.2 + diff --git a/0067-libmultipath-fix-race-between-log_safe-and-log_threa.patch b/0067-libmultipath-fix-race-between-log_safe-and-log_threa.patch new file mode 100644 index 0000000..29f5ce7 --- /dev/null +++ b/0067-libmultipath-fix-race-between-log_safe-and-log_threa.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 15 Oct 2020 16:13:14 +0200 +Subject: [PATCH] libmultipath: fix race between log_safe and log_thread_stop() + +log_safe() could race with log_thread_stop(); simply +checking the value of log_thr has never been safe. By converting the +mutexes to static initializers, we avoid having to destroy them, and thus +possibly accessing a destroyed mutex in log_safe(). Furthermore, taking +both the logev_lock and the logq_lock makes sure the logarea isn't freed +while we are writing to it. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log_pthread.c | 48 +++++++++++++++++++++----------------- + 1 file changed, 26 insertions(+), 22 deletions(-) + +diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c +index 3a2566ae..0d48c52c 100644 +--- a/libmultipath/log_pthread.c ++++ b/libmultipath/log_pthread.c +@@ -17,31 +17,42 @@ + + static pthread_t log_thr; + +-static pthread_mutex_t logq_lock; +-static pthread_mutex_t logev_lock; +-static pthread_cond_t logev_cond; ++/* logev_lock must not be taken with logq_lock held */ ++static pthread_mutex_t logq_lock = PTHREAD_MUTEX_INITIALIZER; ++static pthread_mutex_t logev_lock = PTHREAD_MUTEX_INITIALIZER; ++static pthread_cond_t logev_cond = PTHREAD_COND_INITIALIZER; + + static int logq_running; + static int log_messages_pending; + + void log_safe (int prio, const char * fmt, va_list ap) + { ++ bool running; ++ + if (prio > LOG_DEBUG) + prio = LOG_DEBUG; + +- if (log_thr == (pthread_t)0) { +- vsyslog(prio, fmt, ap); +- return; +- } ++ /* ++ * logev_lock protects logq_running. By holding it, we avoid a race ++ * with log_thread_stop() -> log_close(), which would free the logarea. ++ */ ++ pthread_mutex_lock(&logev_lock); ++ pthread_cleanup_push(cleanup_mutex, &logev_lock); ++ running = logq_running; + +- pthread_mutex_lock(&logq_lock); +- log_enqueue(prio, fmt, ap); +- pthread_mutex_unlock(&logq_lock); ++ if (running) { ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ log_enqueue(prio, fmt, ap); ++ pthread_cleanup_pop(1); + +- pthread_mutex_lock(&logev_lock); +- log_messages_pending = 1; +- pthread_cond_signal(&logev_cond); +- pthread_mutex_unlock(&logev_lock); ++ log_messages_pending = 1; ++ pthread_cond_signal(&logev_cond); ++ } ++ pthread_cleanup_pop(1); ++ ++ if (!running) ++ vsyslog(prio, fmt, ap); + } + + static void flush_logqueue (void) +@@ -103,9 +114,6 @@ void log_thread_start (pthread_attr_t *attr) + int running = 0; + + logdbg(stderr,"enter log_thread_start\n"); +- pthread_mutex_init(&logq_lock, NULL); +- pthread_mutex_init(&logev_lock, NULL); +- pthread_cond_init(&logev_cond, NULL); + + if (log_init("multipathd", 0)) { + fprintf(stderr,"can't initialize log buffer\n"); +@@ -154,13 +162,9 @@ void log_thread_stop (void) + } + pthread_cleanup_pop(1); + +- flush_logqueue(); + if (running) + pthread_join(log_thr, NULL); + +- pthread_mutex_destroy(&logq_lock); +- pthread_mutex_destroy(&logev_lock); +- pthread_cond_destroy(&logev_cond); +- ++ flush_logqueue(); + log_close(); + } +-- +2.17.2 + diff --git a/0068-multipath-add-libmpathvalid-library.patch b/0068-multipath-add-libmpathvalid-library.patch new file mode 100644 index 0000000..24ba4ac --- /dev/null +++ b/0068-multipath-add-libmpathvalid-library.patch @@ -0,0 +1,505 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Wed, 21 Oct 2020 16:39:23 -0500 +Subject: [PATCH] multipath: add libmpathvalid library + +This library allows other programs to check if a path should be claimed +by multipath. It exports an init function, that needs to be called +before and after all other library calls, an exit function, that needs +to be called after all library calls, a function to reread the multipath +configuration files, and two more functions. + +mpath_get_mode() get the configured find_multipaths mode. +mpath_is_path() returns whether the device is claimed by multipath, and +optionally returns the wwid. This code works slightly different than +the multipath -c/u code for SMART mode. Instead of checking all the +existing paths to see if another has the same wwid, it expects the +caller to pass in an array of the already known path wwids, and checks +if the current path matches any of those. + +The library also doesn't set up the device-mapper library. It leaves +this up to the caller. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + Makefile | 3 +- + libmpathvalid/Makefile | 39 ++++++ + libmpathvalid/libmpathvalid.version | 10 ++ + libmpathvalid/mpath_valid.c | 202 ++++++++++++++++++++++++++++ + libmpathvalid/mpath_valid.h | 155 +++++++++++++++++++++ + libmultipath/libmultipath.version | 6 + + 6 files changed, 414 insertions(+), 1 deletion(-) + create mode 100644 libmpathvalid/Makefile + create mode 100644 libmpathvalid/libmpathvalid.version + create mode 100644 libmpathvalid/mpath_valid.c + create mode 100644 libmpathvalid/mpath_valid.h + +diff --git a/Makefile b/Makefile +index 4a3491da..f127ff91 100644 +--- a/Makefile ++++ b/Makefile +@@ -9,6 +9,7 @@ BUILDDIRS := \ + libmultipath/checkers \ + libmultipath/foreign \ + libmpathpersist \ ++ libmpathvalid \ + multipath \ + multipathd \ + mpathpersist \ +@@ -29,7 +30,7 @@ $(BUILDDIRS): + $(MAKE) -C $@ + + libmultipath libdmmp: libmpathcmd +-libmpathpersist multipath multipathd: libmultipath ++libmpathpersist libmpathvalid multipath multipathd: libmultipath + mpathpersist multipathd: libmpathpersist + + libmultipath/checkers.install \ +diff --git a/libmpathvalid/Makefile b/libmpathvalid/Makefile +new file mode 100644 +index 00000000..6bea4bcd +--- /dev/null ++++ b/libmpathvalid/Makefile +@@ -0,0 +1,39 @@ ++include ../Makefile.inc ++ ++SONAME = 0 ++DEVLIB = libmpathvalid.so ++LIBS = $(DEVLIB).$(SONAME) ++VERSION_SCRIPT := libmpathvalid.version ++ ++CFLAGS += $(LIB_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) ++ ++LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) \ ++ -lmultipath -L$(mpathcmddir) -lmpathcmd -ludev ++ ++OBJS = mpath_valid.o ++ ++all: $(LIBS) ++ ++$(LIBS): $(OBJS) $(VERSION_SCRIPT) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) -Wl,--version-script=libmpathvalid.version ++ $(LN) $(LIBS) $(DEVLIB) ++ ++install: $(LIBS) ++ $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir) ++ $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) ++ $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) ++ $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(includedir) ++ $(INSTALL_PROGRAM) -m 644 mpath_valid.h $(DESTDIR)$(includedir) ++ ++uninstall: ++ $(RM) $(DESTDIR)$(syslibdir)/$(LIBS) ++ $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB) ++ $(RM) $(DESTDIR)$(includedir)/mpath_valid.h ++ ++clean: dep_clean ++ $(RM) core *.a *.o *.so *.so.* *.gz ++ ++include $(wildcard $(OBJS:.o=.d)) ++ ++dep_clean: ++ $(RM) $(OBJS:.o=.d) +diff --git a/libmpathvalid/libmpathvalid.version b/libmpathvalid/libmpathvalid.version +new file mode 100644 +index 00000000..3bd0d3c5 +--- /dev/null ++++ b/libmpathvalid/libmpathvalid.version +@@ -0,0 +1,10 @@ ++MPATH_1.0 { ++ global: ++ mpathvalid_init; ++ mpathvalid_reload_config; ++ mpathvalid_exit; ++ mpathvalid_is_path; ++ mpathvalid_get_mode; ++ local: ++ *; ++}; +diff --git a/libmpathvalid/mpath_valid.c b/libmpathvalid/mpath_valid.c +new file mode 100644 +index 00000000..7073d17d +--- /dev/null ++++ b/libmpathvalid/mpath_valid.c +@@ -0,0 +1,202 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "devmapper.h" ++#include "structs.h" ++#include "util.h" ++#include "config.h" ++#include "discovery.h" ++#include "wwids.h" ++#include "sysfs.h" ++#include "mpath_cmd.h" ++#include "valid.h" ++#include "mpath_valid.h" ++#include "debug.h" ++ ++static unsigned int ++get_conf_mode(struct config *conf) ++{ ++ if (conf->find_multipaths == FIND_MULTIPATHS_SMART) ++ return MPATH_SMART; ++ if (conf->find_multipaths == FIND_MULTIPATHS_GREEDY) ++ return MPATH_GREEDY; ++ return MPATH_STRICT; ++} ++ ++static void ++set_conf_mode(struct config *conf, unsigned int mode) ++{ ++ if (mode == MPATH_SMART) ++ conf->find_multipaths = FIND_MULTIPATHS_SMART; ++ else if (mode == MPATH_GREEDY) ++ conf->find_multipaths = FIND_MULTIPATHS_GREEDY; ++ else ++ conf->find_multipaths = FIND_MULTIPATHS_STRICT; ++} ++ ++unsigned int ++mpathvalid_get_mode(void) ++{ ++ int mode; ++ struct config *conf; ++ ++ conf = get_multipath_config(); ++ if (!conf) ++ mode = MPATH_MODE_ERROR; ++ else ++ mode = get_conf_mode(conf); ++ put_multipath_config(conf); ++ return mode; ++} ++ ++static int ++convert_result(int result) { ++ switch (result) { ++ case PATH_IS_ERROR: ++ return MPATH_IS_ERROR; ++ case PATH_IS_NOT_VALID: ++ return MPATH_IS_NOT_VALID; ++ case PATH_IS_VALID: ++ return MPATH_IS_VALID; ++ case PATH_IS_VALID_NO_CHECK: ++ return MPATH_IS_VALID_NO_CHECK; ++ case PATH_IS_MAYBE_VALID: ++ return MPATH_IS_MAYBE_VALID; ++ } ++ return MPATH_IS_ERROR; ++} ++ ++static void ++set_log_style(int log_style) ++{ ++ /* ++ * convert MPATH_LOG_* to LOGSINK_* ++ * currently there is no work to do here. ++ */ ++ logsink = log_style; ++} ++ ++static int ++load_default_config(int verbosity) ++{ ++ /* need to set verbosity here to control logging during init_config() */ ++ libmp_verbosity = verbosity; ++ if (init_config(DEFAULT_CONFIGFILE)) ++ return -1; ++ /* Need to override verbosity from init_config() */ ++ libmp_verbosity = verbosity; ++ ++ return 0; ++} ++ ++int ++mpathvalid_init(int verbosity, int log_style) ++{ ++ unsigned int version[3]; ++ ++ set_log_style(log_style); ++ if (libmultipath_init()) ++ return -1; ++ ++ skip_libmp_dm_init(); ++ if (load_default_config(verbosity)) ++ goto fail; ++ ++ if (dm_prereq(version)) ++ goto fail_config; ++ ++ return 0; ++ ++fail_config: ++ uninit_config(); ++fail: ++ libmultipath_exit(); ++ return -1; ++} ++ ++int ++mpathvalid_reload_config(void) ++{ ++ uninit_config(); ++ return load_default_config(libmp_verbosity); ++} ++ ++int ++mpathvalid_exit(void) ++{ ++ uninit_config(); ++ libmultipath_exit(); ++ return 0; ++} ++ ++/* ++ * name: name of path to check ++ * mode: mode to use for determination. MPATH_DEFAULT uses configured mode ++ * info: on success, contains the path wwid ++ * paths: array of the returned mpath_info from other claimed paths ++ * nr_paths: the size of the paths array ++ */ ++int ++mpathvalid_is_path(const char *name, unsigned int mode, char **wwid, ++ const char **path_wwids, unsigned int nr_paths) ++{ ++ struct config *conf; ++ int find_multipaths_saved, r = MPATH_IS_ERROR; ++ unsigned int i; ++ struct path *pp; ++ ++ if (!name || mode >= MPATH_MODE_ERROR) ++ return r; ++ if (nr_paths > 0 && !path_wwids) ++ return r; ++ if (!udev) ++ return r; ++ ++ pp = alloc_path(); ++ if (!pp) ++ return r; ++ ++ if (wwid) { ++ *wwid = (char *)malloc(WWID_SIZE); ++ if (!*wwid) ++ goto out; ++ } ++ ++ conf = get_multipath_config(); ++ if (!conf) ++ goto out_wwid; ++ find_multipaths_saved = conf->find_multipaths; ++ if (mode != MPATH_DEFAULT) ++ set_conf_mode(conf, mode); ++ r = convert_result(is_path_valid(name, conf, pp, true)); ++ conf->find_multipaths = find_multipaths_saved; ++ put_multipath_config(conf); ++ ++ if (r == MPATH_IS_MAYBE_VALID) { ++ for (i = 0; i < nr_paths; i++) { ++ if (path_wwids[i] && ++ strncmp(path_wwids[i], pp->wwid, WWID_SIZE) == 0) { ++ r = MPATH_IS_VALID; ++ break; ++ } ++ } ++ } ++ ++out_wwid: ++ if (wwid) { ++ if (r == MPATH_IS_VALID || r == MPATH_IS_VALID_NO_CHECK || ++ r == MPATH_IS_MAYBE_VALID) ++ strlcpy(*wwid, pp->wwid, WWID_SIZE); ++ else { ++ free(*wwid); ++ *wwid = NULL; ++ } ++ } ++out: ++ free_path(pp); ++ return r; ++} +diff --git a/libmpathvalid/mpath_valid.h b/libmpathvalid/mpath_valid.h +new file mode 100644 +index 00000000..63de4e1c +--- /dev/null ++++ b/libmpathvalid/mpath_valid.h +@@ -0,0 +1,155 @@ ++/* ++ * Copyright (C) 2015 Red Hat, Inc. ++ * ++ * This file is part of the device-mapper multipath userspace tools. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program. If not, see . ++ */ ++ ++#ifndef LIB_MPATH_VALID_H ++#define LIB_MPATH_VALID_H ++ ++#ifdef __cpluscplus ++extern "C" { ++#endif ++ ++enum mpath_valid_mode { ++ MPATH_DEFAULT, ++ MPATH_STRICT, ++ MPATH_SMART, ++ MPATH_GREEDY, ++ MPATH_MODE_ERROR, ++}; ++ ++/* ++ * MPATH_IS_VALID_NO_CHECK is used to indicate that it is safe to skip ++ * checks to see if the device has already been released to the system ++ * for use by things other that multipath. ++ * MPATH_IS_MAYBE_VALID is used to indicate that this device would ++ * be a valid multipath path device if another device with the same ++ * wwid existed */ ++enum mpath_valid_result { ++ MPATH_IS_ERROR = -1, ++ MPATH_IS_NOT_VALID, ++ MPATH_IS_VALID, ++ MPATH_IS_VALID_NO_CHECK, ++ MPATH_IS_MAYBE_VALID, ++}; ++ ++enum mpath_valid_log_style { ++ MPATH_LOG_STDERR = -1, /* log to STDERR */ ++ MPATH_LOG_STDERR_TIMESTAMP, /* log to STDERR, with timestamps */ ++ MPATH_LOG_SYSLOG, /* log to system log */ ++}; ++ ++enum mpath_valid_verbosity { ++ MPATH_LOG_PRIO_NOLOG = -1, /* log nothing */ ++ MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_PRIO_WARN, ++ MPATH_LOG_PRIO_NOTICE, ++ MPATH_LOG_PRIO_INFO, ++ MPATH_LOG_PRIO_DEBUG, ++}; ++ ++/* Function declarations */ ++ ++/* ++ * DESCRIPTION: ++ * Initialize the device mapper multipath configuration. This ++ * function must be invoked before calling any other ++ * libmpathvalid functions. Call mpathvalid_exit() to cleanup. ++ * @verbosity: the logging level (mpath_valid_verbosity) ++ * @log_style: the logging style (mpath_valid_log_style) ++ * ++ * RESTRICTIONS: ++ * Calling mpathvalid_init() after calling mpathvalid_exit() has no ++ * effect. ++ * ++ * RETURNS: 0 = Success, -1 = Failure ++ */ ++int mpathvalid_init(int verbosity, int log_style); ++ ++ ++/* ++ * DESCRIPTION: ++ * Reread the multipath configuration files and reinitalize ++ * the device mapper multipath configuration. This function can ++ * be called as many times as necessary. ++ * ++ * RETURNS: 0 = Success, -1 = Failure ++ */ ++int mpathvalid_reload_config(void); ++ ++ ++/* ++ * DESCRIPTION: ++ * Release the device mapper multipath configuration. This ++ * function must be called to cleanup resoures allocated by ++ * mpathvalid_init(). After calling this function, no futher ++ * libmpathvalid functions may be called. ++ * ++ * RETURNS: 0 = Success, -1 = Failure ++ */ ++int mpathvalid_exit(void); ++ ++/* ++ * DESCRIPTION: ++ * Return the configured find_multipaths claim mode, using the ++ * configuration from either mpathvalid_init() or ++ * mpathvalid_reload_config() ++ * ++ * RETURNS: ++ * MPATH_STRICT, MPATH_SMART, MPATH_GREEDY, or MPATH_MODE_ERROR ++ * ++ * MPATH_STRICT = find_multiapths (yes|on|no|off) ++ * MPATH_SMART = find_multipaths smart ++ * MPATH_GREEDY = find_multipaths greedy ++ * MPATH_MODE_ERROR = multipath configuration not initialized ++ */ ++unsigned int mpathvalid_get_mode(void); ++/* ++ * DESCRIPTION: ++ * Return whether device-mapper multipath claims a path device, ++ * using the configuration read from either mpathvalid_init() or ++ * mpathvalid_reload_config(). If the device is either claimed or ++ * potentially claimed (MPATH_IS_VALID, MPATH_IS_VALID_NO_CHECK, ++ * or MPATH_IS_MAYBE_VALID) and wwid is not NULL, then *wiid will ++ * be set to point to the wwid of device. If set, *wwid must be ++ * freed by the caller. path_wwids is an obptional parameter that ++ * points to an array of wwids, that were returned from previous ++ * calls to mpathvalid_is_path(). These are wwids of existing ++ * devices that are or potentially are claimed by device-mapper ++ * multipath. path_wwids is used with the MPATH_SMART claim mode, ++ * to claim devices when another device with the same wwid exists. ++ * nr_paths must either be set to the number of elements of ++ * path_wwids, or 0, if path_wwids is NULL. ++ * @name: The kernel name of the device. input argument ++ * @mode: the find_multipaths claim mode (mpath_valid_mode). input argument ++ * @wwid: address of a pointer to the path wwid, or NULL. Output argument. ++ * Set if path is/may be claimed. If set, must be freed by caller ++ * @path_wwids: Array of pointers to path wwids, or NULL. input argument ++ * @nr_paths: number of elements in path_wwids array. input argument. ++ * ++ * RETURNS: device claim result (mpath_valid_result) ++ * Also sets *wwid if wwid is not NULL, and the claim result is ++ * MPATH_IS_VALID, MPATH_IS_VALID_NO_CHECK, or ++ * MPATH_IS_MAYBE_VALID ++ */ ++int mpathvalid_is_path(const char *name, unsigned int mode, char **wwid, ++ const char **path_wwids, unsigned int nr_paths); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif /* LIB_PATH_VALID_H */ +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 67a7379f..2e3583f5 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -264,3 +264,9 @@ LIBMULTIPATH_4.1.0 { + global: + libmp_verbosity; + } LIBMULTIPATH_4.0.0; ++ ++LIBMULTIPATH_4.2.0 { ++global: ++ dm_prereq; ++ skip_libmp_dm_init; ++} LIBMULTIPATH_4.1.0; +-- +2.17.2 + diff --git a/0069-multipath-tools-tests-and-unit-tests-for-libmpathval.patch b/0069-multipath-tools-tests-and-unit-tests-for-libmpathval.patch new file mode 100644 index 0000000..cd24d4e --- /dev/null +++ b/0069-multipath-tools-tests-and-unit-tests-for-libmpathval.patch @@ -0,0 +1,532 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Wed, 21 Oct 2020 16:39:24 -0500 +Subject: [PATCH] multipath-tools tests: and unit tests for libmpathvalid + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + Makefile.inc | 1 + + tests/Makefile | 5 +- + tests/mpathvalid.c | 467 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 472 insertions(+), 1 deletion(-) + create mode 100644 tests/mpathvalid.c + +diff --git a/Makefile.inc b/Makefile.inc +index e05f3a91..13587a9f 100644 +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -66,6 +66,7 @@ libdir = $(prefix)/$(LIB)/multipath + unitdir = $(prefix)/$(SYSTEMDPATH)/systemd/system + mpathpersistdir = $(TOPDIR)/libmpathpersist + mpathcmddir = $(TOPDIR)/libmpathcmd ++mpathvaliddir = $(TOPDIR)/libmpathvalid + thirdpartydir = $(TOPDIR)/third-party + libdmmpdir = $(TOPDIR)/libdmmp + nvmedir = $(TOPDIR)/libmultipath/nvme +diff --git a/tests/Makefile b/tests/Makefile +index 908407ea..54da774e 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -13,7 +13,7 @@ CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) \ + LIBDEPS += -L. -L$(mpathcmddir) -lmultipath -lmpathcmd -lcmocka + + TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \ +- alias directio valid devt ++ alias directio valid devt mpathvalid + HELPERS := test-lib.o test-log.o + + .SILENT: $(TESTS:%=%.o) +@@ -31,6 +31,7 @@ endif + ifneq ($(DIO_TEST_DEV),) + directio-test_FLAGS := -DDIO_TEST_DEV=\"$(DIO_TEST_DEV)\" + endif ++mpathvalid-test_FLAGS := -I$(mpathvaliddir) + + # test-specific linker flags + # XYZ-test_TESTDEPS: test libraries containing __wrap_xyz functions +@@ -56,6 +57,8 @@ alias-test_LIBDEPS := -lpthread -ldl + valid-test_OBJDEPS := ../libmultipath/valid.o + valid-test_LIBDEPS := -ludev -lpthread -ldl + devt-test_LIBDEPS := -ludev ++mpathvalid-test_LIBDEPS := -ludev -lpthread -ldl ++mpathvalid-test_OBJDEPS := ../libmpathvalid/mpath_valid.o + ifneq ($(DIO_TEST_DEV),) + directio-test_LIBDEPS := -laio + endif +diff --git a/tests/mpathvalid.c b/tests/mpathvalid.c +new file mode 100644 +index 00000000..5ffabb9d +--- /dev/null ++++ b/tests/mpathvalid.c +@@ -0,0 +1,467 @@ ++/* ++ * Copyright (c) 2020 Benjamin Marzinski, Red Hat ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "structs.h" ++#include "config.h" ++#include "mpath_valid.h" ++#include "util.h" ++#include "debug.h" ++ ++const char *test_dev = "test_name"; ++#define TEST_WWID "WWID_123" ++#define CONF_TEMPLATE "mpathvalid-testconf-XXXXXXXX" ++char conf_name[] = CONF_TEMPLATE; ++bool initialized; ++ ++#if 0 ++static int mode_to_findmp(unsigned int mode) ++{ ++ switch (mode) { ++ case MPATH_SMART: ++ return FIND_MULTIPATHS_SMART; ++ case MPATH_GREEDY: ++ return FIND_MULTIPATHS_GREEDY; ++ case MPATH_STRICT: ++ return FIND_MULTIPATHS_STRICT; ++ } ++ fail_msg("invalid mode: %u", mode); ++ return FIND_MULTIPATHS_UNDEF; ++} ++#endif ++ ++static unsigned int findmp_to_mode(int findmp) ++{ ++ switch (findmp) { ++ case FIND_MULTIPATHS_SMART: ++ return MPATH_SMART; ++ case FIND_MULTIPATHS_GREEDY: ++ return MPATH_GREEDY; ++ case FIND_MULTIPATHS_STRICT: ++ case FIND_MULTIPATHS_OFF: ++ case FIND_MULTIPATHS_ON: ++ return MPATH_STRICT; ++ } ++ fail_msg("invalid find_multipaths value: %d", findmp); ++ return MPATH_DEFAULT; ++} ++ ++int __wrap_is_path_valid(const char *name, struct config *conf, struct path *pp, ++ bool check_multipathd) ++{ ++ int r = mock_type(int); ++ int findmp = mock_type(int); ++ ++ assert_ptr_equal(name, test_dev); ++ assert_ptr_not_equal(conf, NULL); ++ assert_ptr_not_equal(pp, NULL); ++ assert_true(check_multipathd); ++ ++ assert_int_equal(findmp, conf->find_multipaths); ++ if (r == MPATH_IS_ERROR || r == MPATH_IS_NOT_VALID) ++ return r; ++ ++ strlcpy(pp->wwid, mock_ptr_type(char *), WWID_SIZE); ++ return r; ++} ++ ++int __wrap_libmultipath_init(void) ++{ ++ int r = mock_type(int); ++ ++ assert_false(initialized); ++ if (r != 0) ++ return r; ++ initialized = true; ++ return 0; ++} ++ ++void __wrap_libmultipath_exit(void) ++{ ++ assert_true(initialized); ++ initialized = false; ++} ++ ++int __wrap_dm_prereq(unsigned int *v) ++{ ++ assert_ptr_not_equal(v, NULL); ++ return mock_type(int); ++} ++ ++int __real_init_config(const char *file); ++ ++int __wrap_init_config(const char *file) ++{ ++ int r = mock_type(int); ++ struct config *conf; ++ ++ assert_ptr_equal(file, DEFAULT_CONFIGFILE); ++ if (r != 0) ++ return r; ++ ++ assert_string_not_equal(conf_name, CONF_TEMPLATE); ++ r = __real_init_config(conf_name); ++ conf = get_multipath_config(); ++ assert_ptr_not_equal(conf, NULL); ++ assert_int_equal(conf->find_multipaths, mock_type(int)); ++ return 0; ++} ++ ++static const char * const find_multipaths_optvals[] = { ++ [FIND_MULTIPATHS_OFF] = "off", ++ [FIND_MULTIPATHS_ON] = "on", ++ [FIND_MULTIPATHS_STRICT] = "strict", ++ [FIND_MULTIPATHS_GREEDY] = "greedy", ++ [FIND_MULTIPATHS_SMART] = "smart", ++}; ++ ++void make_config_file(int findmp) ++{ ++ int r, fd; ++ char buf[64]; ++ ++ assert_true(findmp > FIND_MULTIPATHS_UNDEF && ++ findmp < __FIND_MULTIPATHS_LAST); ++ ++ r = snprintf(buf, sizeof(buf), "defaults {\nfind_multipaths %s\n}\n", ++ find_multipaths_optvals[findmp]); ++ assert_true(r > 0 && (long unsigned int)r < sizeof(buf)); ++ ++ memcpy(conf_name, CONF_TEMPLATE, sizeof(conf_name)); ++ fd = mkstemp(conf_name); ++ assert_true(fd >= 0); ++ assert_int_equal(safe_write(fd, buf, r), 0); ++ assert_int_equal(close(fd), 0); ++} ++ ++int setup(void **state) ++{ ++ initialized = false; ++ udev = udev_new(); ++ if (udev == NULL) ++ return -1; ++ return 0; ++} ++ ++int teardown(void **state) ++{ ++ struct config *conf; ++ conf = get_multipath_config(); ++ put_multipath_config(conf); ++ if (conf) ++ uninit_config(); ++ if (strcmp(conf_name, CONF_TEMPLATE) != 0) ++ unlink(conf_name); ++ udev_unref(udev); ++ udev = NULL; ++ return 0; ++} ++ ++static void check_config(bool valid_config) ++{ ++ struct config *conf; ++ ++ conf = get_multipath_config(); ++ put_multipath_config(conf); ++ if (valid_config) ++ assert_ptr_not_equal(conf, NULL); ++} ++ ++/* libmultipath_init fails */ ++static void test_mpathvalid_init_bad1(void **state) ++{ ++ will_return(__wrap_libmultipath_init, 1); ++ assert_int_equal(mpathvalid_init(MPATH_LOG_PRIO_DEBUG, ++ MPATH_LOG_STDERR), -1); ++ assert_false(initialized); ++ check_config(false); ++} ++ ++/* init_config fails */ ++static void test_mpathvalid_init_bad2(void **state) ++{ ++ will_return(__wrap_libmultipath_init, 0); ++ will_return(__wrap_init_config, 1); ++ assert_int_equal(mpathvalid_init(MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR_TIMESTAMP), -1); ++ assert_false(initialized); ++ check_config(false); ++} ++ ++/* dm_prereq fails */ ++static void test_mpathvalid_init_bad3(void **state) ++{ ++ make_config_file(FIND_MULTIPATHS_STRICT); ++ will_return(__wrap_libmultipath_init, 0); ++ will_return(__wrap_init_config, 0); ++ will_return(__wrap_init_config, FIND_MULTIPATHS_STRICT); ++ will_return(__wrap_dm_prereq, 1); ++ assert_int_equal(mpathvalid_init(MPATH_LOG_STDERR, MPATH_LOG_PRIO_ERR), ++ -1); ++ assert_false(initialized); ++ check_config(false); ++} ++ ++static void check_mpathvalid_init(int findmp, int prio, int log_style) ++{ ++ make_config_file(findmp); ++ will_return(__wrap_libmultipath_init, 0); ++ will_return(__wrap_init_config, 0); ++ will_return(__wrap_init_config, findmp); ++ will_return(__wrap_dm_prereq, 0); ++ assert_int_equal(mpathvalid_init(prio, log_style), 0); ++ assert_true(initialized); ++ check_config(true); ++ assert_int_equal(logsink, log_style); ++ assert_int_equal(libmp_verbosity, prio); ++ assert_int_equal(findmp_to_mode(findmp), mpathvalid_get_mode()); ++} ++ ++static void check_mpathvalid_exit(void) ++{ ++ assert_int_equal(mpathvalid_exit(), 0); ++ assert_false(initialized); ++ check_config(false); ++} ++ ++static void test_mpathvalid_init_good1(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR_TIMESTAMP); ++} ++ ++static void test_mpathvalid_init_good2(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_STRICT, MPATH_LOG_PRIO_DEBUG, ++ MPATH_LOG_STDERR); ++} ++ ++static void test_mpathvalid_init_good3(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_NOLOG, ++ MPATH_LOG_SYSLOG); ++} ++ ++static void test_mpathvalid_exit(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ check_mpathvalid_exit(); ++} ++ ++/* fails if config hasn't been set */ ++static void test_mpathvalid_get_mode_bad(void **state) ++{ ++#if 1 ++ assert_int_equal(mpathvalid_get_mode(), MPATH_MODE_ERROR); ++#else ++ assert_int_equal(mpathvalid_get_mode(), 1); ++#endif ++} ++ ++/*fails if config hasn't been set */ ++static void test_mpathvalid_reload_config_bad1(void **state) ++{ ++#if 1 ++ will_return(__wrap_init_config, 1); ++#endif ++ assert_int_equal(mpathvalid_reload_config(), -1); ++ check_config(false); ++} ++ ++/* init_config fails */ ++static void test_mpathvalid_reload_config_bad2(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_init_config, 1); ++ assert_int_equal(mpathvalid_reload_config(), -1); ++ check_config(false); ++ check_mpathvalid_exit(); ++} ++ ++static void check_mpathvalid_reload_config(int findmp) ++{ ++ assert_string_not_equal(conf_name, CONF_TEMPLATE); ++ unlink(conf_name); ++ make_config_file(findmp); ++ will_return(__wrap_init_config, 0); ++ will_return(__wrap_init_config, findmp); ++ assert_int_equal(mpathvalid_reload_config(), 0); ++ check_config(true); ++ assert_int_equal(findmp_to_mode(findmp), mpathvalid_get_mode()); ++} ++ ++static void test_mpathvalid_reload_config_good(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ check_mpathvalid_reload_config(FIND_MULTIPATHS_ON); ++ check_mpathvalid_reload_config(FIND_MULTIPATHS_GREEDY); ++ check_mpathvalid_reload_config(FIND_MULTIPATHS_SMART); ++ check_mpathvalid_reload_config(FIND_MULTIPATHS_STRICT); ++ check_mpathvalid_exit(); ++} ++ ++/* NULL name */ ++static void test_mpathvalid_is_path_bad1(void **state) ++{ ++ assert_int_equal(mpathvalid_is_path(NULL, MPATH_STRICT, NULL, NULL, 0), ++ MPATH_IS_ERROR); ++} ++ ++/* bad mode */ ++static void test_mpathvalid_is_path_bad2(void **state) ++{ ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_MODE_ERROR, NULL, ++ NULL, 0), MPATH_IS_ERROR); ++} ++ ++/* NULL path_wwids and non-zero nr_paths */ ++static void test_mpathvalid_is_path_bad3(void **state) ++{ ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_MODE_ERROR, NULL, ++ NULL, 1), MPATH_IS_ERROR); ++} ++ ++/*fails if config hasn't been set */ ++static void test_mpathvalid_is_path_bad4(void **state) ++{ ++#if 0 ++ will_return(__wrap_is_path_valid, MPATH_IS_ERROR); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_STRICT); ++#endif ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_STRICT, NULL, ++ NULL, 0), MPATH_IS_ERROR); ++} ++ ++/* is_path_valid fails */ ++static void test_mpathvalid_is_path_bad5(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_ERROR); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_GREEDY); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_GREEDY, NULL, ++ NULL, 0), MPATH_IS_ERROR); ++ check_mpathvalid_exit(); ++} ++ ++static void test_mpathvalid_is_path_good1(void **state) ++{ ++ char *wwid; ++ check_mpathvalid_init(FIND_MULTIPATHS_STRICT, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_NOT_VALID); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_STRICT); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, ++ NULL, 0), MPATH_IS_NOT_VALID); ++ assert_ptr_equal(wwid, NULL); ++ check_mpathvalid_exit(); ++} ++ ++static void test_mpathvalid_is_path_good2(void **state) ++{ ++ const char *wwids[] = { "WWID_A", "WWID_B", "WWID_C", "WWID_D" }; ++ char *wwid; ++ check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_VALID); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_ON); ++ will_return(__wrap_is_path_valid, TEST_WWID); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, ++ wwids, 4), MPATH_IS_VALID); ++ assert_string_equal(wwid, TEST_WWID); ++} ++ ++static void test_mpathvalid_is_path_good3(void **state) ++{ ++ const char *wwids[] = { "WWID_A", "WWID_B", "WWID_C", "WWID_D" }; ++ char *wwid; ++ check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_VALID); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_SMART); ++ will_return(__wrap_is_path_valid, TEST_WWID); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_SMART, &wwid, ++ wwids, 4), MPATH_IS_VALID); ++ assert_string_equal(wwid, TEST_WWID); ++} ++ ++/* mabybe valid with no matching paths */ ++static void test_mpathvalid_is_path_good4(void **state) ++{ ++ const char *wwids[] = { "WWID_A", "WWID_B", "WWID_C", "WWID_D" }; ++ char *wwid; ++ check_mpathvalid_init(FIND_MULTIPATHS_SMART, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_MAYBE_VALID); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_SMART); ++ will_return(__wrap_is_path_valid, TEST_WWID); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, ++ wwids, 4), MPATH_IS_MAYBE_VALID); ++ assert_string_equal(wwid, TEST_WWID); ++} ++ ++/* maybe valid with matching paths */ ++static void test_mpathvalid_is_path_good5(void **state) ++{ ++ const char *wwids[] = { "WWID_A", "WWID_B", TEST_WWID, "WWID_D" }; ++ char *wwid; ++ check_mpathvalid_init(FIND_MULTIPATHS_SMART, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_MAYBE_VALID); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_SMART); ++ will_return(__wrap_is_path_valid, TEST_WWID); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, ++ wwids, 4), MPATH_IS_VALID); ++ assert_string_equal(wwid, TEST_WWID); ++} ++ ++#define setup_test(name) \ ++ cmocka_unit_test_setup_teardown(name, setup, teardown) ++ ++int test_mpathvalid(void) ++{ ++ const struct CMUnitTest tests[] = { ++ setup_test(test_mpathvalid_init_bad1), ++ setup_test(test_mpathvalid_init_bad2), ++ setup_test(test_mpathvalid_init_bad3), ++ setup_test(test_mpathvalid_init_good1), ++ setup_test(test_mpathvalid_init_good2), ++ setup_test(test_mpathvalid_init_good3), ++ setup_test(test_mpathvalid_exit), ++ setup_test(test_mpathvalid_get_mode_bad), ++ setup_test(test_mpathvalid_reload_config_bad1), ++ setup_test(test_mpathvalid_reload_config_bad2), ++ setup_test(test_mpathvalid_reload_config_good), ++ setup_test(test_mpathvalid_is_path_bad1), ++ setup_test(test_mpathvalid_is_path_bad2), ++ setup_test(test_mpathvalid_is_path_bad3), ++ setup_test(test_mpathvalid_is_path_bad4), ++ setup_test(test_mpathvalid_is_path_bad5), ++ setup_test(test_mpathvalid_is_path_good1), ++ setup_test(test_mpathvalid_is_path_good2), ++ setup_test(test_mpathvalid_is_path_good3), ++ setup_test(test_mpathvalid_is_path_good4), ++ setup_test(test_mpathvalid_is_path_good5), ++ }; ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} ++ ++int main(void) ++{ ++ int r = 0; ++ ++ r += test_mpathvalid(); ++ return r; ++} +-- +2.17.2 + diff --git a/0070-libmultipath-add-uid-failback-for-dasd-devices.patch b/0070-libmultipath-add-uid-failback-for-dasd-devices.patch new file mode 100644 index 0000000..c052217 --- /dev/null +++ b/0070-libmultipath-add-uid-failback-for-dasd-devices.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Wed, 21 Oct 2020 16:39:25 -0500 +Subject: [PATCH] libmultipath: add uid failback for dasd devices + +Add failback code to get the uid for dasd devices from sysfs. Copied +from dasdinfo + +Reviewed-by: Martin Wilck +Signed-off-by: Benjamin Marzinski +--- + libmultipath/defaults.h | 1 + + libmultipath/discovery.c | 37 ++++++++++++++++++++++++++++++++++++- + 2 files changed, 37 insertions(+), 1 deletion(-) + +diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h +index 39a5e415..947ba467 100644 +--- a/libmultipath/defaults.h ++++ b/libmultipath/defaults.h +@@ -8,6 +8,7 @@ + */ + #define DEFAULT_UID_ATTRIBUTE "ID_SERIAL" + #define DEFAULT_NVME_UID_ATTRIBUTE "ID_WWN" ++#define DEFAULT_DASD_UID_ATTRIBUTE "ID_UID" + #define DEFAULT_UDEVDIR "/dev" + #define DEFAULT_MULTIPATHDIR "/" LIB_STRING "/multipath" + #define DEFAULT_SELECTOR "service-time 0" +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index e7084664..877e8f2b 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -1959,12 +1959,44 @@ get_vpd_uid(struct path * pp) + return get_vpd_sysfs(parent, 0x83, pp->wwid, WWID_SIZE); + } + ++/* based on code from s390-tools/dasdinfo/dasdinfo.c */ ++static ssize_t dasd_get_uid(struct path *pp) ++{ ++ struct udev_device *parent; ++ char value[80]; ++ char *p; ++ int i; ++ ++ parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "ccw", ++ NULL); ++ if (!parent) ++ return -1; ++ ++ if (sysfs_attr_get_value(parent, "uid", value, 80) < 0) ++ return -1; ++ ++ p = value - 1; ++ /* look for the 4th '.' and cut there */ ++ for (i = 0; i < 4; i++) { ++ p = index(p + 1, '.'); ++ if (!p) ++ break; ++ } ++ if (p) ++ *p = '\0'; ++ ++ return strlcpy(pp->wwid, value, WWID_SIZE); ++} ++ + static ssize_t uid_fallback(struct path *pp, int path_state, + const char **origin) + { + ssize_t len = -1; + +- if (pp->bus == SYSFS_BUS_SCSI) { ++ if (pp->bus == SYSFS_BUS_CCW) { ++ len = dasd_get_uid(pp); ++ *origin = "sysfs"; ++ } else if (pp->bus == SYSFS_BUS_SCSI) { + len = get_vpd_uid(pp); + *origin = "sysfs"; + if (len < 0 && path_state == PATH_UP) { +@@ -2012,6 +2044,9 @@ static bool has_uid_fallback(struct path *pp) + !strcmp(pp->uid_attribute, ""))) || + (pp->bus == SYSFS_BUS_NVME && + (!strcmp(pp->uid_attribute, DEFAULT_NVME_UID_ATTRIBUTE) || ++ !strcmp(pp->uid_attribute, ""))) || ++ (pp->bus == SYSFS_BUS_CCW && ++ (!strcmp(pp->uid_attribute, DEFAULT_DASD_UID_ATTRIBUTE) || + !strcmp(pp->uid_attribute, "")))); + } + +-- +2.17.2 + diff --git a/0071-libmultipath-change-log-level-for-null-uid_attribute.patch b/0071-libmultipath-change-log-level-for-null-uid_attribute.patch new file mode 100644 index 0000000..3fa6b93 --- /dev/null +++ b/0071-libmultipath-change-log-level-for-null-uid_attribute.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Wed, 21 Oct 2020 16:39:26 -0500 +Subject: [PATCH] libmultipath: change log level for null uid_attribute + +If uid_attribute is explicitly set to an empty string, multipath should +log the uid at the default log level, since using the fallback code is +the expected behavior. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/discovery.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index 877e8f2b..c74f13bf 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -2086,8 +2086,11 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev, + len = strlen(pp->wwid); + origin = "callout"; + } else { +- bool udev_available = udev && pp->uid_attribute ++ bool valid_uid_attr = pp->uid_attribute + && *pp->uid_attribute; ++ bool empty_uid_attr = pp->uid_attribute ++ && !*pp->uid_attribute; ++ bool udev_available = udev && valid_uid_attr; + + if (udev_available) { + len = get_udev_uid(pp, pp->uid_attribute, udev); +@@ -2097,7 +2100,8 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev, + } + if ((!udev_available || (len <= 0 && allow_fallback)) + && has_uid_fallback(pp)) { +- used_fallback = 1; ++ if (!udev || !empty_uid_attr) ++ used_fallback = 1; + len = uid_fallback(pp, path_state, &origin); + } + } +-- +2.17.2 + diff --git a/0072-libmultipath-move-fast_io_fail-defines-to-structs.h.patch b/0072-libmultipath-move-fast_io_fail-defines-to-structs.h.patch new file mode 100644 index 0000000..8346fa2 --- /dev/null +++ b/0072-libmultipath-move-fast_io_fail-defines-to-structs.h.patch @@ -0,0 +1,160 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 17 Dec 2020 16:50:59 -0600 +Subject: [PATCH] libmultipath: move fast_io_fail defines to structs.h + +Since fast_io_fail is part of the multipath struct, its symbolic values +belong in structs.h. Also, make it an instance of a general enum, which +will be used again in future patches, and change the set/print functions +which use it to use the general enum instead. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/config.h | 8 -------- + libmultipath/dict.c | 30 +++++++++++++++--------------- + libmultipath/dict.h | 2 +- + libmultipath/propsel.c | 2 +- + libmultipath/structs.h | 17 +++++++++++++++++ + 5 files changed, 34 insertions(+), 25 deletions(-) + +diff --git a/libmultipath/config.h b/libmultipath/config.h +index 5d460359..661dd586 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -10,14 +10,6 @@ + #define ORIGIN_DEFAULT 0 + #define ORIGIN_CONFIG 1 + +-/* +- * In kernel, fast_io_fail == 0 means immediate failure on rport delete. +- * OTOH '0' means not-configured in various places in multipath-tools. +- */ +-#define MP_FAST_IO_FAIL_UNSET (0) +-#define MP_FAST_IO_FAIL_OFF (-1) +-#define MP_FAST_IO_FAIL_ZERO (-2) +- + enum devtypes { + DEV_NONE, + DEV_DEVT, +diff --git a/libmultipath/dict.c b/libmultipath/dict.c +index f12c2e5c..f4357da1 100644 +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -822,7 +822,7 @@ declare_mp_attr_handler(gid, set_gid) + declare_mp_attr_snprint(gid, print_gid) + + static int +-set_fast_io_fail(vector strvec, void *ptr) ++set_undef_off_zero(vector strvec, void *ptr) + { + char * buff; + int *int_ptr = (int *)ptr; +@@ -832,36 +832,36 @@ set_fast_io_fail(vector strvec, void *ptr) + return 1; + + if (strcmp(buff, "off") == 0) +- *int_ptr = MP_FAST_IO_FAIL_OFF; ++ *int_ptr = UOZ_OFF; + else if (sscanf(buff, "%d", int_ptr) != 1 || +- *int_ptr < MP_FAST_IO_FAIL_ZERO) +- *int_ptr = MP_FAST_IO_FAIL_UNSET; ++ *int_ptr < UOZ_ZERO) ++ *int_ptr = UOZ_UNDEF; + else if (*int_ptr == 0) +- *int_ptr = MP_FAST_IO_FAIL_ZERO; ++ *int_ptr = UOZ_ZERO; + + FREE(buff); + return 0; + } + + int +-print_fast_io_fail(char * buff, int len, long v) ++print_undef_off_zero(char * buff, int len, long v) + { +- if (v == MP_FAST_IO_FAIL_UNSET) ++ if (v == UOZ_UNDEF) + return 0; +- if (v == MP_FAST_IO_FAIL_OFF) ++ if (v == UOZ_OFF) + return snprintf(buff, len, "\"off\""); +- if (v == MP_FAST_IO_FAIL_ZERO) ++ if (v == UOZ_ZERO) + return snprintf(buff, len, "0"); + return snprintf(buff, len, "%ld", v); + } + +-declare_def_handler(fast_io_fail, set_fast_io_fail) +-declare_def_snprint_defint(fast_io_fail, print_fast_io_fail, ++declare_def_handler(fast_io_fail, set_undef_off_zero) ++declare_def_snprint_defint(fast_io_fail, print_undef_off_zero, + DEFAULT_FAST_IO_FAIL) +-declare_ovr_handler(fast_io_fail, set_fast_io_fail) +-declare_ovr_snprint(fast_io_fail, print_fast_io_fail) +-declare_hw_handler(fast_io_fail, set_fast_io_fail) +-declare_hw_snprint(fast_io_fail, print_fast_io_fail) ++declare_ovr_handler(fast_io_fail, set_undef_off_zero) ++declare_ovr_snprint(fast_io_fail, print_undef_off_zero) ++declare_hw_handler(fast_io_fail, set_undef_off_zero) ++declare_hw_snprint(fast_io_fail, print_undef_off_zero) + + static int + set_dev_loss(vector strvec, void *ptr) +diff --git a/libmultipath/dict.h b/libmultipath/dict.h +index a40ac66f..a917e1ca 100644 +--- a/libmultipath/dict.h ++++ b/libmultipath/dict.h +@@ -13,7 +13,7 @@ int print_rr_weight(char *buff, int len, long v); + int print_pgfailback(char *buff, int len, long v); + int print_pgpolicy(char *buff, int len, long v); + int print_no_path_retry(char *buff, int len, long v); +-int print_fast_io_fail(char *buff, int len, long v); ++int print_undef_off_zero(char *buff, int len, long v); + int print_dev_loss(char *buff, int len, unsigned long v); + int print_reservation_key(char * buff, int len, struct be64 key, uint8_t + flags, int source); +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index 3f2c2cfa..67d025cf 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -754,7 +754,7 @@ int select_fast_io_fail(struct config *conf, struct multipath *mp) + mp_set_conf(fast_io_fail); + mp_set_default(fast_io_fail, DEFAULT_FAST_IO_FAIL); + out: +- print_fast_io_fail(buff, 12, mp->fast_io_fail); ++ print_undef_off_zero(buff, 12, mp->fast_io_fail); + condlog(3, "%s: fast_io_fail_tmo = %s %s", mp->alias, buff, origin); + return 0; + } +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index 4ce30551..cfa7b649 100644 +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -219,6 +219,23 @@ enum vpd_vendor_ids { + VPD_VP_ARRAY_SIZE, /* This must remain the last entry */ + }; + ++/* ++ * Multipath treats 0 as undefined for optional config parameters. ++ * Use this for cases where 0 is a valid option for systems multipath ++ * is communicating with ++ */ ++enum undefined_off_zero { ++ UOZ_UNDEF = 0, ++ UOZ_OFF = -1, ++ UOZ_ZERO = -2, ++}; ++ ++enum fast_io_fail_states { ++ MP_FAST_IO_FAIL_UNSET = UOZ_UNDEF, ++ MP_FAST_IO_FAIL_OFF = UOZ_OFF, ++ MP_FAST_IO_FAIL_ZERO = UOZ_ZERO, ++}; ++ + struct vpd_vendor_page { + int pg; + const char *name; +-- +2.17.2 + diff --git a/0073-libmultipath-add-eh_deadline-multipath.conf-paramete.patch b/0073-libmultipath-add-eh_deadline-multipath.conf-paramete.patch new file mode 100644 index 0000000..f5b1d8a --- /dev/null +++ b/0073-libmultipath-add-eh_deadline-multipath.conf-paramete.patch @@ -0,0 +1,338 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 17 Dec 2020 16:51:00 -0600 +Subject: [PATCH] libmultipath: add eh_deadline multipath.conf parameter + +There are times a fc rport is never lost, meaning that fast_io_fail_tmo +and dev_loss_tmo never trigger, but scsi commands still hang. This can +cause problems in cases where users have strict timing requirements, and +the easiest way to solve these issues is to set eh_deadline. Since it's +already possible to set fast_io_fail_tmo and dev_loss_tmo from +multipath.conf, and have multipath take care of setting it correctly for +the scsi devices in sysfs, it makes sense to allow users to set +eh_deadline here as well. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/config.c | 2 ++ + libmultipath/config.h | 2 ++ + libmultipath/configure.c | 1 + + libmultipath/dict.c | 10 +++++++ + libmultipath/discovery.c | 60 +++++++++++++++++++++++++++++++++----- + libmultipath/propsel.c | 17 +++++++++++ + libmultipath/propsel.h | 1 + + libmultipath/structs.h | 7 +++++ + multipath/multipath.conf.5 | 16 ++++++++++ + 9 files changed, 109 insertions(+), 7 deletions(-) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index 49e7fb81..9f3cb38d 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -424,6 +424,7 @@ merge_hwe (struct hwentry * dst, struct hwentry * src) + merge_num(flush_on_last_del); + merge_num(fast_io_fail); + merge_num(dev_loss); ++ merge_num(eh_deadline); + merge_num(user_friendly_names); + merge_num(retain_hwhandler); + merge_num(detect_prio); +@@ -579,6 +580,7 @@ store_hwe (vector hwtable, struct hwentry * dhwe) + hwe->flush_on_last_del = dhwe->flush_on_last_del; + hwe->fast_io_fail = dhwe->fast_io_fail; + hwe->dev_loss = dhwe->dev_loss; ++ hwe->eh_deadline = dhwe->eh_deadline; + hwe->user_friendly_names = dhwe->user_friendly_names; + hwe->retain_hwhandler = dhwe->retain_hwhandler; + hwe->detect_prio = dhwe->detect_prio; +diff --git a/libmultipath/config.h b/libmultipath/config.h +index 661dd586..9ce37f16 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -63,6 +63,7 @@ struct hwentry { + int flush_on_last_del; + int fast_io_fail; + unsigned int dev_loss; ++ int eh_deadline; + int user_friendly_names; + int retain_hwhandler; + int detect_prio; +@@ -148,6 +149,7 @@ struct config { + int attribute_flags; + int fast_io_fail; + unsigned int dev_loss; ++ int eh_deadline; + int log_checker_err; + int allow_queueing; + int allow_usb_devices; +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 20536e60..c076be72 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -368,6 +368,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size, + select_gid(conf, mpp); + select_fast_io_fail(conf, mpp); + select_dev_loss(conf, mpp); ++ select_eh_deadline(conf, mpp); + select_reservation_key(conf, mpp); + select_deferred_remove(conf, mpp); + select_marginal_path_err_sample_time(conf, mpp); +diff --git a/libmultipath/dict.c b/libmultipath/dict.c +index f4357da1..bab96146 100644 +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -899,6 +899,13 @@ declare_ovr_snprint(dev_loss, print_dev_loss) + declare_hw_handler(dev_loss, set_dev_loss) + declare_hw_snprint(dev_loss, print_dev_loss) + ++declare_def_handler(eh_deadline, set_undef_off_zero) ++declare_def_snprint(eh_deadline, print_undef_off_zero) ++declare_ovr_handler(eh_deadline, set_undef_off_zero) ++declare_ovr_snprint(eh_deadline, print_undef_off_zero) ++declare_hw_handler(eh_deadline, set_undef_off_zero) ++declare_hw_snprint(eh_deadline, print_undef_off_zero) ++ + static int + set_pgpolicy(vector strvec, void *ptr) + { +@@ -1771,6 +1778,7 @@ init_keywords(vector keywords) + install_keyword("gid", &def_gid_handler, &snprint_def_gid); + install_keyword("fast_io_fail_tmo", &def_fast_io_fail_handler, &snprint_def_fast_io_fail); + install_keyword("dev_loss_tmo", &def_dev_loss_handler, &snprint_def_dev_loss); ++ install_keyword("eh_deadline", &def_eh_deadline_handler, &snprint_def_eh_deadline); + install_keyword("bindings_file", &def_bindings_file_handler, &snprint_def_bindings_file); + install_keyword("wwids_file", &def_wwids_file_handler, &snprint_def_wwids_file); + install_keyword("prkeys_file", &def_prkeys_file_handler, &snprint_def_prkeys_file); +@@ -1880,6 +1888,7 @@ init_keywords(vector keywords) + install_keyword("flush_on_last_del", &hw_flush_on_last_del_handler, &snprint_hw_flush_on_last_del); + install_keyword("fast_io_fail_tmo", &hw_fast_io_fail_handler, &snprint_hw_fast_io_fail); + install_keyword("dev_loss_tmo", &hw_dev_loss_handler, &snprint_hw_dev_loss); ++ install_keyword("eh_deadline", &hw_eh_deadline_handler, &snprint_hw_eh_deadline); + install_keyword("user_friendly_names", &hw_user_friendly_names_handler, &snprint_hw_user_friendly_names); + install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler); + install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_hw_detect_prio); +@@ -1920,6 +1929,7 @@ init_keywords(vector keywords) + install_keyword("flush_on_last_del", &ovr_flush_on_last_del_handler, &snprint_ovr_flush_on_last_del); + install_keyword("fast_io_fail_tmo", &ovr_fast_io_fail_handler, &snprint_ovr_fast_io_fail); + install_keyword("dev_loss_tmo", &ovr_dev_loss_handler, &snprint_ovr_dev_loss); ++ install_keyword("eh_deadline", &ovr_eh_deadline_handler, &snprint_ovr_eh_deadline); + install_keyword("user_friendly_names", &ovr_user_friendly_names_handler, &snprint_ovr_user_friendly_names); + install_keyword("retain_attached_hw_handler", &ovr_retain_hwhandler_handler, &snprint_ovr_retain_hwhandler); + install_keyword("detect_prio", &ovr_detect_prio_handler, &snprint_ovr_detect_prio); +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index c74f13bf..add7bb97 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -587,6 +587,42 @@ sysfs_get_asymmetric_access_state(struct path *pp, char *buff, int buflen) + return !!preferred; + } + ++static int ++sysfs_set_eh_deadline(struct multipath *mpp, struct path *pp) ++{ ++ struct udev_device *hostdev; ++ char host_name[HOST_NAME_LEN], value[16]; ++ int ret, len; ++ ++ if (mpp->eh_deadline == EH_DEADLINE_UNSET) ++ return 0; ++ ++ sprintf(host_name, "host%d", pp->sg_id.host_no); ++ hostdev = udev_device_new_from_subsystem_sysname(udev, ++ "scsi_host", host_name); ++ if (!hostdev) ++ return 1; ++ ++ if (mpp->eh_deadline == EH_DEADLINE_OFF) ++ len = sprintf(value, "off"); ++ else if (mpp->eh_deadline == EH_DEADLINE_ZERO) ++ len = sprintf(value, "0"); ++ else ++ len = sprintf(value, "%d", mpp->eh_deadline); ++ ++ ret = sysfs_attr_set_value(hostdev, "eh_deadline", ++ value, len + 1); ++ /* ++ * not all scsi drivers support setting eh_deadline, so failing ++ * is totally reasonable ++ */ ++ if (ret <= 0) ++ condlog(3, "%s: failed to set eh_deadline to %s, error %d", udev_device_get_sysname(hostdev), value, -ret); ++ ++ udev_device_unref(hostdev); ++ return (ret <= 0); ++} ++ + static void + sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp) + { +@@ -596,6 +632,10 @@ sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp) + unsigned int tmo; + int ret; + ++ if (mpp->dev_loss == DEV_LOSS_TMO_UNSET && ++ mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET) ++ return; ++ + sprintf(rport_id, "rport-%d:%d-%d", + pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id); + rport_dev = udev_device_new_from_subsystem_sysname(udev, +@@ -703,6 +743,11 @@ sysfs_set_session_tmo(struct multipath *mpp, struct path *pp) + char session_id[64]; + char value[11]; + ++ if (mpp->dev_loss != DEV_LOSS_TMO_UNSET) ++ condlog(3, "%s: ignoring dev_loss_tmo on iSCSI", pp->dev); ++ if (mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET) ++ return; ++ + sprintf(session_id, "session%d", pp->sg_id.transport_id); + session_dev = udev_device_new_from_subsystem_sysname(udev, + "iscsi_session", session_id); +@@ -714,9 +759,6 @@ sysfs_set_session_tmo(struct multipath *mpp, struct path *pp) + condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no, + pp->sg_id.channel, pp->sg_id.scsi_id, session_id); + +- if (mpp->dev_loss != DEV_LOSS_TMO_UNSET) { +- condlog(3, "%s: ignoring dev_loss_tmo on iSCSI", pp->dev); +- } + if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) { + if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) { + condlog(3, "%s: can't switch off fast_io_fail_tmo " +@@ -744,6 +786,8 @@ sysfs_set_nexus_loss_tmo(struct multipath *mpp, struct path *pp) + char end_dev_id[64]; + char value[11]; + ++ if (mpp->dev_loss == DEV_LOSS_TMO_UNSET) ++ return; + sprintf(end_dev_id, "end_device-%d:%d", + pp->sg_id.host_no, pp->sg_id.transport_id); + sas_dev = udev_device_new_from_subsystem_sysname(udev, +@@ -801,7 +845,8 @@ sysfs_set_scsi_tmo (struct multipath *mpp, unsigned int checkint) + mpp->fast_io_fail = MP_FAST_IO_FAIL_OFF; + } + if (mpp->dev_loss == DEV_LOSS_TMO_UNSET && +- mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET) ++ mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET && ++ mpp->eh_deadline == EH_DEADLINE_UNSET) + return 0; + + vector_foreach_slot(mpp->paths, pp, i) { +@@ -814,17 +859,18 @@ sysfs_set_scsi_tmo (struct multipath *mpp, unsigned int checkint) + switch (pp->sg_id.proto_id) { + case SCSI_PROTOCOL_FCP: + sysfs_set_rport_tmo(mpp, pp); +- continue; ++ break; + case SCSI_PROTOCOL_ISCSI: + sysfs_set_session_tmo(mpp, pp); +- continue; ++ break; + case SCSI_PROTOCOL_SAS: + sysfs_set_nexus_loss_tmo(mpp, pp); +- continue; ++ break; + default: + if (!err_path) + err_path = pp; + } ++ sysfs_set_eh_deadline(mpp, pp); + } + + if (err_path) { +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index 67d025cf..fa4ac5d9 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -775,6 +775,23 @@ out: + return 0; + } + ++int select_eh_deadline(struct config *conf, struct multipath *mp) ++{ ++ const char *origin; ++ char buff[12]; ++ ++ mp_set_ovr(eh_deadline); ++ mp_set_hwe(eh_deadline); ++ mp_set_conf(eh_deadline); ++ mp->eh_deadline = EH_DEADLINE_UNSET; ++ /* not changing sysfs in default cause, so don't print anything */ ++ return 0; ++out: ++ print_undef_off_zero(buff, 12, mp->eh_deadline); ++ condlog(3, "%s: eh_deadline = %s %s", mp->alias, buff, origin); ++ return 0; ++} ++ + int select_flush_on_last_del(struct config *conf, struct multipath *mp) + { + const char *origin; +diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h +index 3d6edd8a..a68bacf0 100644 +--- a/libmultipath/propsel.h ++++ b/libmultipath/propsel.h +@@ -17,6 +17,7 @@ int select_uid(struct config *conf, struct multipath *mp); + int select_gid(struct config *conf, struct multipath *mp); + int select_fast_io_fail(struct config *conf, struct multipath *mp); + int select_dev_loss(struct config *conf, struct multipath *mp); ++int select_eh_deadline(struct config *conf, struct multipath *mp); + int select_reservation_key(struct config *conf, struct multipath *mp); + int select_retain_hwhandler (struct config *conf, struct multipath * mp); + int select_detect_prio(struct config *conf, struct path * pp); +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index cfa7b649..d6ff6762 100644 +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -236,6 +236,12 @@ enum fast_io_fail_states { + MP_FAST_IO_FAIL_ZERO = UOZ_ZERO, + }; + ++enum eh_deadline_states { ++ EH_DEADLINE_UNSET = UOZ_UNDEF, ++ EH_DEADLINE_OFF = UOZ_OFF, ++ EH_DEADLINE_ZERO = UOZ_ZERO, ++}; ++ + struct vpd_vendor_page { + int pg; + const char *name; +@@ -356,6 +362,7 @@ struct multipath { + int ghost_delay; + int ghost_delay_tick; + unsigned int dev_loss; ++ int eh_deadline; + uid_t uid; + gid_t gid; + mode_t mode; +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 +index 7242d39b..ea66a01e 100644 +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -717,6 +717,22 @@ The default is: \fB600\fR + . + . + .TP ++.B eh_deadline ++Specify the maximum number of seconds the SCSI layer will spend doing error ++handling when scsi devices fail. After this timeout the scsi layer will perform ++a full HBA reset. Setting this may be necessary in cases where the rport is ++never lost, so \fIfast_io_fail_tmo\fR and \fIdev_loss_tmo\fR will never ++trigger, but (frequently do to load) scsi commands still hang. \fBNote:\fR when ++the scsi error handler performs the HBA reset, all target paths on that HBA ++will be affected. eh_deadline should only be set in cases where all targets on ++the affected HBAs are multipathed. ++.RS ++.TP ++The default is: \fB\fR ++.RE ++. ++. ++.TP + .B bindings_file + The full pathname of the binding file to be used when the user_friendly_names + option is set. +-- +2.17.2 + diff --git a/0074-multipathd-remove-redundant-vector_free-int-configur.patch b/0074-multipathd-remove-redundant-vector_free-int-configur.patch new file mode 100644 index 0000000..c9947f5 --- /dev/null +++ b/0074-multipathd-remove-redundant-vector_free-int-configur.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 17 Dec 2020 16:51:01 -0600 +Subject: [PATCH] multipathd: remove redundant vector_free() int configure + +remove_maps(vecs) already calls vector_free(vecs->mpvec) + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + multipathd/main.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index b6a5f5b7..2eab4854 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2634,14 +2634,10 @@ configure (struct vectors * vecs) + } + + /* +- * purge dm of old maps ++ * purge dm of old maps and save new set of maps formed by ++ * considering current path state + */ + remove_maps(vecs); +- +- /* +- * save new set of maps formed by considering current path state +- */ +- vector_free(vecs->mpvec); + vecs->mpvec = mpvec; + + /* +-- +2.17.2 + diff --git a/0075-libmultipath-factor-out-code-to-get-vpd-page-data.patch b/0075-libmultipath-factor-out-code-to-get-vpd-page-data.patch new file mode 100644 index 0000000..fe2ea50 --- /dev/null +++ b/0075-libmultipath-factor-out-code-to-get-vpd-page-data.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 17 Dec 2020 16:51:02 -0600 +Subject: [PATCH] libmultipath: factor out code to get vpd page data + +A future patch will reuse the code to get the vpd page data, so factor +it out from get_vpd_sgio(). + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/discovery.c | 27 +++++++++++++++++++-------- + 1 file changed, 19 insertions(+), 8 deletions(-) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index add7bb97..f901e9ff 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -1321,14 +1321,13 @@ get_vpd_sysfs (struct udev_device *parent, int pg, char * str, int maxlen) + return len; + } + +-int +-get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen) ++static int ++fetch_vpd_page(int fd, int pg, unsigned char *buff, int maxlen) + { +- int len, buff_len; +- unsigned char buff[4096]; ++ int buff_len; + +- memset(buff, 0x0, 4096); +- if (sgio_get_vpd(buff, 4096, fd, pg) < 0) { ++ memset(buff, 0x0, maxlen); ++ if (sgio_get_vpd(buff, maxlen, fd, pg) < 0) { + int lvl = pg == 0x80 || pg == 0x83 ? 3 : 4; + + condlog(lvl, "failed to issue vpd inquiry for pg%02x", +@@ -1342,10 +1341,22 @@ get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen) + return -ENODATA; + } + buff_len = get_unaligned_be16(&buff[2]) + 4; +- if (buff_len > 4096) { ++ if (buff_len > maxlen) { + condlog(3, "vpd pg%02x page truncated", pg); +- buff_len = 4096; ++ buff_len = maxlen; + } ++ return buff_len; ++} ++ ++int ++get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen) ++{ ++ int len, buff_len; ++ unsigned char buff[4096]; ++ ++ buff_len = fetch_vpd_page(fd, pg, buff, sizeof(buff)); ++ if (buff_len < 0) ++ return buff_len; + if (pg == 0x80) + len = parse_vpd_pg80(buff, str, maxlen); + else if (pg == 0x83) +-- +2.17.2 + diff --git a/0076-libmultipath-limit-reading-0xc9-vpd-page.patch b/0076-libmultipath-limit-reading-0xc9-vpd-page.patch new file mode 100644 index 0000000..6208fe5 --- /dev/null +++ b/0076-libmultipath-limit-reading-0xc9-vpd-page.patch @@ -0,0 +1,91 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 17 Dec 2020 16:51:03 -0600 +Subject: [PATCH] libmultipath: limit reading 0xc9 vpd page + +Only rdac arrays support 0xC9 vpd page inquiries. All other arrays will +return a failure. Only do the rdac inquiry when detecting array +capabilities if the array's path checker is explicitly set to rdac, or +the path checker is not set, and the array reports that it supports vpd +page 0xC9 in the Supported VPD Pages (0x00) vpd page. + +Multipath was doing the check if either the path checker was set to +rdac, or no path checker was set. This means that for almost all +non-rdac arrays, multipath was issuing a bad inquiry. This was annoying +users. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/discovery.c | 17 +++++++++++++++++ + libmultipath/discovery.h | 1 + + libmultipath/propsel.c | 10 ++++++---- + 3 files changed, 24 insertions(+), 4 deletions(-) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index f901e9ff..e818585a 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -1348,6 +1348,23 @@ fetch_vpd_page(int fd, int pg, unsigned char *buff, int maxlen) + return buff_len; + } + ++/* based on sg_inq.c from sg3_utils */ ++bool ++is_vpd_page_supported(int fd, int pg) ++{ ++ int i, len; ++ unsigned char buff[4096]; ++ ++ len = fetch_vpd_page(fd, 0x00, buff, sizeof(buff)); ++ if (len < 0) ++ return false; ++ ++ for (i = 4; i < len; ++i) ++ if (buff[i] == pg) ++ return true; ++ return false; ++} ++ + int + get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen) + { +diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h +index 6444887d..d3193daf 100644 +--- a/libmultipath/discovery.h ++++ b/libmultipath/discovery.h +@@ -56,6 +56,7 @@ int sysfs_get_asymmetric_access_state(struct path *pp, + char *buff, int buflen); + int get_uid(struct path * pp, int path_state, struct udev_device *udev, + int allow_fallback); ++bool is_vpd_page_supported(int fd, int pg); + + /* + * discovery bitmask +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index fa4ac5d9..f771a830 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -496,13 +496,15 @@ check_rdac(struct path * pp) + { + int len; + char buff[44]; +- const char *checker_name; ++ const char *checker_name = NULL; + + if (pp->bus != SYSFS_BUS_SCSI) + return 0; +- /* Avoid ioctl if this is likely not an RDAC array */ +- if (__do_set_from_hwe(checker_name, pp, checker_name) && +- strcmp(checker_name, RDAC)) ++ /* Avoid checking 0xc9 if this is likely not an RDAC array */ ++ if (!__do_set_from_hwe(checker_name, pp, checker_name) && ++ !is_vpd_page_supported(pp->fd, 0xC9)) ++ return 0; ++ if (checker_name && strcmp(checker_name, RDAC)) + return 0; + len = get_vpd_sgio(pp->fd, 0xC9, 0, buff, 44); + if (len <= 0) +-- +2.17.2 + diff --git a/0077-libmultipath-move-logq_lock-handling-to-log.c.patch b/0077-libmultipath-move-logq_lock-handling-to-log.c.patch new file mode 100644 index 0000000..ae9385f --- /dev/null +++ b/0077-libmultipath-move-logq_lock-handling-to-log.c.patch @@ -0,0 +1,141 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 26 Oct 2020 22:01:18 +0100 +Subject: [PATCH] libmultipath: move logq_lock handling to log.c + +logq_lock protects internal data structures of log.c, and should +be handled there. This patch doesn't change functionality, except +improving cancel-safety somewhat. +Reviewed-by: Benjamin Marzinski + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log.c | 34 ++++++++++++++++++++++++++++++++-- + libmultipath/log_pthread.c | 9 --------- + 2 files changed, 32 insertions(+), 11 deletions(-) + +diff --git a/libmultipath/log.c b/libmultipath/log.c +index debd36de..7f337879 100644 +--- a/libmultipath/log.c ++++ b/libmultipath/log.c +@@ -9,13 +9,16 @@ + #include + #include + #include ++#include + + #include "memory.h" + #include "log.h" ++#include "util.h" + + #define ALIGN(len, s) (((len)+(s)-1)/(s)*(s)) + + struct logarea* la; ++static pthread_mutex_t logq_lock = PTHREAD_MUTEX_INITIALIZER; + + #if LOGDBG + static void dump_logarea (void) +@@ -101,12 +104,17 @@ void log_close (void) + + void log_reset (char *program_name) + { ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ + closelog(); + tzset(); + openlog(program_name, 0, LOG_DAEMON); ++ ++ pthread_cleanup_pop(1); + } + +-int log_enqueue (int prio, const char * fmt, va_list ap) ++static int _log_enqueue(int prio, const char * fmt, va_list ap) + { + int len, fwd; + char buff[MAX_MSG_SIZE]; +@@ -165,7 +173,18 @@ int log_enqueue (int prio, const char * fmt, va_list ap) + return 0; + } + +-int log_dequeue (void * buff) ++int log_enqueue(int prio, const char *fmt, va_list ap) ++{ ++ int ret; ++ ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ ret = _log_enqueue(prio, fmt, ap); ++ pthread_cleanup_pop(1); ++ return ret; ++} ++ ++static int _log_dequeue(void *buff) + { + struct logmsg * src = (struct logmsg *)la->head; + struct logmsg * dst = (struct logmsg *)buff; +@@ -194,6 +213,17 @@ int log_dequeue (void * buff) + return 0; + } + ++int log_dequeue(void *buff) ++{ ++ int ret; ++ ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ ret = _log_dequeue(buff); ++ pthread_cleanup_pop(1); ++ return ret; ++} ++ + /* + * this one can block under memory pressure + */ +diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c +index 0d48c52c..65992101 100644 +--- a/libmultipath/log_pthread.c ++++ b/libmultipath/log_pthread.c +@@ -18,7 +18,6 @@ + static pthread_t log_thr; + + /* logev_lock must not be taken with logq_lock held */ +-static pthread_mutex_t logq_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_mutex_t logev_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_cond_t logev_cond = PTHREAD_COND_INITIALIZER; + +@@ -41,10 +40,7 @@ void log_safe (int prio, const char * fmt, va_list ap) + running = logq_running; + + if (running) { +- pthread_mutex_lock(&logq_lock); +- pthread_cleanup_push(cleanup_mutex, &logq_lock); + log_enqueue(prio, fmt, ap); +- pthread_cleanup_pop(1); + + log_messages_pending = 1; + pthread_cond_signal(&logev_cond); +@@ -60,9 +56,7 @@ static void flush_logqueue (void) + int empty; + + do { +- pthread_mutex_lock(&logq_lock); + empty = log_dequeue(la->buff); +- pthread_mutex_unlock(&logq_lock); + if (!empty) + log_syslog(la->buff); + } while (empty == 0); +@@ -138,10 +132,7 @@ void log_thread_start (pthread_attr_t *attr) + void log_thread_reset (void) + { + logdbg(stderr,"resetting log\n"); +- +- pthread_mutex_lock(&logq_lock); + log_reset("multipathd"); +- pthread_mutex_unlock(&logq_lock); + } + + void log_thread_stop (void) +-- +2.17.2 + diff --git a/0078-libmultipath-protect-logarea-with-logq_lock.patch b/0078-libmultipath-protect-logarea-with-logq_lock.patch new file mode 100644 index 0000000..e27aa64 --- /dev/null +++ b/0078-libmultipath-protect-logarea-with-logq_lock.patch @@ -0,0 +1,110 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 26 Oct 2020 22:13:40 +0100 +Subject: [PATCH] libmultipath: protect logarea with logq_lock + +Make sure the global logarea (la) is only allocated and freed +hile holding logq_lock. This avoids invalid memory access. + +This patch makes free_logarea() static. libmultipath.version +is unchanged, as free_logarea() wasn't exported anyway. +Reviewed-by: Benjamin Marzinski + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log.c | 32 +++++++++++++++++++++++--------- + libmultipath/log.h | 1 - + 2 files changed, 23 insertions(+), 10 deletions(-) + +diff --git a/libmultipath/log.c b/libmultipath/log.c +index 7f337879..95c8f01a 100644 +--- a/libmultipath/log.c ++++ b/libmultipath/log.c +@@ -77,16 +77,23 @@ static int logarea_init (int size) + + int log_init(char *program_name, int size) + { ++ int ret = 1; ++ + logdbg(stderr,"enter log_init\n"); ++ ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ + openlog(program_name, 0, LOG_DAEMON); ++ if (!la) ++ ret = logarea_init(size); + +- if (logarea_init(size)) +- return 1; ++ pthread_cleanup_pop(1); + +- return 0; ++ return ret; + } + +-void free_logarea (void) ++static void free_logarea (void) + { + FREE(la->start); + FREE(la->buff); +@@ -96,9 +103,14 @@ void free_logarea (void) + + void log_close (void) + { +- free_logarea(); ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ ++ if (la) ++ free_logarea(); + closelog(); + ++ pthread_cleanup_pop(1); + return; + } + +@@ -175,11 +187,12 @@ static int _log_enqueue(int prio, const char * fmt, va_list ap) + + int log_enqueue(int prio, const char *fmt, va_list ap) + { +- int ret; ++ int ret = 1; + + pthread_mutex_lock(&logq_lock); + pthread_cleanup_push(cleanup_mutex, &logq_lock); +- ret = _log_enqueue(prio, fmt, ap); ++ if (la) ++ ret = _log_enqueue(prio, fmt, ap); + pthread_cleanup_pop(1); + return ret; + } +@@ -215,11 +228,12 @@ static int _log_dequeue(void *buff) + + int log_dequeue(void *buff) + { +- int ret; ++ int ret = 1; + + pthread_mutex_lock(&logq_lock); + pthread_cleanup_push(cleanup_mutex, &logq_lock); +- ret = _log_dequeue(buff); ++ if (la) ++ ret = _log_dequeue(buff); + pthread_cleanup_pop(1); + return ret; + } +diff --git a/libmultipath/log.h b/libmultipath/log.h +index d2448f6a..fa224e4d 100644 +--- a/libmultipath/log.h ++++ b/libmultipath/log.h +@@ -39,6 +39,5 @@ int log_enqueue (int prio, const char * fmt, va_list ap) + int log_dequeue (void *); + void log_syslog (void *); + void dump_logmsg (void *); +-void free_logarea (void); + + #endif /* LOG_H */ +-- +2.17.2 + diff --git a/0079-libmultipath-prevent-DSO-unloading-with-astray-check.patch b/0079-libmultipath-prevent-DSO-unloading-with-astray-check.patch new file mode 100644 index 0000000..31fd8b4 --- /dev/null +++ b/0079-libmultipath-prevent-DSO-unloading-with-astray-check.patch @@ -0,0 +1,284 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 5 Nov 2020 12:43:25 +0100 +Subject: [PATCH] libmultipath: prevent DSO unloading with astray checker + threads + +The multipathd tur checker thread is designed to be able to finish at +any time, even after the tur checker itself has been freed. The +multipathd shutdown code makes sure all the checkers have been freed +before freeing the checker_class and calling dlclose() to unload the +DSO, but this doesn't guarantee that the checker threads have finished. +If one hasn't, the DSO will get unloaded while the thread still running +code from it, causing a segfault. + +This patch fixes the issue by further incrementing the DSO's refcount +for every running thread. To avoid race conditions leading to segfaults, +the thread's entrypoint must be in libmultipath, not in the DSO itself. +Therefore we add a new optional checker method, libcheck_thread(). +Checkers defining this method may create a detached thread with +entrypoint checker_thread_entry(), which will call the DSO's +libcheck_thread and take care of the refcount handling. + +Reported-by: Benjamin Marzinski +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/checkers.c | 68 +++++++++++++++++++++++++++---- + libmultipath/checkers.h | 25 ++++++++++++ + libmultipath/checkers/tur.c | 12 +++--- + libmultipath/libmultipath.version | 5 +++ + 4 files changed, 97 insertions(+), 13 deletions(-) + +diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c +index 18b1f5eb..2dd9915d 100644 +--- a/libmultipath/checkers.c ++++ b/libmultipath/checkers.c +@@ -3,6 +3,8 @@ + #include + #include + #include ++#include ++#include + + #include "debug.h" + #include "checkers.h" +@@ -20,6 +22,7 @@ struct checker_class { + int (*mp_init)(struct checker *); /* to allocate the mpcontext */ + void (*free)(struct checker *); /* to free the context */ + void (*reset)(void); /* to reset the global variables */ ++ void *(*thread)(void *); /* async thread entry point */ + const char **msgtable; + short msgtable_size; + }; +@@ -55,19 +58,32 @@ static struct checker_class *alloc_checker_class(void) + c = MALLOC(sizeof(struct checker_class)); + if (c) { + INIT_LIST_HEAD(&c->node); +- c->refcount = 1; ++ uatomic_set(&c->refcount, 1); + } + return c; + } + ++/* Use uatomic_{sub,add}_return() to ensure proper memory barriers */ ++static int checker_class_ref(struct checker_class *cls) ++{ ++ return uatomic_add_return(&cls->refcount, 1); ++} ++ ++static int checker_class_unref(struct checker_class *cls) ++{ ++ return uatomic_sub_return(&cls->refcount, 1); ++} ++ + void free_checker_class(struct checker_class *c) + { ++ int cnt; ++ + if (!c) + return; +- c->refcount--; +- if (c->refcount) { +- condlog(4, "%s checker refcount %d", +- c->name, c->refcount); ++ cnt = checker_class_unref(c); ++ if (cnt != 0) { ++ condlog(cnt < 0 ? 1 : 4, "%s checker refcount %d", ++ c->name, cnt); + return; + } + condlog(3, "unloading %s checker", c->name); +@@ -161,7 +177,8 @@ static struct checker_class *add_checker_class(const char *multipath_dir, + + c->mp_init = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_mp_init"); + c->reset = (void (*)(void)) dlsym(c->handle, "libcheck_reset"); +- /* These 2 functions can be NULL. call dlerror() to clear out any ++ c->thread = (void *(*)(void*)) dlsym(c->handle, "libcheck_thread"); ++ /* These 3 functions can be NULL. call dlerror() to clear out any + * error string */ + dlerror(); + +@@ -347,6 +364,43 @@ bad_id: + return generic_msg[CHECKER_MSGID_NONE]; + } + ++static void checker_cleanup_thread(void *arg) ++{ ++ struct checker_class *cls = arg; ++ ++ (void)checker_class_unref(cls); ++ rcu_unregister_thread(); ++} ++ ++static void *checker_thread_entry(void *arg) ++{ ++ struct checker_context *ctx = arg; ++ void *rv; ++ ++ rcu_register_thread(); ++ pthread_cleanup_push(checker_cleanup_thread, ctx->cls); ++ rv = ctx->cls->thread(ctx); ++ pthread_cleanup_pop(1); ++ return rv; ++} ++ ++int start_checker_thread(pthread_t *thread, const pthread_attr_t *attr, ++ struct checker_context *ctx) ++{ ++ int rv; ++ ++ assert(ctx && ctx->cls && ctx->cls->thread); ++ /* Take a ref here, lest the class be freed before the thread starts */ ++ (void)checker_class_ref(ctx->cls); ++ rv = pthread_create(thread, attr, checker_thread_entry, ctx); ++ if (rv != 0) { ++ condlog(1, "failed to start checker thread for %s: %m", ++ ctx->cls->name); ++ checker_class_unref(ctx->cls); ++ } ++ return rv; ++} ++ + void checker_clear_message (struct checker *c) + { + if (!c) +@@ -371,7 +425,7 @@ void checker_get(const char *multipath_dir, struct checker *dst, + if (!src) + return; + +- src->refcount++; ++ (void)checker_class_ref(dst->cls); + } + + int init_checkers(const char *multipath_dir) +diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h +index 9d5f90b9..2fd1d1c6 100644 +--- a/libmultipath/checkers.h ++++ b/libmultipath/checkers.h +@@ -1,6 +1,7 @@ + #ifndef _CHECKERS_H + #define _CHECKERS_H + ++#include + #include "list.h" + #include "memory.h" + #include "defaults.h" +@@ -148,6 +149,28 @@ void checker_set_async (struct checker *); + void checker_set_fd (struct checker *, int); + void checker_enable (struct checker *); + void checker_disable (struct checker *); ++/* ++ * start_checker_thread(): start async path checker thread ++ * ++ * This function provides a wrapper around pthread_create(). ++ * The created thread will call the DSO's "libcheck_thread" function with the ++ * checker context as argument. ++ * ++ * Rationale: ++ * Path checkers that do I/O may hang forever. To avoid blocking, some ++ * checkers therefore use asyncronous, detached threads for checking ++ * the paths. These threads may continue hanging if multipathd is stopped. ++ * In this case, we can't unload the checker DSO at exit. In order to ++ * avoid race conditions and crashes, the entry point of the thread ++ * needs to be in libmultipath, not in the DSO itself. ++ * ++ * @param arg: pointer to struct checker_context. ++ */ ++struct checker_context { ++ struct checker_class *cls; ++}; ++int start_checker_thread (pthread_t *thread, const pthread_attr_t *attr, ++ struct checker_context *ctx); + int checker_check (struct checker *, int); + int checker_is_sync(const struct checker *); + const char *checker_name (const struct checker *); +@@ -164,6 +187,8 @@ void checker_get(const char *, struct checker *, const char *); + int libcheck_check(struct checker *); + int libcheck_init(struct checker *); + void libcheck_free(struct checker *); ++void *libcheck_thread(struct checker_context *ctx); ++ + /* + * msgid => message map. + * +diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c +index e886fcf8..a4b4a213 100644 +--- a/libmultipath/checkers/tur.c ++++ b/libmultipath/checkers/tur.c +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + + #include "checkers.h" +@@ -55,6 +54,7 @@ struct tur_checker_context { + pthread_cond_t active; + int holders; /* uatomic access only */ + int msgid; ++ struct checker_context ctx; + }; + + int libcheck_init (struct checker * c) +@@ -74,6 +74,7 @@ int libcheck_init (struct checker * c) + pthread_mutex_init(&ct->lock, NULL); + if (fstat(c->fd, &sb) == 0) + ct->devt = sb.st_rdev; ++ ct->ctx.cls = c->cls; + c->context = ct; + + return 0; +@@ -204,7 +205,6 @@ static void cleanup_func(void *data) + holders = uatomic_sub_return(&ct->holders, 1); + if (!holders) + cleanup_context(ct); +- rcu_unregister_thread(); + } + + /* +@@ -251,15 +251,15 @@ static void tur_deep_sleep(const struct tur_checker_context *ct) + #define tur_deep_sleep(x) do {} while (0) + #endif /* TUR_TEST_MAJOR */ + +-static void *tur_thread(void *ctx) ++void *libcheck_thread(struct checker_context *ctx) + { +- struct tur_checker_context *ct = ctx; ++ struct tur_checker_context *ct = ++ container_of(ctx, struct tur_checker_context, ctx); + int state, running; + short msgid; + + /* This thread can be canceled, so setup clean up */ + tur_thread_cleanup_push(ct); +- rcu_register_thread(); + + condlog(4, "%d:%d : tur checker starting up", major(ct->devt), + minor(ct->devt)); +@@ -394,7 +394,7 @@ int libcheck_check(struct checker * c) + uatomic_set(&ct->running, 1); + tur_set_async_timeout(c); + setup_thread_attr(&attr, 32 * 1024, 1); +- r = pthread_create(&ct->thread, &attr, tur_thread, ct); ++ r = start_checker_thread(&ct->thread, &attr, &ct->ctx); + pthread_attr_destroy(&attr); + if (r) { + uatomic_sub(&ct->holders, 1); +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 2e3583f5..751099dc 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -270,3 +270,8 @@ global: + dm_prereq; + skip_libmp_dm_init; + } LIBMULTIPATH_4.1.0; ++ ++LIBMULTIPATH_4.3.0 { ++global: ++ start_checker_thread; ++} LIBMULTIPATH_4.2.0; +-- +2.17.2 + diff --git a/0080-libmultipath-force-map-reload-if-udev-incomplete.patch b/0080-libmultipath-force-map-reload-if-udev-incomplete.patch new file mode 100644 index 0000000..913c438 --- /dev/null +++ b/0080-libmultipath-force-map-reload-if-udev-incomplete.patch @@ -0,0 +1,151 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 14 Dec 2020 18:22:55 +0100 +Subject: [PATCH] libmultipath: force map reload if udev incomplete + +We've recently observed various cases of incompletely processed uevents +during initrd processing. Typically, this would leave a dm device in +the state it had after the initial "add" uevent, which is basically unusable, +because udevd had been killed by systemd before processing the subsequent +"change" event. After switching root, the coldplug event would re-read +the db file, which would be in unusable state, and would not do anything. +In such cases, a RELOAD action with force_udev_reload=1 is in order to +make udev re-process the device completely (DM_UDEV_PRIMARY_SOURCE_FLAG=1 and +DM_SUBSYSTEM_UDEV_FLAG0=0). + +The previous commits + +2b25a9e libmultipath: select_action(): force udev reload for uninitialized maps +cb10d38 multipathd: uev_trigger(): handle incomplete ADD events + +addressed the same issue, but incompletely. They would miss cases where the +map was configured correctly but none of the RELOAD criteria were met. +This patch partially reverts 2b25a9e by converting select_reload_action() into +a trivial helper. Instead, we now check for incompletely initialized udev now +before checking any of the other reload criteria. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 45 ++++++++++++++++++++++++++-------------- + 1 file changed, 29 insertions(+), 16 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index c076be72..d9fd9cb8 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -696,12 +696,11 @@ sysfs_set_max_sectors_kb(struct multipath *mpp, int is_reload) + return err; + } + +-static void +-select_reload_action(struct multipath *mpp, const struct multipath *cmpp, +- const char *reason) ++static bool is_udev_ready(struct multipath *cmpp) + { + struct udev_device *mpp_ud; + const char *env; ++ bool rc; + + /* + * MPATH_DEVICE_READY != 1 can mean two things: +@@ -713,14 +712,20 @@ select_reload_action(struct multipath *mpp, const struct multipath *cmpp, + */ + + mpp_ud = get_udev_for_mpp(cmpp); ++ if (!mpp_ud) ++ return true; + env = udev_device_get_property_value(mpp_ud, "MPATH_DEVICE_READY"); +- if ((!env || strcmp(env, "1")) && count_active_paths(mpp) > 0) +- mpp->force_udev_reload = 1; ++ rc = (env != NULL && !strcmp(env, "1")); + udev_device_unref(mpp_ud); ++ condlog(4, "%s: %s: \"%s\" -> %d\n", __func__, cmpp->alias, env, rc); ++ return rc; ++} ++ ++static void ++select_reload_action(struct multipath *mpp, const char *reason) ++{ + mpp->action = ACT_RELOAD; +- condlog(3, "%s: set ACT_RELOAD (%s%s)", mpp->alias, +- mpp->force_udev_reload ? "forced, " : "", +- reason); ++ condlog(3, "%s: set ACT_RELOAD (%s)", mpp->alias, reason); + } + + void select_action (struct multipath *mpp, const struct _vector *curmp, +@@ -789,10 +794,18 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + return; + } + ++ if (!is_udev_ready(cmpp) && count_active_paths(mpp) > 0) { ++ mpp->force_udev_reload = 1; ++ mpp->action = ACT_RELOAD; ++ condlog(3, "%s: set ACT_RELOAD (udev incomplete)", ++ mpp->alias); ++ return; ++ } ++ + if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF && + !!strstr(mpp->features, "queue_if_no_path") != + !!strstr(cmpp->features, "queue_if_no_path")) { +- select_reload_action(mpp, cmpp, "no_path_retry change"); ++ select_reload_action(mpp, "no_path_retry change"); + return; + } + if ((mpp->retain_hwhandler != RETAIN_HWHANDLER_ON || +@@ -800,7 +813,7 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + (strlen(cmpp->hwhandler) != strlen(mpp->hwhandler) || + strncmp(cmpp->hwhandler, mpp->hwhandler, + strlen(mpp->hwhandler)))) { +- select_reload_action(mpp, cmpp, "hwhandler change"); ++ select_reload_action(mpp, "hwhandler change"); + return; + } + +@@ -808,7 +821,7 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + !!strstr(mpp->features, "retain_attached_hw_handler") != + !!strstr(cmpp->features, "retain_attached_hw_handler") && + get_linux_version_code() < KERNEL_VERSION(4, 3, 0)) { +- select_reload_action(mpp, cmpp, "retain_hwhandler change"); ++ select_reload_action(mpp, "retain_hwhandler change"); + return; + } + +@@ -820,7 +833,7 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + remove_feature(&cmpp_feat, "queue_if_no_path"); + remove_feature(&cmpp_feat, "retain_attached_hw_handler"); + if (strncmp(mpp_feat, cmpp_feat, PARAMS_SIZE)) { +- select_reload_action(mpp, cmpp, "features change"); ++ select_reload_action(mpp, "features change"); + FREE(cmpp_feat); + FREE(mpp_feat); + return; +@@ -831,19 +844,19 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + + if (!cmpp->selector || strncmp(cmpp->selector, mpp->selector, + strlen(mpp->selector))) { +- select_reload_action(mpp, cmpp, "selector change"); ++ select_reload_action(mpp, "selector change"); + return; + } + if (cmpp->minio != mpp->minio) { +- select_reload_action(mpp, cmpp, "minio change"); ++ select_reload_action(mpp, "minio change"); + return; + } + if (!cmpp->pg || VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) { +- select_reload_action(mpp, cmpp, "path group number change"); ++ select_reload_action(mpp, "path group number change"); + return; + } + if (pgcmp(mpp, cmpp)) { +- select_reload_action(mpp, cmpp, "path group topology change"); ++ select_reload_action(mpp, "path group topology change"); + return; + } + if (cmpp->nextpg != mpp->bestpg) { +-- +2.17.2 + diff --git a/0081-multipath-tools-avoid-access-to-etc-localtime.patch b/0081-multipath-tools-avoid-access-to-etc-localtime.patch new file mode 100644 index 0000000..1e67613 --- /dev/null +++ b/0081-multipath-tools-avoid-access-to-etc-localtime.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Dec 2020 17:09:49 +0100 +Subject: [PATCH] multipath-tools: avoid access to /etc/localtime + +If the root file system is multipathed, and IO is queued because all paths +are failed, multipathd may block trying to access the root FS, and thus be +unable to reinstate paths. One file that is frequently accessed is +/etc/localtime. Avoid that by printing monotonic timestamps instead. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/debug.c | 14 ++++++++------ + libmultipath/devmapper.c | 12 ++++++------ + libmultipath/log.c | 1 - + multipathd/main.c | 3 --- + 4 files changed, 14 insertions(+), 16 deletions(-) + +diff --git a/libmultipath/debug.c b/libmultipath/debug.c +index 429f2699..510e15e5 100644 +--- a/libmultipath/debug.c ++++ b/libmultipath/debug.c +@@ -14,6 +14,8 @@ + #include "config.h" + #include "defaults.h" + #include "debug.h" ++#include "time-util.h" ++#include "util.h" + + int logsink; + int libmp_verbosity = DEFAULT_VERBOSITY; +@@ -25,13 +27,13 @@ void dlog(int prio, const char * fmt, ...) + va_start(ap, fmt); + if (logsink != LOGSINK_SYSLOG) { + if (logsink == LOGSINK_STDERR_WITH_TIME) { +- time_t t = time(NULL); +- struct tm *tb = localtime(&t); +- char buff[16]; ++ struct timespec ts; ++ char buff[32]; + +- strftime(buff, sizeof(buff), +- "%b %d %H:%M:%S", tb); +- buff[sizeof(buff)-1] = '\0'; ++ get_monotonic_time(&ts); ++ safe_sprintf(buff, "%ld.%06ld", ++ (long)ts.tv_sec, ++ ts.tv_nsec/1000); + fprintf(stderr, "%s | ", buff); + } + vfprintf(stderr, fmt, ap); +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 4977b311..095cbc0c 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -27,6 +27,7 @@ + #include "config.h" + #include "wwids.h" + #include "version.h" ++#include "time-util.h" + + #include "log_pthread.h" + #include +@@ -106,13 +107,12 @@ dm_write_log (int level, const char *file, int line, const char *f, ...) + va_start(ap, f); + if (logsink != LOGSINK_SYSLOG) { + if (logsink == LOGSINK_STDERR_WITH_TIME) { +- time_t t = time(NULL); +- struct tm *tb = localtime(&t); +- char buff[16]; +- +- strftime(buff, sizeof(buff), "%b %d %H:%M:%S", tb); +- buff[sizeof(buff)-1] = '\0'; ++ struct timespec ts; ++ char buff[32]; + ++ get_monotonic_time(&ts); ++ safe_sprintf(buff, "%ld.%06ld", ++ (long)ts.tv_sec, ts.tv_nsec/1000); + fprintf(stderr, "%s | ", buff); + } + fprintf(stderr, "libdevmapper: %s(%i): ", file, line); +diff --git a/libmultipath/log.c b/libmultipath/log.c +index 95c8f01a..6498c88c 100644 +--- a/libmultipath/log.c ++++ b/libmultipath/log.c +@@ -120,7 +120,6 @@ void log_reset (char *program_name) + pthread_cleanup_push(cleanup_mutex, &logq_lock); + + closelog(); +- tzset(); + openlog(program_name, 0, LOG_DAEMON); + + pthread_cleanup_pop(1); +diff --git a/multipathd/main.c b/multipathd/main.c +index 2eab4854..4417860b 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2706,9 +2706,6 @@ reconfigure (struct vectors * vecs) + delete_all_foreign(); + + reset_checker_classes(); +- /* Re-read any timezone changes */ +- tzset(); +- + if (bindings_read_only) + conf->bindings_read_only = bindings_read_only; + check_alias_settings(conf); +-- +2.17.2 + diff --git a/0082-multipath-tools-make-sure-plugin-DSOs-use-symbol-ver.patch b/0082-multipath-tools-make-sure-plugin-DSOs-use-symbol-ver.patch new file mode 100644 index 0000000..cc3a633 --- /dev/null +++ b/0082-multipath-tools-make-sure-plugin-DSOs-use-symbol-ver.patch @@ -0,0 +1,149 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Dec 2020 23:14:59 +0100 +Subject: [PATCH] multipath-tools: make sure plugin DSOs use symbol versions + +By adding -Wl,-z,defs, we'll get warnings about unresolved symbols +at the linking stage. This way we make sure our plugins (checkers etc.) +will use versioned symbols from libmultipath, and incompatible plugins +can't be loaded any more. Doing this requires explicitly linking +the plugins with all libraries they use, in particular libmultipath. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + Makefile | 1 + + Makefile.inc | 2 +- + libmpathpersist/Makefile | 8 ++++---- + libmultipath/checkers/Makefile | 7 +++---- + libmultipath/foreign/Makefile | 4 +++- + libmultipath/prioritizers/Makefile | 7 +++---- + 6 files changed, 15 insertions(+), 14 deletions(-) + +diff --git a/Makefile b/Makefile +index f127ff91..bddb2bf7 100644 +--- a/Makefile ++++ b/Makefile +@@ -31,6 +31,7 @@ $(BUILDDIRS): + + libmultipath libdmmp: libmpathcmd + libmpathpersist libmpathvalid multipath multipathd: libmultipath ++libmultipath/prioritizers libmultipath/checkers libmultipath/foreign: libmultipath + mpathpersist multipathd: libmpathpersist + + libmultipath/checkers.install \ +diff --git a/Makefile.inc b/Makefile.inc +index 13587a9f..05429307 100644 +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -105,7 +105,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 ++LDFLAGS := $(LDFLAGS) -Wl,-z,relro -Wl,-z,now -Wl,-z,defs + BIN_LDFLAGS = -pie + + # Check whether a function with name $1 has been declared in header file $2. +diff --git a/libmpathpersist/Makefile b/libmpathpersist/Makefile +index 456ce4cf..57103e58 100644 +--- a/libmpathpersist/Makefile ++++ b/libmpathpersist/Makefile +@@ -6,17 +6,17 @@ LIBS = $(DEVLIB).$(SONAME) + VERSION_SCRIPT := libmpathpersist.version + + CFLAGS += $(LIB_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir) ++LDFLAGS += -L$(multipathdir) -L$(mpathcmddir) + +-LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \ +- -L$(mpathcmddir) -lmpathcmd ++LIBDEPS += -lmultipath -lmpathcmd -ldevmapper -lpthread -ldl + + OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o + + all: $(DEVLIB) man + + $(LIBS): $(OBJS) $(VERSION_SCRIPT) +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) $(LIBDEPS) -Wl,-soname=$@ \ +- -Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \ ++ -Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS) + + $(DEVLIB): $(LIBS) + $(LN) $(LIBS) $@ +diff --git a/libmultipath/checkers/Makefile b/libmultipath/checkers/Makefile +index 01c04510..8e0ed5e9 100644 +--- a/libmultipath/checkers/Makefile ++++ b/libmultipath/checkers/Makefile +@@ -4,6 +4,8 @@ + include ../../Makefile.inc + + CFLAGS += $(LIB_CFLAGS) -I.. ++LDFLAGS += -L.. -lmultipath ++LIBDEPS = -lmultipath -laio -lpthread -lrt + + # If you add or remove a checker also update multipath/multipath.conf.5 + LIBS= \ +@@ -17,11 +19,8 @@ LIBS= \ + + all: $(LIBS) + +-libcheckdirectio.so: directio.o +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -laio +- + libcheck%.so: %.o +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ $(LIBDEPS) + + install: + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir) +diff --git a/libmultipath/foreign/Makefile b/libmultipath/foreign/Makefile +index fae58a0d..f447a1c4 100644 +--- a/libmultipath/foreign/Makefile ++++ b/libmultipath/foreign/Makefile +@@ -5,13 +5,15 @@ TOPDIR=../.. + include ../../Makefile.inc + + CFLAGS += $(LIB_CFLAGS) -I.. -I$(nvmedir) ++LDFLAGS += -L.. ++LIBDEPS = -lmultipath -ludev -lpthread -lrt + + LIBS = libforeign-nvme.so + + all: $(LIBS) + + libforeign-%.so: %.o +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ $(LIBDEPS) + + install: + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir) +diff --git a/libmultipath/prioritizers/Makefile b/libmultipath/prioritizers/Makefile +index fc6e0e0c..8d34ae32 100644 +--- a/libmultipath/prioritizers/Makefile ++++ b/libmultipath/prioritizers/Makefile +@@ -4,6 +4,8 @@ + include ../../Makefile.inc + + CFLAGS += $(LIB_CFLAGS) -I.. ++LDFLAGS += -L.. ++LIBDEPS = -lmultipath -lm -lpthread -lrt + + # If you add or remove a prioritizer also update multipath/multipath.conf.5 + LIBS = \ +@@ -28,11 +30,8 @@ endif + + all: $(LIBS) + +-libpriopath_latency.so: path_latency.o +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -lm +- + libprio%.so: %.o +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ $(LIBDEPS) + + install: $(LIBS) + $(INSTALL_PROGRAM) -m 755 libprio*.so $(DESTDIR)$(libdir) +-- +2.17.2 + diff --git a/0083-libmultipath.version-add-missing-symbol.patch b/0083-libmultipath.version-add-missing-symbol.patch new file mode 100644 index 0000000..55e4396 --- /dev/null +++ b/0083-libmultipath.version-add-missing-symbol.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 17 Dec 2020 01:30:30 +0100 +Subject: [PATCH] libmultipath.version: add missing symbol + +The weightedpath prioritizer uses get_next_string(). I'd overlooked +this before. This was found with the help of the previous patch. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/libmultipath.version | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 751099dc..2228f4ec 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -275,3 +275,8 @@ LIBMULTIPATH_4.3.0 { + global: + start_checker_thread; + } LIBMULTIPATH_4.2.0; ++ ++LIBMULTIPATH_4.4.0 { ++global: ++ get_next_string; ++} LIBMULTIPATH_4.3.0; +-- +2.17.2 + diff --git a/0084-multipath-tools-tests-unversioned-.so-for-valgrind-t.patch b/0084-multipath-tools-tests-unversioned-.so-for-valgrind-t.patch new file mode 100644 index 0000000..6be89d6 --- /dev/null +++ b/0084-multipath-tools-tests-unversioned-.so-for-valgrind-t.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 23:11:47 +0100 +Subject: [PATCH] multipath-tools tests: unversioned .so for valgrind tests + +We need to the same thing for valgrind tests as we did in +448752f ("libmultipath: create separate .so for unit tests"). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/Makefile b/tests/Makefile +index 54da774e..50673fae 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -76,7 +76,7 @@ lib/libchecktur.so: + + %.vgr: %-test lib/libchecktur.so + @echo == running valgrind for $< == +- @LD_LIBRARY_PATH=$(multipathdir):$(mpathcmddir) \ ++ @LD_LIBRARY_PATH=.:$(mpathcmddir) \ + valgrind --leak-check=full --error-exitcode=128 ./$< >$@ 2>&1 + + OBJS = $(TESTS:%=%.o) $(HELPERS) +-- +2.17.2 + diff --git a/0085-multipath-tools-unit-tests-fix-memory-leaks-in-mpath.patch b/0085-multipath-tools-unit-tests-fix-memory-leaks-in-mpath.patch new file mode 100644 index 0000000..3a3bbbf --- /dev/null +++ b/0085-multipath-tools-unit-tests-fix-memory-leaks-in-mpath.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 23:17:48 +0100 +Subject: [PATCH] multipath-tools unit tests: fix memory leaks in mpathvalid + tests + +They break "make valgrind-test". + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/mpathvalid.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/tests/mpathvalid.c b/tests/mpathvalid.c +index 5ffabb9d..cfe4bae1 100644 +--- a/tests/mpathvalid.c ++++ b/tests/mpathvalid.c +@@ -381,6 +381,7 @@ static void test_mpathvalid_is_path_good2(void **state) + assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, + wwids, 4), MPATH_IS_VALID); + assert_string_equal(wwid, TEST_WWID); ++ free(wwid); + } + + static void test_mpathvalid_is_path_good3(void **state) +@@ -395,6 +396,7 @@ static void test_mpathvalid_is_path_good3(void **state) + assert_int_equal(mpathvalid_is_path(test_dev, MPATH_SMART, &wwid, + wwids, 4), MPATH_IS_VALID); + assert_string_equal(wwid, TEST_WWID); ++ free(wwid); + } + + /* mabybe valid with no matching paths */ +@@ -410,6 +412,7 @@ static void test_mpathvalid_is_path_good4(void **state) + assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, + wwids, 4), MPATH_IS_MAYBE_VALID); + assert_string_equal(wwid, TEST_WWID); ++ free(wwid); + } + + /* maybe valid with matching paths */ +@@ -425,6 +428,7 @@ static void test_mpathvalid_is_path_good5(void **state) + assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, + wwids, 4), MPATH_IS_VALID); + assert_string_equal(wwid, TEST_WWID); ++ free(wwid); + } + + #define setup_test(name) \ +-- +2.17.2 + diff --git a/0086-mpathpersist-Fix-Register-and-Ignore-with-0x00-SARK.patch b/0086-mpathpersist-Fix-Register-and-Ignore-with-0x00-SARK.patch new file mode 100644 index 0000000..3e152fc --- /dev/null +++ b/0086-mpathpersist-Fix-Register-and-Ignore-with-0x00-SARK.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 18 Dec 2020 17:06:37 -0600 +Subject: [PATCH] mpathpersist: Fix Register and Ignore with 0x00 SARK + +When the Register and Ignore command is run with sg_persist, if a 0x00 +Service Action Reservation Key is given or the --param-sark option is +not used at all, sg_persist will clear the registration. mpathpersist +will fail with an error. This patch fixes mpathpersist to work like +sg_persist in this case. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmpathpersist/mpath_persist.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 79322e86..41789c46 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -304,7 +304,8 @@ int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, + } + + if (memcmp(paramp->key, &mpp->reservation_key, 8) && +- memcmp(paramp->sa_key, &mpp->reservation_key, 8)) { ++ memcmp(paramp->sa_key, &mpp->reservation_key, 8) && ++ (prkey || rq_servact != MPATH_PROUT_REG_IGN_SA)) { + condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64, alias, get_be64(mpp->reservation_key)); + ret = MPATH_PR_SYNTAX_ERROR; + goto out1; +-- +2.17.2 + diff --git a/0087-mpathpersist-update-prkeys-file-on-changing-registra.patch b/0087-mpathpersist-update-prkeys-file-on-changing-registra.patch new file mode 100644 index 0000000..79bee15 --- /dev/null +++ b/0087-mpathpersist-update-prkeys-file-on-changing-registra.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 18 Dec 2020 17:06:38 -0600 +Subject: [PATCH] mpathpersist: update prkeys file on changing registrations + +When the "reservation_key" option is set to "file" and Register command +is run with both the current Reservation Key and a new Service Action +Reservation Key, mpathpersist will change the registration, but will not +update the prkeys file. This means that future paths that come online +will not be able to register, since multipathd is still using the old +reservation key. Fix this. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmpathpersist/mpath_persist.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 41789c46..08077936 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -290,9 +290,10 @@ int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, + + memcpy(&prkey, paramp->sa_key, 8); + if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey && +- ((!get_be64(mpp->reservation_key) && +- rq_servact == MPATH_PROUT_REG_SA) || +- rq_servact == MPATH_PROUT_REG_IGN_SA)) { ++ (rq_servact == MPATH_PROUT_REG_IGN_SA || ++ (rq_servact == MPATH_PROUT_REG_SA && ++ (!get_be64(mpp->reservation_key) || ++ memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) { + memcpy(&mpp->reservation_key, paramp->sa_key, 8); + if (update_prkey_flags(alias, get_be64(mpp->reservation_key), + paramp->sa_flags)) { +-- +2.17.2 + diff --git a/0088-libmultipath-warn-about-missing-braces-at-end-of-mul.patch b/0088-libmultipath-warn-about-missing-braces-at-end-of-mul.patch new file mode 100644 index 0000000..bbb9f13 --- /dev/null +++ b/0088-libmultipath-warn-about-missing-braces-at-end-of-mul.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 18 Dec 2020 17:06:39 -0600 +Subject: [PATCH] libmultipath: warn about missing braces at end of + multipath.conf + +Multipath doesn't warn when multipath.conf is missing closing braces at +the end of the file. This has confused people about the correct config +file syntax, so add a warning. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/parser.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/libmultipath/parser.c b/libmultipath/parser.c +index 163ffbc9..c70243c3 100644 +--- a/libmultipath/parser.c ++++ b/libmultipath/parser.c +@@ -537,7 +537,7 @@ process_stream(struct config *conf, FILE *stream, vector keywords, + if (!strcmp(str, EOB)) { + if (kw_level > 0) { + free_strvec(strvec); +- break; ++ goto out; + } + condlog(0, "unmatched '%s' at line %d of %s", + EOB, line_nr, file); +@@ -576,7 +576,8 @@ process_stream(struct config *conf, FILE *stream, vector keywords, + + free_strvec(strvec); + } +- ++ if (kw_level == 1) ++ condlog(1, "missing '%s' at end of %s", EOB, file); + out: + FREE(buf); + free_uniques(uniques); +-- +2.17.2 + diff --git a/0089-libmultipath-ignore-multipaths-sections-without-wwid.patch b/0089-libmultipath-ignore-multipaths-sections-without-wwid.patch new file mode 100644 index 0000000..25aa7ea --- /dev/null +++ b/0089-libmultipath-ignore-multipaths-sections-without-wwid.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 18 Dec 2020 17:06:40 -0600 +Subject: [PATCH] libmultipath: ignore multipaths sections without wwid option + +"multipathd show config local" was crashing in find_mp_by_wwid() if +the multipath configuration included a multipaths section that did +not set a wwid option. There is no reason to keep a mpentry that +didn't set its wwid. Remove it in merge_mptable(). + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/config.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index 9f3cb38d..a643703e 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -509,6 +509,13 @@ void merge_mptable(vector mptable) + int i, j; + + vector_foreach_slot(mptable, mp1, i) { ++ /* drop invalid multipath configs */ ++ if (!mp1->wwid) { ++ condlog(0, "multipaths config section missing wwid"); ++ vector_del_slot(mptable, i--); ++ free_mpe(mp1); ++ continue; ++ } + j = i + 1; + vector_foreach_slot_after(mptable, mp2, j) { + if (strcmp(mp1->wwid, mp2->wwid)) +-- +2.17.2 + diff --git a/0090-libmultipath-fix-format-warning-with-clang.patch b/0090-libmultipath-fix-format-warning-with-clang.patch new file mode 100644 index 0000000..931e81c --- /dev/null +++ b/0090-libmultipath-fix-format-warning-with-clang.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 23:34:35 +0100 +Subject: [PATCH] libmultipath: fix format warning with clang + +Reported-by: Xose Vazquez Perez +Tested-by: Xose Vazquez Perez +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libmultipath/log.c b/libmultipath/log.c +index 6498c88c..10fa32cd 100644 +--- a/libmultipath/log.c ++++ b/libmultipath/log.c +@@ -125,6 +125,7 @@ void log_reset (char *program_name) + pthread_cleanup_pop(1); + } + ++__attribute__((format(printf, 2, 0))) + static int _log_enqueue(int prio, const char * fmt, va_list ap) + { + int len, fwd; +-- +2.17.2 + diff --git a/0091-libmultipath-check-for-null-wwid-before-strcmp.patch b/0091-libmultipath-check-for-null-wwid-before-strcmp.patch new file mode 100644 index 0000000..1f6894d --- /dev/null +++ b/0091-libmultipath-check-for-null-wwid-before-strcmp.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 4 Jan 2021 21:59:54 -0600 +Subject: [PATCH] libmultipath: check for null wwid before strcmp + +Commit 749aabd0 (libmultipath: ignore multipaths sections without wwid +option) removed all mpentries with a NULL wwid, but didn't stop strcmp() +from being run on them in merge_mptable(). The result of strcmp() with +a NULL parameter is undefined, so fix that. + +Signed-off-by: Benjamin Marzinski + +Reviewed-by: Martin Wilck +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index a643703e..be310159 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -518,7 +518,7 @@ void merge_mptable(vector mptable) + } + j = i + 1; + vector_foreach_slot_after(mptable, mp2, j) { +- if (strcmp(mp1->wwid, mp2->wwid)) ++ if (!mp2->wwid || strcmp(mp1->wwid, mp2->wwid)) + continue; + condlog(1, "%s: duplicate multipath config section for %s", + __func__, mp1->wwid); +-- +2.17.2 + diff --git a/0092-multipath.conf.5-Improve-checker_timeout-description.patch b/0092-multipath.conf.5-Improve-checker_timeout-description.patch new file mode 100644 index 0000000..120c637 --- /dev/null +++ b/0092-multipath.conf.5-Improve-checker_timeout-description.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 4 Jan 2021 21:59:55 -0600 +Subject: [PATCH] multipath.conf.5: Improve checker_timeout description + +I was asked to explain how checker_timeout works for checkers like +directio, that don't issue scsi commands with an explicit timeout. +Also, undeprecate the directio checker. + +Signed-off-by: Benjamin Marzinski + +Reviewed-by: Martin Wilck +Signed-off-by: Benjamin Marzinski +--- + multipath/multipath.conf.5 | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 +index ea66a01e..8ef3a747 100644 +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -472,8 +472,12 @@ The default is: \fB\fR + . + .TP + .B path_checker +-The default method used to determine the paths state. Possible values +-are: ++The default method used to determine the path's state. The synchronous ++checkers (all except \fItur\fR and \fIdirectio\fR) will cause multipathd to ++pause most activity, waiting up to \fIchecker_timeout\fR seconds for the path ++to respond. The asynchronous checkers (\fItur\fR and \fIdirectio\fR) will not ++pause multipathd. Instead, multipathd will check for a response once per ++second, until \fIchecker_timeout\fR seconds have elapsed. Possible values are: + .RS + .TP 12 + .I readsector0 +@@ -499,10 +503,8 @@ Check the path state for LSI/Engenio/NetApp RDAC class as NetApp SANtricity E/EF + Series, and OEM arrays from IBM DELL SGI STK and SUN. + .TP + .I directio +-(Deprecated) Read the first sector with direct I/O. If you have a large number +-of paths, or many AIO users on a system, you may need to use sysctl to +-increase fs.aio-max-nr. This checker is being deprecated, it could cause +-spurious path failures under high load. Please use \fItur\fR instead. ++Read the first sector with direct I/O. This checker could cause spurious path ++failures under high load. Increasing \fIchecker_timeout\fR can help with this. + .TP + .I cciss_tur + (Hardware-dependent) +@@ -639,8 +641,10 @@ The default is: \fBno\fR + . + .TP + .B checker_timeout +-Specify the timeout to use for path checkers and prioritizers that issue SCSI +-commands with an explicit timeout, in seconds. ++Specify the timeout to use for path checkers and prioritizers, in seconds. ++Only prioritizers that issue scsi commands use checker_timeout. If a path ++does not respond to the checker command after \fIchecker_timeout\fR ++seconds have elapsed, it is considered down. + .RS + .TP + The default is: in \fB/sys/block/sd/device/timeout\fR +-- +2.17.2 + diff --git a/0093-multipathd-fix-path-checkint-not-changed-when-path-s.patch b/0093-multipathd-fix-path-checkint-not-changed-when-path-s.patch new file mode 100644 index 0000000..868fa18 --- /dev/null +++ b/0093-multipathd-fix-path-checkint-not-changed-when-path-s.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chongyun Wu +Date: Wed, 6 Jan 2021 09:39:12 +0800 +Subject: [PATCH] multipathd: fix path checkint not changed when path state + changed from delay to failed + +Check_path: when path state change back to failed from delay state, +should change this path's check interval time to the shortest delay +to faster path state check. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Chongyun Wu +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 4417860b..7612430a 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2161,6 +2161,11 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + (pp->state == PATH_DELAYED)) { + /* If path state become failed again cancel path delay state */ + pp->state = newstate; ++ /* ++ * path state bad again should change the check interval time ++ * to the shortest delay ++ */ ++ pp->checkint = checkint; + return 1; + } + if (!pp->mpp) { +-- +2.17.2 + diff --git a/0094-libmultipath-select_action-skip-is_mpp_known_to_udev.patch b/0094-libmultipath-select_action-skip-is_mpp_known_to_udev.patch new file mode 100644 index 0000000..e37e4da --- /dev/null +++ b/0094-libmultipath-select_action-skip-is_mpp_known_to_udev.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Jan 2021 17:22:09 +0100 +Subject: [PATCH] libmultipath: select_action(): skip is_mpp_known_to_udev() + test + +This test is now superseded by the check introduced in +0d66e03 ("libmultipath: force map reload if udev incomplete"). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 15 --------------- + 1 file changed, 15 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index d9fd9cb8..999f3106 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -635,15 +635,6 @@ trigger_paths_udev_change(struct multipath *mpp, bool is_mpath) + mpp->needs_paths_uevent = 0; + } + +-static int +-is_mpp_known_to_udev(const struct multipath *mpp) +-{ +- struct udev_device *udd = get_udev_for_mpp(mpp); +- int ret = (udd != NULL); +- udev_device_unref(udd); +- return ret; +-} +- + static int + sysfs_set_max_sectors_kb(struct multipath *mpp, int is_reload) + { +@@ -865,12 +856,6 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + mpp->alias); + return; + } +- if (!is_mpp_known_to_udev(cmpp)) { +- mpp->action = ACT_RELOAD; +- condlog(3, "%s: set ACT_RELOAD (udev device not initialized)", +- mpp->alias); +- return; +- } + mpp->action = ACT_NOTHING; + condlog(3, "%s: set ACT_NOTHING (map unchanged)", + mpp->alias); +-- +2.17.2 + diff --git a/0095-libmultipath-coalesce_paths-stop-triggering-spurious.patch b/0095-libmultipath-coalesce_paths-stop-triggering-spurious.patch new file mode 100644 index 0000000..033525b --- /dev/null +++ b/0095-libmultipath-coalesce_paths-stop-triggering-spurious.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Jan 2021 17:36:40 +0100 +Subject: [PATCH] libmultipath: coalesce_paths(): stop triggering spurious + uevents + +Since 0d66e03 ("libmultipath: force map reload if udev incomplete"), we +force-reload maps that we find incompletely initialized by udev. If +select_action returns ACT_NOTHING nonetheless, the map must be initialized +in udev, and thus and "add" uevent must have been seen already. Triggering +this event once more is unlikely to fix anything for real. + +Reverts: b516118 ("libmultipath: coalesce_paths: trigger uevent if nothing done") + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 24 ------------------------ + 1 file changed, 24 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 999f3106..3263bb01 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -527,18 +527,6 @@ get_udev_for_mpp(const struct multipath *mpp) + return udd; + } + +-static void +-trigger_udev_change(const struct multipath *mpp) +-{ +- static const char change[] = "change"; +- struct udev_device *udd = get_udev_for_mpp(mpp); +- if (!udd) +- return; +- condlog(3, "triggering %s uevent for %s", change, mpp->alias); +- sysfs_attr_set_value(udd, "uevent", change, sizeof(change)-1); +- udev_device_unref(udd); +-} +- + static void trigger_partitions_udev_change(struct udev_device *dev, + const char *action, int len) + { +@@ -1297,18 +1285,6 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, + continue; + } + +- if (r == DOMAP_EXIST && mpp->action == ACT_NOTHING && +- force_reload == FORCE_RELOAD_WEAK) +- /* +- * First time we're called, and no changes applied. +- * domap() was a noop. But we can't be sure that +- * udev has already finished setting up this device +- * (udev in initrd may have been shut down while +- * processing this device or its children). +- * Trigger a change event, just in case. +- */ +- trigger_udev_change(find_mp_by_wwid(curmp, mpp->wwid)); +- + conf = get_multipath_config(); + allow_queueing = conf->allow_queueing; + put_multipath_config(conf); +-- +2.17.2 + diff --git a/0096-Revert-multipathd-uev_trigger-handle-incomplete-ADD-.patch b/0096-Revert-multipathd-uev_trigger-handle-incomplete-ADD-.patch new file mode 100644 index 0000000..79912f0 --- /dev/null +++ b/0096-Revert-multipathd-uev_trigger-handle-incomplete-ADD-.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Jan 2021 17:27:10 +0100 +Subject: [PATCH] Revert "multipathd: uev_trigger(): handle incomplete ADD + events" + +cb10d38 ("multipathd: uev_trigger(): handle incomplete ADD events") was an +attempt to fix issues with incompletely initialized multipath maps observed +in various scenarious. However, that patch was wrong. Spurious "change" events +as this patch would generate have no effect, because they are ignored by +the device-mapper udev rules. The correct fix for the problem we were +facing is 0d66e03 ("libmultipath: force map reload if udev incomplete"), +which forces a full map reload. + +Reverts: cb10d38 ("multipathd: uev_trigger(): handle incomplete ADD events") + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 25 ------------------------- + 1 file changed, 25 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 7612430a..92c45d44 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1499,31 +1499,6 @@ uev_trigger (struct uevent * uev, void * trigger_data) + uev_pathfail_check(uev, vecs); + } else if (!strncmp(uev->action, "remove", 6)) { + r = uev_remove_map(uev, vecs); +- } else if (!strncmp(uev->action, "add", 3)) { +- const char *ev_name; +- char *dm_name; +- int major = -1, minor = -1; +- +- /* +- * If DM_NAME is not set for a valid map, trigger a +- * change event. This can happen during coldplug +- * if udev was killed between handling the 'add' and +- * 'change' events before. +- */ +- ev_name = uevent_get_dm_name(uev); +- if (!ev_name) { +- major = uevent_get_major(uev); +- minor = uevent_get_minor(uev); +- dm_name = dm_mapname(major, minor); +- if (dm_name && *dm_name) { +- condlog(2, "%s: received incomplete 'add' uevent, triggering change", +- dm_name); +- udev_device_set_sysattr_value(uev->udev, +- "uevent", +- "change"); +- free(dm_name); +- } +- } + } + goto out; + } +-- +2.17.2 + diff --git a/0097-libmultipath-make-find_err_path_by_dev-static.patch b/0097-libmultipath-make-find_err_path_by_dev-static.patch new file mode 100644 index 0000000..a19afc4 --- /dev/null +++ b/0097-libmultipath-make-find_err_path_by_dev-static.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 14 Jan 2021 20:20:22 -0600 +Subject: [PATCH] libmultipath: make find_err_path_by_dev() static + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index 5363049d..2e48ee81 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -88,7 +88,7 @@ static void rcu_unregister(__attribute__((unused)) void *param) + rcu_unregister_thread(); + } + +-struct io_err_stat_path *find_err_path_by_dev(vector pathvec, char *dev) ++static struct io_err_stat_path *find_err_path_by_dev(vector pathvec, char *dev) + { + int i; + struct io_err_stat_path *pp; +-- +2.17.2 + diff --git a/0098-multipathd-avoid-io_err_stat-crash-during-shutdown.patch b/0098-multipathd-avoid-io_err_stat-crash-during-shutdown.patch new file mode 100644 index 0000000..4c21465 --- /dev/null +++ b/0098-multipathd-avoid-io_err_stat-crash-during-shutdown.patch @@ -0,0 +1,257 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 14 Jan 2021 20:20:23 -0600 +Subject: [PATCH] multipathd: avoid io_err_stat crash during shutdown + +The checker thread is reponsible for enqueueing paths for the +io_err_stat thread to check. During shutdown, the io_err_stat thread is +shut down and cleaned up before the checker thread. There is no code +to make sure that the checker thread isn't accessing the io_err_stat +pathvec or its mutex while they are being freed, which can lead to +memory corruption crashes. + +To solve this, get rid of the io_err_stat_pathvec structure, and +statically define the mutex. This means that the mutex is always valid +to access, and the io_err_stat pathvec can only be accessed while +holding it. If the io_err_stat thread has already been cleaned up +when the checker tries to access the pathvec, it will be NULL, and the +checker will simply fail to enqueue the path. + +This change also fixes a bug in free_io_err_pathvec(), which previously +only attempted to free the pathvec if it was not set, instead of when it +was set. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 111 ++++++++++++++----------------------- + 1 file changed, 43 insertions(+), 68 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index 2e48ee81..feb66469 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -46,12 +46,6 @@ + #define io_err_stat_log(prio, fmt, args...) \ + condlog(prio, "io error statistic: " fmt, ##args) + +- +-struct io_err_stat_pathvec { +- pthread_mutex_t mutex; +- vector pathvec; +-}; +- + struct dio_ctx { + struct timespec io_starttime; + unsigned int blksize; +@@ -75,9 +69,10 @@ static pthread_t io_err_stat_thr; + + static pthread_mutex_t io_err_thread_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_cond_t io_err_thread_cond = PTHREAD_COND_INITIALIZER; ++static pthread_mutex_t io_err_pathvec_lock = PTHREAD_MUTEX_INITIALIZER; + static int io_err_thread_running = 0; + +-static struct io_err_stat_pathvec *paths; ++static vector io_err_pathvec; + struct vectors *vecs; + io_context_t ioctx; + +@@ -207,46 +202,23 @@ static void free_io_err_stat_path(struct io_err_stat_path *p) + FREE(p); + } + +-static struct io_err_stat_pathvec *alloc_pathvec(void) +-{ +- struct io_err_stat_pathvec *p; +- int r; +- +- p = (struct io_err_stat_pathvec *)MALLOC(sizeof(*p)); +- if (!p) +- return NULL; +- p->pathvec = vector_alloc(); +- if (!p->pathvec) +- goto out_free_struct_pathvec; +- r = pthread_mutex_init(&p->mutex, NULL); +- if (r) +- goto out_free_member_pathvec; +- +- return p; +- +-out_free_member_pathvec: +- vector_free(p->pathvec); +-out_free_struct_pathvec: +- FREE(p); +- return NULL; +-} +- +-static void free_io_err_pathvec(struct io_err_stat_pathvec *p) ++static void free_io_err_pathvec(void) + { + struct io_err_stat_path *path; + int i; + +- if (!p) +- return; +- pthread_mutex_destroy(&p->mutex); +- if (!p->pathvec) { +- vector_foreach_slot(p->pathvec, path, i) { +- destroy_directio_ctx(path); +- free_io_err_stat_path(path); +- } +- vector_free(p->pathvec); ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ pthread_cleanup_push(cleanup_mutex, &io_err_pathvec_lock); ++ if (!io_err_pathvec) ++ goto out; ++ vector_foreach_slot(io_err_pathvec, path, i) { ++ destroy_directio_ctx(path); ++ free_io_err_stat_path(path); + } +- FREE(p); ++ vector_free(io_err_pathvec); ++ io_err_pathvec = NULL; ++out: ++ pthread_cleanup_pop(1); + } + + /* +@@ -258,13 +230,13 @@ static int enqueue_io_err_stat_by_path(struct path *path) + { + struct io_err_stat_path *p; + +- pthread_mutex_lock(&paths->mutex); +- p = find_err_path_by_dev(paths->pathvec, path->dev); ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ p = find_err_path_by_dev(io_err_pathvec, path->dev); + if (p) { +- pthread_mutex_unlock(&paths->mutex); ++ pthread_mutex_unlock(&io_err_pathvec_lock); + return 0; + } +- pthread_mutex_unlock(&paths->mutex); ++ pthread_mutex_unlock(&io_err_pathvec_lock); + + p = alloc_io_err_stat_path(); + if (!p) +@@ -276,18 +248,18 @@ static int enqueue_io_err_stat_by_path(struct path *path) + + if (setup_directio_ctx(p)) + goto free_ioerr_path; +- pthread_mutex_lock(&paths->mutex); +- if (!vector_alloc_slot(paths->pathvec)) ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ if (!vector_alloc_slot(io_err_pathvec)) + goto unlock_destroy; +- vector_set_slot(paths->pathvec, p); +- pthread_mutex_unlock(&paths->mutex); ++ vector_set_slot(io_err_pathvec, p); ++ pthread_mutex_unlock(&io_err_pathvec_lock); + + io_err_stat_log(2, "%s: enqueue path %s to check", + path->mpp->alias, path->dev); + return 0; + + unlock_destroy: +- pthread_mutex_unlock(&paths->mutex); ++ pthread_mutex_unlock(&io_err_pathvec_lock); + destroy_directio_ctx(p); + free_ioerr_path: + free_io_err_stat_path(p); +@@ -412,9 +384,9 @@ static int delete_io_err_stat_by_addr(struct io_err_stat_path *p) + { + int i; + +- i = find_slot(paths->pathvec, p); ++ i = find_slot(io_err_pathvec, p); + if (i != -1) +- vector_del_slot(paths->pathvec, i); ++ vector_del_slot(io_err_pathvec, i); + + destroy_directio_ctx(p); + free_io_err_stat_path(p); +@@ -585,7 +557,7 @@ static void poll_async_io_timeout(void) + + if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0) + return; +- vector_foreach_slot(paths->pathvec, pp, i) { ++ vector_foreach_slot(io_err_pathvec, pp, i) { + for (j = 0; j < CONCUR_NR_EVENT; j++) { + rc = try_to_cancel_timeout_io(pp->dio_ctx_array + j, + &curr_time, pp->devname); +@@ -631,7 +603,7 @@ static void handle_async_io_done_event(struct io_event *io_evt) + int rc = PATH_UNCHECKED; + int i, j; + +- vector_foreach_slot(paths->pathvec, pp, i) { ++ vector_foreach_slot(io_err_pathvec, pp, i) { + for (j = 0; j < CONCUR_NR_EVENT; j++) { + ct = pp->dio_ctx_array + j; + if (&ct->io == io_evt->obj) { +@@ -665,19 +637,14 @@ static void service_paths(void) + struct io_err_stat_path *pp; + int i; + +- pthread_mutex_lock(&paths->mutex); +- vector_foreach_slot(paths->pathvec, pp, i) { ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ vector_foreach_slot(io_err_pathvec, pp, i) { + send_batch_async_ios(pp); + process_async_ios_event(TIMEOUT_NO_IO_NSEC, pp->devname); + poll_async_io_timeout(); + poll_io_err_stat(vecs, pp); + } +- pthread_mutex_unlock(&paths->mutex); +-} +- +-static void cleanup_unlock(void *arg) +-{ +- pthread_mutex_unlock((pthread_mutex_t*) arg); ++ pthread_mutex_unlock(&io_err_pathvec_lock); + } + + static void cleanup_exited(__attribute__((unused)) void *arg) +@@ -736,13 +703,18 @@ int start_io_err_stat_thread(void *data) + io_err_stat_log(4, "io_setup failed"); + return 1; + } +- paths = alloc_pathvec(); +- if (!paths) ++ ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ io_err_pathvec = vector_alloc(); ++ if (!io_err_pathvec) { ++ pthread_mutex_unlock(&io_err_pathvec_lock); + goto destroy_ctx; ++ } ++ pthread_mutex_unlock(&io_err_pathvec_lock); + + setup_thread_attr(&io_err_stat_attr, 32 * 1024, 0); + pthread_mutex_lock(&io_err_thread_lock); +- pthread_cleanup_push(cleanup_unlock, &io_err_thread_lock); ++ pthread_cleanup_push(cleanup_mutex, &io_err_thread_lock); + + ret = pthread_create(&io_err_stat_thr, &io_err_stat_attr, + io_err_stat_loop, data); +@@ -763,7 +735,10 @@ int start_io_err_stat_thread(void *data) + return 0; + + out_free: +- free_io_err_pathvec(paths); ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ vector_free(io_err_pathvec); ++ io_err_pathvec = NULL; ++ pthread_mutex_unlock(&io_err_pathvec_lock); + destroy_ctx: + io_destroy(ioctx); + io_err_stat_log(0, "failed to start io_error statistic thread"); +@@ -779,6 +754,6 @@ void stop_io_err_stat_thread(void) + pthread_cancel(io_err_stat_thr); + + pthread_join(io_err_stat_thr, NULL); +- free_io_err_pathvec(paths); ++ free_io_err_pathvec(); + io_destroy(ioctx); + } +-- +2.17.2 + diff --git a/0099-multipathd-avoid-io_err_stat-ABBA-deadlock.patch b/0099-multipathd-avoid-io_err_stat-ABBA-deadlock.patch new file mode 100644 index 0000000..30584f6 --- /dev/null +++ b/0099-multipathd-avoid-io_err_stat-ABBA-deadlock.patch @@ -0,0 +1,146 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 14 Jan 2021 20:20:24 -0600 +Subject: [PATCH] multipathd: avoid io_err_stat ABBA deadlock + +When the checker thread enqueues paths for the io_err_stat thread to +check, it calls enqueue_io_err_stat_by_path() with the vecs lock held. +start_io_err_stat_thread() is also called with the vecs lock held. +These two functions both lock io_err_pathvec_lock. When the io_err_stat +thread updates the paths in vecs->pathvec in poll_io_err_stat(), it has +the io_err_pathvec_lock held, and then locks the vecs lock. This can +cause an ABBA deadlock. + +To solve this, service_paths() no longer updates the paths in +vecs->pathvec with the io_err_pathvec_lock held. It does this by moving +the io_err_stat_path from io_err_pathvec to a local vector when it needs +to update the path. After releasing the io_err_pathvec_lock, it goes +through this temporary vector, updates the paths with the vecs lock +held, and then frees everything. + +This change fixes a bug in service_paths() where elements were being +deleted from io_err_pathvec, without the index being decremented, +causing the loop to skip elements. Also, service_paths() could be +cancelled while holding the io_err_pathvec_lock, so it should have a +cleanup handler. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 56 ++++++++++++++++++++++---------------- + 1 file changed, 32 insertions(+), 24 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index feb66469..775e7259 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -380,20 +380,6 @@ recover: + return 0; + } + +-static int delete_io_err_stat_by_addr(struct io_err_stat_path *p) +-{ +- int i; +- +- i = find_slot(io_err_pathvec, p); +- if (i != -1) +- vector_del_slot(io_err_pathvec, i); +- +- destroy_directio_ctx(p); +- free_io_err_stat_path(p); +- +- return 0; +-} +- + static void account_async_io_state(struct io_err_stat_path *pp, int rc) + { + switch (rc) { +@@ -410,17 +396,26 @@ static void account_async_io_state(struct io_err_stat_path *pp, int rc) + } + } + +-static int poll_io_err_stat(struct vectors *vecs, struct io_err_stat_path *pp) ++static int io_err_stat_time_up(struct io_err_stat_path *pp) + { + struct timespec currtime, difftime; +- struct path *path; +- double err_rate; + + if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) +- return 1; ++ return 0; + timespecsub(&currtime, &pp->start_time, &difftime); + if (difftime.tv_sec < pp->total_time) + return 0; ++ return 1; ++} ++ ++static void end_io_err_stat(struct io_err_stat_path *pp) ++{ ++ struct timespec currtime; ++ struct path *path; ++ double err_rate; ++ ++ if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) ++ currtime = pp->start_time; + + io_err_stat_log(4, "%s: check end", pp->devname); + +@@ -459,10 +454,6 @@ static int poll_io_err_stat(struct vectors *vecs, struct io_err_stat_path *pp) + pp->devname); + } + lock_cleanup_pop(vecs->lock); +- +- delete_io_err_stat_by_addr(pp); +- +- return 0; + } + + static int send_each_async_io(struct dio_ctx *ct, int fd, char *dev) +@@ -622,6 +613,7 @@ static void process_async_ios_event(int timeout_nsecs, char *dev) + struct timespec timeout = { .tv_nsec = timeout_nsecs }; + + errno = 0; ++ pthread_testcancel(); + n = io_getevents(ioctx, 1L, CONCUR_NR_EVENT, events, &timeout); + if (n < 0) { + io_err_stat_log(3, "%s: async io events returned %d (errno=%s)", +@@ -634,17 +626,33 @@ static void process_async_ios_event(int timeout_nsecs, char *dev) + + static void service_paths(void) + { ++ struct _vector _pathvec = {0}; ++ /* avoid gcc warnings that &_pathvec will never be NULL in vector ops */ ++ struct _vector * const tmp_pathvec = &_pathvec; + struct io_err_stat_path *pp; + int i; + + pthread_mutex_lock(&io_err_pathvec_lock); ++ pthread_cleanup_push(cleanup_mutex, &io_err_pathvec_lock); + vector_foreach_slot(io_err_pathvec, pp, i) { + send_batch_async_ios(pp); + process_async_ios_event(TIMEOUT_NO_IO_NSEC, pp->devname); + poll_async_io_timeout(); +- poll_io_err_stat(vecs, pp); ++ if (io_err_stat_time_up(pp)) { ++ if (!vector_alloc_slot(tmp_pathvec)) ++ continue; ++ vector_del_slot(io_err_pathvec, i--); ++ vector_set_slot(tmp_pathvec, pp); ++ } + } +- pthread_mutex_unlock(&io_err_pathvec_lock); ++ pthread_cleanup_pop(1); ++ vector_foreach_slot_backwards(tmp_pathvec, pp, i) { ++ end_io_err_stat(pp); ++ vector_del_slot(tmp_pathvec, i); ++ destroy_directio_ctx(pp); ++ free_io_err_stat_path(pp); ++ } ++ vector_reset(tmp_pathvec); + } + + static void cleanup_exited(__attribute__((unused)) void *arg) +-- +2.17.2 + diff --git a/0100-multipathd-use-get_monotonic_time-in-io_err_stat-cod.patch b/0100-multipathd-use-get_monotonic_time-in-io_err_stat-cod.patch new file mode 100644 index 0000000..89d9f73 --- /dev/null +++ b/0100-multipathd-use-get_monotonic_time-in-io_err_stat-cod.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 14 Jan 2021 20:20:25 -0600 +Subject: [PATCH] multipathd: use get_monotonic_time() in io_err_stat code + +Instead of calling clock_gettime(), and dealing with failure +conditions, just call get_monotonic_time(). + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 34 +++++++++++----------------------- + 1 file changed, 11 insertions(+), 23 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index 775e7259..92871f40 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -295,8 +295,7 @@ int io_err_stat_handle_pathfail(struct path *path) + * the repeated count threshold and time frame, we assume a path + * which fails at least twice within 60 seconds is flaky. + */ +- if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0) +- return 1; ++ get_monotonic_time(&curr_time); + if (path->io_err_pathfail_cnt == 0) { + path->io_err_pathfail_cnt++; + path->io_err_pathfail_starttime = curr_time.tv_sec; +@@ -352,9 +351,9 @@ int need_io_err_check(struct path *pp) + } + if (pp->io_err_pathfail_cnt != PATH_IO_ERR_WAITING_TO_CHECK) + return 1; +- if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0 || +- (curr_time.tv_sec - pp->io_err_dis_reinstate_time) > +- pp->mpp->marginal_path_err_recheck_gap_time) { ++ get_monotonic_time(&curr_time); ++ if ((curr_time.tv_sec - pp->io_err_dis_reinstate_time) > ++ pp->mpp->marginal_path_err_recheck_gap_time) { + io_err_stat_log(4, "%s: reschedule checking after %d seconds", + pp->dev, + pp->mpp->marginal_path_err_recheck_gap_time); +@@ -400,8 +399,7 @@ static int io_err_stat_time_up(struct io_err_stat_path *pp) + { + struct timespec currtime, difftime; + +- if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) +- return 0; ++ get_monotonic_time(&currtime); + timespecsub(&currtime, &pp->start_time, &difftime); + if (difftime.tv_sec < pp->total_time) + return 0; +@@ -414,8 +412,7 @@ static void end_io_err_stat(struct io_err_stat_path *pp) + struct path *path; + double err_rate; + +- if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) +- currtime = pp->start_time; ++ get_monotonic_time(&currtime); + + io_err_stat_log(4, "%s: check end", pp->devname); + +@@ -464,11 +461,7 @@ static int send_each_async_io(struct dio_ctx *ct, int fd, char *dev) + ct->io_starttime.tv_sec == 0) { + struct iocb *ios[1] = { &ct->io }; + +- if (clock_gettime(CLOCK_MONOTONIC, &ct->io_starttime) != 0) { +- ct->io_starttime.tv_sec = 0; +- ct->io_starttime.tv_nsec = 0; +- return rc; +- } ++ get_monotonic_time(&ct->io_starttime); + io_prep_pread(&ct->io, fd, ct->buf, ct->blksize, 0); + if (io_submit(ioctx, 1, ios) != 1) { + io_err_stat_log(5, "%s: io_submit error %i", +@@ -487,8 +480,7 @@ static void send_batch_async_ios(struct io_err_stat_path *pp) + struct dio_ctx *ct; + struct timespec currtime, difftime; + +- if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) +- return; ++ get_monotonic_time(&currtime); + /* + * Give a free time for all IO to complete or timeout + */ +@@ -503,11 +495,8 @@ static void send_batch_async_ios(struct io_err_stat_path *pp) + if (!send_each_async_io(ct, pp->fd, pp->devname)) + pp->io_nr++; + } +- if (pp->start_time.tv_sec == 0 && pp->start_time.tv_nsec == 0 && +- clock_gettime(CLOCK_MONOTONIC, &pp->start_time)) { +- pp->start_time.tv_sec = 0; +- pp->start_time.tv_nsec = 0; +- } ++ if (pp->start_time.tv_sec == 0 && pp->start_time.tv_nsec == 0) ++ get_monotonic_time(&pp->start_time); + } + + static int try_to_cancel_timeout_io(struct dio_ctx *ct, struct timespec *t, +@@ -546,8 +535,7 @@ static void poll_async_io_timeout(void) + int rc = PATH_UNCHECKED; + int i, j; + +- if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0) +- return; ++ get_monotonic_time(&curr_time); + vector_foreach_slot(io_err_pathvec, pp, i) { + for (j = 0; j < CONCUR_NR_EVENT; j++) { + rc = try_to_cancel_timeout_io(pp->dio_ctx_array + j, +-- +2.17.2 + diff --git a/0101-multipathd-combine-free_io_err_stat_path-and-destroy.patch b/0101-multipathd-combine-free_io_err_stat_path-and-destroy.patch new file mode 100644 index 0000000..90fd516 --- /dev/null +++ b/0101-multipathd-combine-free_io_err_stat_path-and-destroy.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 14 Jan 2021 20:20:26 -0600 +Subject: [PATCH] multipathd: combine free_io_err_stat_path and + destroy_directio_ctx + +destroy_directio_ctx() is only called from free_io_err_stat_path(), and +free_io_err_stat_path() is very short, so combine them. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 24 ++++++++++-------------- + 1 file changed, 10 insertions(+), 14 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index 92871f40..bf78a236 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -161,12 +161,15 @@ fail_close: + return 1; + } + +-static void destroy_directio_ctx(struct io_err_stat_path *p) ++static void free_io_err_stat_path(struct io_err_stat_path *p) + { + int i; + +- if (!p || !p->dio_ctx_array) ++ if (!p) + return; ++ if (!p->dio_ctx_array) ++ goto free_path; ++ + cancel_inflight_io(p); + + for (i = 0; i < CONCUR_NR_EVENT; i++) +@@ -175,6 +178,8 @@ static void destroy_directio_ctx(struct io_err_stat_path *p) + + if (p->fd > 0) + close(p->fd); ++free_path: ++ FREE(p); + } + + static struct io_err_stat_path *alloc_io_err_stat_path(void) +@@ -197,11 +202,6 @@ static struct io_err_stat_path *alloc_io_err_stat_path(void) + return p; + } + +-static void free_io_err_stat_path(struct io_err_stat_path *p) +-{ +- FREE(p); +-} +- + static void free_io_err_pathvec(void) + { + struct io_err_stat_path *path; +@@ -211,10 +211,8 @@ static void free_io_err_pathvec(void) + pthread_cleanup_push(cleanup_mutex, &io_err_pathvec_lock); + if (!io_err_pathvec) + goto out; +- vector_foreach_slot(io_err_pathvec, path, i) { +- destroy_directio_ctx(path); ++ vector_foreach_slot(io_err_pathvec, path, i) + free_io_err_stat_path(path); +- } + vector_free(io_err_pathvec); + io_err_pathvec = NULL; + out: +@@ -250,7 +248,7 @@ static int enqueue_io_err_stat_by_path(struct path *path) + goto free_ioerr_path; + pthread_mutex_lock(&io_err_pathvec_lock); + if (!vector_alloc_slot(io_err_pathvec)) +- goto unlock_destroy; ++ goto unlock_pathvec; + vector_set_slot(io_err_pathvec, p); + pthread_mutex_unlock(&io_err_pathvec_lock); + +@@ -258,9 +256,8 @@ static int enqueue_io_err_stat_by_path(struct path *path) + path->mpp->alias, path->dev); + return 0; + +-unlock_destroy: ++unlock_pathvec: + pthread_mutex_unlock(&io_err_pathvec_lock); +- destroy_directio_ctx(p); + free_ioerr_path: + free_io_err_stat_path(p); + +@@ -637,7 +634,6 @@ static void service_paths(void) + vector_foreach_slot_backwards(tmp_pathvec, pp, i) { + end_io_err_stat(pp); + vector_del_slot(tmp_pathvec, i); +- destroy_directio_ctx(pp); + free_io_err_stat_path(pp); + } + vector_reset(tmp_pathvec); +-- +2.17.2 + diff --git a/0102-multipathd-cleanup-logging-for-marginal-paths.patch b/0102-multipathd-cleanup-logging-for-marginal-paths.patch new file mode 100644 index 0000000..79ad137 --- /dev/null +++ b/0102-multipathd-cleanup-logging-for-marginal-paths.patch @@ -0,0 +1,123 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 18 Jan 2021 22:46:04 -0600 +Subject: [PATCH] multipathd: cleanup logging for marginal paths + +io_err_stat logged at level 2 whenever it enqueued a path to check, +which could happen multiple times while a path was marginal. On the +other hand if marginal_pathgroups wasn't set, multipathd didn't log when +paths were set to marginal. Now io_err_stat only logs at level 2 when +something unexpected happens, but multipathd will always log when a +path switches its marginal state. + +This patch also fixes an issue where paths in the delayed state could +get set to the pending state if they could not be checked in time. +Aside from going against the idea the paths should not be set to pending +if they already have a valid state, this caused multipathd to log a +message whenever the path state switched to from delayed to pending and +then back. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 7 +++---- + multipathd/main.c | 25 ++++++++++++++----------- + 2 files changed, 17 insertions(+), 15 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index bf78a236..abdd0b4f 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -252,7 +252,7 @@ static int enqueue_io_err_stat_by_path(struct path *path) + vector_set_slot(io_err_pathvec, p); + pthread_mutex_unlock(&io_err_pathvec_lock); + +- io_err_stat_log(2, "%s: enqueue path %s to check", ++ io_err_stat_log(3, "%s: enqueue path %s to check", + path->mpp->alias, path->dev); + return 0; + +@@ -343,7 +343,7 @@ int need_io_err_check(struct path *pp) + if (uatomic_read(&io_err_thread_running) == 0) + return 0; + if (count_active_paths(pp->mpp) <= 0) { +- io_err_stat_log(2, "%s: recover path early", pp->dev); ++ io_err_stat_log(2, "%s: no paths. recovering early", pp->dev); + goto recover; + } + if (pp->io_err_pathfail_cnt != PATH_IO_ERR_WAITING_TO_CHECK) +@@ -361,8 +361,7 @@ int need_io_err_check(struct path *pp) + * Or else, return 1 to set path state to PATH_SHAKY + */ + if (r == 1) { +- io_err_stat_log(3, "%s: enqueue fails, to recover", +- pp->dev); ++ io_err_stat_log(2, "%s: enqueue failed. recovering early", pp->dev); + goto recover; + } else + pp->io_err_pathfail_cnt = PATH_IO_ERR_IN_CHECKING; +diff --git a/multipathd/main.c b/multipathd/main.c +index 92c45d44..99a89a69 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2132,8 +2132,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + pathinfo(pp, conf, 0); + pthread_cleanup_pop(1); + return 1; +- } else if ((newstate != PATH_UP && newstate != PATH_GHOST) && +- (pp->state == PATH_DELAYED)) { ++ } else if ((newstate != PATH_UP && newstate != PATH_GHOST && ++ newstate != PATH_PENDING) && (pp->state == PATH_DELAYED)) { + /* If path state become failed again cancel path delay state */ + pp->state = newstate; + /* +@@ -2200,8 +2200,9 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + if ((newstate == PATH_UP || newstate == PATH_GHOST) && + (san_path_check_enabled(pp->mpp) || + marginal_path_check_enabled(pp->mpp))) { +- int was_marginal = pp->marginal; + if (should_skip_path(pp)) { ++ if (!pp->marginal && pp->state != PATH_DELAYED) ++ condlog(2, "%s: path is now marginal", pp->dev); + if (!marginal_pathgroups) { + if (marginal_path_check_enabled(pp->mpp)) + /* to reschedule as soon as possible, +@@ -2211,13 +2212,18 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + pp->state = PATH_DELAYED; + return 1; + } +- if (!was_marginal) { ++ if (!pp->marginal) { + pp->marginal = 1; + marginal_changed = 1; + } +- } else if (marginal_pathgroups && was_marginal) { +- pp->marginal = 0; +- marginal_changed = 1; ++ } else { ++ if (pp->marginal || pp->state == PATH_DELAYED) ++ condlog(2, "%s: path is no longer marginal", ++ pp->dev); ++ if (marginal_pathgroups && pp->marginal) { ++ pp->marginal = 0; ++ marginal_changed = 1; ++ } + } + } + +@@ -2343,11 +2349,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + */ + condlog(4, "path prio refresh"); + +- if (marginal_changed) { +- condlog(2, "%s: path is %s marginal", pp->dev, +- (pp->marginal)? "now" : "no longer"); ++ if (marginal_changed) + reload_and_sync_map(pp->mpp, vecs, 1); +- } + else if (update_prio(pp, new_path_up) && + (pp->mpp->pgpolicyfn == (pgpolicyfn *)group_by_prio) && + pp->mpp->pgfailback == -FAILBACK_IMMEDIATE) { +-- +2.17.2 + diff --git a/0103-libmultipath-fix-NULL-dereference-in-find_path_by_de.patch b/0103-libmultipath-fix-NULL-dereference-in-find_path_by_de.patch new file mode 100644 index 0000000..4dd4051 --- /dev/null +++ b/0103-libmultipath-fix-NULL-dereference-in-find_path_by_de.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: lixiaokeng +Date: Sat, 23 Jan 2021 16:19:28 +0800 +Subject: [PATCH] libmultipath: fix NULL dereference in find_path_by_dev + +When I test the 0.8.5 code with iscsi login/out, multipathd command +and multipath command concurrently, there is a multipathd coredump. +The stack is shown: + +uxlsnrloop + ->cli_list_devices + ->show_devices + ->snprint_devices + ->find_path_by_dev + +The reason is that devname is NULL in snprint_devices, then it will +be dereference. Here we check dev in find_path_by_dev. + +Reviewed-by: Martin Wilck +Signed-off-by: Benjamin Marzinski +--- + libmultipath/structs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libmultipath/structs.c b/libmultipath/structs.c +index 464596fc..a3f27fd6 100644 +--- a/libmultipath/structs.c ++++ b/libmultipath/structs.c +@@ -453,12 +453,12 @@ find_mp_by_str (const struct _vector *mpvec, const char * str) + } + + struct path * +-find_path_by_dev (const struct _vector *pathvec, const char * dev) ++find_path_by_dev (const struct _vector *pathvec, const char *dev) + { + int i; + struct path * pp; + +- if (!pathvec) ++ if (!pathvec || !dev) + return NULL; + + vector_foreach_slot (pathvec, pp, i) +-- +2.17.2 + diff --git a/0104-libmultipath-snprint_devices-avoid-NULL-dereference.patch b/0104-libmultipath-snprint_devices-avoid-NULL-dereference.patch new file mode 100644 index 0000000..04ff739 --- /dev/null +++ b/0104-libmultipath-snprint_devices-avoid-NULL-dereference.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 25 Jan 2021 16:12:10 +0100 +Subject: [PATCH] libmultipath: snprint_devices(): avoid NULL dereference + +All libudev functions may return NULL. Watch out for it. + +Fixes: d041258 ("libmultipath: snprint_devices(): use udev_enumerate" +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/print.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/libmultipath/print.c b/libmultipath/print.c +index 19de2c7c..8151e11e 100644 +--- a/libmultipath/print.c ++++ b/libmultipath/print.c +@@ -2055,8 +2055,16 @@ int snprint_devices(struct config *conf, char *buff, size_t len, + struct udev_device *u_dev; + + path = udev_list_entry_get_name(item); ++ if (!path) ++ continue; + u_dev = udev_device_new_from_syspath(udev, path); ++ if (!u_dev) ++ continue; + devname = udev_device_get_sysname(u_dev); ++ if (!devname) { ++ udev_device_unref(u_dev); ++ continue; ++ } + + fwd += snprintf(buff + fwd, len - fwd, " %s", devname); + if (fwd >= len) +-- +2.17.2 + diff --git a/0105-libmpathpersist-fix-thread-safety-of-default-functio.patch b/0105-libmpathpersist-fix-thread-safety-of-default-functio.patch new file mode 100644 index 0000000..dad9963 --- /dev/null +++ b/0105-libmpathpersist-fix-thread-safety-of-default-functio.patch @@ -0,0 +1,274 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 25 Jan 2021 23:31:04 -0600 +Subject: [PATCH] libmpathpersist: fix thread safety of default functions + +commit a839e39e ("libmpathpersist: factor out initialization and +teardown") made mpath_presistent_reserve_{in,out} use share variables +for curmp and pathvec. There are users of this library that call these +functions in a multi-threaded process, and this change causes their +application to crash. config and udev are also shared variables, but +libmpathpersist doesn't write to the config in +mpath_presistent_reserve_{in,out}, and looking into the libudev code, I +don't see any place where libmpathpersist uses the udev object in a way +that isn't thread-safe. + +This patch makes mpath_presistent_reserve_{in,out} go back to using +local variables for curmp and pathvec, so that multiple threads won't +be operating on these variables at the same time. + +Fixes: a839e39e ("libmpathpersist: factor out initialization and teardown") +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmpathpersist/mpath_persist.c | 116 +++++++++++++++++++++----------- + libmpathpersist/mpath_persist.h | 24 +++++-- + 2 files changed, 94 insertions(+), 46 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 08077936..5c95af20 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -133,69 +133,57 @@ mpath_prin_activepath (struct multipath *mpp, int rq_servact, + return ret; + } + +-int mpath_persistent_reserve_in (int fd, int rq_servact, +- struct prin_resp *resp, int noisy, int verbose) +-{ +- int ret = mpath_persistent_reserve_init_vecs(verbose); +- +- if (ret != MPATH_PR_SUCCESS) +- return ret; +- ret = __mpath_persistent_reserve_in(fd, rq_servact, resp, noisy); +- mpath_persistent_reserve_free_vecs(); +- return ret; +-} +- +-int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, +- unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose) +-{ +- int ret = mpath_persistent_reserve_init_vecs(verbose); +- +- if (ret != MPATH_PR_SUCCESS) +- return ret; +- ret = __mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type, +- paramp, noisy); +- mpath_persistent_reserve_free_vecs(); +- return ret; +-} +- + static vector curmp; + static vector pathvec; + +-void mpath_persistent_reserve_free_vecs(void) ++static void __mpath_persistent_reserve_free_vecs(vector curmp, vector pathvec) + { + free_multipathvec(curmp, KEEP_PATHS); + free_pathvec(pathvec, FREE_PATHS); ++} ++ ++void mpath_persistent_reserve_free_vecs(void) ++{ ++ __mpath_persistent_reserve_free_vecs(curmp, pathvec); + curmp = pathvec = NULL; + } + +-int mpath_persistent_reserve_init_vecs(int verbose) ++static int __mpath_persistent_reserve_init_vecs(vector *curmp_p, ++ vector *pathvec_p, int verbose) + { + libmp_verbosity = verbose; + +- if (curmp) ++ if (*curmp_p) + return MPATH_PR_SUCCESS; + /* + * allocate core vectors to store paths and multipaths + */ +- curmp = vector_alloc (); +- pathvec = vector_alloc (); ++ *curmp_p = vector_alloc (); ++ *pathvec_p = vector_alloc (); + +- if (!curmp || !pathvec){ ++ if (!*curmp_p || !*pathvec_p){ + condlog (0, "vector allocation failed."); + goto err; + } + +- if (dm_get_maps(curmp)) ++ if (dm_get_maps(*curmp_p)) + goto err; + + return MPATH_PR_SUCCESS; + + err: +- mpath_persistent_reserve_free_vecs(); ++ __mpath_persistent_reserve_free_vecs(*curmp_p, *pathvec_p); ++ *curmp_p = *pathvec_p = NULL; + return MPATH_PR_DMMP_ERROR; + } + +-static int mpath_get_map(int fd, char **palias, struct multipath **pmpp) ++int mpath_persistent_reserve_init_vecs(int verbose) ++{ ++ return __mpath_persistent_reserve_init_vecs(&curmp, &pathvec, verbose); ++} ++ ++static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias, ++ struct multipath **pmpp) + { + int ret = MPATH_PR_DMMP_ERROR; + struct stat info; +@@ -255,13 +243,13 @@ out: + return ret; + } + +-int __mpath_persistent_reserve_in (int fd, int rq_servact, +- struct prin_resp *resp, int noisy) ++static int do_mpath_persistent_reserve_in (vector curmp, vector pathvec, ++ int fd, int rq_servact, struct prin_resp *resp, int noisy) + { + struct multipath *mpp; + int ret; + +- ret = mpath_get_map(fd, NULL, &mpp); ++ ret = mpath_get_map(curmp, pathvec, fd, NULL, &mpp); + if (ret != MPATH_PR_SUCCESS) + return ret; + +@@ -270,8 +258,17 @@ int __mpath_persistent_reserve_in (int fd, int rq_servact, + return ret; + } + +-int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, +- unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy) ++ ++int __mpath_persistent_reserve_in (int fd, int rq_servact, ++ struct prin_resp *resp, int noisy) ++{ ++ return do_mpath_persistent_reserve_in(curmp, pathvec, fd, rq_servact, ++ resp, noisy); ++} ++ ++static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd, ++ int rq_servact, int rq_scope, unsigned int rq_type, ++ struct prout_param_descriptor *paramp, int noisy) + { + struct multipath *mpp; + char *alias; +@@ -279,7 +276,7 @@ int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, + uint64_t prkey; + struct config *conf; + +- ret = mpath_get_map(fd, &alias, &mpp); ++ ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp); + if (ret != MPATH_PR_SUCCESS) + return ret; + +@@ -349,6 +346,45 @@ out1: + return ret; + } + ++ ++int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, ++ unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy) ++{ ++ return do_mpath_persistent_reserve_out(curmp, pathvec, fd, rq_servact, ++ rq_scope, rq_type, paramp, ++ noisy); ++} ++ ++int mpath_persistent_reserve_in (int fd, int rq_servact, ++ struct prin_resp *resp, int noisy, int verbose) ++{ ++ vector curmp = NULL, pathvec; ++ int ret = __mpath_persistent_reserve_init_vecs(&curmp, &pathvec, ++ verbose); ++ ++ if (ret != MPATH_PR_SUCCESS) ++ return ret; ++ ret = do_mpath_persistent_reserve_in(curmp, pathvec, fd, rq_servact, ++ resp, noisy); ++ __mpath_persistent_reserve_free_vecs(curmp, pathvec); ++ return ret; ++} ++ ++int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, ++ unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose) ++{ ++ vector curmp = NULL, pathvec; ++ int ret = __mpath_persistent_reserve_init_vecs(&curmp, &pathvec, ++ verbose); ++ ++ if (ret != MPATH_PR_SUCCESS) ++ return ret; ++ ret = do_mpath_persistent_reserve_out(curmp, pathvec, fd, rq_servact, ++ rq_scope, rq_type, paramp, noisy); ++ __mpath_persistent_reserve_free_vecs(curmp, pathvec); ++ return ret; ++} ++ + int + get_mpvec (vector curmp, vector pathvec, char * refwwid) + { +diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h +index 5435eae4..9e9c0a82 100644 +--- a/libmpathpersist/mpath_persist.h ++++ b/libmpathpersist/mpath_persist.h +@@ -246,9 +246,13 @@ extern int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp + + /* + * DESCRIPTION : +- * This function is like mpath_persistent_reserve_in(), except that it doesn't call +- * mpath_persistent_reserve_init_vecs() and mpath_persistent_reserve_free_vecs() +- * before and after the actual PR call. ++ * This function is like mpath_persistent_reserve_in(), except that it ++ * requires mpath_persistent_reserve_init_vecs() to be called before the ++ * PR call to set up internal variables. These must later be cleanup up ++ * by calling mpath_persistent_reserve_free_vecs(). ++ * ++ * RESTRICTIONS: ++ * This function uses static internal variables, and is not thread-safe. + */ + extern int __mpath_persistent_reserve_in(int fd, int rq_servact, + struct prin_resp *resp, int noisy); +@@ -280,9 +284,13 @@ extern int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, + int verbose); + /* + * DESCRIPTION : +- * This function is like mpath_persistent_reserve_out(), except that it doesn't call +- * mpath_persistent_reserve_init_vecs() and mpath_persistent_reserve_free_vecs() +- * before and after the actual PR call. ++ * This function is like mpath_persistent_reserve_out(), except that it ++ * requires mpath_persistent_reserve_init_vecs() to be called before the ++ * PR call to set up internal variables. These must later be cleanup up ++ * by calling mpath_persistent_reserve_free_vecs(). ++ * ++ * RESTRICTIONS: ++ * This function uses static internal variables, and is not thread-safe. + */ + extern int __mpath_persistent_reserve_out( int fd, int rq_servact, int rq_scope, + unsigned int rq_type, struct prout_param_descriptor *paramp, +@@ -296,6 +304,7 @@ extern int __mpath_persistent_reserve_out( int fd, int rq_servact, int rq_scope, + * @verbose: Set verbosity level. Input argument. value:0 to 3. 0->disabled, 3->Max verbose + * + * RESTRICTIONS: ++ * This function uses static internal variables, and is not thread-safe. + * + * RETURNS: MPATH_PR_SUCCESS if successful else returns any of the status specified + * above in RETURN_STATUS. +@@ -306,6 +315,9 @@ int mpath_persistent_reserve_init_vecs(int verbose); + * DESCRIPTION : + * This function frees data structures allocated by + * mpath_persistent_reserve_init_vecs(). ++ * ++ * RESTRICTIONS: ++ * This function uses static internal variables, and is not thread-safe. + */ + void mpath_persistent_reserve_free_vecs(void); + +-- +2.17.2 + diff --git a/0106-Added-github-action-for-building.patch b/0106-Added-github-action-for-building.patch new file mode 100644 index 0000000..8a8a7d0 --- /dev/null +++ b/0106-Added-github-action-for-building.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 21:38:43 +0100 +Subject: [PATCH] Added github action for building + +Signed-off-by: Benjamin Marzinski +--- + .github/workflows/build-and-unittest.yaml | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + create mode 100644 .github/workflows/build-and-unittest.yaml + +diff --git a/.github/workflows/build-and-unittest.yaml b/.github/workflows/build-and-unittest.yaml +new file mode 100644 +index 00000000..2b13c65c +--- /dev/null ++++ b/.github/workflows/build-and-unittest.yaml +@@ -0,0 +1,17 @@ ++name: basic-build-and-ci ++on: [push] ++jobs: ++ build: ++ runs-on: ubuntu-latest ++ steps: ++ - uses: actions/checkout@v2 ++ - name: dependencies ++ run: > ++ sudo apt-get install --yes gcc ++ make perl-base pkg-config ++ libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev ++ libudev-dev libjson-c-dev liburcu-dev libcmocka-dev ++ - name: build ++ run: make -O -j$(grep -c ^processor /proc/cpuinfo) ++ - name: test ++ run: make -O -j$(grep -c ^processor /proc/cpuinfo) test +-- +2.17.2 + diff --git a/0107-github-workflow-use-zram-device-as-test-block-device.patch b/0107-github-workflow-use-zram-device-as-test-block-device.patch new file mode 100644 index 0000000..5b25c29 --- /dev/null +++ b/0107-github-workflow-use-zram-device-as-test-block-device.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 22:18:20 +0100 +Subject: [PATCH] github workflow: use zram device as test block device + +Signed-off-by: Benjamin Marzinski +--- + .github/workflows/build-and-unittest.yaml | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/.github/workflows/build-and-unittest.yaml b/.github/workflows/build-and-unittest.yaml +index 2b13c65c..ef55b8c1 100644 +--- a/.github/workflows/build-and-unittest.yaml ++++ b/.github/workflows/build-and-unittest.yaml +@@ -5,6 +5,14 @@ jobs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 ++ - name: mpath ++ run: sudo modprobe dm_multipath ++ - name: zram ++ run: sudo modprobe zram num_devices=0 ++ - name: zram-device ++ run: echo ZRAM=$(sudo cat /sys/class/zram-control/hot_add) >> $GITHUB_ENV ++ - name: set-zram-size ++ run: echo 1G | sudo tee /sys/block/zram$ZRAM/disksize + - name: dependencies + run: > + sudo apt-get install --yes gcc +@@ -15,3 +23,7 @@ jobs: + run: make -O -j$(grep -c ^processor /proc/cpuinfo) + - name: test + run: make -O -j$(grep -c ^processor /proc/cpuinfo) test ++ - name: clean-nonroot-artifacts ++ run: rm -f tests/dmevents.out tests/directio.out ++ - name: root-test ++ run: sudo make DIO_TEST_DEV=/dev/zram$ZRAM test +-- +2.17.2 + diff --git a/0108-github-workflow-use-explicit-Ubuntu-version.patch b/0108-github-workflow-use-explicit-Ubuntu-version.patch new file mode 100644 index 0000000..ff565d6 --- /dev/null +++ b/0108-github-workflow-use-explicit-Ubuntu-version.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 22:54:24 +0100 +Subject: [PATCH] github workflow: use explicit Ubuntu version + +Signed-off-by: Benjamin Marzinski +--- + .github/workflows/build-and-unittest.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/.github/workflows/build-and-unittest.yaml b/.github/workflows/build-and-unittest.yaml +index ef55b8c1..577a14ac 100644 +--- a/.github/workflows/build-and-unittest.yaml ++++ b/.github/workflows/build-and-unittest.yaml +@@ -2,7 +2,7 @@ name: basic-build-and-ci + on: [push] + jobs: + build: +- runs-on: ubuntu-latest ++ runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - name: mpath +-- +2.17.2 + diff --git a/0109-github-workflow-add-valgrind-tests.patch b/0109-github-workflow-add-valgrind-tests.patch new file mode 100644 index 0000000..5c4e366 --- /dev/null +++ b/0109-github-workflow-add-valgrind-tests.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 23:21:16 +0100 +Subject: [PATCH] github workflow: add valgrind tests + +Signed-off-by: Benjamin Marzinski +--- + .github/workflows/build-and-unittest.yaml | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/.github/workflows/build-and-unittest.yaml b/.github/workflows/build-and-unittest.yaml +index 577a14ac..929f63a6 100644 +--- a/.github/workflows/build-and-unittest.yaml ++++ b/.github/workflows/build-and-unittest.yaml +@@ -16,13 +16,17 @@ jobs: + - name: dependencies + run: > + sudo apt-get install --yes gcc +- make perl-base pkg-config ++ make perl-base pkg-config valgrind + libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev + libudev-dev libjson-c-dev liburcu-dev libcmocka-dev + - name: build + run: make -O -j$(grep -c ^processor /proc/cpuinfo) + - name: test + run: make -O -j$(grep -c ^processor /proc/cpuinfo) test ++ - name: valgrind-test ++ run: make -O -j$(grep -c ^processor /proc/cpuinfo) valgrind-test ++ - name: valgrind-results ++ run: cat tests/*.vgr + - name: clean-nonroot-artifacts + run: rm -f tests/dmevents.out tests/directio.out + - name: root-test +-- +2.17.2 + diff --git a/0110-github-workflow-run-apt-get-update.patch b/0110-github-workflow-run-apt-get-update.patch new file mode 100644 index 0000000..d27f1ca --- /dev/null +++ b/0110-github-workflow-run-apt-get-update.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 23:26:16 +0100 +Subject: [PATCH] github workflow: run apt-get update + +E: Failed to fetch http://azure.archive.ubuntu.com/ubuntu/pool/main/g/glibc/libc6-dbg_2.27-3ubuntu1.3_amd64.deb 404 Not Found [IP: 52.252.75.106 80] +E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing? +Signed-off-by: Benjamin Marzinski +--- + .github/workflows/build-and-unittest.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/.github/workflows/build-and-unittest.yaml b/.github/workflows/build-and-unittest.yaml +index 929f63a6..389578be 100644 +--- a/.github/workflows/build-and-unittest.yaml ++++ b/.github/workflows/build-and-unittest.yaml +@@ -13,6 +13,8 @@ jobs: + run: echo ZRAM=$(sudo cat /sys/class/zram-control/hot_add) >> $GITHUB_ENV + - name: set-zram-size + run: echo 1G | sudo tee /sys/block/zram$ZRAM/disksize ++ - name: update ++ run: sudo apt-get update + - name: dependencies + run: > + sudo apt-get install --yes gcc +-- +2.17.2 + diff --git a/0111-github-workflow-add-tests-with-gcc-10-and-clang.patch b/0111-github-workflow-add-tests-with-gcc-10-and-clang.patch new file mode 100644 index 0000000..e95b3f8 --- /dev/null +++ b/0111-github-workflow-add-tests-with-gcc-10-and-clang.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 23:44:11 +0100 +Subject: [PATCH] github workflow: add tests with gcc 10 and clang + +Signed-off-by: Benjamin Marzinski +--- + .github/workflows/build-and-unittest.yaml | 62 ++++++++++++++++++++++- + 1 file changed, 61 insertions(+), 1 deletion(-) + +diff --git a/.github/workflows/build-and-unittest.yaml b/.github/workflows/build-and-unittest.yaml +index 389578be..4173576f 100644 +--- a/.github/workflows/build-and-unittest.yaml ++++ b/.github/workflows/build-and-unittest.yaml +@@ -1,7 +1,7 @@ + name: basic-build-and-ci + on: [push] + jobs: +- build: ++ bionic: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 +@@ -33,3 +33,63 @@ jobs: + run: rm -f tests/dmevents.out tests/directio.out + - name: root-test + run: sudo make DIO_TEST_DEV=/dev/zram$ZRAM test ++ focal-gcc10: ++ runs-on: ubuntu-20.04 ++ steps: ++ - uses: actions/checkout@v2 ++ - name: mpath ++ run: sudo modprobe dm_multipath ++ - name: brd ++ run: sudo modprobe brd rd_nr=1 rd_size=65536 ++ - name: update ++ run: sudo apt-get update ++ - name: dependencies ++ run: > ++ sudo apt-get install --yes gcc-10 ++ make perl-base pkg-config valgrind ++ libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev ++ libudev-dev libjson-c-dev liburcu-dev libcmocka-dev ++ - name: set CC ++ run: echo CC=gcc-10 >> $GITHUB_ENV ++ - name: build ++ run: make -O -j$(grep -c ^processor /proc/cpuinfo) ++ - name: test ++ run: make -O -j$(grep -c ^processor /proc/cpuinfo) test ++ - name: valgrind-test ++ run: make -O -j$(grep -c ^processor /proc/cpuinfo) valgrind-test ++ - name: valgrind-results ++ run: cat tests/*.vgr ++ - name: clean-nonroot-artifacts ++ run: rm -f tests/dmevents.out tests/directio.out ++ - name: root-test ++ run: sudo make DIO_TEST_DEV=/dev/ram0 test ++ focal-clang10: ++ runs-on: ubuntu-20.04 ++ steps: ++ - uses: actions/checkout@v2 ++ - name: mpath ++ run: sudo modprobe dm_multipath ++ - name: brd ++ run: sudo modprobe brd rd_nr=1 rd_size=65536 ++ - name: update ++ run: sudo apt-get update ++ - name: dependencies ++ run: > ++ sudo apt-get install --yes clang ++ make perl-base pkg-config valgrind ++ libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev ++ libudev-dev libjson-c-dev liburcu-dev libcmocka-dev ++ - name: set CC ++ run: echo CC=clang >> $GITHUB_ENV ++ - name: build ++ run: make -O -j$(grep -c ^processor /proc/cpuinfo) ++ - name: test ++ run: make -O -j$(grep -c ^processor /proc/cpuinfo) test ++ - name: valgrind-test ++ run: make -O -j$(grep -c ^processor /proc/cpuinfo) valgrind-test ++ - name: valgrind-results ++ run: cat tests/*.vgr ++ - name: clean-nonroot-artifacts ++ run: rm -f tests/dmevents.out tests/directio.out ++ - name: root-test ++ run: sudo make DIO_TEST_DEV=/dev/ram0 test +-- +2.17.2 + diff --git a/0112-multipathd-Fix-multipathd-stopping-on-shutdown.patch b/0112-multipathd-Fix-multipathd-stopping-on-shutdown.patch new file mode 100644 index 0000000..49ea563 --- /dev/null +++ b/0112-multipathd-Fix-multipathd-stopping-on-shutdown.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 18 Dec 2020 17:06:41 -0600 +Subject: [PATCH] multipathd: Fix multipathd stopping on shutdown + +According to man "systemd.special" + +"shutdown.target: ... Services that shall be terminated on system +shutdown shall add Conflicts= and Before= dependencies to this unit for +their service unit, which is implicitly done when +DefaultDependencies=yes is set (the default)." + +multipathd.service sets DefaultDependencies=no and includes the +Conflits= dependency, but not the Before= one. This can cause multipathd +to continue running past when it is supposed to during shutdown. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + multipathd/multipathd.service | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service +index ba24983e..7d547fa7 100644 +--- a/multipathd/multipathd.service ++++ b/multipathd/multipathd.service +@@ -2,7 +2,7 @@ + Description=Device-Mapper Multipath Device Controller + Wants=systemd-udev-trigger.service systemd-udev-settle.service + Before=iscsi.service iscsid.service lvm2-activation-early.service +-Before=local-fs-pre.target blk-availability.service ++Before=local-fs-pre.target blk-availability.service shutdown.target + After=multipathd.socket systemd-udev-trigger.service systemd-udev-settle.service + DefaultDependencies=no + Conflicts=shutdown.target +-- +2.17.2 + diff --git a/0113-libmultipath-use-3rd-digit-as-transport_id-for-expan.patch b/0113-libmultipath-use-3rd-digit-as-transport_id-for-expan.patch new file mode 100644 index 0000000..17d53ce --- /dev/null +++ b/0113-libmultipath-use-3rd-digit-as-transport_id-for-expan.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 13 Nov 2020 22:34:41 +0100 +Subject: [PATCH] libmultipath: use 3rd digit as transport_id for expanders + +On SAS expanders, node id's have 3 digits. sysfs paths look like this: + +/sys/devices/pci0000:80/0000:80:02.0/0000:8b:00.0/0000:8c:09.0/0000:8f:00.0/host9/port-9:0/expander-9:0/port-9:0:13/expander-9:1/port-9:1:12/expander-9:2/port-9:2:4/end_device-9:2:4/target9:0:29/9:0:29:0/block/sdac + +In that case, we should use the last digit as transport id. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/discovery.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index e818585a..6d74cc07 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -358,10 +358,17 @@ sysfs_get_tgt_nodename(struct path *pp, char *node) + if (value) { + tgtdev = udev_device_get_parent(parent); + while (tgtdev) { ++ char c; ++ + tgtname = udev_device_get_sysname(tgtdev); +- if (tgtname && sscanf(tgtname, "end_device-%d:%d", +- &host, &tgtid) == 2) +- break; ++ if (tgtname) { ++ if (sscanf(tgtname, "end_device-%d:%d:%d%c", ++ &host, &channel, &tgtid, &c) == 3) ++ break; ++ if (sscanf(tgtname, "end_device-%d:%d%c", ++ &host, &tgtid, &c) == 2) ++ break; ++ } + tgtdev = udev_device_get_parent(tgtdev); + tgtid = -1; + } +-- +2.17.2 + diff --git a/0114-libmultipath-sysfs_set_nexus_loss_tmo-support-SAS-ex.patch b/0114-libmultipath-sysfs_set_nexus_loss_tmo-support-SAS-ex.patch new file mode 100644 index 0000000..3207d2d --- /dev/null +++ b/0114-libmultipath-sysfs_set_nexus_loss_tmo-support-SAS-ex.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 13 Nov 2020 22:38:21 +0100 +Subject: [PATCH] libmultipath: sysfs_set_nexus_loss_tmo(): support SAS + expanders + +With SAS expanders, SAS node names have 3 digits. libmultipath +would fail to discover the sas_end_device matching a given SCSI +target in this case. Fix it. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/discovery.c | 24 +++++++++++++++++++----- + 1 file changed, 19 insertions(+), 5 deletions(-) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index 6d74cc07..921025d4 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -789,14 +789,28 @@ sysfs_set_session_tmo(struct multipath *mpp, struct path *pp) + static void + sysfs_set_nexus_loss_tmo(struct multipath *mpp, struct path *pp) + { +- struct udev_device *sas_dev = NULL; +- char end_dev_id[64]; ++ struct udev_device *parent, *sas_dev = NULL; ++ const char *end_dev_id = NULL; + char value[11]; ++ static const char ed_str[] = "end_device-"; + +- if (mpp->dev_loss == DEV_LOSS_TMO_UNSET) ++ if (!pp->udev || mpp->dev_loss == DEV_LOSS_TMO_UNSET) + return; +- sprintf(end_dev_id, "end_device-%d:%d", +- pp->sg_id.host_no, pp->sg_id.transport_id); ++ ++ for (parent = udev_device_get_parent(pp->udev); ++ parent; ++ parent = udev_device_get_parent(parent)) { ++ const char *ed = udev_device_get_sysname(parent); ++ ++ if (!strncmp(ed, ed_str, sizeof(ed_str) - 1)) { ++ end_dev_id = ed; ++ break; ++ } ++ } ++ if (!end_dev_id) { ++ condlog(1, "%s: No SAS end device", pp->dev); ++ return; ++ } + sas_dev = udev_device_new_from_subsystem_sysname(udev, + "sas_end_device", end_dev_id); + if (!sas_dev) { +-- +2.17.2 + diff --git a/0115-multipathd-add-code-to-initalize-unwinder.patch b/0115-multipathd-add-code-to-initalize-unwinder.patch new file mode 100644 index 0000000..e231733 --- /dev/null +++ b/0115-multipathd-add-code-to-initalize-unwinder.patch @@ -0,0 +1,134 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 17 Dec 2020 16:50:06 +0100 +Subject: [PATCH] multipathd: add code to initalize unwinder + +glibc's implementation of pthread_cancel() loads symbols from +libgcc_s.so using dlopen() when pthread_cancel() is called +for the first time. This happens even with LD_BIND_NOW=1. +This may imply the need for file system access when a thread is +cancelled, which in the case of multipath-tools might be in a +dangerous situation where multipathd must avoid blocking. + +Call load_unwinder() during startup to make sure the dynamic +linker has all necessary symbols resolved early on. + +This implementation simply creates a dummy thread and cancels +it. This way all necessary symbols for thread cancellation +will be loaded, no matter what the C library needs to implement +cancellation. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/Makefile | 2 +- + multipathd/init_unwinder.c | 34 ++++++++++++++++++++++++++++++++++ + multipathd/init_unwinder.h | 21 +++++++++++++++++++++ + multipathd/main.c | 2 ++ + 4 files changed, 58 insertions(+), 1 deletion(-) + create mode 100644 multipathd/init_unwinder.c + create mode 100644 multipathd/init_unwinder.h + +diff --git a/multipathd/Makefile b/multipathd/Makefile +index 632b82b1..d053c1ed 100644 +--- a/multipathd/Makefile ++++ b/multipathd/Makefile +@@ -30,7 +30,7 @@ ifeq ($(ENABLE_DMEVENTS_POLL),0) + endif + + OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o \ +- dmevents.o ++ dmevents.o init_unwinder.o + + EXEC = multipathd + +diff --git a/multipathd/init_unwinder.c b/multipathd/init_unwinder.c +new file mode 100644 +index 00000000..14467f3d +--- /dev/null ++++ b/multipathd/init_unwinder.c +@@ -0,0 +1,34 @@ ++#include ++#include ++#include "init_unwinder.h" ++ ++static pthread_mutex_t dummy_mtx = PTHREAD_MUTEX_INITIALIZER; ++static pthread_cond_t dummy_cond = PTHREAD_COND_INITIALIZER; ++ ++static void *dummy_thread(void *arg __attribute__((unused))) ++{ ++ pthread_mutex_lock(&dummy_mtx); ++ pthread_cond_broadcast(&dummy_cond); ++ pthread_mutex_unlock(&dummy_mtx); ++ pause(); ++ return NULL; ++} ++ ++int init_unwinder(void) ++{ ++ pthread_t dummy; ++ int rc; ++ ++ pthread_mutex_lock(&dummy_mtx); ++ ++ rc = pthread_create(&dummy, NULL, dummy_thread, NULL); ++ if (rc != 0) { ++ pthread_mutex_unlock(&dummy_mtx); ++ return rc; ++ } ++ ++ pthread_cond_wait(&dummy_cond, &dummy_mtx); ++ pthread_mutex_unlock(&dummy_mtx); ++ ++ return pthread_cancel(dummy); ++} +diff --git a/multipathd/init_unwinder.h b/multipathd/init_unwinder.h +new file mode 100644 +index 00000000..ada09f82 +--- /dev/null ++++ b/multipathd/init_unwinder.h +@@ -0,0 +1,21 @@ ++#ifndef _INIT_UNWINDER_H ++#define _INIT_UNWINDER_H 1 ++ ++/* ++ * init_unwinder(): make sure unwinder symbols are loaded ++ * ++ * libc's implementation of pthread_cancel() loads symbols from ++ * libgcc_s.so using dlopen() when pthread_cancel() is called ++ * for the first time. This happens even with LD_BIND_NOW=1. ++ * This may imply the need for file system access when a thread is ++ * cancelled, which in the case of multipath-tools might be in a ++ * dangerous situation where multipathd must avoid blocking. ++ * ++ * Call load_unwinder() during startup to make sure the dynamic ++ * linker has all necessary symbols resolved early on. ++ * ++ * Return: 0 if successful, an error number otherwise. ++ */ ++int init_unwinder(void); ++ ++#endif +diff --git a/multipathd/main.c b/multipathd/main.c +index 99a89a69..6f851ae8 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -83,6 +83,7 @@ + #include "wwids.h" + #include "foreign.h" + #include "../third-party/valgrind/drd.h" ++#include "init_unwinder.h" + + #define FILE_NAME_SIZE 256 + #define CMDSIZE 160 +@@ -3041,6 +3042,7 @@ child (__attribute__((unused)) void *param) + enum daemon_status state; + int exit_code = 1; + ++ init_unwinder(); + mlockall(MCL_CURRENT | MCL_FUTURE); + signal_init(); + mp_rcu_data = setup_rcu(); +-- +2.17.2 + diff --git a/0116-libmultipath-check-if-adopt_path-really-added-curren.patch b/0116-libmultipath-check-if-adopt_path-really-added-curren.patch new file mode 100644 index 0000000..b656c08 --- /dev/null +++ b/0116-libmultipath-check-if-adopt_path-really-added-curren.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 2 Feb 2021 11:12:21 +0100 +Subject: [PATCH] libmultipath: check if adopt_path() really added current path + +The description of 2d32d6f ("libmultipath: adopt_paths(): don't bail out on +single path failure") said "we need to check after successful call to +adopt_paths() if that specific path had been actually added, and fail in the +caller otherwise". But the commit failed to actually implement this check. +Instead, it just checked if the path was member of the pathvec, which will +almost always be the case. + +Fix it by checking what actually needs to be checked, membership of the +path to be added in mpp->paths. + +Fixes: 2d32d6f ("libmultipath: adopt_paths(): don't bail out on single path failure") + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/structs_vec.c | 4 ++-- + multipathd/main.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c +index f7f45f11..47b1d03e 100644 +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -707,8 +707,8 @@ struct multipath *add_map_with_path(struct vectors *vecs, struct path *pp, + goto out; + mpp->size = pp->size; + +- if (adopt_paths(vecs->pathvec, mpp) || +- find_slot(vecs->pathvec, pp) == -1) ++ if (adopt_paths(vecs->pathvec, mpp) || pp->mpp != mpp || ++ find_slot(mpp->paths, pp) == -1) + goto out; + + if (add_vec) { +diff --git a/multipathd/main.c b/multipathd/main.c +index 6f851ae8..43d77688 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1008,8 +1008,8 @@ rescan: + if (mpp) { + condlog(4,"%s: adopting all paths for path %s", + mpp->alias, pp->dev); +- if (adopt_paths(vecs->pathvec, mpp) || +- find_slot(vecs->pathvec, pp) == -1) ++ if (adopt_paths(vecs->pathvec, mpp) || pp->mpp != mpp || ++ find_slot(mpp->paths, pp) == -1) + goto fail; /* leave path added to pathvec */ + + verify_paths(mpp); +-- +2.17.2 + diff --git a/0117-multipathd-ev_add_path-fail-if-add_map_with_path-fai.patch b/0117-multipathd-ev_add_path-fail-if-add_map_with_path-fai.patch new file mode 100644 index 0000000..f223728 --- /dev/null +++ b/0117-multipathd-ev_add_path-fail-if-add_map_with_path-fai.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 1 Feb 2021 13:10:46 +0100 +Subject: [PATCH] multipathd: ev_add_path: fail if add_map_with_path() fails + +If start_waiter was set before and the "rescan" label was used, +we may try to set up an empty/invalid map. +Always fail if add_map_with_path() isn't successful. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 43d77688..425492a9 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1028,7 +1028,7 @@ rescan: + */ + start_waiter = 1; + } +- if (!start_waiter) ++ else + goto fail; /* leave path added to pathvec */ + } + +-- +2.17.2 + diff --git a/0118-libmultipath-check-return-value-of-udev_device_get_d.patch b/0118-libmultipath-check-return-value-of-udev_device_get_d.patch new file mode 100644 index 0000000..fe69708 --- /dev/null +++ b/0118-libmultipath-check-return-value-of-udev_device_get_d.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 2 Feb 2021 15:18:33 +0100 +Subject: [PATCH] libmultipath: check return value of udev_device_get_devnum() + +udev_device_get_devnum() may fail, in which case it returns +makedev(0, 0). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/discovery.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index 921025d4..15cf6413 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -1659,6 +1659,9 @@ common_sysfs_pathinfo (struct path * pp) + return PATHINFO_FAILED; + } + devt = udev_device_get_devnum(pp->udev); ++ if (major(devt) == 0 && minor(devt) == 0) ++ return PATHINFO_FAILED; ++ + snprintf(pp->dev_t, BLK_DEV_SIZE, "%d:%d", major(devt), minor(devt)); + + condlog(4, "%s: dev_t = %s", pp->dev, pp->dev_t); +-- +2.17.2 + diff --git a/0119-pathinfo-call-filter_property-after-sysfs_pathinfo.patch b/0119-pathinfo-call-filter_property-after-sysfs_pathinfo.patch new file mode 100644 index 0000000..cf106c2 --- /dev/null +++ b/0119-pathinfo-call-filter_property-after-sysfs_pathinfo.patch @@ -0,0 +1,281 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 2 Feb 2021 17:07:37 +0100 +Subject: [PATCH] pathinfo: call filter_property() after sysfs_pathinfo() + +The of filter_property() depends on the value of pp->uid_attribute. +This may in turn depend on pp->hwe, which is initialized in +sysfs_pathinfo(). To obtain consistent results from pathinfo(), +make sure uid_attribute is correctly set before calling filter_property(). + +filter_property() is now called from pathinfo() with properly set +uid_attribute, thus we don't need to call it from is_path_valid() any more. + +Thes changes require modifications to the unit tests. The is_path_valid() +test now wouldn't need to test filter_property() any more, because +is_path_valid() calls filter_property() no more. But that doesn't feel +right. Instead, test_filter_property() is modified to test the behavior +with the filter_property() test called indirectly from pathinfo(). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/discovery.c | 21 +++++++++- + libmultipath/valid.c | 4 -- + tests/Makefile | 2 +- + tests/test-lib.c | 5 ++- + tests/valid.c | 91 ++++++++++++++++++++++++++++++++++++---- + 5 files changed, 105 insertions(+), 18 deletions(-) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index 15cf6413..febcd0ae 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -2247,9 +2247,17 @@ int pathinfo(struct path *pp, struct config *conf, int mask) + condlog(4, "%s: hidden", pp->dev); + return PATHINFO_SKIPPED; + } +- if (is_claimed_by_foreign(pp->udev) || +- filter_property(conf, pp->udev, 4, pp->uid_attribute) > 0) ++ ++ if (is_claimed_by_foreign(pp->udev)) + return PATHINFO_SKIPPED; ++ ++ /* ++ * uid_attribute is required for filter_property below, ++ * and needs access to pp->hwe. ++ */ ++ if (!(mask & DI_SYSFS) && !pp->uid_attribute && ++ VECTOR_SIZE(pp->hwe) == 0) ++ mask |= DI_SYSFS; + } + + if (strlen(pp->dev) != 0 && filter_devnode(conf->blist_devnode, +@@ -2287,6 +2295,15 @@ int pathinfo(struct path *pp, struct config *conf, int mask) + } + } + ++ if (pp->udev) { ++ /* uid_attribute is required for filter_property() */ ++ if (!pp->uid_attribute) ++ select_getuid(conf, pp); ++ ++ if (filter_property(conf, pp->udev, 4, pp->uid_attribute) > 0) ++ return PATHINFO_SKIPPED; ++ } ++ + if (mask & DI_BLACKLIST && mask & DI_SYSFS) { + if (filter_device(conf->blist_device, conf->elist_device, + pp->vendor_id, pp->product_id, pp->dev) > 0 || +diff --git a/libmultipath/valid.c b/libmultipath/valid.c +index 456b1f6e..a6aa9215 100644 +--- a/libmultipath/valid.c ++++ b/libmultipath/valid.c +@@ -89,10 +89,6 @@ is_path_valid(const char *name, struct config *conf, struct path *pp, + if (pp->wwid[0] == '\0') + return PATH_IS_NOT_VALID; + +- if (pp->udev && pp->uid_attribute && +- filter_property(conf, pp->udev, 3, pp->uid_attribute) > 0) +- return PATH_IS_NOT_VALID; +- + r = is_failed_wwid(pp->wwid); + if (r != WWID_IS_NOT_FAILED) { + if (r == WWID_IS_FAILED) +diff --git a/tests/Makefile b/tests/Makefile +index 50673fae..11ca1be5 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -54,7 +54,7 @@ vpd-test_OBJDEPS := ../libmultipath/discovery.o + vpd-test_LIBDEPS := -ludev -lpthread -ldl + alias-test_TESTDEPS := test-log.o + alias-test_LIBDEPS := -lpthread -ldl +-valid-test_OBJDEPS := ../libmultipath/valid.o ++valid-test_OBJDEPS := ../libmultipath/valid.o ../libmultipath/discovery.o + valid-test_LIBDEPS := -ludev -lpthread -ldl + devt-test_LIBDEPS := -ludev + mpathvalid-test_LIBDEPS := -ludev -lpthread -ldl +diff --git a/tests/test-lib.c b/tests/test-lib.c +index e7663f9a..960a7665 100644 +--- a/tests/test-lib.c ++++ b/tests/test-lib.c +@@ -257,6 +257,9 @@ void mock_pathinfo(int mask, const struct mocked_path *mp) + } else + will_return(__wrap_udev_device_get_sysattr_value, "0"); + ++ if (mask & DI_SYSFS) ++ mock_sysfs_pathinfo(mp); ++ + /* filter_property */ + will_return(__wrap_udev_device_get_sysname, mp->devnode); + if (mp->flags & BL_BY_PROPERTY) { +@@ -265,8 +268,6 @@ void mock_pathinfo(int mask, const struct mocked_path *mp) + } else + will_return(__wrap_udev_list_entry_get_name, + "SCSI_IDENT_LUN_NAA_EXT"); +- if (mask & DI_SYSFS) +- mock_sysfs_pathinfo(mp); + + if (mp->flags & BL_BY_DEVICE && + (mask & DI_BLACKLIST && mask & DI_SYSFS)) +diff --git a/tests/valid.c b/tests/valid.c +index 693c72c5..8ec803e8 100644 +--- a/tests/valid.c ++++ b/tests/valid.c +@@ -25,13 +25,18 @@ + #include + #include + #include ++#include ++ + #include "globals.c" + #include "util.h" + #include "discovery.h" + #include "wwids.h" + #include "blacklist.h" ++#include "foreign.h" + #include "valid.h" + ++#define PATHINFO_REAL 9999 ++ + int test_fd; + struct udev_device { + int unused; +@@ -78,12 +83,66 @@ struct udev_device *__wrap_udev_device_new_from_subsystem_sysname(struct udev *u + return NULL; + } + ++/* For the "hidden" check in pathinfo() */ ++const char *__wrap_udev_device_get_sysattr_value(struct udev_device *udev_device, ++ const char *sysattr) ++{ ++ check_expected(sysattr); ++ return mock_ptr_type(char *); ++} ++ ++/* For pathinfo() -> is_claimed_by_foreign() */ ++int __wrap_add_foreign(struct udev_device *udev_device) ++{ ++ return mock_type(int); ++} ++ ++/* called from pathinfo() */ ++int __wrap_filter_devnode(struct config *conf, const struct _vector *elist, ++ const char *vendor, const char * product, const char *dev) ++{ ++ return mock_type(int); ++} ++ ++/* called from pathinfo() */ ++int __wrap_filter_device(const struct _vector *blist, const struct _vector *elist, ++ const char *vendor, const char * product, const char *dev) ++{ ++ return mock_type(int); ++} ++ ++/* for common_sysfs_pathinfo() */ ++dev_t __wrap_udev_device_get_devnum(struct udev_device *ud) ++{ ++ return mock_type(dev_t); ++} ++ ++/* for common_sysfs_pathinfo() */ ++int __wrap_sysfs_get_size(struct path *pp, unsigned long long * size) ++{ ++ return mock_type(int); ++} ++ ++/* called in pathinfo() before filter_property() */ ++int __wrap_select_getuid(struct config *conf, struct path *pp) ++{ ++ pp->uid_attribute = mock_ptr_type(char *); ++ return 0; ++} ++ ++int __real_pathinfo(struct path *pp, struct config *conf, int mask); ++ + int __wrap_pathinfo(struct path *pp, struct config *conf, int mask) + { + int ret = mock_type(int); ++ + assert_string_equal(pp->dev, mock_ptr_type(char *)); + assert_int_equal(mask, DI_SYSFS | DI_WWID | DI_BLACKLIST); +- if (ret == PATHINFO_OK) { ++ if (ret == PATHINFO_REAL) { ++ /* for test_filter_property() */ ++ ret = __real_pathinfo(pp, conf, mask); ++ return ret; ++ } else if (ret == PATHINFO_OK) { + pp->uid_attribute = "ID_TEST"; + strlcpy(pp->wwid, mock_ptr_type(char *), WWID_SIZE); + } else +@@ -128,6 +187,7 @@ enum { + STAGE_IS_MULTIPATHED, + STAGE_CHECK_MULTIPATHD, + STAGE_GET_UDEV_DEVICE, ++ STAGE_PATHINFO_REAL, + STAGE_PATHINFO, + STAGE_FILTER_PROPERTY, + STAGE_IS_FAILED, +@@ -167,12 +227,25 @@ static void setup_passing(char *name, char *wwid, unsigned int check_multipathd, + name); + if (stage == STAGE_GET_UDEV_DEVICE) + return; ++ if (stage == STAGE_PATHINFO_REAL) { ++ /* special case for test_filter_property() */ ++ will_return(__wrap_pathinfo, PATHINFO_REAL); ++ will_return(__wrap_pathinfo, name); ++ expect_string(__wrap_udev_device_get_sysattr_value, ++ sysattr, "hidden"); ++ will_return(__wrap_udev_device_get_sysattr_value, NULL); ++ will_return(__wrap_add_foreign, FOREIGN_IGNORED); ++ will_return(__wrap_filter_devnode, MATCH_NOTHING); ++ will_return(__wrap_udev_device_get_devnum, makedev(259, 0)); ++ will_return(__wrap_sysfs_get_size, 0); ++ will_return(__wrap_select_getuid, "ID_TEST"); ++ return; ++ } + will_return(__wrap_pathinfo, PATHINFO_OK); + will_return(__wrap_pathinfo, name); + will_return(__wrap_pathinfo, wwid); + if (stage == STAGE_PATHINFO) + return; +- will_return(__wrap_filter_property, MATCH_PROPERTY_BLIST_EXCEPT); + if (stage == STAGE_FILTER_PROPERTY) + return; + will_return(__wrap_is_failed_wwid, WWID_IS_NOT_FAILED); +@@ -317,24 +390,24 @@ static void test_filter_property(void **state) + /* test blacklist property */ + memset(&pp, 0, sizeof(pp)); + conf.find_multipaths = FIND_MULTIPATHS_STRICT; +- setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO); ++ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO_REAL); + will_return(__wrap_filter_property, MATCH_PROPERTY_BLIST); + assert_int_equal(is_path_valid(name, &conf, &pp, false), + PATH_IS_NOT_VALID); + assert_ptr_equal(pp.udev, &test_udev); +- assert_string_equal(pp.wwid, wwid); ++ + /* test missing property */ + memset(&pp, 0, sizeof(pp)); +- setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO); ++ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO_REAL); + will_return(__wrap_filter_property, MATCH_PROPERTY_BLIST_MISSING); + assert_int_equal(is_path_valid(name, &conf, &pp, false), + PATH_IS_NOT_VALID); +- /* test MATCH_NOTHING fail on is_failed_wwid */ ++ ++ /* test MATCH_NOTHING fail on filter_device */ + memset(&pp, 0, sizeof(pp)); +- setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO); ++ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO_REAL); + will_return(__wrap_filter_property, MATCH_NOTHING); +- will_return(__wrap_is_failed_wwid, WWID_IS_FAILED); +- will_return(__wrap_is_failed_wwid, wwid); ++ will_return(__wrap_filter_device, MATCH_DEVICE_BLIST); + assert_int_equal(is_path_valid(name, &conf, &pp, false), + PATH_IS_NOT_VALID); + } +-- +2.17.2 + diff --git a/0120-libmultipath-pathinfo-call-filter_property-only-with.patch b/0120-libmultipath-pathinfo-call-filter_property-only-with.patch new file mode 100644 index 0000000..c4c8efc --- /dev/null +++ b/0120-libmultipath-pathinfo-call-filter_property-only-with.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 2 Feb 2021 19:55:28 +0100 +Subject: [PATCH] libmultipath: pathinfo: call filter_property only with + DI_BLACKLIST + +With the previous change to call filter_property() after sysfs_pathinfo(), +it can't happen any more that filter_property() is called from pathinfo +with uid_attribute not set. This may cause pathinfo() to return failure +in some cases where it should actually proceed (e.g. when called from +"multipath -m" -> get_refwwid(). Therefore, don't call filter_property() +any more unless DI_BLACKLIST is set. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/discovery.c | 16 ++++++---------- + tests/test-lib.c | 17 +++++++++-------- + 2 files changed, 15 insertions(+), 18 deletions(-) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index febcd0ae..9be94cd1 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -2255,8 +2255,8 @@ int pathinfo(struct path *pp, struct config *conf, int mask) + * uid_attribute is required for filter_property below, + * and needs access to pp->hwe. + */ +- if (!(mask & DI_SYSFS) && !pp->uid_attribute && +- VECTOR_SIZE(pp->hwe) == 0) ++ if (!(mask & DI_SYSFS) && (mask & DI_BLACKLIST) && ++ !pp->uid_attribute && VECTOR_SIZE(pp->hwe) == 0) + mask |= DI_SYSFS; + } + +@@ -2295,17 +2295,13 @@ int pathinfo(struct path *pp, struct config *conf, int mask) + } + } + +- if (pp->udev) { ++ if (mask & DI_BLACKLIST && mask & DI_SYSFS) { + /* uid_attribute is required for filter_property() */ +- if (!pp->uid_attribute) ++ if (pp->udev && !pp->uid_attribute) + select_getuid(conf, pp); + +- if (filter_property(conf, pp->udev, 4, pp->uid_attribute) > 0) +- return PATHINFO_SKIPPED; +- } +- +- if (mask & DI_BLACKLIST && mask & DI_SYSFS) { +- if (filter_device(conf->blist_device, conf->elist_device, ++ if (filter_property(conf, pp->udev, 4, pp->uid_attribute) > 0 || ++ filter_device(conf->blist_device, conf->elist_device, + pp->vendor_id, pp->product_id, pp->dev) > 0 || + filter_protocol(conf->blist_protocol, conf->elist_protocol, + pp) > 0) +diff --git a/tests/test-lib.c b/tests/test-lib.c +index 960a7665..f5542ed0 100644 +--- a/tests/test-lib.c ++++ b/tests/test-lib.c +@@ -260,14 +260,15 @@ void mock_pathinfo(int mask, const struct mocked_path *mp) + if (mask & DI_SYSFS) + mock_sysfs_pathinfo(mp); + +- /* filter_property */ +- will_return(__wrap_udev_device_get_sysname, mp->devnode); +- if (mp->flags & BL_BY_PROPERTY) { +- will_return(__wrap_udev_list_entry_get_name, "BAZ"); +- return; +- } else +- will_return(__wrap_udev_list_entry_get_name, +- "SCSI_IDENT_LUN_NAA_EXT"); ++ if (mask & DI_BLACKLIST) { ++ will_return(__wrap_udev_device_get_sysname, mp->devnode); ++ if (mp->flags & BL_BY_PROPERTY) { ++ will_return(__wrap_udev_list_entry_get_name, "BAZ"); ++ return; ++ } else ++ will_return(__wrap_udev_list_entry_get_name, ++ "SCSI_IDENT_LUN_NAA_EXT"); ++ } + + if (mp->flags & BL_BY_DEVICE && + (mask & DI_BLACKLIST && mask & DI_SYSFS)) +-- +2.17.2 + diff --git a/0121-multipath-w-allow-removing-blacklisted-paths.patch b/0121-multipath-w-allow-removing-blacklisted-paths.patch new file mode 100644 index 0000000..db6fe52 --- /dev/null +++ b/0121-multipath-w-allow-removing-blacklisted-paths.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 2 Feb 2021 21:54:37 +0100 +Subject: [PATCH] multipath -w: allow removing blacklisted paths + +multipath should allow removing WWIDs of paths even if they +are blacklisted. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 3263bb01..598efe05 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -1441,7 +1441,7 @@ static int _get_refwwid(enum mpath_cmds cmd, const char *dev, + return ret; + } + } +- if (pp->udev && pp->uid_attribute && ++ if (flags & DI_BLACKLIST && + filter_property(conf, pp->udev, 3, pp->uid_attribute) > 0) + return PATHINFO_SKIPPED; + refwwid = pp->wwid; +@@ -1466,7 +1466,7 @@ static int _get_refwwid(enum mpath_cmds cmd, const char *dev, + refwwid = dev; + } + +- if (refwwid && strlen(refwwid) && ++ if (flags & DI_BLACKLIST && refwwid && strlen(refwwid) && + filter_wwid(conf->blist_wwid, conf->elist_wwid, refwwid, + NULL) > 0) + return PATHINFO_SKIPPED; +-- +2.17.2 + diff --git a/0122-libmultipath-fix-use-after-free-in-uev_add_path.patch b/0122-libmultipath-fix-use-after-free-in-uev_add_path.patch new file mode 100644 index 0000000..6a5fcad --- /dev/null +++ b/0122-libmultipath-fix-use-after-free-in-uev_add_path.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 1 Feb 2021 19:47:11 -0600 +Subject: [PATCH] libmultipath: fix use-after-free in uev_add_path + +if ev_remove_path() returns success the path has very likely been +deleted. However, if pathinfo() returned something besides PATHINFO_OK, +but ev_remove_path() succeeded, uev_add_path() was still accessing the +the path afterwards, which would likely cause a use-after-free error. +Insted, uev_add_path() should only continue to access the path if +ev_remove_path() didn't succeed. + +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 425492a9..19679848 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -890,13 +890,7 @@ uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map) + */ + pp->mpp = prev_mpp; + ret = ev_remove_path(pp, vecs, true); +- if (r == PATHINFO_OK && !ret) +- /* +- * Path successfully freed, move on to +- * "new path" code path below +- */ +- pp = NULL; +- else { ++ if (ret != 0) { + /* + * Failure in ev_remove_path will keep + * path in pathvec in INIT_REMOVED state +@@ -907,7 +901,12 @@ uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map) + dm_fail_path(pp->mpp->alias, pp->dev_t); + condlog(1, "%s: failed to re-add path still mapped in %s", + pp->dev, pp->mpp->alias); +- } ++ } else if (r == PATHINFO_OK) ++ /* ++ * Path successfully freed, move on to ++ * "new path" code path below ++ */ ++ pp = NULL; + } else if (r == PATHINFO_SKIPPED) { + condlog(3, "%s: remove blacklisted path", + uev->kernel); +-- +2.17.2 + diff --git a/0123-kpartx-free-loop-device-after-listing-partitions.patch b/0123-kpartx-free-loop-device-after-listing-partitions.patch new file mode 100644 index 0000000..4db7cfd --- /dev/null +++ b/0123-kpartx-free-loop-device-after-listing-partitions.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Tue, 9 Feb 2021 17:16:04 -0600 +Subject: [PATCH] kpartx: free loop device after listing partitions + +If "kpartx -l" is run on a file that doesn't already have a loop device +associated with it, it will create a loop device to run the command. +Starting with da59d15c6 ("Fix loopback file with kpartx -av"), it will +not free the loop device when exitting. This is because it checks if the +the file it stat()ed is a regular file, before freeing the loop device. +However, after da59d15c6, stat() is rerun on the loop device itself, so +the check fails. There is no need to check this, if loopcreated is +true, then the file will be a kpartx created loop device, and should be +freed. + +Also, keep kpartx from printing that the loop device has been removed +at normal verbosity. + +Fixes: da59d15c6 ("Fix loopback file with kpartx -av") +Signed-off-by: Benjamin Marzinski +--- + kpartx/kpartx.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c +index 6a7933fa..8ff116b8 100644 +--- a/kpartx/kpartx.c ++++ b/kpartx/kpartx.c +@@ -424,7 +424,7 @@ main(int argc, char **argv){ + fprintf(stderr, "can't del loop : %s\n", + loopdev); + r = 1; +- } else ++ } else if (verbose) + fprintf(stderr, "loop deleted : %s\n", loopdev); + } + goto end; +@@ -668,16 +668,17 @@ main(int argc, char **argv){ + if (n > 0) + break; + } +- if (what == LIST && loopcreated && S_ISREG (buf.st_mode)) { ++ if (what == LIST && loopcreated) { + if (fd != -1) + close(fd); + if (del_loop(device)) { + if (verbose) +- printf("can't del loop : %s\n", ++ fprintf(stderr, "can't del loop : %s\n", + device); + exit(1); + } +- printf("loop deleted : %s\n", device); ++ if (verbose) ++ fprintf(stderr, "loop deleted : %s\n", device); + } + + end: +-- +2.17.2 + diff --git a/0124-RH-fixup-udev-rules-for-redhat.patch b/0124-RH-fixup-udev-rules-for-redhat.patch new file mode 100644 index 0000000..d5bbd5b --- /dev/null +++ b/0124-RH-fixup-udev-rules-for-redhat.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +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 +--- + 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 05429307..24e943d5 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 d7527d7d..0e0d70d5 100644 +--- a/kpartx/kpartx.rules ++++ b/kpartx/kpartx.rules +@@ -36,6 +36,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 + diff --git a/0002-RH-Remove-the-property-blacklist-exception-builtin.patch b/0125-RH-Remove-the-property-blacklist-exception-builtin.patch similarity index 77% rename from 0002-RH-Remove-the-property-blacklist-exception-builtin.patch rename to 0125-RH-Remove-the-property-blacklist-exception-builtin.patch index b8e580a..9c44867 100644 --- a/0002-RH-Remove-the-property-blacklist-exception-builtin.patch +++ b/0125-RH-Remove-the-property-blacklist-exception-builtin.patch @@ -1,4 +1,4 @@ -From f7be16ac9fce97585a4552d49f3d3c54a93c9c17 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Wed, 2 Jul 2014 12:49:53 -0500 Subject: [PATCH] RH: Remove the property blacklist exception builtin @@ -13,25 +13,26 @@ it. Signed-off-by: Benjamin Marzinski --- - libmultipath/blacklist.c | 5 ++--- - multipath/multipath.conf.5.in | 11 ++++++----- - tests/blacklist.c | 7 ++----- - 3 files changed, 10 insertions(+), 13 deletions(-) + libmultipath/blacklist.c | 6 ++---- + multipath/multipath.conf.5 | 11 ++++++----- + tests/blacklist.c | 7 ++----- + 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c -index 17e1b54a..10d13e98 100644 +index 6c6a5979..785f5ee9 100644 --- a/libmultipath/blacklist.c +++ b/libmultipath/blacklist.c -@@ -230,8 +230,6 @@ setup_default_blist (struct config * conf) - ORIGIN_DEFAULT)) - return 1; - } +@@ -201,9 +201,6 @@ setup_default_blist (struct config * conf) + if (store_ble(conf->blist_devnode, "!^(sd[a-z]|dasd[a-z]|nvme[0-9])", ORIGIN_DEFAULT)) + return 1; + - if (store_ble(conf->elist_property, "(SCSI_IDENT_|ID_WWN)", ORIGIN_DEFAULT)) - return 1; - +- vector_foreach_slot (conf->hwtable, hwe, i) { if (hwe->bl_product) { -@@ -438,7 +436,8 @@ filter_property(const struct config *conf, struct udev_device *udev, + if (find_blacklist_device(conf->blist_device, +@@ -407,7 +404,8 @@ filter_property(const struct config *conf, struct udev_device *udev, *uid_attribute != '\0'; bool uid_attr_seen = false; @@ -41,11 +42,11 @@ index 17e1b54a..10d13e98 100644 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev)) { -diff --git a/multipath/multipath.conf.5.in b/multipath/multipath.conf.5.in -index 3c9ae097..ba291e11 100644 ---- a/multipath/multipath.conf.5.in -+++ b/multipath/multipath.conf.5.in -@@ -1470,9 +1470,14 @@ keywords. Both are regular expressions. For a full description of these keywords +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 +index 8ef3a747..1e95a854 100644 +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -1333,9 +1333,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, @@ -61,7 +62,7 @@ index 3c9ae097..ba291e11 100644 . .RS .PP -@@ -1483,10 +1488,6 @@ Blacklisting by missing properties is only applied to devices which do have the +@@ -1346,10 +1351,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. @@ -73,10 +74,10 @@ index 3c9ae097..ba291e11 100644 .TP .B protocol diff --git a/tests/blacklist.c b/tests/blacklist.c -index ab3da619..52ae03e0 100644 +index 0b42e255..4d595eda 100644 --- a/tests/blacklist.c +++ b/tests/blacklist.c -@@ -371,9 +371,8 @@ static void test_property_missing(void **state) +@@ -375,9 +375,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; @@ -87,7 +88,7 @@ index ab3da619..52ae03e0 100644 assert_int_equal(filter_property(&conf, &udev, 3, "ID_BLAH"), MATCH_NOTHING); assert_int_equal(filter_property(&conf, &udev, 3, ""), -@@ -465,9 +464,7 @@ static void test_filter_path_missing1(void **state) +@@ -469,9 +468,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; @@ -98,3 +99,6 @@ index ab3da619..52ae03e0 100644 } /* This one matches the property whitelist, to test the other missing +-- +2.17.2 + diff --git a/0126-RH-don-t-start-without-a-config-file.patch b/0126-RH-don-t-start-without-a-config-file.patch new file mode 100644 index 0000000..2931726 --- /dev/null +++ b/0126-RH-don-t-start-without-a-config-file.patch @@ -0,0 +1,97 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +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 +--- + libmultipath/config.c | 13 +++++++++++++ + libmultipath/config.h | 1 + + multipath/multipath.rules | 1 + + multipathd/multipathd.8 | 2 ++ + multipathd/multipathd.service | 1 + + 5 files changed, 18 insertions(+) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index be310159..8d291491 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -893,6 +893,19 @@ int _init_config (const char *file, struct config *conf) + 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, ".*", 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 9ce37f16..7f8d9cd0 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 + + enum devtypes { + DEV_NONE, +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 7d547fa7..af592057 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 shutdown.target + 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 + diff --git a/0004-RH-Fix-nvme-function-missing-argument.patch b/0127-RH-Fix-nvme-function-missing-argument.patch similarity index 83% rename from 0004-RH-Fix-nvme-function-missing-argument.patch rename to 0127-RH-Fix-nvme-function-missing-argument.patch index 33a8d5f..b5c63c0 100644 --- a/0004-RH-Fix-nvme-function-missing-argument.patch +++ b/0127-RH-Fix-nvme-function-missing-argument.patch @@ -1,4 +1,4 @@ -From 283b5dd645663a2cf16f2813581772d7a84db6ad Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Fri, 25 Jan 2019 14:54:56 -0600 Subject: [PATCH] RH: Fix nvme function missing argument @@ -12,10 +12,10 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmultipath/nvme/argconfig.h b/libmultipath/nvme/argconfig.h -index b3caa7be..f91504c9 100644 +index adb192b6..bfd10ef8 100644 --- a/libmultipath/nvme/argconfig.h +++ b/libmultipath/nvme/argconfig.h -@@ -63,7 +63,7 @@ struct argconfig_commandline_options { +@@ -76,7 +76,7 @@ struct argconfig_commandline_options { extern "C" { #endif @@ -24,3 +24,6 @@ index b3caa7be..f91504c9 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 + diff --git a/0128-RH-use-rpm-optflags-if-present.patch b/0128-RH-use-rpm-optflags-if-present.patch new file mode 100644 index 0000000..f765f47 --- /dev/null +++ b/0128-RH-use-rpm-optflags-if-present.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +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 +--- + Makefile.inc | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/Makefile.inc b/Makefile.inc +index 24e943d5..e978d306 100644 +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -90,15 +90,27 @@ 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,) + +-OPTFLAGS := -O2 -g $(STACKPROT) --param=ssp-buffer-size=4 +-WARNFLAGS := -Werror -Wall -Wextra -Wformat=2 -Werror=implicit-int \ ++ifndef RPM_OPT_FLAGS ++ STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector) ++ OPTFLAGS := -O2 -g -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions \ ++ $(STACKPROT) -grecord-gcc-switches \ ++ -fasynchronous-unwind-tables --param=ssp-buffer-size=4 ++ 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 -Werror=implicit-int \ + -Werror=implicit-function-declaration -Werror=format-security \ +- $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) +-CPPFLAGS := -Wp,-D_FORTIFY_SOURCE=2 ++ $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) \ ++ -Wstrict-prototypes + CFLAGS := --std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \ + -DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \ + -MMD -MP +@@ -136,4 +148,4 @@ check_file = $(shell \ + + %.o: %.c + @echo building $@ because of $? +- $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< ++ $(CC) $(CFLAGS) -c -o $@ $< +-- +2.17.2 + diff --git a/0006-RH-add-mpathconf.patch b/0129-RH-add-mpathconf.patch similarity index 64% rename from 0006-RH-add-mpathconf.patch rename to 0129-RH-add-mpathconf.patch index 46f1126..346251a 100644 --- a/0006-RH-add-mpathconf.patch +++ b/0129-RH-add-mpathconf.patch @@ -1,4 +1,4 @@ -From 29e5c6d6e2177e73d1be2ed2af66c1007487bf60 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 16 Oct 2014 15:49:01 -0500 Subject: [PATCH] RH: add mpathconf @@ -10,48 +10,22 @@ 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 Signed-off-by: Benjamin Marzinski --- - .github/actions/spelling/expect.txt | 3 + - libmultipath/config.c | 2 + - multipath/Makefile | 4 + - multipath/mpathconf | 658 ++++++++++++++++++++++++++++ - multipath/mpathconf.8 | 151 +++++++ - 5 files changed, 818 insertions(+) + libmultipath/config.c | 2 + + multipath/Makefile | 5 + + multipath/mpathconf | 555 ++++++++++++++++++++++++++++++++++++++++++ + multipath/mpathconf.8 | 135 ++++++++++ + 4 files changed, 697 insertions(+) create mode 100644 multipath/mpathconf create mode 100644 multipath/mpathconf.8 -diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt -index a5856bcc..5c9113ba 100644 ---- a/.github/actions/spelling/expect.txt -+++ b/.github/actions/spelling/expect.txt -@@ -131,9 +131,11 @@ Marzinski - misdetection - mpath - mpathb -+mpathconf - mpathpersist - mpathvalid - msecs -+multipathable - multipathc - multipathd - multipathed -@@ -154,6 +156,7 @@ ontap - OOM - opensvc - OPTFLAGS -+outfile - paramp - partx - pathgroup diff --git a/libmultipath/config.c b/libmultipath/config.c -index b8317f4d..0bbaa981 100644 +index 8d291491..bbdd1617 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c -@@ -939,6 +939,8 @@ int init_config__ (const char *file, struct config *conf) - validate_pctable(conf->overrides, 0, file); +@@ -895,6 +895,8 @@ int _init_config (const char *file, struct config *conf) + factorize_hwtable(conf->hwtable, builtin_hwtable_size, file); } else { condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices."); + condlog(0, "You can run \"/sbin/mpathconf --enable\" to create"); @@ -60,46 +34,45 @@ index b8317f4d..0bbaa981 100644 conf->blist_devnode = vector_alloc(); if (!conf->blist_devnode) { diff --git a/multipath/Makefile b/multipath/Makefile -index 2ea9e528..3dc241cc 100644 +index b9bbb3cf..e720c7f6 100644 --- a/multipath/Makefile +++ b/multipath/Makefile -@@ -24,6 +24,7 @@ $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so +@@ -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 + 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) -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 + $(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) uninstall: - $(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 + $(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 + clean: dep_clean + $(RM) core *.o $(EXEC) *.gz diff --git a/multipath/mpathconf b/multipath/mpathconf new file mode 100644 -index 00000000..ce430075 +index 00000000..2f4f3eaf --- /dev/null +++ b/multipath/mpathconf -@@ -0,0 +1,658 @@ +@@ -0,0 +1,555 @@ +#!/bin/bash +# +# Copyright (C) 2010 Red Hat, Inc. All rights reserved. @@ -119,7 +92,7 @@ index 00000000..ce430075 +# 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 HAVE_OPTION OPTION_NAME OPTION_VALUE HAVE_RECHECK_WWID RECHECK_WWID ++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 + +DEFAULT_CONFIG="# device-mapper-multipath configuration file + @@ -133,7 +106,12 @@ index 00000000..ce430075 + +defaults { + user_friendly_names yes -+ find_multipaths on ++ find_multipaths yes ++ enable_foreign \"^$\" ++} ++ ++blacklist_exceptions { ++ property \"(SCSI_IDENT_|ID_WWN)\" +}" + +CONFIGFILE="/etc/multipath.conf" @@ -151,11 +129,9 @@ index 00000000..ce430075 + echo "Disable: --disable" + echo "Only allow certain wwids (instead of enable): --allow " + echo "Set user_friendly_names (Default y): --user_friendly_names " -+ echo "Set find_multipaths (Default on): --find_multipaths " -+ echo "Set default property blacklist (Default n): --property_blacklist " ++ echo "Set find_multipaths (Default y): --find_multipaths " ++ echo "Set default property blacklist (Default y): --property_blacklist " + echo "Set enable_foreign to show foreign devices (Default n): --enable_foreign " -+ echo "Set recheck_wwid (Defaut n): --recheck_wwid " -+ echo "Add/Change/Remove option in defaults section: --option :" + echo "Load the dm-multipath modules on enable (Default y): --with_module " + echo "start/stop/reload multipathd (Default n): --with_multipathd " + echo "select output file (Default /etc/multipath.conf): --outfile " @@ -248,15 +224,6 @@ index 00000000..ce430075 + 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 @@ -275,20 +242,6 @@ index 00000000..ce430075 + 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 @@ -335,31 +288,23 @@ index 00000000..ce430075 + +function validate_args +{ -+ 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 ++ if [ "$ENABLE" = "0" ] && [ -n "$FRIENDLY" -o -n "$FIND" -o -n "$PROPERTY" -o -n "$MODULE" ]; 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 "$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" ++ FIND="yes" + 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'" ++ FIND="no" ++ elif [ -n "$FIND" ] && [ "$FIND" != "yes" -a "$FIND" != "no" -a "$FIND" != "strict" -a "$FIND" != "greedy" -a "$FIND" != "smart" ]; then ++ echo "--find_multipaths must be one of 'yes' 'no' 'strict' 'greedy' or 'smart'" + exit 1 + fi + if [ -n "$PROPERTY" ] && [ "$PROPERTY" != "y" -a "$PROPERTY" != "n" ]; then @@ -370,19 +315,7 @@ index 00000000..ce430075 + echo "--enable_foreign must be either 'y' or 'n'" + exit 1 + fi -+ 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 ++ if [ -z "$ENABLE" -a -z "$FIND" -a -z "$FRIENDLY" -a -z "$PROPERTY" ]; then + SHOW_STATUS=1 + fi + if [ -n "$MODULE" ] && [ "$MODULE" != "y" -a "$MODULE" != "n" ]; then @@ -457,62 +390,46 @@ index 00000000..ce430075 +fi + +if [ "$HAVE_BLACKLIST" = "1" ]; then -+ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"" ; then ++ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*devnode \"\.\?\*\"" ; then + HAVE_DISABLE=1 -+ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"" ; then ++ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*devnode \"\.\?\*\"" ; then + HAVE_DISABLE=0 + fi +fi + +if [ "$HAVE_BLACKLIST" = "1" ]; then -+ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*wwid[[:space:]][[:space:]]*\"\.\?\*\"" ; then ++ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*wwid \"\.\?\*\"" ; then + HAVE_WWID_DISABLE=1 -+ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*wwid[[:space:]][[:space:]]*\"\.\?\*\"" ; then ++ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*wwid \"\.\?\*\"" ; then + HAVE_WWID_DISABLE=0 + fi +fi + +if [ "$HAVE_DEFAULTS" = "1" ]; then -+ HAVE_FIND=`sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | sed -n 's/^[[:blank:]]*find_multipaths[[:blank:]][[:blank:]]*\([^[:blank:]]*\).*$/\1/p' | sed -n 1p` ++ HAVE_FIND=`sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | sed -n 's/^[[:blank:]]*find_multipaths[[:blank:]]*\([^[:blank:]]*\).*$/\1/p' | sed -n 1p` + if [ "$HAVE_FIND" = "1" ]; then + HAVE_FIND="yes" + elif [ "$HAVE_FIND" = "0" ]; then + HAVE_FIND="no" + fi -+ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]][[:space:]]*\(yes\|1\)" ; then ++ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]]*\(yes\|1\)" ; then + HAVE_FRIENDLY=1 -+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]][[:space:]]*\(no\|0\)" ; then ++ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[: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:]][[:space:]]*\"\.\*\"" ; then ++ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign[[:space:]]*\"\^\$\"" ; then + HAVE_FOREIGN=1 -+ 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 ++ HAVE_FOREIGN=2 + fi +fi + +if [ "$HAVE_EXCEPTIONS" = "1" ]; then -+ if sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*property[[:space:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then ++ if sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then + HAVE_PROPERTY=1 -+ elif sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*property[[:space:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then ++ elif sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then + HAVE_PROPERTY=0 + fi +fi @@ -524,7 +441,7 @@ index 00000000..ce430075 + echo "multipath is disabled" + fi + if [ -z "$HAVE_FIND" ]; then -+ echo "find_multipaths is off" ++ echo "find_multipaths is no" + else + echo "find_multipaths is $HAVE_FIND" + fi @@ -533,21 +450,14 @@ index 00000000..ce430075 + 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 (no foreign multipath devices will be shown)" ++ echo "enable_foreign is not set (all 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)" @@ -592,14 +502,14 @@ index 00000000..ce430075 + +if [ "$ENABLE" = 2 ]; then + if [ "$HAVE_DISABLE" = 1 ]; then -+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"/# devnode ".*"/' $TMPFILE ++ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode \"\.\?\*\"/# 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[[:space:]][[:space:]]*\"\.\?\*\"/ wwid ".*"/' $TMPFILE ++ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*wwid \"\.\?\*\"/ wwid ".*"/' $TMPFILE + fi + if [ "$HAVE_EXCEPTIONS" = 1 ]; then + sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ {/^[[:space:]]*wwid/ d}' $TMPFILE @@ -613,7 +523,7 @@ index 00000000..ce430075 + add_blacklist_exceptions +elif [ "$ENABLE" = 1 ]; then + if [ "$HAVE_DISABLE" = 1 ]; then -+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"/# devnode ".*"/' $TMPFILE ++ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode \"\.\?\*\"/# devnode ".*"/' $TMPFILE + fi +elif [ "$ENABLE" = 0 ]; then + if [ -z "$HAVE_DISABLE" ]; then @@ -621,7 +531,7 @@ index 00000000..ce430075 + devnode ".*" +' $TMPFILE + elif [ "$HAVE_DISABLE" = 0 ]; then -+ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*devnode[[:space:]][[:space:]]*\"\.\?\*\"/ devnode ".*"/' $TMPFILE ++ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*devnode \"\.\?\*\"/ devnode ".*"/' $TMPFILE + fi +fi + @@ -632,14 +542,14 @@ index 00000000..ce430075 +' $TMPFILE + CHANGED_CONFIG=1 + elif [ "$FIND" != "$HAVE_FIND" ]; then -+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:blank:]]*find_multipaths[[:blank:]][[:blank:]]*[^[:blank:]]*/ find_multipaths '"$FIND"'/' $TMPFILE ++ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:blank:]]*find_multipaths[[: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:]][[:space:]]*\(yes\|1\)/ user_friendly_names no/' $TMPFILE ++ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]]*\(yes\|1\)/ user_friendly_names no/' $TMPFILE + CHANGED_CONFIG=1 + fi +elif [ "$FRIENDLY" = "y" ]; then @@ -649,85 +559,45 @@ index 00000000..ce430075 +' $TMPFILE + CHANGED_CONFIG=1 + elif [ "$HAVE_FRIENDLY" = 0 ]; then -+ 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 ++ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]]*\(no\|0\)/ user_friendly_names yes/' $TMPFILE + CHANGED_CONFIG=1 + fi +fi + +if [ "$PROPERTY" = "n" ]; then + if [ "$HAVE_PROPERTY" = 1 ]; then -+ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*property[[:space:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/# property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE ++ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/# property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE + CHANGED_CONFIG=1 + fi +elif [ "$PROPERTY" = "y" ]; 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 ++ if [ -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:]][[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/ property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE ++ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/ property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE + CHANGED_CONFIG=1 + fi +fi + -+if [ "$FOREIGN" = "n" ]; then -+ if [ "$HAVE_FOREIGN" = 1 -o "$HAVE_FOREIGN" = 3 ]; then ++if [ "$FOREIGN" = "y" ]; then ++ if [ "$HAVE_FOREIGN" = 1 -o "$HAVE_FOREIGN" = 2 ]; then + sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*enable_foreign/# enable_foreign/' $TMPFILE + CHANGED_CONFIG=1 + fi -+elif [ "$FOREIGN" = "y" ]; then ++elif [ "$FOREIGN" = "n" ]; 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 -o "$HAVE_FOREIGN" = 3 ]; then -+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*#\?[[:space:]]*enable_foreign.*$/ enable_foreign ".*"/' $TMPFILE ++ elif [ "$HAVE_FOREIGN" = 0 -o "$HAVE_FOREIGN" = 2 ]; 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 @@ -760,10 +630,10 @@ index 00000000..ce430075 +fi diff --git a/multipath/mpathconf.8 b/multipath/mpathconf.8 new file mode 100644 -index 00000000..ec4e5c56 +index 00000000..83515eb4 --- /dev/null +++ b/multipath/mpathconf.8 -@@ -0,0 +1,151 @@ +@@ -0,0 +1,135 @@ +.TH MPATHCONF 8 "June 2010" "" "Linux Administrator's Manual" +.SH NAME +mpathconf - A tool for configuring device-mapper-multipath @@ -806,10 +676,10 @@ index 00000000..ec4e5c56 +.B user_friendly_names +set and +.B find_multipaths -+set to \fBon\fP. To disable these, use the ++set to \fByes\fP. To disable these, use the +.B --user_friendly_names n +and -+.B --find_multipaths off ++.B --find_multipaths n +options +.SH COMMANDS +.TP @@ -843,16 +713,7 @@ index 00000000..ec4e5c56 +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 --recheck_wwid \fP { \fBy\fP | \fBn\fP } -+If set to \fBy\fP, this adds the line -+.B recheck_wwid yes -+to the -+.B /etc/multipath.conf -+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 } ++.B --find_multipaths\fP { \fByes\fP | \fBno\fP | \fBstrict\fP | \fBgreedy\fP | \fBsmart\fP } +If set to \fB\fP, this adds the line +.B find_multipaths +to the @@ -869,18 +730,11 @@ index 00000000..ec4e5c56 +present. This command can be used along with any other command. +.TP +.B --enable_foreign\fP { \fBy\fP | \fBn\fP } -+If set to \fBy\fP, this adds the line -+.B enable_foreign ".*" ++If set to \fBn\fP, this adds the line ++.B enable_foreign "^$" +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. -+.TP -+.B --option \fB:[]\fP -+Sets the defaults section option \fB\fP to \fB\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\fP. If \fB\fP is left blank, -+then the option is removed from the defaults section, if was set there. This ++defaults section. if set to \fBy\fP, this removes the line, if present. This +command can be used along with any other command. +.TP +.B --outfile \fB\fP @@ -902,7 +756,7 @@ index 00000000..ec4e5c56 +.B service multipathd stop +to stop the multipathd daemon on \fB--disable\fP, and +.B service multipathd reload -+to reconfigure multipathd on \fB--user_friendly_names\fP and ++to reconfigure multipathd on \fB--user_frindly_names\fP and +\fB--find_multipaths\fP. +This option is set to \fBn\fP by default. +.SH FILES @@ -915,3 +769,6 @@ index 00000000..ec4e5c56 +.BR service (8), +.SH AUTHOR +Benjamin Marzinski +-- +2.17.2 + diff --git a/0007-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch b/0130-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch similarity index 72% rename from 0007-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch rename to 0130-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch index cef8b56..3f0a9ad 100644 --- a/0007-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch +++ b/0130-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch @@ -1,4 +1,4 @@ -From d6ad888bad3850bb0a342ebcdc9fd78773eb3b2a Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Fri, 17 Oct 2014 11:20:34 -0500 Subject: [PATCH] RH: add wwids from kernel cmdline mpath.wwids with -A @@ -14,16 +14,16 @@ multipathd.service Signed-off-by: Benjamin Marzinski --- - multipath/main.c | 54 ++++++++++++++++++++++++++++++-- - multipath/multipath.8.in | 7 ++++- - multipathd/multipathd.service.in | 1 + + multipath/main.c | 54 +++++++++++++++++++++++++++++++++-- + multipath/multipath.8 | 7 ++++- + multipathd/multipathd.service | 1 + 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/multipath/main.c b/multipath/main.c -index 31012874..a667c2ee 100644 +index 9ac42869..beaac3ca 100644 --- a/multipath/main.c +++ b/multipath/main.c -@@ -111,7 +111,7 @@ usage (char * progname) +@@ -122,7 +122,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); @@ -32,7 +32,7 @@ index 31012874..a667c2ee 100644 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); -@@ -125,6 +125,8 @@ usage (char * progname) +@@ -136,6 +136,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" @@ -41,7 +41,7 @@ index 31012874..a667c2ee 100644 " -c check if a device should be a path in a multipath device\n" " -C check if a multipath device has usable paths\n" " -q allow queue_if_no_path when multipathd is not running\n" -@@ -440,6 +442,50 @@ static void cleanup_vecs(void) +@@ -452,6 +454,50 @@ static void cleanup_vecs(void) free_pathvec(vecs.pathvec, FREE_PATHS); } @@ -92,16 +92,16 @@ index 31012874..a667c2ee 100644 static int configure (struct config *conf, enum mpath_cmds cmd, enum devtypes dev_type, char *devpath) -@@ -851,7 +897,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"); +@@ -825,7 +871,7 @@ main (int argc, char *argv[]) + conf = get_multipath_config(); + conf->retrigger_tries = 0; + conf->force_sync = 1; - 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 'v': - if (!isdigit(optarg[0])) { -@@ -922,6 +968,10 @@ main (int argc, char *argv[]) + case 1: printf("optarg : %s\n",optarg); + break; +@@ -902,6 +948,10 @@ main (int argc, char *argv[]) case 'T': cmd = CMD_DUMP_CONFIG; break; @@ -112,11 +112,11 @@ index 31012874..a667c2ee 100644 case 'h': usage(argv[0]); exit(RTVL_OK); -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. +diff --git a/multipath/multipath.8 b/multipath/multipath.8 +index 5b29a5d9..0478f4e7 100644 +--- a/multipath/multipath.8 ++++ b/multipath/multipath.8 +@@ -63,7 +63,7 @@ multipath \- Device mapper target autoconfig. .B multipath .RB [\| \-v\ \c .IR level \|] @@ -125,7 +125,7 @@ index b88e9a4c..edd742aa 100644 . .LP .B multipath -@@ -146,6 +146,11 @@ device mapper, path checkers ...). +@@ -145,6 +145,11 @@ device mapper, path checkers ...). Add the WWID for the specified device to the WWIDs file. . .TP @@ -137,15 +137,18 @@ index b88e9a4c..edd742aa 100644 .B \-w Remove the WWID for the specified device from the WWIDs file. . -diff --git a/multipathd/multipathd.service.in b/multipathd/multipathd.service.in -index ab166435..1ec08c6e 100644 ---- a/multipathd/multipathd.service.in -+++ b/multipathd/multipathd.service.in -@@ -19,6 +19,7 @@ StartLimitBurst=3 - [Service] - Type=notify +diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service +index af592057..bc8fa07a 100644 +--- a/multipathd/multipathd.service ++++ b/multipathd/multipathd.service +@@ -15,6 +15,7 @@ Type=notify NotifyAccess=main -+ExecStartPre=-@BINDIR@/multipath -A - ExecStart=@BINDIR@/multipathd -d -s - ExecReload=@BINDIR@/multipathd reconfigure - Restart=on-failure + 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 + diff --git a/0008-RH-reset-default-find_mutipaths-value-to-off.patch b/0131-RH-reset-default-find_mutipaths-value-to-off.patch similarity index 52% rename from 0008-RH-reset-default-find_mutipaths-value-to-off.patch rename to 0131-RH-reset-default-find_mutipaths-value-to-off.patch index fdc90d4..304db61 100644 --- a/0008-RH-reset-default-find_mutipaths-value-to-off.patch +++ b/0131-RH-reset-default-find_mutipaths-value-to-off.patch @@ -1,4 +1,4 @@ -From 064d761121e7e2c7b63ab280e341d8010a413119 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 7 Jun 2018 17:43:52 -0500 Subject: [PATCH] RH: reset default find_mutipaths value to off @@ -6,18 +6,16 @@ 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 Signed-off-by: Benjamin Marzinski --- - libmultipath/defaults.h | 2 +- - multipath/multipath.conf.5.in | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) + libmultipath/defaults.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h -index 134b690a..e2fe7ac4 100644 +index 947ba467..518d0b16 100644 --- a/libmultipath/defaults.h +++ b/libmultipath/defaults.h -@@ -24,7 +24,7 @@ +@@ -23,7 +23,7 @@ #define DEFAULT_NO_PATH_RETRY NO_PATH_RETRY_UNDEF #define DEFAULT_VERBOSITY 2 #define DEFAULT_REASSIGN_MAPS 0 @@ -26,16 +24,6 @@ index 134b690a..e2fe7ac4 100644 #define DEFAULT_FAST_IO_FAIL 5 #define DEFAULT_DEV_LOSS_TMO 600 #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_ON -diff --git a/multipath/multipath.conf.5.in b/multipath/multipath.conf.5.in -index ba291e11..b8389db3 100644 ---- a/multipath/multipath.conf.5.in -+++ b/multipath/multipath.conf.5.in -@@ -1227,7 +1227,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 - . - . +-- +2.17.2 + diff --git a/0009-RH-attempt-to-get-ANA-info-via-sysfs-first.patch b/0132-RH-attempt-to-get-ANA-info-via-sysfs-first.patch similarity index 85% rename from 0009-RH-attempt-to-get-ANA-info-via-sysfs-first.patch rename to 0132-RH-attempt-to-get-ANA-info-via-sysfs-first.patch index 8065e9f..14b3367 100644 --- a/0009-RH-attempt-to-get-ANA-info-via-sysfs-first.patch +++ b/0132-RH-attempt-to-get-ANA-info-via-sysfs-first.patch @@ -1,4 +1,4 @@ -From 335b8eb2773b07a602e84e14c1f3e289a9b25b5a Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 11 Apr 2019 13:25:42 -0500 Subject: [PATCH] RH: attempt to get ANA info via sysfs first @@ -13,10 +13,10 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/libmultipath/prioritizers/ana.c b/libmultipath/prioritizers/ana.c -index 34527b22..4eaa3cc3 100644 +index b5c7873d..e139360c 100644 --- a/libmultipath/prioritizers/ana.c +++ b/libmultipath/prioritizers/ana.c -@@ -23,6 +23,7 @@ +@@ -24,6 +24,7 @@ #include "prio.h" #include "util.h" #include "structs.h" @@ -24,7 +24,7 @@ index 34527b22..4eaa3cc3 100644 enum { ANA_ERR_GETCTRL_FAILED = 1, -@@ -35,6 +36,7 @@ enum { +@@ -36,6 +37,7 @@ enum { ANA_ERR_GETNS_FAILED, ANA_ERR_NO_MEMORY, ANA_ERR_NO_INFORMATION, @@ -32,7 +32,7 @@ index 34527b22..4eaa3cc3 100644 }; static const char *ana_errmsg[] = { -@@ -48,6 +50,7 @@ static const char *ana_errmsg[] = { +@@ -49,6 +51,7 @@ static const char *ana_errmsg[] = { [ANA_ERR_GETNS_FAILED] = "couldn't get namespace info", [ANA_ERR_NO_MEMORY] = "out of memory", [ANA_ERR_NO_INFORMATION] = "invalid fd", @@ -40,7 +40,7 @@ index 34527b22..4eaa3cc3 100644 }; static const char *anas_string[] = { -@@ -106,6 +109,27 @@ static int get_ana_state(__u32 nsid, __u32 anagrpid, void *ana_log, +@@ -107,6 +110,27 @@ static int get_ana_state(__u32 nsid, __u32 anagrpid, void *ana_log, return -ANA_ERR_GETANAS_NOTFOUND; } @@ -68,7 +68,7 @@ index 34527b22..4eaa3cc3 100644 static int get_ana_info(struct path * pp) { int rc; -@@ -208,8 +232,11 @@ int getprio(struct path *pp, __attribute__((unused)) char *args) +@@ -210,8 +234,11 @@ int getprio(struct path *pp, __attribute__((unused)) char *args, if (pp->fd < 0) rc = -ANA_ERR_NO_INFORMATION; @@ -82,3 +82,6 @@ index 34527b22..4eaa3cc3 100644 switch (rc) { case NVME_ANA_OPTIMIZED: +-- +2.17.2 + diff --git a/device-mapper-multipath.spec b/device-mapper-multipath.spec index 5d80d4e..a304363 100644 --- a/device-mapper-multipath.spec +++ b/device-mapper-multipath.spec @@ -1,37 +1,153 @@ Name: device-mapper-multipath -Version: 0.13.0 -Release: 2%{?dist} +Version: 0.8.5 +Release: 4%{?dist} Summary: Tools to manage multipath devices using device-mapper -# readline uses GPL-3.0-only -License: GPL-2.0-only AND GPL-3.0-only +License: GPLv2 URL: http://christophe.varoqui.free.fr/ # The source for this package was pulled from upstream's git repo. Use the # following command to generate the tarball -# curl -L https://github.com/opensvc/multipath-tools/archive/0.13.0.tar.gz -o multipath-tools-0.13.0.tgz -Source0: multipath-tools-0.13.0.tgz +# curl -L https://github.com/opensvc/multipath-tools/archive/0.8.5.tar.gz -o multipath-tools-0.8.5.tgz +Source0: multipath-tools-0.8.5.tgz Source1: multipath.conf -Patch0001: 0001-RH-fixup-udev-rules-for-redhat.patch -Patch0002: 0002-RH-Remove-the-property-blacklist-exception-builtin.patch -Patch0003: 0003-RH-don-t-start-without-a-config-file.patch -Patch0004: 0004-RH-Fix-nvme-function-missing-argument.patch -Patch0005: 0005-RH-use-rpm-optflags-if-present.patch -Patch0006: 0006-RH-add-mpathconf.patch -Patch0007: 0007-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch -Patch0008: 0008-RH-reset-default-find_mutipaths-value-to-off.patch -Patch0009: 0009-RH-attempt-to-get-ANA-info-via-sysfs-first.patch -Patch0010: 0010-RH-make-parse_vpd_pg83-match-scsi_id-output.patch -Patch0011: 0011-RH-add-scsi-device-handlers-to-modules-load.d.patch -Patch0012: 0012-RH-compile-with-libreadline-support.patch -Patch0013: 0013-RH-Add-mpathcleanup.patch +Patch0001: 0001-Change-the-multipath.conf-manpage-uxsock_timeout-def.patch +Patch0002: 0002-libmultipath-find_mpe-don-t-match-with-empty-WWID.patch +Patch0003: 0003-libmultipath-copy-mpp-hwe-from-pp-hwe.patch +Patch0004: 0004-libmultipath-dm_map_present_by_uuid-fix-dm_task_crea.patch +Patch0005: 0005-libdmmp-tests-fix-compilation.patch +Patch0006: 0006-libmultipath-prio-constify-some-function-parameters.patch +Patch0007: 0007-libmultipath-checkers-prio-allow-non-lazy-.so-loadin.patch +Patch0008: 0008-multipath-tools-Makefiles-separate-rules-for-.so-and.patch +Patch0009: 0009-libmultipath-create-separate-.so-for-unit-tests.patch +Patch0010: 0010-libmultipath-add-linker-version-script.patch +Patch0011: 0011-libmpathpersist-add-linker-version-script.patch +Patch0012: 0012-libmpathcmd-add-linker-version-script.patch +Patch0013: 0013-libmpathpersist-initialize-mpp-hwe-in-get_mpvec.patch +Patch0014: 0014-multipathd-allow-shutdown-during-configure.patch +Patch0015: 0015-multipathd-avoid-sending-READY-1-to-systemd-on-early.patch +Patch0016: 0016-multipathd-send-STOPPING-1-to-systemd-on-shutdown.patch +Patch0017: 0017-multipathd-send-RELOADING-1-to-systemd-on-DAEMON_CON.patch +Patch0018: 0018-multipathd-use-volatile-qualifier-for-running_state.patch +Patch0019: 0019-multipathd-generalize-and-fix-wait_for_state_change_.patch +Patch0020: 0020-multipathd-set_config_state-avoid-code-duplication.patch +Patch0021: 0021-multipathd-cancel-threads-early-during-shutdown.patch +Patch0022: 0022-multipath-tools-don-t-call-dm_lib_release-any-more.patch +Patch0023: 0023-libmultipath-devmapper-refactor-libdm-version-determ.patch +Patch0024: 0024-libmultipath-protect-racy-libdevmapper-calls-with-a-.patch +Patch0025: 0025-libmultipath-constify-file-argument-in-config-parser.patch +Patch0026: 0026-libmultipath-provide-defaults-for-get-put-_multipath.patch +Patch0027: 0027-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch +Patch0028: 0028-multipath-use-get_put-_multipath_config-from-libmult.patch +Patch0029: 0029-mpathpersist-use-get-put-_multipath_config-from-libm.patch +Patch0030: 0030-libmultipath-add-udev-and-logsink-symbols.patch +Patch0031: 0031-multipath-remove-logsink-and-udev.patch +Patch0032: 0032-libmpathpersist-call-libmultipath_-init-exit.patch +Patch0033: 0033-mpathpersist-remove-logsink-and-udev.patch +Patch0034: 0034-multipathd-remove-logsink-and-udev.patch +Patch0035: 0035-multipath-tools-add-Vexata-by-StorCentric-VX-arrays.patch +Patch0036: 0036-multipath-tools-Violin-and-Nexsan-were-bought-by-Sto.patch +Patch0037: 0037-libmultipath-fix-memory-leaks-in-coalesce_paths.patch +Patch0038: 0038-multipath-tools-replace-hidden-tab-by-space-in-hwtab.patch +Patch0039: 0039-multipathd-uxlsnr-avoid-deadlock-on-exit.patch +Patch0040: 0040-multipathd-Fix-liburcu-memory-leak.patch +Patch0041: 0041-multipathd-move-handling-of-io_err_stat_attr-into-li.patch +Patch0042: 0042-multipathd-move-vecs-desctruction-into-cleanup-funct.patch +Patch0043: 0043-multipathd-make-some-globals-static.patch +Patch0044: 0044-multipathd-move-threads-destruction-into-separate-fu.patch +Patch0045: 0045-multipathd-move-conf-destruction-into-separate-funct.patch +Patch0046: 0046-multipathd-move-pid-destruction-into-separate-functi.patch +Patch0047: 0047-multipathd-close-pidfile-on-exit.patch +Patch0048: 0048-multipathd-add-helper-for-systemd-notification-at-ex.patch +Patch0049: 0049-multipathd-child-call-cleanups-in-failure-case-too.patch +Patch0050: 0050-multipathd-unwatch_all_dmevents-check-if-waiter-is-i.patch +Patch0051: 0051-multipathd-print-error-message-if-config-can-t-be-lo.patch +Patch0052: 0052-libmultipath-add-libmp_dm_exit.patch +Patch0053: 0053-multipathd-fixup-libdm-deinitialization.patch +Patch0054: 0054-libmultipath-log_thread_stop-check-if-logarea-is-ini.patch +Patch0055: 0055-multipathd-add-cleanup_child-exit-handler.patch +Patch0056: 0056-libmultipath-fix-log_thread-startup-and-teardown.patch +Patch0057: 0057-multipathd-move-cleanup_-prio-checkers-foreign-to-li.patch +Patch0058: 0058-multipath-use-atexit-for-cleanup-handlers.patch +Patch0059: 0059-mpathpersist-use-atexit-for-cleanup-handlers.patch +Patch0060: 0060-multipath-fix-leak-in-check_path_valid.patch +Patch0061: 0061-multipath-tools-mpath-tools.supp-file-with-valgrind-.patch +Patch0062: 0062-libmultipath-use-libmp_verbosity-to-track-verbosity.patch +Patch0063: 0063-libmultipath-introduce-symbolic-values-for-logsink.patch +Patch0064: 0064-libmultipath-simplify-dlog.patch +Patch0065: 0065-multipathd-common-code-for-k-and-command-args.patch +Patch0066: 0066-multipathd-sanitize-uxsock_listen.patch +Patch0067: 0067-libmultipath-fix-race-between-log_safe-and-log_threa.patch +Patch0068: 0068-multipath-add-libmpathvalid-library.patch +Patch0069: 0069-multipath-tools-tests-and-unit-tests-for-libmpathval.patch +Patch0070: 0070-libmultipath-add-uid-failback-for-dasd-devices.patch +Patch0071: 0071-libmultipath-change-log-level-for-null-uid_attribute.patch +Patch0072: 0072-libmultipath-move-fast_io_fail-defines-to-structs.h.patch +Patch0073: 0073-libmultipath-add-eh_deadline-multipath.conf-paramete.patch +Patch0074: 0074-multipathd-remove-redundant-vector_free-int-configur.patch +Patch0075: 0075-libmultipath-factor-out-code-to-get-vpd-page-data.patch +Patch0076: 0076-libmultipath-limit-reading-0xc9-vpd-page.patch +Patch0077: 0077-libmultipath-move-logq_lock-handling-to-log.c.patch +Patch0078: 0078-libmultipath-protect-logarea-with-logq_lock.patch +Patch0079: 0079-libmultipath-prevent-DSO-unloading-with-astray-check.patch +Patch0080: 0080-libmultipath-force-map-reload-if-udev-incomplete.patch +Patch0081: 0081-multipath-tools-avoid-access-to-etc-localtime.patch +Patch0082: 0082-multipath-tools-make-sure-plugin-DSOs-use-symbol-ver.patch +Patch0083: 0083-libmultipath.version-add-missing-symbol.patch +Patch0084: 0084-multipath-tools-tests-unversioned-.so-for-valgrind-t.patch +Patch0085: 0085-multipath-tools-unit-tests-fix-memory-leaks-in-mpath.patch +Patch0086: 0086-mpathpersist-Fix-Register-and-Ignore-with-0x00-SARK.patch +Patch0087: 0087-mpathpersist-update-prkeys-file-on-changing-registra.patch +Patch0088: 0088-libmultipath-warn-about-missing-braces-at-end-of-mul.patch +Patch0089: 0089-libmultipath-ignore-multipaths-sections-without-wwid.patch +Patch0090: 0090-libmultipath-fix-format-warning-with-clang.patch +Patch0091: 0091-libmultipath-check-for-null-wwid-before-strcmp.patch +Patch0092: 0092-multipath.conf.5-Improve-checker_timeout-description.patch +Patch0093: 0093-multipathd-fix-path-checkint-not-changed-when-path-s.patch +Patch0094: 0094-libmultipath-select_action-skip-is_mpp_known_to_udev.patch +Patch0095: 0095-libmultipath-coalesce_paths-stop-triggering-spurious.patch +Patch0096: 0096-Revert-multipathd-uev_trigger-handle-incomplete-ADD-.patch +Patch0097: 0097-libmultipath-make-find_err_path_by_dev-static.patch +Patch0098: 0098-multipathd-avoid-io_err_stat-crash-during-shutdown.patch +Patch0099: 0099-multipathd-avoid-io_err_stat-ABBA-deadlock.patch +Patch0100: 0100-multipathd-use-get_monotonic_time-in-io_err_stat-cod.patch +Patch0101: 0101-multipathd-combine-free_io_err_stat_path-and-destroy.patch +Patch0102: 0102-multipathd-cleanup-logging-for-marginal-paths.patch +Patch0103: 0103-libmultipath-fix-NULL-dereference-in-find_path_by_de.patch +Patch0104: 0104-libmultipath-snprint_devices-avoid-NULL-dereference.patch +Patch0105: 0105-libmpathpersist-fix-thread-safety-of-default-functio.patch +Patch0106: 0106-Added-github-action-for-building.patch +Patch0107: 0107-github-workflow-use-zram-device-as-test-block-device.patch +Patch0108: 0108-github-workflow-use-explicit-Ubuntu-version.patch +Patch0109: 0109-github-workflow-add-valgrind-tests.patch +Patch0110: 0110-github-workflow-run-apt-get-update.patch +Patch0111: 0111-github-workflow-add-tests-with-gcc-10-and-clang.patch +Patch0112: 0112-multipathd-Fix-multipathd-stopping-on-shutdown.patch +Patch0113: 0113-libmultipath-use-3rd-digit-as-transport_id-for-expan.patch +Patch0114: 0114-libmultipath-sysfs_set_nexus_loss_tmo-support-SAS-ex.patch +Patch0115: 0115-multipathd-add-code-to-initalize-unwinder.patch +Patch0116: 0116-libmultipath-check-if-adopt_path-really-added-curren.patch +Patch0117: 0117-multipathd-ev_add_path-fail-if-add_map_with_path-fai.patch +Patch0118: 0118-libmultipath-check-return-value-of-udev_device_get_d.patch +Patch0119: 0119-pathinfo-call-filter_property-after-sysfs_pathinfo.patch +Patch0120: 0120-libmultipath-pathinfo-call-filter_property-only-with.patch +Patch0121: 0121-multipath-w-allow-removing-blacklisted-paths.patch +Patch0122: 0122-libmultipath-fix-use-after-free-in-uev_add_path.patch +Patch0123: 0123-kpartx-free-loop-device-after-listing-partitions.patch +Patch0124: 0124-RH-fixup-udev-rules-for-redhat.patch +Patch0125: 0125-RH-Remove-the-property-blacklist-exception-builtin.patch +Patch0126: 0126-RH-don-t-start-without-a-config-file.patch +Patch0127: 0127-RH-Fix-nvme-function-missing-argument.patch +Patch0128: 0128-RH-use-rpm-optflags-if-present.patch +Patch0129: 0129-RH-add-mpathconf.patch +Patch0130: 0130-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch +Patch0131: 0131-RH-reset-default-find_mutipaths-value-to-off.patch +Patch0132: 0132-RH-attempt-to-get-ANA-info-via-sysfs-first.patch # runtime Requires: %{name}-libs = %{version}-%{release} Requires: kpartx = %{version}-%{release} Requires: device-mapper >= 1.02.96 Requires: userspace-rcu -Requires: readline -Requires: libmount Requires(post): systemd-units Requires(preun): systemd-units Requires(postun): systemd-units @@ -53,7 +169,6 @@ BuildRequires: readline-devel, ncurses-devel BuildRequires: systemd-units, systemd-devel BuildRequires: json-c-devel, perl-interpreter, pkgconfig, gcc BuildRequires: userspace-rcu-devel -BuildRequires: libmount-devel BuildRequires: make %description @@ -65,8 +180,8 @@ The tools are : %package libs Summary: The %{name} modules and shared library -# only libmpathcmd is LGPL-2.1-or-later AND LGPL-2.0-or-later -License: GPL-2.0-or-later AND LGPL-2.1-or-later AND LGPL-2.0-or-later +# only libmpathcmd is LGPLv2+ +License: GPLv2 and LGPLv2+ %description libs The %{name}-libs provides the path checker @@ -91,8 +206,7 @@ kpartx manages partition creation and removal for device-mapper devices. %package -n libdmmp Summary: device-mapper-multipath C API library -# Automatically converted from old format: GPLv3+ - review is highly recommended. -License: GPL-3.0-or-later +License: GPLv3+ Requires: json-c Requires: %{name} = %{version}-%{release} Requires: %{name}-libs = %{version}-%{release} @@ -111,10 +225,11 @@ This package contains the files needed to develop applications that use device-mapper-multipath's libdmmp C API library %prep -%autosetup -n multipath-tools-0.13.0 -p1 +%autosetup -n multipath-tools-0.8.5 -p1 cp %{SOURCE1} . %build +%define _sbindir /usr/sbin %define _libdir /usr/%{_lib} %define _libmpathdir %{_libdir}/multipath %define _pkgconfdir %{_libdir}/pkgconfig @@ -125,12 +240,11 @@ cp %{SOURCE1} . bindir=%{_sbindir} \ syslibdir=%{_libdir} \ usrlibdir=%{_libdir} \ - plugindir=%{_libmpathdir} \ - mandir=%{_mandir} \ + libdir=%{_libmpathdir} \ + rcdir=%{_initrddir} \ unitdir=%{_unitdir} \ includedir=%{_includedir} \ - pkgconfdir=%{_pkgconfdir} \ - tmpfilesdir=%{_tmpfilesdir} + pkgconfdir=%{_pkgconfdir} # tree fix up install -d %{buildroot}/etc/multipath @@ -145,7 +259,7 @@ rm -rf %{buildroot}/%{_initrddir} %postun if [ $1 -ge 1 ] ; then - multipathd forcequeueing daemon > /dev/null 2>&1 || : + /sbin/multipathd forcequeueing daemon > /dev/null 2>&1 || : fi %systemd_postun_with_restart multipathd.service @@ -155,39 +269,30 @@ fi /bin/systemctl --quiet is-enabled multipathd.service >/dev/null 2>&1 && /bin/systemctl reenable multipathd.service ||: %files -%license LICENSES/GPL-2.0 LICENSES/LGPL-2.0 LICENSES/GPL-3.0 +%license LICENSES/GPL-2.0 LICENSES/LGPL-2.0 %{_sbindir}/multipath %{_sbindir}/multipathd -%{_sbindir}/multipathc %{_sbindir}/mpathconf -%{_sbindir}/mpathcleanup %{_sbindir}/mpathpersist %{_unitdir}/multipathd.service -%{_unitdir}/multipathd-queueing.service %{_unitdir}/multipathd.socket -%{_mandir}/man5/multipath.conf.5* -%{_mandir}/man8/multipath.8* -%{_mandir}/man8/multipathd.8* -%{_mandir}/man8/multipathc.8* -%{_mandir}/man8/mpathconf.8* -%{_mandir}/man8/mpathpersist.8* +%{_mandir}/man5/multipath.conf.5.gz +%{_mandir}/man8/multipath.8.gz +%{_mandir}/man8/multipathd.8.gz +%{_mandir}/man8/mpathconf.8.gz +%{_mandir}/man8/mpathpersist.8.gz %config /usr/lib/udev/rules.d/62-multipath.rules %config /usr/lib/udev/rules.d/11-dm-mpath.rules -%config /usr/lib/udev/rules.d/99-z-dm-mpath-late.rules -%dir %{_modulesloaddir} -%{_modulesloaddir}/scsi_dh.conf -%{_tmpfilesdir}/multipath.conf %doc README.md +%doc README.alua %doc multipath.conf %dir /etc/multipath %files libs -%license LICENSES/GPL-2.0 LICENSES/LGPL-2.0 LICENSES/LGPL-2.1 +%license LICENSES/GPL-2.0 LICENSES/LGPL-2.0 %doc README.md %{_libdir}/libmultipath.so %{_libdir}/libmultipath.so.* -%{_libdir}/libmpathutil.so -%{_libdir}/libmpathutil.so.* %{_libdir}/libmpathpersist.so.* %{_libdir}/libmpathcmd.so.* %{_libdir}/libmpathvalid.so.* @@ -204,15 +309,15 @@ fi %{_includedir}/mpath_cmd.h %{_includedir}/mpath_persist.h %{_includedir}/mpath_valid.h -%{_mandir}/man3/mpath_persistent_reserve_in.3* -%{_mandir}/man3/mpath_persistent_reserve_out.3* +%{_mandir}/man3/mpath_persistent_reserve_in.3.gz +%{_mandir}/man3/mpath_persistent_reserve_out.3.gz %files -n kpartx %license LICENSES/GPL-2.0 %doc README.md %{_sbindir}/kpartx /usr/lib/udev/kpartx_id -%{_mandir}/man8/kpartx.8* +%{_mandir}/man8/kpartx.8.gz %config /usr/lib/udev/rules.d/11-dm-parts.rules %config /usr/lib/udev/rules.d/66-kpartx.rules %config /usr/lib/udev/rules.d/68-del-part-nodes.rules @@ -230,287 +335,10 @@ fi %dir %{_includedir}/libdmmp %{_includedir}/libdmmp/* %{_mandir}/man3/dmmp_* -%{_mandir}/man3/libdmmp.h.3* +%{_mandir}/man3/libdmmp.h.3.gz %{_pkgconfdir}/libdmmp.pc %changelog -* Thu Nov 13 2025 Benjamin Marzinski - 0.13.0-2 -- Move STI tests to TMT - -* Tue Nov 4 2025 Benjamin Marzinski - 0.13.0-1 -- Update source to upstream release 0.13.0 - * Previous patches 0001-0004 are included in the tarball -- Install /lib/systemd/system/multipathd-queueing.service -- Rename redhat patches - * Previous patches 0005-0017 are now patches 0001-0013 - -* Wed Jul 23 2025 Fedora Release Engineering - 0.11.1-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild - -* Thu Feb 27 2025 Benjamin Marzinski - 0.11.1-1 -- Update source to upstream staging branch for 0.11.1 plus additional - stable branch patches. - * Previous patches 0001-0032 are included in the tarball -- Rename redhat patches - * Previous patches 0033-0045 are now patches 0005-0017 - -* Sat Feb 1 2025 Benjamin Marzinski - 0.10.0-5 -- Update source to upstream staging branch for 0.10.y (will be 0.10.2 when - merged). -- Rebase redhat patches - -* Thu Jan 16 2025 Fedora Release Engineering - 0.10.0-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild - -* Sun Jan 12 2025 Zbigniew Jędrzejewski-Szmek - 0.10.0-3 -- Rebuilt for the bin-sbin merge (2nd attempt) - -* Thu Aug 29 2024 Benjamin Marzinski - 0.10.0-2 -- update CI tests. - -* Thu Aug 29 2024 Benjamin Marzinski - 0.10.0-1 -- Update source to upstream version 0.9.9 - * Previous patch 0014-multipathd-fix-flush-check-in-flush_map.patch is - included in the source tarball -- Rebase redhat patches - -* Fri Aug 9 2024 Benjamin Marzinski - 0.9.9-6 -- Add 0014-multipathd-fix-null-pointer-dereference-in-uev_updat.patch - * multipath features tracking on failed removes - -* Mon Jul 29 2024 Miroslav Suchý - 0.9.9-5 -- convert license to SPDX - -* Thu Jul 25 2024 Miroslav Suchý - 0.9.9-4 -- convert license to SPDX - -* Wed Jul 17 2024 Fedora Release Engineering - 0.9.9-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild - -* Tue Jul 09 2024 Zbigniew Jędrzejewski-Szmek - 0.9.9-2 -- Rebuilt for the bin-sbin merge - -* Thu Jun 13 2024 Benjamin Marzinski - 0.9.9-1 -- Update source to upstream version 0.9.9 - * Previous patches 0001-0044 are included in the source tarball -- Rename redhat patches - * Previous patches 0045-0057 are now patches 0001-0013 - -* Mon May 20 2024 Benjamin Marzinski - 0.9.8-1 -- Update source to upstream version 0.9.8 plus latest staging branch - * Previous patches 0014 & 0015 are included in the source tarball - * patches 0001-0044 are from the upstream staging branch -- Rename redhat patches - * Previous patches 0001-0013 are now patches 0045-0057 -- Install /lib/udev/rules.d/99-z-dm-mpath-late.rules - -* Wed Jan 24 2024 Fedora Release Engineering - 0.9.7-7 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Fri Jan 19 2024 Fedora Release Engineering - 0.9.7-6 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Tue Jan 16 2024 Benjamin Marzinski - 0.9.7-5 -- Add 0014-multipathd-fix-null-pointer-dereference-in-uev_updat.patch - * Fix auto_resize code to avoid a segfault -- Add 0015-multipathd-fix-auto-resize-configuration.patch - * Fix auto_resize default value - -* Thu Nov 30 2023 Benjamin Marzinski - 0.9.7-4 -- Use modulesloaddir macro for installing scsi_dh.conf - -* Wed Nov 29 2023 Benjamin Marzinski - 0.9.7-3 -- Fix multipath_conf_syntax test -- Fix restate_module test - -* Tue Nov 28 2023 Paul Donohue - 0.9.7-2 -- Modify 0006-RH-add-mpathconf.patch -- Modify 0008-RH-reset-default-find_mutipaths-value-to-off.patch - * Fix find_multipaths values in docs and mpathconf - -* Tue Nov 21 2023 Benjamin Marzinski - 0.9.7-1 -- Update source to upstream version 0.9.7 - * Previous patches 0001-0040 are included in the source tarball -- Rename redhat patches - * Previous patches 0041-0053 are now patches 0001-0013 -- Remove /usr/lib/modules-load.d/multipath.conf - * has been replaced with modprobe@dm_multipath.service unit Wants. - -* Fri Sep 22 2023 Benjamin Marzinski - 0.9.6-1 -- Update to the head of the upstream staging branch -- Rename redhat patches - * Previous patches 0001-0012 are now patches 0041-0052 -- Add 0053-RH-Add-mpathcleanup.patch - * add mpathcleanup program - -* Wed Jul 19 2023 Fedora Release Engineering - 0.9.5-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild - -* Tue May 16 2023 Benjamin Marzinski - 0.9.5-1 -- Update to the latest upstream release - * Previous patches 0001-0015 are included in the source tarball -- Rename redhat patches - * Previous patches 0016-0027 are now patches 0001-0012 - -* Thu Feb 2 2023 Benjamin Marzinski - 0.9.4-2 -- Update to the head of the upstream staging branch - * Patches 0011-0015 are from the upstream staging branch -- Rename redhat patches - * Previous patches 0011-0022 are now patches 0016-0027 - -* Thu Jan 26 2023 Benjamin Marzinski - 0.9.4-1 -- Update to the head of the upstream staging branch - * Previous patches 0001-0032 are included in the source tarball - * Patches 0001-0010 are from the upstream staging branch -- Rename redhat patches - * Previous patches 0033-0044 are now patches 0011-0022 -- Add dependency on libmount - -* Thu Jan 19 2023 Fedora Release Engineering - 0.9.3-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild - -* Tue Nov 15 2022 Benjamin Marzinski - 0.9.3-1 -- Update to the head of the upstream staging branch - * Previous patches 0001-0042 are included in the source tarball - * Patches 0001-0032 are from the upstream staging branch -- Rename redhat patches - * Previous patches 0043-0053 are now patches 0033-0043 -- Change back to using readline instead of libedit - * The code the uses readline has been isolated from the code that - is licensed gpl v2 only. -- Add libmpathutil libraries to spec file -- Add multipathc program to spec file -- Add multipath.conf systemd tempfile configuration to spec file -- Misc spec file cleanups - -* Fri Aug 19 2022 Benjamin Marzinski - 0.9.0-3 -- Update to the head of the upstream staging branch - * Patches 0005-0042 are from the upstream staging branch - * Previous patches 0005 & 0006 are now patches 0023 & 0005 -- Rename redhat patches - * Previous patches 0007-0017 are now patches 0043-0053 -- Change from using readline to libedit - * readline is licensed GPL v3, and multipathd includes code - licensed gpl v2. -- Remove README.alua - * information moved to README.md - -* Thu Jul 21 2022 Fedora Release Engineering - 0.9.0-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild - -* Wed Jul 13 2022 Benjamin Marzinski - 0.9.0-1 -- Update source to upstream version 0.9.0 - * Previous patches 0001-0005 are included in the commit. - * This version deprecates multiple options: mutlipath_dir, config_dir, and - getuid_callout, along with the "default_" prefixed alternate names for the - default section parameters. -- Add patches from upstream staging branch - * Patches 0001-0006 are from the upstream staging branch -- Rename redhat patches - * Previous patches 0006-0016 are now patches 0007-0017 - -* Mon Mar 28 2022 Benjamin Marzinski - 0.8.9-1 -- Update source to upstream version 0.8.9 - * Previous patches 0001-0024 & 0035 are included in the commit. -- Add patches from upstream staging branch - * Patches 0001-0005 are from the upstream staging branch -- Rename redhat patches - * Previous patches 0025-0034 are now patches 0006-0015 -- Combine redhat patches - * Previous patches 0036 & 0037 are now part of patch 0011 -- Add 0016-RH-add-scsi-device-handlers-to-modules-load.d.patch -- Spec file changes - * Install multipath.conf and scsi_dh.conf to /usr/lib/modules-load.d - -* Mon Feb 7 2022 Benjamin Marzinski - 0.8.7-8 -- Add 0036-RH-add-support-to-mpathconf-for-setting-arbitrary-de.patch - * add the ability for mpathconf to set arbitray options with --option -- Add 0037-RH-add-support-to-mpathconf-for-setting-recheck_wwid.patch - * add --recheck_wwid option to mpathconf - -* Wed Jan 26 2022 Benjamin Marzinski - 0.8.7-7 -- Add 0035-libmultipath-use-asprintf-to-allocate-prefixed_uuid.patch -- Resolves: bz #2045309 - -* Thu Jan 20 2022 Fedora Release Engineering - 0.8.7-6 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild - -* Thu Jan 6 2022 Benjamin Marzinski - 0.8.7-5 -- Modify 0030-RH-add-mpathconf.patch - * fix setting property_blacklist with no blacklist_exceptions section - -* Mon Dec 13 2021 Benjamin Marzinski - 0.8.7-4 -- Update to the head of the upstream staging branch - * Patches 0013 - 0024 are from the upstream staging branch -- Rename redhat patches - * Previous patches 0013-0022 are now patches 0025-0034 - -* Thu Oct 28 2021 Benjamin Marzinski - 0.8.7-3 -- Update to the head of the upstream staging branch - * Patches 0011 & 0012 are from the upstream staging branch -- Rename redhat patches - * Previous patches 0011-0020 are now patches 0013-0022 - -* Wed Oct 6 2021 Benjamin Marzinski - 0.8.7-2 -- Modify 0013-RH-don-t-start-without-a-config-file.patch - * add condtion to multipathd.socket as well - -* Wed Oct 6 2021 Benjamin Marzinski - 0.8.7-1 -- Update source to upstream version 0.8.7 - * Previous patches 0001-0023 are included in the commit. -- Add patches from upstream staging branch - * Patches 0001-0010 are from the upstream staging branch -- Rename redhat patches - * Previous patches 0024-0033 are now patches 0011-0020 - -* Fri Jul 30 2021 Benjamin Marzinski - 0.8.6-5 -- Update to the head of the upstream staging branch plus redhat patches - * Patches 0016-0018 are from the upstream staging branch - * Patches 0019-0024 have been submitted upstream -- Rename files - * Previous patches 0016-0025 are now patches 0024-0033 - -* Wed Jul 21 2021 Fedora Release Engineering - 0.8.6-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild - -* Sat Jul 10 2021 Björn Esser - 0.8.6-3 -- Rebuild for versioned symbols in json-c - -* Thu Jul 1 2021 Benjamin Marzinski - 0.8.6-2 -- Pull in latest upstream post-tag commits - * Patches 0001-0015 are from - https://github.com/openSUSE/multipath-tools/tree/queue and are - already queued for upstream -- Rename files - * Previous patches 0001-0010 and now patches 0016-0025 - -* Wed Jun 23 2021 Cole Robinson - 0.8.6-1.fc35.1 -- Rebuild for userspace-rcu soname bump - -* Mon Apr 5 2021 Benjamin Marzinski - 0.8.6-1 -- Update Source to upstream version 0.8.6 - * Previous patches 0001-0146 are included in the commit -- Rename files - * Previous patches 0147-0156 are now patches 0001-0010 -- sync tests with RHEL repository - -* Fri Mar 26 2021 Benjamin Marzinski - 0.8.5-6 -- Change patch format to remove Git version - * Patches 0001-0122 only have the patch format modified -- Update to the head of the upstream staging branch plus redhat patches - * Patches 0123-0134 & 1036-0142 are from the upstream staging branch - * Patches 0143-1046 have been submitted upstream - * Patch 0156 is a Red Hat only patch. Red Hat udev rules set ID_SERIAL - from 60-persistent-storage.rules instead of 55-scsi-sg3_id.rules. - Multipath's parse_vpd_pg83() function needs to match the ID_SERIAL - value from udev. -- Rename files - * Previous patches 0123-0132 are now patches 1035 & 0147-0155 - -* Tue Mar 02 2021 Zbigniew Jędrzejewski-Szmek - 0.8.5-5 -- Rebuilt for updated systemd-rpm-macros - See https://pagure.io/fesco/issue/2583. - * Thu Feb 11 2021 Benjamin Marzinski - 0.8.5-4 - Update Source to upstream version 0.8.5 plus post tag commits * Patches 0001-0121 are from diff --git a/plans/multipath.fmf b/plans/multipath.fmf deleted file mode 100644 index 876c77a..0000000 --- a/plans/multipath.fmf +++ /dev/null @@ -1,58 +0,0 @@ -summary: basic functionality tests - -provision: - hardware: - memory: ">= 2 GB" - -prepare: - how: install - package: - - device-mapper-multipath - - perl - -discover: - how: shell - tests: - - name: medium_error_scsi_debug - path: /tests/medium_error_scsi_debug - test: ./main.sh - duration: 15m - - name: squelch_scsi_id - path: /tests/squelch_scsi_id - test: ./main.sh - duration: 15m - - name: multipathd_oom - path: /tests/multipathd_oom - test: ./main.sh - duration: 15m - - name: user_friendly_names - path: /tests/user_friendly_names - test: ./main.sh - duration: 15m - - name: kpartx_4k_aligned - path: /tests/kpartx_4k_aligned - test: ./main.sh - duration: 15m - - name: bindings - path: /tests/bindings - test: ./main.sh - duration: 15m - - name: restate_module - path: /tests/restate_module - test: ./main.sh - duration: 15m - - name: find_multipaths - path: /tests/find_multipaths - test: ./main.sh - duration: 15m - - name: multipath_conf_syntax - path: /tests/multipath_conf_syntax - test: ./main.sh - duration: 15m - - name: alias_clash - path: /tests/alias_clash - test: ./main.sh - duration: 15m - -execute: - how: tmt diff --git a/sources b/sources index 233c4ea..cf508e4 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (multipath-tools-0.13.0.tgz) = 75c84524ee27590b8b751ea500898a44e5ac3d58d55be6bcab919d0d423049db3a4466fcb9135705cf63ba074416973bb651255063269e9f682f11d21ba57e59 +SHA512 (multipath-tools-0.8.5.tgz) = 3b65f89621203304cdc0d074124627132f0a600c347f2eec03372463737493e3a7da38813d375c1f7d6fe2e55a7d4f7494574f74412534832f217954ba34c293 SHA512 (multipath.conf) = 71953dce5a68adcf60a942305f5a66023e6f4c4baf53b1bfdb4edf65ed5b8e03db804363c36d1dcfd85591f4766f52b515269904c53b84d7b076da0b80b09942 diff --git a/.fmf/version b/tests/.fmf/version similarity index 100% rename from .fmf/version rename to tests/.fmf/version diff --git a/tests/alias_clash/LICENSE b/tests/alias_clash/LICENSE deleted file mode 100644 index 10926e8..0000000 --- a/tests/alias_clash/LICENSE +++ /dev/null @@ -1,675 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. - diff --git a/tests/alias_clash/PURPOSE b/tests/alias_clash/PURPOSE deleted file mode 100644 index ba496c4..0000000 --- a/tests/alias_clash/PURPOSE +++ /dev/null @@ -1,20 +0,0 @@ -verify that multipath doesn't try to assign new devices in-use user_friendly -aliases. - -steps: -1. setup config file and remove existing bindings file -2. create scsi_debug devices -3. start multipathd to create devices and bindings file -4. look at path device ordering in multipathd output -5. stop multipathd and remove devices -6. blacklist the devices which were multipathed early in the config file -7. remove the bindings file -8. restart multipathd to create devices, where the later devices grab the - earlier user_friendly_names -9. stop multipathd -10. remove blacklists from the config file and remove bindings file -11. restart multipathd -12. Verify that all devices are there, the previously existing devices - still have the same alias, and all the devices match the bindings file -13. reconfigure multipathd -14. Verify that all devices are still there and still match. diff --git a/tests/alias_clash/main.sh b/tests/alias_clash/main.sh deleted file mode 100755 index 6e3b23c..0000000 --- a/tests/alias_clash/main.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2021 Red Hat, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# Author: Benjamin Marzinski - -source ../include/ec.sh || exit 200 -tlog "running $0" - -cleanup () -{ - trun "multipathd disablequeueing maps" - sleep 5 - trun "multipath -DF" - trun "service multipathd stop" - sleep 5 - trun "udevadm settle" - trun "modprobe -r scsi_debug" -} - -assert () -{ - local cmd="$*" - _trun_ "$cmd" 0 - if test $? -eq 0; then - tpass_ "$cmd" ; - else - tfail_ "$cmd" ; - cleanup ; - tend ; - fi -} - -tlog "running $0" - -rpm -q device-mapper-multipath || dnf install -y device-mapper-multipath - -# cleanup existing devices and restart -cleanup -trun "rm -f /etc/multipath.conf" -trun "rm -f /etc/multipath.conf.bak" -trun "rm -r /etc/multipath/bindings" -trun "mpathconf --enable --with_module y --with_multipathd n --find_multipaths n" -sed -i '/^blacklist[[:space:]]*{/ a\ - device {\n vendor ".*"\n product ".*"\n } -' /etc/multipath.conf -if grep -qw blacklist_exceptions /etc/multipath.conf ; then - sed -i '/^blacklist_exceptions[[:space:]]*{/ a\ - device {\n vendor Linux\n product scsi_debug\n } -' /etc/multipath.conf -else - cat << _EOF_ >> /etc/multipath.conf -blacklist_exceptions { - device { - vendor Linux - product scsi_debug - } -} -_EOF_ -fi -trun "modprobe scsi_debug num_tgts=20 vpd_use_hostno=0" -sleep 5 -trun "service multipathd start" -sleep 5 -pathcount=`multipathd show paths raw format %w | wc -l` -assert "[[ $pathcount -eq 20 ]]" -wwids=`multipathd show paths raw format " wwid %w" | sed '11,$d'` -wwids="${wwids//$'\n'/\\n}" -trun "multipath -DF" -trun "service multipathd stop" -sleep 5 -tnot "pidof multipathd" -tok "cp /etc/multipath.conf /etc/mulitpath.conf.bak" -sed -i '/^blacklist[[:space:]]*{/ a\ -'"$wwids"' -' /etc/multipath.conf -tok "rm -f /etc/multipath/bindings" -trun "service multipathd start" -sleep 5 -mapcount=`multipathd show maps raw format %w | wc -l` -assert "[[ $mapcount -eq 10 ]]" -orig_maps=`multipathd show maps raw format "%n %w"` -trun "service multipathd stop" -sleep 5 -tnot "pidof multipathd" -tok "mv -f /etc/mulitpath.conf.bak /etc/multipath.conf" -tok "rm -f /etc/multipath/bindings" -trun "service multipathd start" -sleep 5 -mapcount=`multipathd show maps raw format %w | wc -l` -assert "[[ $mapcount -eq 20 ]]" -new_maps=`multipathd show maps raw format "%n %w" | sort` -tlog "Checking if devices have been renamed" -while IFS= read -r line; do - echo "$new_maps" | grep "$line" - assert "[[ $? -eq 0 ]]" -done <<< "$orig_maps" -bindings=`cat /etc/multipath/bindings | sed '/^#.*$/d' | sort` -tlog "Checking if devices match bindings" -assert "[[ \"$new_maps\" = \"$bindings\" ]]" -trun "service multipathd reload" -sleep 5 -mapcount=`multipathd show maps raw format %w | wc -l` -assert "[[ $mapcount -eq 20 ]]" -reload_maps=`multipathd show maps raw format "%n %w" | sort` -tlog "Checking if devices change on reconfigure" -assert "[[ \"$new_maps\" = \"$reload_maps\" ]]" -cleanup -tend diff --git a/tests/bindings/main.sh b/tests/bindings/main.sh index 76292e4..2d6f284 100755 --- a/tests/bindings/main.sh +++ b/tests/bindings/main.sh @@ -18,110 +18,40 @@ # Author: Lin Li #set -x -source ../include/tc.sh || exit 200 +source ../include/ec.sh || exit 200 + tlog "running $0" -cleanup () -{ - local retries - if pidof multipathd; then - tlog "stopping multipathd" - trun "systemctl stop multipathd.service || pkill multipathd" - sleep 1 - fi - retries=10 - while pidof multipathd; do - ((retries--)) - if [[ $retries -le 0 ]]; then - tfail_ "failed to stop multipath" - tend - fi - tlog "waiting for multipathd to stop" - sleep 2 - pidof multipathd && pkill multipathd - done - trun "multipath -l -v1" - retries=10 - while [[ -n `multipath -l -v1` ]]; do - ((retries--)) - if [[ $retries -le 0 ]]; then - tfail_ "failed to remove deviece" - tend - fi - tlog "removing multipath device" - trun "udevadm settle" - trun "multipath -DF" - sleep 2 - done - if lsmod | grep -q "^scsi_debug"; then - tlog "removing scsi_debug module" - tok "rmmod scsi_debug" - fi - trun "rm -f /etc/multipath.conf" -} - -assert () -{ - local cmd="$*" - _trun_ "$cmd" 0 - if test $? -eq 0; then - tpass_ "$cmd" ; - else - tfail_ "$cmd" ; - cleanup ; - tend ; - fi -} - -setup_config () -{ - trun "mpathconf --enable --user_friendly_names y" - sed -i '/^blacklist[[:space:]]*{/ a\ - device {\ - vendor ".*"\ - product ".*"\ - } -' /etc/multipath.conf - cat << _EOF_ >> /etc/multipath.conf - -blacklist_exceptions { - device { - vendor Linux - product scsi_debug - } -} -_EOF_ - trun "cat /etc/multipath.conf" -} - -do_reconfigure () -{ - tok "multipathd reconfigure" - sleep 5 -} - -rpm -q device-mapper-multipath || dnf install -y device-mapper-multipath -cleanup -setup_config -trun "rm -r /etc/multipath/bindings" -trun "modprobe scsi_debug vpd_use_hostno=0 add_host=2" +trun "service multipathd stop" +rpm -q device-mapper-multipath || yum install -y device-mapper-multipath +trun "mpathconf --enable --with_multipathd y --user_friendly_names y" +trun "service multipathd status" sleep 5 -trun "systemctl start multipathd.service" -while multipathd show daemon | grep -qv idle; do - tlog "waiting for multipathd to start" - sleep 1 -done -trun 'multipathd show maps raw format "%n"' -mpath_name=`multipathd show maps raw format "%n" | head -1` -assert "[[ -n $mpath_name ]] && [[ $mpath_name != ok ]]" +trun "multipath -F" +sleep 5 +terr "modprobe -r scsi_debug" +terr "modprobe scsi_debug num_tgts=1 vpd_use_hostno=0 add_host=2 delay=20 \ +max_luns=2 no_lun_0=1" +sleep 60 + +disk_path=$(get_scsi_debug_devices) +disk=$(basename $disk_path) +mpath_name=$(get_mpath_disk_by_scsi_device $disk) new_alias="mpath_test_$$" trun "sed -i 's/$mpath_name/$new_alias/' /etc/multipath/bindings" -do_reconfigure -trun 'multipathd show maps raw format "%n"' -mpath_name=`multipathd show maps raw format "%n" | head -1` -assert "[[ $mpath_name = $new_alias ]]" +trun "multipath -r" +sleep 5 +tok "[[ -b /dev/mapper/$new_alias ]]" +tok is_mpath $new_alias +sleep 5 -cleanup +trun "multipath -F" +sleep 5 +trun "modprobe -r scsi_debug" +trun "service multipathd stop" +sleep 3 +trun "multipath -W" +trun "rm /etc/multipath/bindings" tend diff --git a/tests/find_multipaths/Makefile b/tests/find_multipaths/Makefile new file mode 100644 index 0000000..b78dc57 --- /dev/null +++ b/tests/find_multipaths/Makefile @@ -0,0 +1,49 @@ +#!/bin/bash + +# Copyright (c) 2016 Red Hat, Inc. +# # +# # This program is free software: you can redistribute it and/or modify +# # it under the terms of the GNU General Public License as published by +# # the Free Software Foundation, either version 3 of the License, or +# # (at your option) any later version. +# # +# # This program is distributed in the hope that it will be useful, +# # but WITHOUT ANY WARRANTY; without even the implied warranty of +# # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# # GNU General Public License for more details. +# # +# # You should have received a copy of the GNU General Public License +# # along with this program. If not, see . +# +# # Author: Lin Li + +.PHONY: all install download clean + +BUILT_FILES= + +FILES=$(METADATA) Makefile PURPOSE main.sh + +run: $(FILES) build + ./main.sh + +build: $(BUILT_FILES) + chmod a+x ./main.sh + +clean: + rm -f *~ *.rpm $(BUILT_FILES) + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @touch $(METADATA) + @echo "Owner: LiLin " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "License: GPLv3" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Description: find_multipaths" >> $(METADATA) + @echo "TestTime: 15m" >> $(METADATA) + @echo "RunFor: device-mapper-multipath" >> $(METADATA) + @echo "Requires: device-mapper-multipath" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/find_multipaths/main.sh b/tests/find_multipaths/main.sh index 28c325c..ed51e10 100755 --- a/tests/find_multipaths/main.sh +++ b/tests/find_multipaths/main.sh @@ -18,162 +18,77 @@ # Author: Lin Li #set -x -source ../include/tc.sh || exit 200 +source ../include/ec.sh || exit 200 + tlog "running $0" -remove_devices () -{ - local retries - retries=10 - while [[ -n `multipath -l -v1` ]]; do - ((retries--)) - if [[ $retries -le 0 ]]; then - tfail_ "failed to remove devices" - cleanup - tend - fi - tlog "removing multipath devices" - trun "udevadm settle" - trun "multipath -F" - sleep 2 - done -} +# which not set find_multipaths yes, so multipath always create a multipath device for single device +# so stop service and reconfig with --find_multipaths y, and reload/start the service again. +trun "service multipathd stop" +rpm -q device-mapper-multipath || yum install -y device-mapper-multipath -cleanup () -{ - local retries - if pidof multipathd; then - tlog "stopping multipathd" - trun "systemctl stop multipathd.service || pkill multipathd" - sleep 1 - fi - retries=10 - while pidof multipathd; do - ((retries--)) - if [[ $retries -le 0 ]]; then - tfail_ "failed to stop multipath" - tend - fi - tlog "waiting for multipathd to stop" - sleep 2 - pidof multipathd && pkill multipathd - done - trun "multipath -l -v1" - retries=10 - while [[ -n `multipath -l -v1` ]]; do - ((retries--)) - if [[ $retries -le 0 ]]; then - tfail_ "failed to remove devices" - tend - fi - tlog "removing multipath devices" - trun "udevadm settle" - trun "multipath -DF" - sleep 2 - done - if lsmod | grep -q "^scsi_debug"; then - tlog "removing scsi_debug module" - tok "rmmod scsi_debug" - fi - trun "rm -f /etc/multipath.conf" - trun "rm -f /etc/multipath/wwids" - trun "rm -r /etc/multipath/bindings" -} - -assert () -{ - local cmd="$*" - _trun_ "$cmd" 0 - if test $? -eq 0; then - tpass_ "$cmd" ; - else - tfail_ "$cmd" ; - cleanup ; - tend ; - fi -} - -setup_config () -{ - trun "mpathconf --enable --user_friendly_names y --find_multipaths y" - sed -i '/^blacklist[[:space:]]*{/ a\ - device {\ - vendor ".*"\ - product ".*"\ - } -' /etc/multipath.conf - cat << _EOF_ >> /etc/multipath.conf - -blacklist_exceptions { - device { - vendor Linux - product scsi_debug - } -} -_EOF_ - trun "cat /etc/multipath.conf" -} - -do_reconfigure () -{ - trun "cat /etc/multipath.conf" - tok "multipathd reconfigure" - sleep 5 -} - -trun "rpm -q device-mapper-multipath || dnf install -y device-mapper-multipath" -cleanup -setup_config - -# test with find_multipath=y, will not multipath the single device +# test with find_multipath=y, will not multipath for the single device; reload/start the service to enable the config +trun "mpathconf --enable --user_friendly_names y --find_multipaths y --with_multipathd y" +trun "service multipathd status" +# use scsi_debug to simulate a drive +trun "multipath -F" +terr "modprobe -r scsi_debug" trun "modprobe scsi_debug" -sleep 5 -trun "systemctl start multipathd.service" -while multipathd show daemon | grep -qv idle; do - tlog "waiting for multipathd to start" - sleep 1 -done -trun 'multipathd show paths raw format "%d %m"' -trun 'cat /etc/multipath/wwids' -mpath_name=`multipathd show paths raw format "%m" | head -1` -tok "[[ $mpath_name = '[orphan]' ]]" -remove_devices - -# test with find_multipath=n, will multipath the single device -trun 'mpathconf --find_multipaths n' -do_reconfigure -trun 'multipathd show paths raw format "%d %m"' -trun 'cat /etc/multipath/wwids' -mpath_name=`multipathd show paths raw format "%m" | head -1` -tok "[[ -n $mpath_name ]] && [[ $mpath_name != '[orphan]' ]]" -remove_devices - -# test with find_multipath=y, with multipath single device with known WWID -trun 'mpathconf --find_multipaths y' -do_reconfigure -trun 'multipathd show paths raw format "%d %m"' -trun 'cat /etc/multipath/wwids' -mpath_name=`multipathd show paths raw format "%m" | head -1` -tok "[[ -n $mpath_name ]] && [[ $mpath_name != '[orphan]' ]]" -remove_devices - -# Clear WWID, test with find_multipath=y, will not multipath single device +sleep 3 trun "multipath -W" -do_reconfigure -trun 'multipathd show paths raw format "%d %m"' -trun 'cat /etc/multipath/wwids' -mpath_name=`multipathd show paths raw format "%m" | head -1` -tok "[[ $mpath_name = '[orphan]' ]]" -remove_devices -assert 'rmmod scsi_debug' +cat /etc/multipath/wwids +trun "multipath" +disk_path=$(get_scsi_debug_devices) +disk_node=$(basename $disk_path) +mpath_name=$(get_mpath_disk_by_scsi_device $disk_node) +tok '[[ -z $mpath_name ]]' + +# test with find_multipath=n, will multipath for the single device +trun "mpathconf --enable --user_friendly_names y --find_multipaths n --with_multipathd y" +sleep 5 +trun "multipath" +mpath_name=$(get_mpath_disk_by_scsi_device $disk_node) +tok "is_mpath $mpath_name" + +# flush new created path +sleep 3 +trun "multipath -F" +sleep 3 + +# test with find_multipath=y, A path has the same WWID as a multipath device that was previously created +trun "mpathconf --enable --user_friendly_names y --find_multipaths y --with_multipathd y" +sleep 5 +trun "multipath" +mpath_name=$(get_mpath_disk_by_scsi_device $disk_node) +tok "is_mpath $mpath_name" + +# Clear wwid, test with find_multipath=y, will not multipath for the single device +trun "multipath -W" +trun "mpathconf --disable --with_multipathd y" +sleep 5 +mpath_name=$(get_mpath_disk_by_scsi_device $disk_node) +tok '[[ -z $mpath_name ]]' + +trun "multipath -F" +sleep 5 +trun "modprobe -r scsi_debug" # test find_multipaths=y create device for paths have same wwid -trun "modprobe scsi_debug vpd_use_hostno=0 add_host=2" -sleep 5 -trun 'multipathd show paths raw format "%d %m"' -trun 'cat /etc/multipath/wwids' -mpath_name=`multipathd show paths raw format "%m" | head -1` -tok "[[ -n $mpath_name ]] && [[ $mpath_name != '[orphan]' ]]" +tok "modprobe scsi_debug num_tgts=1 vpd_use_hostno=0 add_host=2 delay=20 max_luns=2 no_lun_0=1" +sleep 10 +disk_paths=$(get_scsi_debug_devices) +disk_node=$(basename $disk_paths) +mpath_name=$(get_mpath_disk_by_scsi_device $disk_node) +tok "is_mpath $mpath_name" -cleanup +sleep 10 + +trun "multipath -F" +sleep 5 +trun "modprobe -r scsi_debug" +# remove the scsi_debug wwid +trun "service multipathd stop" +sleep 3 +trun "multipath -W" +cat /etc/multipath/wwids tend diff --git a/tests/include/ec.sh b/tests/include/ec.sh index 4b0aba9..22dfc40 100755 --- a/tests/include/ec.sh +++ b/tests/include/ec.sh @@ -44,12 +44,9 @@ function _init (){ } function _destroy (){ - Cmd "multipathd disablequeueing maps" + sleep 10 + Cmd "multipath -F" sleep 5 - Cmd "multipath -DF -R2" - Cmd "service multipathd stop" - sleep 5 - Cmd "udevadm settle" Cmd "modprobe -r scsi_debug" } @@ -177,7 +174,10 @@ AA fi #setup scsi_debug echo "INFO: Loading scsi_debug module for simulation of mpath" - modprobe scsi_debug vpd_use_hostno=0 add_host=2 + modprobe scsi_debug \ + num_tgts=1 vpd_use_hostno=0 \ + add_host=4 delay=20 \ + max_luns=2 no_lun_0=1 2>&1 1>/dev/null echo "INFO: Waiting for udev to create /dev/sdX" sleep 15s #wait for udev to create /dev/sdX @@ -189,6 +189,8 @@ AA #enable multipath for scsi_debug. cat << AA > /etc/multipath.conf defaults { +#Enable multibus is for mutlbus testing + path_grouping_policy multibus user_friendly_names yes } blacklist { diff --git a/tests/include/mpath.sh b/tests/include/mpath.sh index b894c27..806225e 100644 --- a/tests/include/mpath.sh +++ b/tests/include/mpath.sh @@ -78,7 +78,8 @@ get_mpath_disk_by_scsi_device() { # multipathd_running || texit "multipathd is not running" local disk=$1 - local mpath=$(multipathd show paths raw format "%d,%m" | grep "^$disk\s*," \ + wwid=$(get_wwid_of_disk $disk) + local mpath=$(multipathd show maps format %w,%n | grep "^$wwid\s*," \ | awk -F, '{ print $2 }' | sed 's/\s//g') echo $mpath } diff --git a/tests/medium_error_scsi_debug/main.sh b/tests/medium_error_scsi_debug/main.sh index 35c6e6f..db2f008 100755 --- a/tests/medium_error_scsi_debug/main.sh +++ b/tests/medium_error_scsi_debug/main.sh @@ -16,51 +16,47 @@ # along with this program. If not, see . # Author: LiLin -source ../include/tc.sh || exit 200 -cleanup() +function cleanup() { sleep 5 udevadm settle - trun "multipath -DF" + multipath -F sleep 5 - trun "modprobe -r scsi_debug" + modprobe -r scsi_debug + + return 0 } -assert () -{ - local cmd="$*" - _trun_ "$cmd" 0 - if test $? -eq 0; then - tpass_ "$cmd" ; - else - tfail_ "$cmd" ; - cleanup ; - tend ; - fi -} - -tlog "running $0" -rpm -q device-mapper-multipath || dnf install -y device-mapper-multipath -trun "multipathd disablequeueing maps" -cleanup -trun "service multipathd stop" -trun "rm -f /etc/multipath.conf" -trun "mpathconf --enable" -trun "modprobe scsi_debug vpd_use_hostno=0 add_host=2 opts=2" +yum -y install device-mapper device-mapper-multipath +mpathconf --enable +service multipathd stop +modprobe scsi_debug num_tgts=1 vpd_use_hostno=0 add_host=2 delay=20 max_luns=2 no_lun_0=1 opts=2 sleep 5 -trun "multipath" +multipath > /dev/null sleep 5 -trun "multipath -l" mpathdev=`multipath -l | grep scsi_debug | awk '{print $1}' | head -1` -assert "[[ -n \"$mpathdev\" ]]" +if [ -z "$mpathdev" ]; then + echo "------- FAIL, no multipath device created -----" + cleanup + exit 1 +fi before_active=`multipath -l $mpathdev | grep "active undef" | wc -l` -tlog "before active = ${before_active}" IO_error=`dd if=/dev/zero of=/dev/mapper/$mpathdev bs=1024 seek=2330 count=10 2>&1 | grep -o "Input/output error" ` -assert "[[ -n \"$IO_error\" ]]" -after_active=`multipath -l $mpathdev | grep "active undef" | wc -l` -tlog "after active = ${after_active}" -assert "[[ \"$before_active\" -eq \"$after_active\" ]]" -cleanup -tend +if [ -n "$IO_error" ];then + after_active=`multipath -l $mpathdev | grep "active undef" | wc -l` + if [ "$before_active" -eq "$after_active" ]; then + echo "------- PASS, a medium error, correctly generated an I/O error and did not fail paths -----" + cleanup + exit 0 + else + echo "------- FAIL, paths failed -----" + cleanup + exit 1 + fi +else + echo "------- FAIL, did not generate an I/O error -----" + cleanup + exit 1 +fi diff --git a/tests/multipath_conf_syntax/main.sh b/tests/multipath_conf_syntax/main.sh index fb303c3..f29109d 100755 --- a/tests/multipath_conf_syntax/main.sh +++ b/tests/multipath_conf_syntax/main.sh @@ -17,129 +17,96 @@ # Author: Lin Li -source ../include/ec.sh || exit 200 -tlog "running $0" -cleanup () -{ - trun "multipathd disablequeueing maps" - sleep 5 - trun "multipath -F" - trun "service multipathd stop" - sleep 5 - trun "udevadm settle" - trun "modprobe -r scsi_debug" -} +# Include Beaker environment +. /usr/bin/rhts-environment.sh || exit 1 +. /usr/share/beakerlib/beakerlib.sh || exit 1 -assert () -{ - local cmd="$*" - _trun_ "$cmd" 0 - if test $? -eq 0; then - tpass_ "$cmd" ; - else - tfail_ "$cmd" ; - cleanup ; - tend ; - fi -} +PACKAGE="device-mapper-multipath" -rpm -q device-mapper-multipath || yum install -y device-mapper-multipath +rlJournalStart + rlPhaseStartSetup + rlAssertRpm $PACKAGE + rlRun "multipath -F; sleep 5" + rlRun "modprobe -r scsi_debug" 0 "Remove if scsi_debug load before" + rlRun "rm -f /etc/multipath.conf" + rlRun "mpathconf --enable --with_module y --with_multipathd y --find_multipaths n" 0 "Set up multipath" + rlServiceStart multipathd + rlRun "cp /etc/multipath.conf /etc/multipath.conf.bak" 0 "Backup /etc/multipath.conf first" + rlPhaseEnd -# cleanup existing devices and restart -cleanup -trun "rm -f /etc/multipath.conf" -trun "mpathconf --enable --with_module y --with_multipathd n --find_multipaths n" -sed -i '/^blacklist[[:space:]]*{/ a\ - device {\n vendor ".*"\n product ".*"\n } -' /etc/multipath.conf -if grep -qw blacklist_exceptions /etc/multipath.conf ; then - sed -i '/^blacklist_exceptions[[:space:]]*{/ a\ - device {\n vendor Linux\n product scsi_debug\n } -' /etc/multipath.conf -else - cat << _EOF_ >> /etc/multipath.conf -blacklist_exceptions { - device { - vendor Linux - product scsi_debug - } -} -_EOF_ -fi - -trun "cp /etc/multipath.conf /etc/multipath.conf.bak" -trun "service multipathd stop" -trun "service multipathd start" - -trun "modprobe scsi_debug" -sleep 5 -trun "multipath -ll" -pathcount=`multipathd show maps format %w | grep -v uuid | wc -l` -assert "[[ $pathcount -eq 1 ]]" -wwid=`multipathd show maps format %w | grep -v uuid` - -# test missing closing quote on alias -cat << _EOF_ >> /etc/multipath.conf + rlPhaseStartTest + rlRun "modprobe scsi_debug" + sleep 5 + rlLogInfo "`multipath -ll`" + wwid=`multipathd show maps format %w | grep -v uuid` + # test missing closing quote on alias + cat << _EOF_ >> /etc/multipath.conf multipaths { - multipath { - wwid "$wwid" - alias "mypath - } + multipath { + wwid "$wwid" + alias "mypath + } } _EOF_ -tok "multipath 2>&1 | grep 'missing closing quotes on line'" -trun "multipath -r" -tok "multipath -ll | grep mypath" + rlRun "multipath 2>&1 | grep 'missing closing quotes on line'" 0 "test missing closing quote on alias" + rlRun "multipath -r" + rlRun "multipath -ll |grep mypath" 0 "check if mpath rename to mypath successfully" -# test no value for alias -trun "sed -i 's/alias.*$/alias/g' /etc/multipath.conf" -multipath -tok "multipath 2>&1 | grep \"missing value for option 'alias' on line\"" -trun "multipath -r" -tok "multipath -ll | grep mpath" + # test no value for alias + rlRun "sed -i 's/alias.*$/alias/g' /etc/multipath.conf" + rlRun "multipath 2>&1 | grep \"missing value for option 'alias' on line\"" 0 "test no value for alias" + rlRun "multipath -r" + rlRun "multipath -ll |grep mpath*" 0 "check if mpath rename to mpath* from mypath successfully" -# test missing starting quote on alias -trun "sed -i 's/alias.*$/alias mypath\"/g' /etc/multipath.conf" -tok "multipath 2>&1 |grep 'ignoring extra data starting with'" -trun "multipath -r" -tok "multipath -ll | grep mypath" + # test missing starting quote on alias + rlRun "sed -i 's/alias.*$/alias mypath\"/g' /etc/multipath.conf" + rlRun "multipath 2>&1 |grep 'ignoring extra data starting with'" 0 "test missing starting quote on alias" + rlRun "multipath -r" + rlRun "multipath -ll |grep mypath" 0 "check if mpath rename to mypath successfully" -# test wrong quote on alias -trun "sed -i 's/alias.*$/alias /g' /etc/multipath.conf" -tnot "multipath 2>&1 | grep config" -trun "multipath -r" -tok "multipath -ll | grep ''" + # test wrong quote on alias + rlRun "sed -i 's/alias.*$/alias /g' /etc/multipath.conf" + rlRun "multipath 2>&1 | grep config" 1 "no warning" + rlRun "multipath -r" + rlRun "multipath -ll |grep ''" 0 "check if mpath rename to successfully" -# test value has a space -trun "sed -i 's/alias.*$/alias mypath test/g' /etc/multipath.conf" -tok "multipath 2>&1 |grep 'ignoring extra data starting with'" -trun "multipath -r" -tok "multipath -ll | grep mypath" + # test value has a space + rlRun "sed -i 's/alias.*$/alias mypath test/g' /etc/multipath.conf" + rlRun "multipath 2>&1 |grep 'ignoring extra data starting with'" 0 "test value has a space" + rlRun "multipath -r" + rlRun "multipath -ll |grep mypath" 0 "check if mpath rename to mypath successfully" -# test wrong alias keyword -trun "sed -i 's/alias.*$/alia mypath/g' /etc/multipath.conf" -tok "multipath 2>&1 | grep 'invalid keyword in the multipath section: alia'" -trun "multipath -r" -tok "multipath -ll | grep mpath" -trun "sed -i 's/alia.*$/alias mypath/g' /etc/multipath.conf" + # test wrong alias keyword + rlRun "sed -i 's/alias.*$/alia mypath/g' /etc/multipath.conf" + rlRun "multipath 2>&1 |grep 'invalid keyword: alia'" 0 "invalid keyword: alia" + rlRun "multipath -r" + rlRun "multipath -ll |grep mpath*" 0 "check if mpath rename to mpath* from mypath successfully" + rlRun "sed -i 's/alia.*$/alias mypath/g' /etc/multipath.conf" -# test no space between the section name and the open bracket that followed it -# fix issue about if a section doesn't have a space between the section name -# and the open bracket, that section isn't read in. -trun "sed -i 's/multipaths.*/multipaths{/g' /etc/multipath.conf" -tnot "multipath 2>&1 | grep config" -trun "multipath -r" -tok "multipath -ll |grep mypath" + # test no space between the section name and the open bracket that followed it + # fix issue about if a section doesn't have a space between the section name and the open bracket, that section isn't read in. + rlRun "sed -i 's/multipaths.*/multipaths{/g' /etc/multipath.conf" + rlRun "multipath 2>&1 | grep config" 1 "no warning" + rlRun "multipath -r" + rlRun "multipath -ll |grep mypath" 0 "check if mpath rename to mypath successfully" -# test wrong section keywords -trun "sed -i 's/multipaths.*/ultipaths {/g' /etc/multipath.conf" -tok "multipath 2>&1 | grep 'invalid keyword: ultipaths'" -trun "sed -i 's/defaults.*/efaults {/g' /etc/multipath.conf" -tok "multipath 2>&1 | grep 'invalid keyword: efaults'" -trun "sed -i 's/blacklist {/lacklist {/g' /etc/multipath.conf" -tok "multipath 2>&1 | grep 'invalid keyword: lacklist'" -trun "mv /etc/multipath.conf.bak /etc/multipath.conf" + # test wrong section keywords + rlRun "sed -i 's/multipaths.*/ultipaths {/g' /etc/multipath.conf" + rlRun "multipath 2>&1 | grep 'invalid keyword: ultipaths'" 0 "test wrong multipaths section keyword" + rlRun "sed -i 's/defaults.*/efaults {/g' /etc/multipath.conf" + rlRun "multipath 2>&1 | grep 'invalid keyword: efaults'" 0 "test wrong defaults section keyword" + rlRun "sed -i 's/blacklist {/lacklist {/g' /etc/multipath.conf" + rlRun "multipath 2>&1 | grep 'invalid keyword: lacklist'" 0 "test wrong blacklist section keyword" -cleanup -tend + rlPhaseEnd + + rlPhaseStartCleanup + rlRun "udevadm settle" + rlRun "multipath -F" 0 "Flush all unused multipath device maps" + rlServiceStop multipathd + rlRun "modprobe -r scsi_debug" 0 "Remove scsi_debug" + rlRun "cp -f /etc/multipath.conf.bak /etc/multipath.conf" 0 "Recovery /etc/multipath.conf" + rlPhaseEnd +rlJournalPrintText +rlJournalEnd diff --git a/tests/provision.fmf b/tests/provision.fmf new file mode 100644 index 0000000..62a6eba --- /dev/null +++ b/tests/provision.fmf @@ -0,0 +1,5 @@ +--- + +standard-inventory-qcow2: + qemu: + m: 2G diff --git a/tests/restate_module/main.sh b/tests/restate_module/main.sh index be60eba..6d5b0c5 100755 --- a/tests/restate_module/main.sh +++ b/tests/restate_module/main.sh @@ -48,8 +48,10 @@ rpm -q device-mapper-multipath || yum install -y device-mapper-multipath tlog "device-mapper-multipath is installed" # cleanup existing devices trun "rm /etc/multipath.conf" -trun "mpathconf --enable --with_module y --option max_polling_interval:10" -trun "mpathconf --option detect_pgpolicy_use_tpg:yes" +trun "mpathconf --enable --with_module y" +sed -i '/^defaults[[:space:]]*{/ a\ + max_polling_interval 10 +' /etc/multipath.conf trun "service multipathd stop" trun "multipath -F" sleep 5 @@ -67,7 +69,7 @@ tlog "Checking if active path count equals 2" assert "[[ $pathcount -eq 2 ]]" tlog "offline one path device" -pathname=`multipathd show paths raw format "%d %m %p" | grep ${mpathdev} | sort -k 3n | head -1 | awk '{print $1}'` +pathname=`multipathd show paths raw format "%d %m" | grep ${mpathdev} | head -1 | awk '{print $1}'` tlog "path to offline: ${pathname}" trun "echo 'offline' > /sys/block/${pathname}/device/state" tlog "waiting for multipathd to fail path" @@ -91,5 +93,4 @@ path_state=`multipathd show paths raw format "%d %t %T %o" | grep ${pathname} | tlog "Checking state of ${pathname}" assert "[[ $path_state -eq 1 ]]" -cleanup tend diff --git a/tests/tests.yml b/tests/tests.yml new file mode 100644 index 0000000..4c396d2 --- /dev/null +++ b/tests/tests.yml @@ -0,0 +1,42 @@ +--- +# No tests suitable for atomic environment +# No tests suitable for container environment + +# Tests suitable for classic environment +- hosts: localhost + roles: + - role: standard-test-basic + tags: + - classic + tests: + - medium_error_scsi_debug: + run: ./main.sh + timeout: 15m + - squelch_scsi_id: + run: ./main.sh + timeout: 15m + - multipathd_oom: + run: ./main.sh + timeout: 15m + - user_friendly_names: + run: ./main.sh + timeout: 15m + - kpartx_4k_aligned: + run: ./main.sh + timeout: 15m + - bindings: + run: ./main.sh + timeout: 15m + required_packages: + - device-mapper-multipath + - perl + + - role: standard-test-beakerlib + tags: + - classic + tests: + - multipath_conf_syntax: + timeout: 15m + required_packages: + - device-mapper-multipath + - perl diff --git a/tests/user_friendly_names/main.sh b/tests/user_friendly_names/main.sh index 1d48801..56082fd 100755 --- a/tests/user_friendly_names/main.sh +++ b/tests/user_friendly_names/main.sh @@ -17,125 +17,50 @@ # Author: Lin Li -source ../include/tc.sh || exit 200 +source ../include/ec.sh || exit 200 + tlog "running $0" -cleanup () -{ - local retries - if pidof multipathd; then - tlog "stopping multipathd" - trun "systemctl stop multipathd.service || pkill multipathd" - sleep 1 - fi - retries=10 - while pidof multipathd; do - ((retries--)) - if [[ $retries -le 0 ]]; then - tfail_ "failed to stop multipath" - tend - fi - tlog "waiting for multipathd to stop" - sleep 2 - pidof multipathd && pkill multipathd - done - trun "multipath -l -v1" - retries=10 - while [[ -n `multipath -l -v1` ]]; do - ((retries--)) - if [[ $retries -le 0 ]]; then - tfail_ "failed to remove deviece" - tend - fi - tlog "removing multipath device" - trun "udevadm settle" - trun "multipath -DF" - sleep 2 - done - if lsmod | grep -q "^scsi_debug"; then - tlog "removing scsi_debug module" - tok "rmmod scsi_debug" - fi - trun "rm -f /etc/multipath.conf" -} +trun "rpm -q device-mapper-multipath || yum install -y device-mapper-multipath" +trun "mpathconf --enable --with_multipathd y --user_friendly_names y" -assert () -{ - local cmd="$*" - _trun_ "$cmd" 0 - if test $? -eq 0; then - tpass_ "$cmd" ; - else - tfail_ "$cmd" ; - cleanup ; - tend ; - fi -} +# backup the /etc/multipath.conf +trun "cp /etc/multipath.conf /etc/multipath.conf.$$" +trun "multipath -F" -setup_config () -{ - trun "mpathconf --enable --user_friendly_names y" - sed -i '/^blacklist[[:space:]]*{/ a\ - device {\ - vendor ".*"\ - product ".*"\ - } -' /etc/multipath.conf - cat << _EOF_ >> /etc/multipath.conf +trun "modprobe scsi_debug num_tgts=1 vpd_use_hostno=0 add_host=2 delay=20 \ +max_luns=2 no_lun_0=1" +trun "multipath" +# wwid shown slowly on s390x by the script framework, but normally when run by multipath command directly +# so extend sleep time +sleep 20 -blacklist_exceptions { - device { - vendor Linux - product scsi_debug - } -} +disk=$(get_scsi_debug_devices) +disk=$(basename $disk) +wwid=$(get_wwid_of_disk $disk) +mpath=$(get_mpath_disk_by_scsi_device $disk) -multipaths { - multipath { - wwid TEST_WWID - alias test - } -} -_EOF_ - trun "cat /etc/multipath.conf" -} +# user_friendly_names = yes and mpath=test +#cur_dir=/mnt/tests/kernel/storage/multipath/user_friendly_names/ +#cur_dir=/home/test/scratch/device-mapper-multipath/user_friendly_names +trun "cat multipath.conf.yes | sed "s/your_wwid/$wwid/g" > /etc/multipath.conf" +trun "cat -n /etc/multipath.conf" +trun "multipath -r" +echo ">>> Verify 'test ($wwid)' is present ..." +trun "multipath -ll" +tok "multipath -ll | egrep \"^test\"" -do_reconfigure () -{ - trun "cat /etc/multipath.conf" - tok "multipathd reconfigure" - sleep 5 -} +# user_friendly_names = no +trun "cat multipath.conf.no > /etc/multipath.conf" +trun "multipath -r" +echo ">>> Verify 'test' is gone but '$wwid' present ..." +trun "multipath -ll" +tok "multipath -ll | egrep \"^$wwid\"" +sleep 10 +tok "multipath -F $wwid" +sleep 10 +trun "modprobe -r scsi_debug" -trun "rpm -q device-mapper-multipath || dnf install -y device-mapper-multipath" -cleanup -setup_config -trun "rm -r /etc/multipath/bindings" -trun "modprobe scsi_debug vpd_use_hostno=0 add_host=2" -sleep 5 -trun "systemctl start multipathd.service" -while multipathd show daemon | grep -qv idle; do - tlog "waiting for multipathd to start" - sleep 1 -done -trun 'multipathd show maps raw format "%n %w"' -# verify user_friendly_name -tok 'multipathd show maps raw format "%n" | head -1 | grep -q mpath' -wwid=`multipathd show maps raw format "%w" | head -1` -assert "[[ -n $wwid ]] && [[ $wwid != ok ]]" -sed -i 's/TEST_WWID/'"$wwid"'/' /etc/multipath.conf -do_reconfigure -trun 'multipathd show maps raw format "%n %w"' -# verify configured alias takes precedence over user_friendly_name -tok 'multipathd show maps raw format "%n" | head -1 | grep -q test' -trun "mpathconf --user_friendly_names n" -do_reconfigure -trun 'multipathd show maps raw format "%n %w"' -# verify configured alias takes precedence over wwid name -tok 'multipathd show maps raw format "%n" | head -1 | grep -q test' -sed -i 's/'"$wwid"'/TEST_WWID/' /etc/multipath.conf -do_reconfigure -trun 'multipathd show maps raw format "%n %w"' -tok 'multipathd show maps raw format "%n" | head -1 | grep -q '"$wwid" -cleanup +trun "cp /etc/multipath.conf.$$ /etc/multipath.conf" +trun "multipath -F; multipath" tend diff --git a/tests/user_friendly_names/multipath.conf.no b/tests/user_friendly_names/multipath.conf.no new file mode 100644 index 0000000..b916bfb --- /dev/null +++ b/tests/user_friendly_names/multipath.conf.no @@ -0,0 +1,3 @@ +defaults { + user_friendly_names no +} diff --git a/tests/user_friendly_names/multipath.conf.yes b/tests/user_friendly_names/multipath.conf.yes new file mode 100644 index 0000000..ffc21bb --- /dev/null +++ b/tests/user_friendly_names/multipath.conf.yes @@ -0,0 +1,11 @@ +defaults { + user_friendly_names yes +} + +multipaths { + multipath { + wwid your_wwid + alias test + } +} +