<div dir="ltr"><div>Hi Bart,</div><div><br></div>This patch seems to depend on another patch flagging tur.c some function static.<div>It seems I missed this patch. Is it tanked in your tree, and you want to post it for inclusion ? Or do you prefer to rebase this "clock jump" patch ?</div><div><br></div><div>Best regards,</div><div>Christophe Varoqui</div><div>OpenSVC</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Sep 29, 2016 at 11:29 PM, Bart Van Assche <span dir="ltr"><<a href="mailto:bart.vanassche@sandisk.com" target="_blank">bart.vanassche@sandisk.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Time synchronization software like ntpd can adjust the clock<br>
forwards and backwards. Avoid that the duration of a delay is<br>
influenced by clock jumps initiated by time synchronization<br>
software.<br>
<br>
Signed-off-by: Bart Van Assche <<a href="mailto:bart.vanassche@sandisk.com">bart.vanassche@sandisk.com</a>><br>
Cc: Mike Christie <<a href="mailto:mchristi@redhat.com">mchristi@redhat.com</a>><br>
---<br>
 libmultipath/Makefile       |  2 +-<br>
 libmultipath/checkers/rbd.c | 12 +++++-------<br>
 libmultipath/checkers/tur.c | 20 +++++++++-----------<br>
 libmultipath/time-util.c    | 42 ++++++++++++++++++++++++++++++<wbr>++++++++++++<br>
 libmultipath/time-util.h    | 13 +++++++++++++<br>
 multipathd/cli.c            |  6 ++----<br>
 multipathd/main.c           | 39 +++++++++++++++++++++++-------<wbr>---------<br>
 multipathd/uxlsnr.c         | 19 +++++++++++--------<br>
 8 files changed, 106 insertions(+), 47 deletions(-)<br>
 create mode 100644 libmultipath/time-util.c<br>
 create mode 100644 libmultipath/time-util.h<br>
<br>
diff --git a/libmultipath/Makefile b/libmultipath/Makefile<br>
index 92f130c..495cebe 100644<br>
--- a/libmultipath/Makefile<br>
+++ b/libmultipath/Makefile<br>
@@ -47,7 +47,7 @@ endif<br>
 OBJS = memory.o parser.o vector.o devmapper.o callout.o \<br>
        hwtable.o blacklist.o util.o dmparser.o config.o \<br>
        structs.o discovery.o propsel.o dict.o \<br>
-       pgpolicies.o debug.o defaults.o uevent.o \<br>
+       pgpolicies.o debug.o defaults.o uevent.o time-util.o \<br>
        switchgroup.o uxsock.o print.o alias.o log_pthread.o \<br>
        log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \<br>
        lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o<br>
diff --git a/libmultipath/checkers/rbd.c b/libmultipath/checkers/rbd.c<br>
index 41259c3..bfec2c9 100644<br>
--- a/libmultipath/checkers/rbd.c<br>
+++ b/libmultipath/checkers/rbd.c<br>
@@ -27,6 +27,7 @@<br>
<br>
 #include "../libmultipath/debug.h"<br>
 #include "../libmultipath/uevent.h"<br>
+#include "../libmultipath/time-util.h"<br>
<br>
 struct rbd_checker_context;<br>
 typedef int (thread_fn)(struct rbd_checker_context *ct, char *msg);<br>
@@ -75,7 +76,7 @@ int libcheck_init(struct checker * c)<br>
                return 1;<br>
        memset(ct, 0, sizeof(struct rbd_checker_context));<br>
        ct->holders = 1;<br>
-       pthread_cond_init(&ct->active, NULL);<br>
+       pthread_cond_init_mono(&ct-><wbr>active);<br>
        pthread_mutex_init(&ct->lock, NULL);<br>
        pthread_spin_init(&ct->hldr_<wbr>lock, PTHREAD_PROCESS_PRIVATE);<br>
        c->context = ct;<br>
