diff options
author | Benjamin Marzinski <bmarzins@redhat.com> | 2009-04-02 22:36:41 +0200 |
---|---|---|
committer | Christophe Varoqui <christophe.varoqui@free.fr> | 2009-04-02 22:36:41 +0200 |
commit | be6b014d785d0e6bc34d3a5f2ac531df8b3d8690 (patch) | |
tree | ce765485441464f882033334df3af411b905d878 | |
parent | 0a0319d381249760c71023edbe0ac9c093bb4a74 (diff) | |
download | multipath-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.c | 10 | ||||
-rw-r--r-- | libmultipath/lock.h | 3 | ||||
-rw-r--r-- | libmultipath/log_pthread.c | 8 | ||||
-rw-r--r-- | libmultipath/waiter.c | 5 | ||||
-rw-r--r-- | multipathd/main.c | 10 |
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); |