Commit 6edc4f5f authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Time precision, adjtime(x) vs. gettimeofday

From: Stephen Hemminger <shemminger@osdl.org>

The following will prevent adjtime from causing time regression.  It delays
starting the adjtime mechanism for one tick, and keeps gettimeofday inside
the window.

Only fixes i386, but changes to other arch would be similar.

Running a simple clock test program and playing with adjtime demonstrates
that this fixes the problem (and 2.6.0-test6 is broken).  But given the
fragile nature of the timer code, it should go through some more testing
before inclusion.
parent 83c87843
......@@ -104,6 +104,15 @@ void do_gettimeofday(struct timeval *tv)
lost = jiffies - wall_jiffies;
if (lost)
usec += lost * (1000000 / HZ);
/*
* If time_adjust is negative then NTP is slowing the clock
* so make sure not to go into next possible interval.
* Better to lose some accuracy than have time go backwards..
*/
if (unlikely(time_adjust < 0) && usec > tickadj)
usec = tickadj;
sec = xtime.tv_sec;
usec += (xtime.tv_nsec / 1000);
} while (read_seqretry(&xtime_lock, seq));
......
......@@ -302,6 +302,7 @@ extern long time_adj; /* tick adjust (scaled 1 / HZ) */
extern long time_reftime; /* time at last adjustment (s) */
extern long time_adjust; /* The amount of adjtime left */
extern long time_next_adjust; /* Value for time_adjust at next tick */
/* interface variables pps->timer interrupt */
extern long pps_offset; /* pps time offset (us) */
......
......@@ -236,7 +236,7 @@ int do_adjtimex(struct timex *txc)
result = time_state; /* mostly `TIME_OK' */
/* Save for later - semantics of adjtime is to return old value */
save_adjust = time_adjust;
save_adjust = time_next_adjust ? time_next_adjust : time_adjust;
#if 0 /* STA_CLOCKERR is never set yet */
time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */
......@@ -283,7 +283,8 @@ int do_adjtimex(struct timex *txc)
if (txc->modes & ADJ_OFFSET) { /* values checked earlier */
if (txc->modes == ADJ_OFFSET_SINGLESHOT) {
/* adjtime() is independent from ntp_adjtime() */
time_adjust = txc->offset;
if ((time_next_adjust = txc->offset) == 0)
time_adjust = 0;
}
else if ( time_status & (STA_PLL | STA_PPSTIME) ) {
ltemp = (time_status & (STA_PPSTIME | STA_PPSSIGNAL)) ==
......
......@@ -474,6 +474,7 @@ long time_freq = (((NSEC_PER_SEC + HZ/2) % HZ - HZ/2) << SHIFT_USEC) / NSEC_PER_
long time_adj; /* tick adjust (scaled 1 / HZ) */
long time_reftime; /* time at last adjustment (s) */
long time_adjust;
long time_next_adjust;
/*
* this routine handles the overflow of the microsecond field
......@@ -654,6 +655,12 @@ static void update_wall_time_one_tick(void)
}
xtime.tv_nsec += delta_nsec;
time_interpolator_update(delta_nsec);
/* Changes by adjtime() do not take effect till next tick. */
if (time_next_adjust != 0) {
time_adjust = time_next_adjust;
time_next_adjust = 0;
}
}
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment