From e8b1ad4c2b3985eb9e826fd279e419719a2c03ce Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 4 Sep 2024 16:55:43 +0200 Subject: [PATCH] BUG/MEDIUM: clock: also update the date offset on time jumps In GH issue #2704, @swimlessbird and @xanoxes reported problems handling time jumps. Indeed, since 2.7 with commit 4eaf85f5d9 ("MINOR: clock: do not update the global date too often") we refrain from updating the global offset in case it didn't change. But there's a catch: in case of a large time jump, if the poller was interrupted, the local time remains the same and we return immediately from there without updating the offset. It then becomes incorrect regarding the "date" value, and upon subsequent call to the poller, there's no way to detect a jump anymore so we apply the old, incorrect offset and the date becomes wrong. Worse, going back to the original time (then in the past), global_now_ns remains higher than the local time and neither get updated anymore. What is missing in practice is to immediately update the offset when detecting a time jump. In an ideal world, the offset would be updated upon every call, that's what was being done prior to commit above but it's extremely CPU intensive on large systems. However we can perfectly afford to update the offset every time we detect a time jump, as it's not as common. This needs to be backported as far as 2.8. Thanks to both participants above for providing very helpful details. --- src/clock.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/clock.c b/src/clock.c index 7734389a71..296bf63320 100644 --- a/src/clock.c +++ b/src/clock.c @@ -222,6 +222,12 @@ void clock_update_local_date(int max_wait, int interrupted) __tv_islt(&max_deadline, &date))) { // big jump forwards if (!interrupted) now_ns += ms_to_ns(max_wait); + + /* this event is rare, but it requires proper handling because if + * we just left now_ns where it was, the date will not be updated + * by clock_update_global_date(). + */ + HA_ATOMIC_STORE(&now_offset, now_ns - tv_to_ns(&date)); } else { /* The date is still within expectations. Let's apply the * now_offset to the system date. Note: ofs if made of two