@@ -538,12 +539,9 @@ static void *rbd_thread(void *ctx)<br>
<br>
 static void rbd_timeout(struct timespec *tsp)<br>
 {<br>
-       struct timeval now;<br>
-<br>
-       gettimeofday(&now, NULL);<br>
-       tsp->tv_sec = now.tv_sec;<br>
-       tsp->tv_nsec = now.tv_usec * 1000;<br>
-       tsp->tv_nsec += 1000000; /* 1 millisecond */<br>
+       clock_gettime(CLOCK_MONOTONIC, tsp);<br>
+       tsp->tv_nsec += 1000 * 1000; /* 1 millisecond */<br>
+       normalize_timespec(tsp);<br>
 }<br>
<br>
 static int rbd_exec_fn(struct checker *c, thread_fn *fn)<br>
diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c<br>
index 94e4190..ac272d4 100644<br>
--- a/libmultipath/checkers/tur.c<br>
+++ b/libmultipath/checkers/tur.c<br>
@@ -20,6 +20,7 @@<br>
 #include "../libmultipath/debug.h"<br>
 #include "../libmultipath/sg_include.h"<br>
 #include "../libmultipath/uevent.h"<br>
+#include "../libmultipath/time-util.h"<br>
<br>
 #define TUR_CMD_LEN 6<br>
 #define HEAVY_CHECK_COUNT       10<br>
@@ -60,7 +61,7 @@ int libcheck_init (struct checker * c)<br>
        ct->state = PATH_UNCHECKED;<br>
        ct->fd = -1;<br>
        ct->holders = 1;<br>
-       pthread_cond_init(&ct->active, NULL);<br>
+       pthread_cond_init_mono(&ct-><wbr>active);<br>
        pthread_mutex_init(&ct->lock, NULL);<br>
        pthread_spin_init(&ct->hldr_<wbr>lock, PTHREAD_PROCESS_PRIVATE);<br>
        c->context = ct;<br>
@@ -237,29 +238,26 @@ static void *tur_thread(void *ctx)<br>
<br>
 static void tur_timeout(struct timespec *tsp)<br>
 {<br>
-       struct timeval now;<br>
-<br>
-       gettimeofday(&now, NULL);<br>
-       tsp->tv_sec = now.tv_sec;<br>
-       tsp->tv_nsec = now.tv_usec * 1000;<br>
-       tsp->tv_nsec += 1000000; /* 1 millisecond */<br>
+       clock_gettime(CLOCK_MONOTONIC, tsp);<br>
+       tsp->tv_nsec += 1000 * 1000; /* 1 millisecond */<br>
+       normalize_timespec(tsp);<br>
 }<br>
<br>
 static void tur_set_async_timeout(struct checker *c)<br>
 {<br>
        struct tur_checker_context *ct = c->context;<br>
-       struct timeval now;<br>
+       struct timespec now;<br>
<br>
-       gettimeofday(&now, NULL);<br>
+       clock_gettime(CLOCK_MONOTONIC, &now);<br>
        ct->time = now.tv_sec + c->timeout;<br>
 }<br>
<br>
 static int tur_check_async_timeout(struct checker *c)<br>
 {<br>
        struct tur_checker_context *ct = c->context;<br>
-       struct timeval now;<br>
+       struct timespec now;<br>
<br>
-       gettimeofday(&now, NULL);<br>
+       clock_gettime(CLOCK_MONOTONIC, &now);<br>
        return (now.tv_sec > ct->time);<br>
 }<br>
