aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Stultz <[email protected]>2015-03-11 21:16:34 -0700
committerIngo Molnar <[email protected]>2015-03-13 08:07:05 +0100
commit057b87e3161d1194a095718f9918c01b2c389e74 (patch)
tree8f6b79b5f9d6c12b8a53148e04961081eb9f3243
parenta558cd021d83b65c47ee5b9bec1fcfe5298a769f (diff)
timekeeping: Try to catch clocksource delta underflows
In the case where there is a broken clocksource where there are multiple actual clocks that aren't perfectly aligned, we may see small "negative" deltas when we subtract 'now' from 'cycle_last'. The values are actually negative with respect to the clocksource mask value, not necessarily negative if cast to a s64, but we can check by checking the delta to see if it is a small (relative to the mask) negative value (again negative relative to the mask). If so, we assume we jumped backwards somehow and instead use zero for our delta. Signed-off-by: John Stultz <[email protected]> Cc: Dave Jones <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Prarit Bhargava <[email protected]> Cc: Richard Cochran <[email protected]> Cc: Stephen Boyd <[email protected]> Cc: Thomas Gleixner <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
-rw-r--r--kernel/time/timekeeping.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 657414cf2e46..187149be83ea 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -148,6 +148,13 @@ static inline cycle_t timekeeping_get_delta(struct tk_read_base *tkr)
/* calculate the delta since the last update_wall_time */
delta = clocksource_delta(cycle_now, tkr->cycle_last, tkr->mask);
+ /*
+ * Try to catch underflows by checking if we are seeing small
+ * mask-relative negative values.
+ */
+ if (unlikely((~delta & tkr->mask) < (tkr->mask >> 3)))
+ delta = 0;
+
/* Cap delta value to the max_cycles values to avoid mult overflows */
if (unlikely(delta > tkr->clock->max_cycles))
delta = tkr->clock->max_cycles;