device-mapper-multipath/0115-multipathd-add-code-to-initalize-unwinder.patch

132 lines
4.0 KiB
Diff
Raw Normal View History

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 17 Dec 2020 16:50:06 +0100
Subject: [PATCH] multipathd: add code to initalize unwinder
glibc's implementation of pthread_cancel() loads symbols from
libgcc_s.so using dlopen() when pthread_cancel() is called
for the first time. This happens even with LD_BIND_NOW=1.
This may imply the need for file system access when a thread is
cancelled, which in the case of multipath-tools might be in a
dangerous situation where multipathd must avoid blocking.
Call load_unwinder() during startup to make sure the dynamic
linker has all necessary symbols resolved early on.
This implementation simply creates a dummy thread and cancels
it. This way all necessary symbols for thread cancellation
will be loaded, no matter what the C library needs to implement
cancellation.
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/Makefile | 2 +-
multipathd/init_unwinder.c | 34 ++++++++++++++++++++++++++++++++++
multipathd/init_unwinder.h | 21 +++++++++++++++++++++
multipathd/main.c | 2 ++
4 files changed, 58 insertions(+), 1 deletion(-)
create mode 100644 multipathd/init_unwinder.c
create mode 100644 multipathd/init_unwinder.h
diff --git a/multipathd/Makefile b/multipathd/Makefile
index 632b82b1..d053c1ed 100644
--- a/multipathd/Makefile
+++ b/multipathd/Makefile
@@ -30,7 +30,7 @@ ifeq ($(ENABLE_DMEVENTS_POLL),0)
endif
OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o \
- dmevents.o
+ dmevents.o init_unwinder.o
EXEC = multipathd
diff --git a/multipathd/init_unwinder.c b/multipathd/init_unwinder.c
new file mode 100644
index 00000000..14467f3d
--- /dev/null
+++ b/multipathd/init_unwinder.c
@@ -0,0 +1,34 @@
+#include <pthread.h>
+#include <unistd.h>
+#include "init_unwinder.h"
+
+static pthread_mutex_t dummy_mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t dummy_cond = PTHREAD_COND_INITIALIZER;
+
+static void *dummy_thread(void *arg __attribute__((unused)))
+{
+ pthread_mutex_lock(&dummy_mtx);
+ pthread_cond_broadcast(&dummy_cond);
+ pthread_mutex_unlock(&dummy_mtx);
+ pause();
+ return NULL;
+}
+
+int init_unwinder(void)
+{
+ pthread_t dummy;
+ int rc;
+
+ pthread_mutex_lock(&dummy_mtx);
+
+ rc = pthread_create(&dummy, NULL, dummy_thread, NULL);
+ if (rc != 0) {
+ pthread_mutex_unlock(&dummy_mtx);
+ return rc;
+ }
+
+ pthread_cond_wait(&dummy_cond, &dummy_mtx);
+ pthread_mutex_unlock(&dummy_mtx);
+
+ return pthread_cancel(dummy);
+}
diff --git a/multipathd/init_unwinder.h b/multipathd/init_unwinder.h
new file mode 100644
index 00000000..ada09f82
--- /dev/null
+++ b/multipathd/init_unwinder.h
@@ -0,0 +1,21 @@
+#ifndef _INIT_UNWINDER_H
+#define _INIT_UNWINDER_H 1
+
+/*
+ * init_unwinder(): make sure unwinder symbols are loaded
+ *
+ * libc's implementation of pthread_cancel() loads symbols from
+ * libgcc_s.so using dlopen() when pthread_cancel() is called
+ * for the first time. This happens even with LD_BIND_NOW=1.
+ * This may imply the need for file system access when a thread is
+ * cancelled, which in the case of multipath-tools might be in a
+ * dangerous situation where multipathd must avoid blocking.
+ *
+ * Call load_unwinder() during startup to make sure the dynamic
+ * linker has all necessary symbols resolved early on.
+ *
+ * Return: 0 if successful, an error number otherwise.
+ */
+int init_unwinder(void);
+
+#endif
diff --git a/multipathd/main.c b/multipathd/main.c
index 99a89a69..6f851ae8 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -83,6 +83,7 @@
#include "wwids.h"
#include "foreign.h"
#include "../third-party/valgrind/drd.h"
+#include "init_unwinder.h"
#define FILE_NAME_SIZE 256
#define CMDSIZE 160
@@ -3041,6 +3042,7 @@ child (__attribute__((unused)) void *param)
enum daemon_status state;
int exit_code = 1;
+ init_unwinder();
mlockall(MCL_CURRENT | MCL_FUTURE);
signal_init();
mp_rcu_data = setup_rcu();