<br>
diff --git a/libmultipath/time-util.c b/libmultipath/time-util.c<br>
new file mode 100644<br>
index 0000000..6d79c0e<br>
--- /dev/null<br>
+++ b/libmultipath/time-util.c<br>
@@ -0,0 +1,42 @@<br>
+#include <assert.h><br>
+#include <pthread.h><br>
+#include <time.h><br>
+#include "time-util.h"<br>
+<br>
+/* Initialize @cond as a condition variable that uses the monotonic clock */<br>
+void pthread_cond_init_mono(<wbr>pthread_cond_t *cond)<br>
+{<br>
+       pthread_condattr_t attr;<br>
+       int res;<br>
+<br>
+       res = pthread_condattr_init(&attr);<br>
+       assert(res == 0);<br>
+       res = pthread_condattr_setclock(&<wbr>attr, CLOCK_MONOTONIC);<br>
+       assert(res == 0);<br>
+       res = pthread_cond_init(cond, &attr);<br>
+       assert(res == 0);<br>
+       res = pthread_condattr_destroy(&<wbr>attr);<br>
+       assert(res == 0);<br>
+}<br>
+<br>
+/* Ensure that 0 <= ts->tv_nsec && ts->tv_nsec < 1000 * 1000 * 1000. */<br>
+void normalize_timespec(struct timespec *ts)<br>
+{<br>
+       while (ts->tv_nsec < 0) {<br>
+               ts->tv_nsec += 1000UL * 1000 * 1000;<br>
+               ts->tv_sec--;<br>
+       }<br>
+       while (ts->tv_nsec >= 1000UL * 1000 * 1000) {<br>
+               ts->tv_nsec -= 1000UL * 1000 * 1000;<br>
+               ts->tv_sec++;<br>
+       }<br>
+}<br>
+<br>
+/* Compute *res = *a - *b */<br>
+void timespecsub(const struct timespec *a, const struct timespec *b,<br>
+                struct timespec *res)<br>
+{<br>
+       res->tv_sec = a->tv_sec - b->tv_sec;<br>
+       res->tv_nsec = a->tv_nsec - b->tv_nsec;<br>
+       normalize_timespec(res);<br>
+}<br>
diff --git a/libmultipath/time-util.h b/libmultipath/time-util.h<br>
new file mode 100644<br>
index 0000000..b76d2aa<br>
--- /dev/null<br>
+++ b/libmultipath/time-util.h<br>
@@ -0,0 +1,13 @@<br>
+#ifndef _TIME_UTIL_H_<br>
+#define _TIME_UTIL_H_<br>
+<br>
+#include <pthread.h><br>
+<br>
+struct timespec;<br>
+<br>
+void pthread_cond_init_mono(<wbr>pthread_cond_t *cond);<br>
+void normalize_timespec(struct timespec *ts);<br>
+void timespecsub(const struct timespec *a, const struct timespec *b,<br>
+                struct timespec *res);<br>
+<br>
+#endif /* _TIME_UTIL_H_ */<br>
diff --git a/multipathd/cli.c b/multipathd/cli.c<br>
index 9a19728..e8a9384 100644<br>
--- a/multipathd/cli.c<br>
+++ b/multipathd/cli.c<br>
@@ -454,7 +454,6 @@ parse_cmd (char * cmd, char ** reply, int * len, void * data, int timeout )<br>
        struct handler * h;<br>
        vector cmdvec = NULL;<br>
        struct timespec tmo;<br>
-       struct timeval now;<br>
<br>
        r = get_cmdvec(cmd, &cmdvec);<br>
<br>
@@ -476,9 +475,8 @@ parse_cmd (char * cmd, char ** reply, int * len, void * data, int timeout )<br>
        /*<br>
         * execute handler<br>
         */<br>
