aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/pvclock.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c
index f7fdd56bc0ab..f5bc40e1697e 100644
--- a/arch/x86/kernel/pvclock.c
+++ b/arch/x86/kernel/pvclock.c
@@ -118,11 +118,14 @@ unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src)
118 return pv_tsc_khz; 118 return pv_tsc_khz;
119} 119}
120 120
121static atomic64_t last_value = ATOMIC64_INIT(0);
122
121cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) 123cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
122{ 124{
123 struct pvclock_shadow_time shadow; 125 struct pvclock_shadow_time shadow;
124 unsigned version; 126 unsigned version;
125 cycle_t ret, offset; 127 cycle_t ret, offset;
128 u64 last;
126 129
127 do { 130 do {
128 version = pvclock_get_time_values(&shadow, src); 131 version = pvclock_get_time_values(&shadow, src);
@@ -132,6 +135,27 @@ cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
132 barrier(); 135 barrier();
133 } while (version != src->version); 136 } while (version != src->version);
134 137
138 /*
139 * Assumption here is that last_value, a global accumulator, always goes
140 * forward. If we are less than that, we should not be much smaller.
141 * We assume there is an error marging we're inside, and then the correction
142 * does not sacrifice accuracy.
143 *
144 * For reads: global may have changed between test and return,
145 * but this means someone else updated poked the clock at a later time.
146 * We just need to make sure we are not seeing a backwards event.
147 *
148 * For updates: last_value = ret is not enough, since two vcpus could be
149 * updating at the same time, and one of them could be slightly behind,
150 * making the assumption that last_value always go forward fail to hold.
151 */
152 last = atomic64_read(&last_value);
153 do {
154 if (ret < last)
155 return last;
156 last = atomic64_cmpxchg(&last_value, last, ret);
157 } while (unlikely(last != ret));
158
135 return ret; 159 return ret;
136} 160}
137 161