summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Marzinski <bmarzins@redhat.com>2009-04-02 22:36:41 +0200
committerChristophe Varoqui <christophe.varoqui@free.fr>2009-04-02 22:36:41 +0200
commitbe6b014d785d0e6bc34d3a5f2ac531df8b3d8690 (patch)
treece765485441464f882033334df3af411b905d878
parent0a0319d381249760c71023edbe0ac9c093bb4a74 (diff)
downloadmultipath-tools-be6b014d785d0e6bc34d3a5f2ac531df8b3d8690.tar.gz
multipath-tools-be6b014d785d0e6bc34d3a5f2ac531df8b3d8690.tar.bz2
multipath-tools-be6b014d785d0e6bc34d3a5f2ac531df8b3d8690.zip
[multipathd] signal deadlock
If multipathd is run with -v3, both the SIGHUP, and the SIGUSR1 signal handlers will log a message. If a multipathd thread receives one of these signals while it has a log lock held, it deadlocks itself. Also, the SIGHUP handler will grab the vecs lock, so if any thread receives a SIGHUP while holding the vecs lock, it deadlocks itself. This commit blocks the appropriate signals to guard against this.
-rw-r--r--libmultipath/lock.c10
-rw-r--r--libmultipath/lock.h3
-rw-r--r--libmultipath/log_pthread.c8
-rw-r--r--libmultipath/waiter.c5
-rw-r--r--multipathd/main.c10
5 files changed, 36 insertions, 0 deletions
diff --git a/libmultipath/lock.c b/libmultipath/lock.c
index 54e2988..4439a51 100644
--- a/libmultipath/lock.c
+++ b/libmultipath/lock.c
@@ -1,6 +1,16 @@
#include <pthread.h>
+#include <signal.h>
#include "lock.h"
#include <stdio.h>
+
+void block_signal (int signum, sigset_t *old)
+{
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, signum);
+ pthread_sigmask(SIG_BLOCK, &set, old);
+}
+
void cleanup_lock (void * data)
{
unlock ((*(struct mutex_lock *)data));
diff --git a/libmultipath/lock.h b/libmultipath/lock.h
index 1f9a0f3..6897a74 100644
--- a/libmultipath/lock.h
+++ b/libmultipath/lock.h
@@ -1,6 +1,8 @@
#ifndef _LOCK_H
#define _LOCK_H
+#include <signal.h>
+
/*
* Wrapper for the mutex. Includes a ref-count to keep
* track of how many there are out-standing threads blocking
@@ -27,5 +29,6 @@ struct mutex_lock {
#endif
void cleanup_lock (void * data);
+void block_signal(int signum, sigset_t *old);
#endif /* _LOCK_H */
diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c
index a1d4a10..6997cff 100644
--- a/libmultipath/log_pthread.c
+++ b/libmultipath/log_pthread.c
@@ -11,9 +11,15 @@
#include "log_pthread.h"
#include "log.h"
+#include "lock.h"
void log_safe (int prio, const char * fmt, va_list ap)
{
+ sigset_t old;
+
+ block_signal(SIGUSR1, &old);
+ block_signal(SIGHUP, NULL);
+
pthread_mutex_lock(logq_lock);
log_enqueue(prio, fmt, ap);
pthread_mutex_unlock(logq_lock);
@@ -21,6 +27,8 @@ void log_safe (int prio, const char * fmt, va_list ap)
pthread_mutex_lock(logev_lock);
pthread_cond_signal(logev_cond);
pthread_mutex_unlock(logev_lock);
+
+ pthread_sigmask(SIG_SETMASK, &old, NULL);
}
static void flush_logqueue (void)
diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c
index 28b810f..99bfdbf 100644
--- a/libmultipath/waiter.c
+++ b/libmultipath/waiter.c
@@ -32,11 +32,13 @@ struct event_thread *alloc_waiter (void)
void free_waiter (void *data)
{
+ sigset_t old;
struct event_thread *wp = (struct event_thread *)data;
/*
* indicate in mpp that the wp is already freed storage
*/
+ block_signal(SIGHUP, &old);
lock(wp->vecs->lock);
if (wp->mpp)
@@ -51,6 +53,7 @@ void free_waiter (void *data)
condlog(3, "free_waiter, mpp freed before wp=%p (%s).", wp, wp->mapname);
unlock(wp->vecs->lock);
+ pthread_sigmask(SIG_SETMASK, &old, NULL);
if (wp->dmt)
dm_task_destroy(wp->dmt);
@@ -185,6 +188,8 @@ void *waitevent (void *et)
waiter = (struct event_thread *)et;
pthread_cleanup_push(free_waiter, et);
+ block_signal(SIGUSR1, NULL);
+ block_signal(SIGHUP, NULL);
while (1) {
r = waiteventloop(waiter);
diff --git a/multipathd/main.c b/multipathd/main.c
index 9957f1f..a4ee10c 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -688,6 +688,9 @@ out:
static void *
ueventloop (void * ap)
{
+ block_signal(SIGUSR1, NULL);
+ block_signal(SIGHUP, NULL);
+
if (uevent_listen(&uev_trigger, ap))
fprintf(stderr, "error starting uevent listener");
@@ -697,6 +700,9 @@ ueventloop (void * ap)
static void *
uxlsnrloop (void * ap)
{
+ block_signal(SIGUSR1, NULL);
+ block_signal(SIGHUP, NULL);
+
if (cli_init())
return NULL;
@@ -1007,6 +1013,7 @@ checkerloop (void *ap)
struct path *pp;
int count = 0;
unsigned int i;
+ sigset_t old;
mlockall(MCL_CURRENT | MCL_FUTURE);
vecs = (struct vectors *)ap;
@@ -1020,6 +1027,7 @@ checkerloop (void *ap)
}
while (1) {
+ block_signal(SIGHUP, &old);
pthread_cleanup_push(cleanup_lock, &vecs->lock);
lock(vecs->lock);
condlog(4, "tick");
@@ -1042,6 +1050,7 @@ checkerloop (void *ap)
}
lock_cleanup_pop(vecs->lock);
+ pthread_sigmask(SIG_SETMASK, &old, NULL);
sleep(1);
}
return NULL;
@@ -1358,6 +1367,7 @@ child (void * param)
/*
* exit path
*/
+ block_signal(SIGHUP, NULL);
lock(vecs->lock);
remove_maps_and_stop_waiters(vecs);
free_pathvec(vecs->pathvec, FREE_PATHS);