device-mapper-multipath-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
This commit is contained in:
Benjamin Marzinski 2021-04-05 22:37:31 -05:00
parent b05147c356
commit ac4e55e1c0
167 changed files with 1012 additions and 15115 deletions

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ 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

View File

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Christophe Varoqui <christophe.varoqui@opensvc.com>
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 <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/multipath.conf.5 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 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
.
.

View File

@ -15,10 +15,10 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc
index 05429307..24e943d5 100644
index f1e23131..c593fd3b 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -53,7 +53,7 @@ endif
@@ -55,7 +55,7 @@ endif
prefix =
exec_prefix = $(prefix)
usr_prefix = $(prefix)

View File

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 16 Sep 2020 21:59:11 +0200
Subject: [PATCH] libmultipath: find_mpe(): don't match with empty WWID
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 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)

View File

@ -1,257 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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);

View File

@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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);

View File

@ -13,10 +13,10 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc
index 24e943d5..e978d306 100644
index c593fd3b..87fb39f2 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -90,15 +90,27 @@ TEST_CC_OPTION = $(shell \
@@ -92,15 +92,27 @@ TEST_CC_OPTION = $(shell \
echo "$(2)"; \
fi)
@ -49,7 +49,7 @@ index 24e943d5..e978d306 100644
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 \
@@ -138,4 +150,4 @@ check_file = $(shell \
%.o: %.c
@echo building $@ because of $?

View File

@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 <libdmmp/libdmmp.h>
-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;

View File

@ -1,50 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Fri, 18 Sep 2020 23:57:22 +0200
Subject: [PATCH] libmultipath: prio: constify some function parameters
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 *);

View File

@ -1,87 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;
}

View File

@ -1,93 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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)

View File

@ -1,84 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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))

View File

@ -13,7 +13,7 @@ Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
1 file changed, 2 insertions(+), 16 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index f8044141..e6590d07 100644
index ec99a7aa..2704270e 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1135,12 +1135,9 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,

View File

@ -1,300 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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:
+ *;
+};

View File

@ -1,78 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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: *;
+};

View File

@ -1,71 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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:
+ *;
+};

View File

@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 ;
}

View File

@ -1,137 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <wu.chongyun@h3c.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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)

View File

@ -1,64 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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
}
}

View File

@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;
}

View File

@ -1,39 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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

View File

@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;

View File

@ -1,69 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;
}

View File

@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;

View File

@ -1,58 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <wu.chongyun@h3c.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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);

View File

@ -1,162 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 */

View File

@ -1,503 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 <sys/types.h>
@@ -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 <errno.h>
#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);

View File

@ -1,434 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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) {

View File

@ -1,95 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 16 Sep 2020 12:02:01 +0200
Subject: [PATCH] libmultipath: constify file argument in config parser
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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);

View File

@ -1,201 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;

View File

@ -1,153 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 :

View File

@ -1,64 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 16 Sep 2020 12:27:09 +0200
Subject: [PATCH] multipath: use {get_put}_multipath_config from libmultipath
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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);

View File

@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 16 Sep 2020 12:39:01 +0200
Subject: [PATCH] mpathpersist: use {get,put}_multipath_config() from
libmultipath
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;

View File

@ -1,165 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;

View File

@ -1,45 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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_

View File

@ -1,93 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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.

View File

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;
}

View File

@ -1,54 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 ) {

View File

@ -1,37 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Xose Vazquez Perez <xose.vazquez@gmail.com>
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 <mwilck@suse.com>
Cc: Martin Wilck <mwilck@suse.com>
Cc: Benjamin Marzinski <bmarzins@redhat.com>
Cc: Christophe Varoqui <christophe.varoqui@opensvc.com>
Cc: DM-DEVEL ML <dm-devel@redhat.com>
Signed-off-by: Xose Vazquez Perez <xose.vazquez@gmail.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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

View File

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Xose Vazquez Perez <xose.vazquez@gmail.com>
Date: Wed, 16 Dec 2020 23:17:40 +0100
Subject: [PATCH] multipath-tools: Violin and Nexsan were bought by StorCentric
Reviewed-by: Martin Wilck <mwilck@suse.com>
Cc: Martin Wilck <mwilck@suse.com>
Cc: Benjamin Marzinski <bmarzins@redhat.com>
Cc: Christophe Varoqui <christophe.varoqui@opensvc.com>
Cc: DM-DEVEL ML <dm-devel@redhat.com>
Signed-off-by: Xose Vazquez Perez <xose.vazquez@gmail.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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",

View File

@ -1,114 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: lixiaokeng <lixiaokeng@huawei.com>
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 <bmarzins@redhat.com>
Signed-off-by: Lixiaokeng <lixiaokeng@huawei.com>
Signed-off-by: Zhiqiang Liu <liuzhiqiang26@huawei.com>
Signed-off-by: Linfeilong <linfeilong@huawei.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/configure.c | 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;
}

