diff mbox

[4/5] ntp: Do leapsecond adjustment in adjtimex read path

Message ID 1434063297-28657-5-git-send-email-john.stultz@linaro.org
State Accepted
Commit 96efdcf2d080687e041b0353c604b708546689fd
Headers show

Commit Message

John Stultz June 11, 2015, 10:54 p.m. UTC
Since the leapsecond is applied at tick-time, this
means there is a small window of time at the start
of a leap-second where we cross into the next second
before applying the leap.

This patch modified adjtimex so that the leap-second
is applied on the second edge. Providing more correct
leapsecond behavior.

This does make it so that adjtimex()'s returned time
values can be inconsistent with time values read from
gettimeofday() or clock_gettime(CLOCK_REALTIME,...)
for a brief period of one tick at the leapsecond.
However, those other interfaces do not provide the
TIME_OOP time_state return that adjtimex() provides, which
allows the leapsecond to be properly represented. They
instead only see a time discontinuity, and cannot tell the
first 23:59:59 from the repeated 23:59:59 leap second.

This seems like a reasonable tradeoff given clock_gettime()
/ gettimeofday() cannot properly represent a leapsecond,
and users likely care more about performance, while folks
who are using adjtimex() more likely care about leap-second
correctness.

Cc: Prarit Bhargava <prarit@redhat.com>
Cc: Daniel Bristot de Oliveira <bristot@redhat.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Jiri Bohac <jbohac@suse.cz>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
---
 kernel/time/ntp.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
diff mbox

Patch

diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 033743e..fb4d98c 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -740,6 +740,24 @@  int __do_adjtimex(struct timex *txc, struct timespec64 *ts, s32 *time_tai)
 	if (!(time_status & STA_NANO))
 		txc->time.tv_usec /= NSEC_PER_USEC;
 
+	/* Handle leapsec adjustments */
+	if (unlikely(ts->tv_sec >= ntp_next_leap_sec)) {
+		if ((time_state == TIME_INS) && (time_status & STA_INS)) {
+			result = TIME_OOP;
+			txc->tai++;
+			txc->time.tv_sec--;
+		}
+		if ((time_state == TIME_DEL) && (time_status & STA_DEL)) {
+			result = TIME_WAIT;
+			txc->tai--;
+			txc->time.tv_sec++;
+		}
+		if ((time_state == TIME_OOP) &&
+					(ts->tv_sec == ntp_next_leap_sec)) {
+			result = TIME_WAIT;
+		}
+	}
+
 	return result;
 }