I noticed that ntpd(8) was regularly reporting it was unsynced, which
in turn impacts down stream clients.

ntpd_adjtime() in usr.sbin/ntpd/ntpd.c uses the olddelta returned by
adjtime(2) to determine whether the previous adjustment was completed.
The clock is considered to be synced only if olddelta is zero. However,
olddelta may be returned using a non-normalised zero, which is not the
zero that ntpd_adjtime() is expecting. ntpd(8) will then report that it
is unsynced, even though the previous adjustment was completed.

The non-normalised zero arises from the adjustment calculation
performed by ntp_update_second() in sys/kern/kern_tc.c. Consider a
-100usec adjustment applied by adjtime(2):
        adjtimedelta = { tv_sec = -1, tv_usec = 999900 }
ntp_update_second() will then calculate a non-normalised adj:
        adj = { tv_sec = 0, tv_usec = -100 }
and call timersub() to apply adj to adjtimedelta. In response to the
non-normalised adj timersub() produces a non-normalised zero:
        adjtimedelta = { tv_sec = -1, tv_usec = 1000000 }.

With the diff below I find ntpd(8) loses sync far less often.

Nathanael

Index: kern_tc.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_tc.c,v
retrieving revision 1.21
diff -u -p -r1.21 kern_tc.c
--- kern_tc.c   6 Oct 2013 01:27:49 -0000       1.21
+++ kern_tc.c   28 Jan 2014 16:12:30 -0000
@@ -623,9 +623,13 @@ ntp_update_second(int64_t *adjust, time_
                adj.tv_usec = -5000;
        else if (adjtimedelta.tv_sec == -1)
                adj.tv_usec = MAX(-5000, adjtimedelta.tv_usec - 1000000);
-       timersub(&adjtimedelta, &adj, &adjtimedelta);
        *adjust = ((int64_t)adj.tv_usec * 1000) << 32;
        *adjust += timecounter->tc_freq_adj;
+       if (adj.tv_usec < 0) {
+               adj.tv_sec = -1;
+               adj.tv_usec += 1000000;
+       }
+       timersub(&adjtimedelta, &adj, &adjtimedelta);
 }
 
 int

Reply via email to