Blame SOURCES/0044-libmultipath-don-t-dlclose-tur-checker-DSO.patch

60b218
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
60b218
From: Benjamin Marzinski <bmarzins@redhat.com>
60b218
Date: Fri, 23 Oct 2020 11:38:24 -0500
60b218
Subject: [PATCH] libmultipath: don't dlclose tur checker DSO
60b218
60b218
The multipathd tur checker thread is designed to be able to finish at
60b218
any time, even after the tur checker itself has been freed. The
60b218
multipathd shutdown code makes sure all the checkers have been freed
60b218
before freeing the checker_class and calling dlclose() to unload the
60b218
DSO, but this doesn't guarantee that the checker threads have finished.
60b218
If one hasn't, the DSO will get unloaded while the thread still running
60b218
code from it, causing a segfault. Unfortunately, it's not possible to be
60b218
sure that all tur checker threads have ended during shutdown, without
60b218
making them joinable.
60b218
60b218
However, since libmultipath will never be reinitialized after it has
60b218
been uninitialzed, not dlclosing the tur checker DSO once a thread is
60b218
started has minimal cost (keeping the DSO code around until the program
60b218
exits, which usually happens right after freeing the checkers).
60b218
60b218
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
60b218
---
60b218
 libmultipath/checkers.c     | 10 +++++++++-
60b218
 libmultipath/checkers.h     |  1 +
60b218
 libmultipath/checkers/tur.c |  1 +
60b218
 3 files changed, 11 insertions(+), 1 deletion(-)
60b218
60b218
diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c
60b218
index 8d2be8a9..6359e5d8 100644
60b218
--- a/libmultipath/checkers.c
60b218
+++ b/libmultipath/checkers.c
60b218
@@ -21,6 +21,7 @@ struct checker_class {
60b218
 	void (*reset)(void);		     /* to reset the global variables */
60b218
 	const char **msgtable;
60b218
 	short msgtable_size;
60b218
+	int keep_dso;
60b218
 };
60b218
 
60b218
 char *checker_state_names[] = {
60b218
@@ -69,7 +70,7 @@ void free_checker_class(struct checker_class *c)
60b218
 	list_del(&c->node);
60b218
 	if (c->reset)
60b218
 		c->reset();
60b218
-	if (c->handle) {
60b218
+	if (c->handle && !c->keep_dso) {
60b218
 		if (dlclose(c->handle) != 0) {
60b218
 			condlog(0, "Cannot unload checker %s: %s",
60b218
 				c->name, dlerror());
60b218
@@ -192,6 +193,13 @@ out:
60b218
 	return NULL;
60b218
 }
60b218
 
60b218
+void checker_keep_dso(struct checker * c)
60b218
+{
60b218
+	if (!c || !c->cls)
60b218
+		return;
60b218
+	c->cls->keep_dso = 1;
60b218
+}
60b218
+
60b218
 void checker_set_fd (struct checker * c, int fd)
60b218
 {
60b218
 	if (!c)
60b218
diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h
60b218
index b458118d..f183cff9 100644
60b218
--- a/libmultipath/checkers.h
60b218
+++ b/libmultipath/checkers.h
60b218
@@ -145,6 +145,7 @@ void checker_reset (struct checker *);
60b218
 void checker_set_sync (struct checker *);
60b218
 void checker_set_async (struct checker *);
60b218
 void checker_set_fd (struct checker *, int);
60b218
+void checker_keep_dso(struct checker *c);
60b218
 void checker_enable (struct checker *);
60b218
 void checker_disable (struct checker *);
60b218
 int checker_check (struct checker *, int);
60b218
diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c
60b218
index e886fcf8..fd58d62a 100644
60b218
--- a/libmultipath/checkers/tur.c
60b218
+++ b/libmultipath/checkers/tur.c
60b218
@@ -394,6 +394,7 @@ int libcheck_check(struct checker * c)
60b218
 		uatomic_set(&ct->running, 1);
60b218
 		tur_set_async_timeout(c);
60b218
 		setup_thread_attr(&attr, 32 * 1024, 1);
60b218
+		checker_keep_dso(c);
60b218
 		r = pthread_create(&ct->thread, &attr, tur_thread, ct);
60b218
 		pthread_attr_destroy(&attr);
60b218
 		if (r) {
60b218
-- 
60b218
2.17.2
60b218