From 9cacdceb085d5d9e7f63f38b65b74afd4a25cf81 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Tue, 11 May 2010 12:17:40 -0400 Subject: [PATCH] --- yaml --- r: 197835 b: refs/heads/master c: 489fb490dbf8dab0249ad82b56688ae3842a79e8 h: refs/heads/master i: 197833: c51a77db615a347a47a30fd8f4286e5513a56b02 197831: 9263fe75777000353eaec41a9c7cfd146dcb4da4 v: v3 --- [refs] | 2 +- trunk/arch/x86/kernel/pvclock.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index bff2bc37d13e..eb9d584e7138 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 424c32f1aa3112632a657d45698c8e7666668f78 +refs/heads/master: 489fb490dbf8dab0249ad82b56688ae3842a79e8 diff --git a/trunk/arch/x86/kernel/pvclock.c b/trunk/arch/x86/kernel/pvclock.c index f7fdd56bc0ab..f5bc40e1697e 100644 --- a/trunk/arch/x86/kernel/pvclock.c +++ b/trunk/arch/x86/kernel/pvclock.c @@ -118,11 +118,14 @@ unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src) return pv_tsc_khz; } +static atomic64_t last_value = ATOMIC64_INIT(0); + cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) { struct pvclock_shadow_time shadow; unsigned version; cycle_t ret, offset; + u64 last; do { version = pvclock_get_time_values(&shadow, src); @@ -132,6 +135,27 @@ cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) barrier(); } while (version != src->version); + /* + * Assumption here is that last_value, a global accumulator, always goes + * forward. If we are less than that, we should not be much smaller. + * We assume there is an error marging we're inside, and then the correction + * does not sacrifice accuracy. + * + * For reads: global may have changed between test and return, + * but this means someone else updated poked the clock at a later time. + * We just need to make sure we are not seeing a backwards event. + * + * For updates: last_value = ret is not enough, since two vcpus could be + * updating at the same time, and one of them could be slightly behind, + * making the assumption that last_value always go forward fail to hold. + */ + last = atomic64_read(&last_value); + do { + if (ret < last) + return last; + last = atomic64_cmpxchg(&last_value, last, ret); + } while (unlikely(last != ret)); + return ret; }