about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2015-03-09 20:22:23 +0000
committerEric Wong <e@80x24.org>2015-03-09 20:39:10 +0000
commitc659acbb8d7a6b0c8098646981124a47f15cceae (patch)
tree41667f3f21e4870cbfed41f89944921637779134
parent1a7f32d0d8a48b9f26f595d0fa9f5db0c657bc3a (diff)
downloadcmogstored-c659acbb8d7a6b0c8098646981124a47f15cceae.tar.gz
During the initial device scan, it is possible for the waiter to be
interrupted while awaiting cancellation.  We must account for this
on all platforms regardless of whether pselect or ppoll is used.

Reported-by: Mykola Golub <trociny@FreeBSD.org>
-rw-r--r--cmogstored.h2
-rw-r--r--mnt.c6
-rw-r--r--sig.c26
3 files changed, 24 insertions, 10 deletions
diff --git a/cmogstored.h b/cmogstored.h
index c6c5291..a7309b5 100644
--- a/cmogstored.h
+++ b/cmogstored.h
@@ -291,7 +291,7 @@ struct mog_file {
 extern sigset_t mog_emptyset;
 void mog_intr_disable(void);
 void mog_intr_enable(void);
-void mog_sleep(long seconds);
+int mog_sleep(long seconds);
 #include "selfwake.h"
 
 enum mog_fd_type {
diff --git a/mnt.c b/mnt.c
index 0de0bb9..ca4bdf8 100644
--- a/mnt.c
+++ b/mnt.c
@@ -122,6 +122,7 @@ skip:
 static void * init_once(void *ptr)
 {
         struct init_args *ia = ptr;
+        int err;
 
         CHECK(int, 0, pthread_mutex_lock(&by_dev_lock) );
         assert(by_dev == NULL &&
@@ -135,7 +136,10 @@ static void * init_once(void *ptr)
         CHECK(int, 0, pthread_cond_signal(&ia->cond));
         CHECK(int, 0, pthread_mutex_unlock(&ia->cond_lock));
 
-        mog_sleep(-1); /* wait for cancellation */
+        /* wait for cancellation, mog_sleep may return ENOMEM or EINTR */
+        do {
+                err = mog_sleep(-1);
+        } while (err == EINTR || err == ENOMEM);
         assert(0 && "init_once did not get cancelled");
         return NULL;
 }
diff --git a/sig.c b/sig.c
index c04117a..cfbffc2 100644
--- a/sig.c
+++ b/sig.c
@@ -32,23 +32,33 @@ void mog_intr_enable(void)
  * would increase the size of the executable
  */
 #ifdef HAVE_PPOLL
-static void sleeper(struct timespec *tsp, const sigset_t *sigmask)
+static int sleeper(struct timespec *tsp, const sigset_t *sigmask)
 {
-        if (ppoll(NULL, 0, tsp, sigmask) < 0)
-                assert((errno == EINTR || errno == ENOMEM) &&
+        int err = 0;
+
+        if (ppoll(NULL, 0, tsp, sigmask) < 0) {
+                err = errno;
+                assert((err == EINTR || err == ENOMEM) &&
                        "BUG in ppoll usage");
+        }
+        return err;
 }
 #else /* PSELECT */
-static void sleeper(struct timespec *tsp, const sigset_t *sigmask)
+static int sleeper(struct timespec *tsp, const sigset_t *sigmask)
 {
-        if (pselect(0, NULL, NULL, NULL, tsp, sigmask) < 0)
-                assert((errno == EINTR || errno == ENOMEM) &&
+        int err = 0;
+
+        if (pselect(0, NULL, NULL, NULL, tsp, sigmask) < 0) {
+                err = errno;
+                assert((err == EINTR || err == ENOMEM) &&
                        "BUG in pselect usage");
+        }
+        return err;
 }
 #endif /* PSELECT */
 
 /* thread-safe, interruptible sleep, negative seconds -> sleep forever */
-void mog_sleep(long seconds)
+int mog_sleep(long seconds)
 {
         struct timespec ts;
         struct timespec *tsp;
@@ -61,5 +71,5 @@ void mog_sleep(long seconds)
                 tsp = &ts;
         }
 
-        sleeper(tsp, &mog_emptyset);
+        return sleeper(tsp, &mog_emptyset);
 }