-       if (gettimeofday(&now, NULL) == 0) {<br>
-               tmo.tv_sec = now.tv_sec + timeout;<br>
-               tmo.tv_nsec = now.tv_usec * 1000;<br>
+       if (clock_gettime(CLOCK_<wbr>MONOTONIC, &tmo) == 0) {<br>
+               tmo.tv_sec += timeout;<br>
        } else {<br>
                tmo.tv_sec = 0;<br>
        }<br>
diff --git a/multipathd/main.c b/multipathd/main.c<br>
index 96ef01f..76c049f 100644<br>
--- a/multipathd/main.c<br>
+++ b/multipathd/main.c<br>
@@ -25,6 +25,11 @@<br>
 #include <time.h><br>
<br>
 /*<br>
+ * libmultipath<br>
+ */<br>
+#include "time-util.h"<br>
+<br>
+/*<br>
  * libcheckers<br>
  */<br>
 #include "checkers.h"<br>
@@ -106,7 +111,7 @@ int ignore_new_devs;<br>
 enum daemon_status running_state = DAEMON_INIT;<br>
 pid_t daemon_pid;<br>
 pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER;<br>
-pthread_cond_t config_cond = PTHREAD_COND_INITIALIZER;<br>
+pthread_cond_t config_cond;<br>
<br>
 /*<br>
  * global copy of vecs for use in sig handlers<br>
@@ -193,7 +198,7 @@ int set_config_state(enum daemon_status state)<br>
                if (running_state != DAEMON_IDLE) {<br>
                        struct timespec ts;<br>
<br>
-                       clock_gettime(CLOCK_REALTIME, &ts);<br>
+                       clock_gettime(CLOCK_MONOTONIC, &ts);<br>
                        ts.tv_sec += 1;<br>
                        rc = pthread_cond_timedwait(&<wbr>config_cond,<br>
                                                    &config_lock, &ts);<br>
@@ -1744,7 +1749,7 @@ checkerloop (void *ap)<br>
        int count = 0;<br>
        unsigned int i;<br>
        struct itimerval timer_tick_it;<br>
-       struct timeval last_time;<br>
+       struct timespec last_time;<br>
        struct config *conf;<br>
<br>
        pthread_cleanup_push(rcu_<wbr>unregister, NULL);<br>
@@ -1763,24 +1768,23 @@ checkerloop (void *ap)<br>
        }<br>
<br>
        /* Tweak start time for initial path check */<br>
-       if (gettimeofday(&last_time, NULL) != 0)<br>
+       if (clock_gettime(CLOCK_<wbr>MONOTONIC, &last_time) != 0)<br>
                last_time.tv_sec = 0;<br>
        else<br>
                last_time.tv_sec -= 1;<br>
<br>
        while (1) {<br>
-               struct timeval diff_time, start_time, end_time;<br>
+               struct timespec diff_time, start_time, end_time;<br>
                int num_paths = 0, ticks = 0, signo, strict_timing, rc = 0;<br>
                sigset_t mask;<br>
<br>
-               if (gettimeofday(&start_time, NULL) != 0)<br>
+               if (clock_gettime(CLOCK_<wbr>MONOTONIC, &start_time) != 0)<br>
                        start_time.tv_sec = 0;<br>
                if (start_time.tv_sec && last_time.tv_sec) {<br>
-                       timersub(&start_time, &last_time, &diff_time);<br>
+                       timespecsub(&start_time, &last_time, &diff_time);<br>
                        condlog(4, "tick (%lu.%06lu secs)",<br>
-                               diff_time.tv_sec, diff_time.tv_usec);<br>
-                       last_time.tv_sec = start_time.tv_sec;<br>
-                       last_time.tv_usec = start_time.tv_usec;<br>
+                               diff_time.tv_sec, diff_time.tv_nsec / 1000);<br>
+                       last_time = start_time;<br>
                        ticks = diff_time.tv_sec;<br>
                } else {<br>
                        ticks = 1;<br>
@@ -1831,16 +1835,17 @@ checkerloop (void *ap)<br>
                        lock_cleanup_pop(vecs->lock);<br>
                }<br>
<br>
-               diff_time.tv_usec = 0;<br>
+               diff_time.tv_nsec = 0;<br>
                if (start_time.tv_sec &&<br>
-                   gettimeofday(&end_time, NULL) == 0) {<br>
-                       timersub(&end_time, &start_time, &diff_time);<br>
+                   clock_gettime(CLOCK_MONOTONIC, &end_time) == 0) {<br>
+                       timespecsub(&end_time, &start_time, &diff_time);<br>
                        if (num_paths) {<br>
                                unsigned int max_checkint;<br>
<br>
                                condlog(3, "checked %d path%s in %lu.%06lu secs",<br>
                                        num_paths, num_paths > 1 ? "s" : "",<br>
-                                       diff_time.tv_sec, diff_time.tv_usec);<br>
+                                       diff_time.tv_sec,<br>
+                                       diff_time.tv_nsec / 1000);<br>
                                conf = get_multipath_config();<br>
                                max_checkint = conf->max_checkint;<br>
                                put_multipath_config(conf);<br>
@@ -1861,10 +1866,10 @@ checkerloop (void *ap)<br>
                else {<br>
                        timer_tick_it.it_interval.tv_<wbr>sec = 0;<br>
                        timer_tick_it.it_interval.tv_<wbr>usec = 0;<br>
-                       if (diff_time.tv_usec) {<br>
+                       if (diff_time.tv_nsec) {<br>
                                timer_tick_it.it_value.tv_sec = 0;<br>
                                timer_tick_it.it_value.tv_usec =<br>
-                                       (unsigned long)1000000 - diff_time.tv_usec;<br>
+                                    1000ULL * 1000 * 1000 - diff_time.tv_nsec;<br>
                        } else {<br>
                                timer_tick_it.it_value.tv_sec = 1;<br>
                                timer_tick_it.it_value.tv_usec = 0;<br>
@@ -2523,6 +2528,8 @@ main (int argc, char *argv[])<br>
                        strerror(errno));<br>
        umask(umask(077) | 022);<br>
<br>
+       pthread_cond_init_mono(&<wbr>config_cond);<br>
+<br>
        udev = udev_new();<br>
<br>
        while ((arg = getopt(argc, argv, ":dsv:k::Bn")) != EOF ) {<br>
diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c<br>
index 7a9faf3..daaaa99 100644<br>
--- a/multipathd/uxlsnr.c<br>
+++ b/multipathd/uxlsnr.c<br>
@@ -32,6 +32,7 @@<br>
 #include "defaults.h"<br>
 #include "config.h"<br>
 #include "mpath_cmd.h"<br>
+#include "time-util.h"<br>
<br>
 #include "main.h"<br>
 #include "cli.h"<br>
@@ -99,21 +100,22 @@ void free_polls (void)<br>
                FREE(polls);<br>
 }<br>
<br>
-void check_timeout(struct timeval start_time, char *inbuf,<br>
+void check_timeout(struct timespec start_time, char *inbuf,<br>
                   unsigned int timeout)<br>
 {<br>
-       struct timeval diff_time, end_time;<br>
+       struct timespec diff_time, end_time;<br>
<br>
-       if (start_time.tv_sec && gettimeofday(&end_time, NULL) == 0) {<br>
-               timersub(&end_time, &start_time, &diff_time);<br>
+       if (start_time.tv_sec &&<br>
+           clock_gettime(CLOCK_MONOTONIC, &end_time) == 0) {<br>
                unsigned long msecs;<br>
<br>
+               timespecsub(&end_time, &start_time, &diff_time);<br>
                msecs = diff_time.tv_sec * 1000 +<br>
-                       diff_time.tv_usec / 1000;<br>
+                       diff_time.tv_nsec / (1000 * 1000);<br>
                if (msecs > timeout)<br>
                        condlog(2, "cli cmd '%s' timeout reached "<br>
                                "after %lu.%06lu secs", inbuf,<br>
-                               diff_time.tv_sec, diff_time.tv_usec);<br>
+                               diff_time.tv_sec, diff_time.tv_nsec / 1000);<br>
        }<br>
 }<br>
<br>
@@ -220,7 +222,7 @@ void * uxsock_listen(uxsock_trigger_<wbr>fn uxsock_trigger, void * trigger_data)<br>
                /* see if a client wants to speak to us */<br>
                for (i = 1; i < num_clients + 1; i++) {<br>
                        if (polls[i].revents & POLLIN) {<br>
-                               struct timeval start_time;<br>
+                               struct timespec start_time;<br>
<br>
                                c = NULL;<br>
                                pthread_mutex_lock(&client_<wbr>lock);<br>
@@ -236,7 +238,8 @@ void * uxsock_listen(uxsock_trigger_<wbr>fn uxsock_trigger, void * trigger_data)<br>
                                                i, polls[i].fd);<br>
                                        continue;<br>
                                }<br>
-                               if (gettimeofday(&start_time, NULL) != 0)<br>
+                               if (clock_gettime(CLOCK_<wbr>MONOTONIC, &start_time)<br>
+                                   != 0)<br>
                                        start_time.tv_sec = 0;<br>
                                if (recv_packet(c->fd, &inbuf,<br>
                                                uxsock_timeout) != 0) {<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.10.0<br>
<br>
</font></span></blockquote></div><br></div>