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

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