aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/timekeeping.c
diff options
context:
space:
mode:
authorRoman Zippel <zippel@linux-m68k.org>2008-09-22 17:42:43 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-09-24 11:33:13 -0400
commit5cd1c9c5cf30d4b33df3d3f74d8142f278d536b7 (patch)
tree6d74ddeff7e9a044d961d36db13071c158f0557a /kernel/time/timekeeping.c
parenteb3f938fd6292dc79f43a5fe14784b044776e9f0 (diff)
timekeeping: fix rounding problem during clock update
Due to a rounding problem during a clock update it's possible for readers to observe the clock jumping back by 1nsec. The following simplified example demonstrates the problem: cycle xtime 0 0 1000 999999.6 2000 1999999.2 3000 2999998.8 ... 1500 = 1499999.4 = 0.0 + 1499999.4 = 999999.6 + 499999.8 When reading the clock only the full nanosecond part is used, while timekeeping internally keeps nanosecond fractions. If the clock is now updated at cycle 1500 here, a nanosecond is missing due to the truncation. The simple fix is to round up the xtime value during the update, this also changes the distance to the reference time, but the adjustment will automatically take care that it stays under control. Signed-off-by: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: John Stultz <johnstul@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time/timekeeping.c')
-rw-r--r--kernel/time/timekeeping.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index e91c29f961c9..5ecbfc39a268 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -454,7 +454,7 @@ void update_wall_time(void)
454#else 454#else
455 offset = clock->cycle_interval; 455 offset = clock->cycle_interval;
456#endif 456#endif
457 clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift; 457 clock->xtime_nsec = (s64)xtime.tv_nsec << clock->shift;
458 458
459 /* normally this loop will run just once, however in the 459 /* normally this loop will run just once, however in the
460 * case of lost or late ticks, it will accumulate correctly. 460 * case of lost or late ticks, it will accumulate correctly.
@@ -479,9 +479,12 @@ void update_wall_time(void)
479 /* correct the clock when NTP error is too big */ 479 /* correct the clock when NTP error is too big */
480 clocksource_adjust(offset); 480 clocksource_adjust(offset);
481 481
482 /* store full nanoseconds into xtime */ 482 /* store full nanoseconds into xtime after rounding it up and
483 xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift; 483 * add the remainder to the error difference.
484 */
485 xtime.tv_nsec = ((s64)clock->xtime_nsec >> clock->shift) + 1;
484 clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift; 486 clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift;
487 clock->error += clock->xtime_nsec << (NTP_SCALE_SHIFT - clock->shift);
485 488
486 update_xtime_cache(cyc2ns(clock, offset)); 489 update_xtime_cache(cyc2ns(clock, offset));
487 490