multipathd: fix signal blocking logic
authorMartin Wilck <mwilck@suse.com>
Mon, 5 Mar 2018 23:15:07 +0000 (00:15 +0100)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Wed, 7 Mar 2018 09:40:32 +0000 (10:40 +0100)
multipathd is supposed to block all signals in all threads, except
the uxlsnr thread which handles termination and reconfiguration
signals (SIGUSR1) in its ppoll() call, SIGUSR2 in the waiter thread
and the marginal path checker thread, and occasional SIGALRM. The current
logic does exactly the oppsite, it blocks termination signals in SIGPOLL and
allows multipathd to be killed e.g. by SIGALRM.

Fix that by inverting the logic. The argument to pthread_sigmask and
ppoll is the set of *blocked* signals, not vice versa.

The marginal paths code needs to unblock SIGUSR2 now explicity, as
the dm-event waiter code already does. Doing this with pselect()
avoids asynchronous cancellation.

Fixes: 810082e "libmultipath, multipathd: Rework SIGPIPE handling"
Fixes: 534ec4c "multipathd: Ensure that SIGINT, SIGTERM, SIGHUP and SIGUSR1
are delivered to the uxsock thread"

Signed-off-by: Martin Wilck <mwilck@suse.com>
libmultipath/io_err_stat.c
multipathd/main.c
multipathd/uxlsnr.c

index 5b10f03..00bac9e 100644 (file)
@@ -21,6 +21,7 @@
 #include <libaio.h>
 #include <errno.h>
 #include <sys/mman.h>
+#include <sys/select.h>
 
 #include "vector.h"
 #include "memory.h"
@@ -691,14 +692,28 @@ static void service_paths(void)
 
 static void *io_err_stat_loop(void *data)
 {
+       sigset_t set;
+
        vecs = (struct vectors *)data;
        pthread_cleanup_push(rcu_unregister, NULL);
        rcu_register_thread();
 
+       sigfillset(&set);
+       sigdelset(&set, SIGUSR2);
+
        mlockall(MCL_CURRENT | MCL_FUTURE);
        while (1) {
+               struct timespec ts;
+
                service_paths();
-               usleep(100000);
+
+               ts.tv_sec = 0;
+               ts.tv_nsec = 100 * 1000 * 1000;
+               /*
+                * pselect() with no fds, a timeout, and a sigmask:
+                * sleep for 100ms and react on SIGUSR2.
+                */
+               pselect(1, NULL, NULL, NULL, &ts, &set);
        }
 
        pthread_cleanup_pop(1);
index 97c5f70..3c86c72 100644 (file)
@@ -2243,10 +2243,13 @@ signal_init(void)
 {
        sigset_t set;
 
-       sigemptyset(&set);
-       sigaddset(&set, SIGUSR2);
+       /* block all signals */
+       sigfillset(&set);
+       /* SIGPIPE occurs if logging fails */
+       sigdelset(&set, SIGPIPE);
        pthread_sigmask(SIG_SETMASK, &set, NULL);
 
+       /* Other signals will be unblocked in the uxlsnr thread */
        signal_set(SIGHUP, sighup);
        signal_set(SIGUSR1, sigusr1);
        signal_set(SIGUSR2, sigusr2);
index 52901a5..0531061 100644 (file)
@@ -189,11 +189,11 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data)
                condlog(0, "uxsock: failed to allocate poll fds");
                return NULL;
        }
-       sigemptyset(&mask);
-       sigaddset(&mask, SIGINT);
-       sigaddset(&mask, SIGTERM);
-       sigaddset(&mask, SIGHUP);
-       sigaddset(&mask, SIGUSR1);
+       sigfillset(&mask);
+       sigdelset(&mask, SIGINT);
+       sigdelset(&mask, SIGTERM);
+       sigdelset(&mask, SIGHUP);
+       sigdelset(&mask, SIGUSR1);
        while (1) {
                struct client *c, *tmp;
                int i, poll_count, num_clients;