diff options
-rw-r--r-- | arch/x86/kernel/pvclock.c | 24 |
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 | ||
121 | static atomic64_t last_value = ATOMIC64_INIT(0); | ||
122 | |||
121 | cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) | 123 | cycle_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 | ||