View File

@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Xose Vazquez Perez <xose.vazquez@gmail.com>
Date: Thu, 17 Dec 2020 16:49:38 +0100
Subject: [PATCH] multipath-tools: replace hidden tab by space in hwtable
Cc: Martin Wilck <mwilck@suse.com>
Cc: Benjamin Marzinski <bmarzins@redhat.com>
Cc: Christophe Varoqui <christophe.varoqui@opensvc.com>
Cc: DM-DEVEL ML <dm-devel@redhat.com>
Signed-off-by: Xose Vazquez Perez <xose.vazquez@gmail.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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,

View File

@ -1,102 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;

View File

@ -1,95 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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);

View File

@ -1,143 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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

View File

@ -1,122 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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();

View File

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 23 Sep 2020 11:18:02 +0200
Subject: [PATCH] multipathd: make some globals static
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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)
{

View File

@ -1,161 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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

View File

@ -1,53 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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

View File

@ -1,39 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 23 Sep 2020 16:10:19 +0200
Subject: [PATCH] multipathd: move pid destruction into separate function
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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)

View File

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;

View File

@ -1,57 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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

View File

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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

View File

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 23 Sep 2020 18:45:30 +0200
Subject: [PATCH] multipathd: unwatch_all_dmevents: check if waiter is
initialized
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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);

View File

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;

View File

@ -1,89 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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);

View File

@ -1,37 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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");

View File

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 23 Sep 2020 21:04:04 +0200
Subject: [PATCH] libmultipath: log_thread_stop(): check if logarea is
initialized
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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);

View File

@ -1,92 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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);
}

View File

@ -1,145 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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);

View File

@ -1,90 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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();

View File

@ -1,107 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 23 Sep 2020 00:30:02 +0200
Subject: [PATCH] multipath: use atexit() for cleanup handlers
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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

View File

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 23 Sep 2020 00:32:48 +0200
Subject: [PATCH] mpathpersist: use atexit() for cleanup handlers
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;
}

View File

@ -1,92 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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

View File

@ -1,59 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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
+}

View File

@ -1,438 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;
}

View File

@ -1,182 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Sat, 26 Sep 2020 00:32:05 +0200
Subject: [PATCH] libmultipath: introduce symbolic values for logsink
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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)
{

View File

@ -1,149 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 <pthread.h>
@@ -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

View File

@ -1,84 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;

View File

@ -1,154 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;

View File

@ -1,104 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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();
}

View File

@ -1,502 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
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 <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <libdevmapper.h>
+#include <libudev.h>
+#include <errno.h>
+
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#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;

View File

@ -1,529 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 21 Oct 2020 16:39:24 -0500
Subject: [PATCH] multipath-tools tests: and unit tests for libmpathvalid
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
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 <stdbool.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libudev.h>
+#include <cmocka.h>
+#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;
+}

View File

@ -1,87 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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, ""))));
}

View File

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
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);
}
}

View File

@ -1,157 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/config.h | 8 --------
libmultipath/dict.c | 30 +++++++++++++++---------------
libmultipath/dict.h | 2 +-
libmultipath/propsel.c | 2 +-
libmultipath/structs.h | 17 +++++++++++++++++
5 files changed, 34 insertions(+), 25 deletions(-)
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 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;

View File

@ -1,335 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
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<unset>\fR
+.RE
+.
+.
+.TP
.B bindings_file
The full pathname of the binding file to be used when the user_friendly_names
option is set.

View File

@ -1,34 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
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;
/*

View File

@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
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)

View File

@ -1,88 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
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)

View File

@ -1,138 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 <string.h>
#include <syslog.h>
#include <time.h>
+#include <pthread.h>
#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)

View File

@ -1,107 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 */

View File

@ -1,281 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 <stddef.h>
#include <dlfcn.h>
#include <sys/stat.h>
+#include <urcu.h>
+#include <urcu/uatomic.h>
#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 <pthread.h>
#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 <errno.h>
#include <sys/time.h>
#include <pthread.h>
-#include <urcu.h>
#include <urcu/uatomic.h>
#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;

View File

@ -1,148 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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) {

View File

@ -1,109 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 <sys/types.h>
@@ -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);

View File

@ -1,146 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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)

View File

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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;

View File

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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)

View File

@ -1,50 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
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 <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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) \

View File

@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmpathpersist/mpath_persist.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index 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;

View File

@ -1,36 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmpathpersist/mpath_persist.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index 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)) {

View File

@ -1,39 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
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);

View File

@ -1,34 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
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 <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
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))

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