diff options
Diffstat (limited to 'arch/x86/vdso/vclock_gettime.c')
-rw-r--r-- | arch/x86/vdso/vclock_gettime.c | 34 |
1 files changed, 19 insertions, 15 deletions
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 9793322751e0..40d2473836c9 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c | |||
@@ -82,18 +82,15 @@ static notrace cycle_t vread_pvclock(int *mode) | |||
82 | cycle_t ret; | 82 | cycle_t ret; |
83 | u64 last; | 83 | u64 last; |
84 | u32 version; | 84 | u32 version; |
85 | u32 migrate_count; | ||
85 | u8 flags; | 86 | u8 flags; |
86 | unsigned cpu, cpu1; | 87 | unsigned cpu, cpu1; |
87 | 88 | ||
88 | 89 | ||
89 | /* | 90 | /* |
90 | * Note: hypervisor must guarantee that: | 91 | * When looping to get a consistent (time-info, tsc) pair, we |
91 | * 1. cpu ID number maps 1:1 to per-CPU pvclock time info. | 92 | * also need to deal with the possibility we can switch vcpus, |
92 | * 2. that per-CPU pvclock time info is updated if the | 93 | * so make sure we always re-fetch time-info for the current vcpu. |
93 | * underlying CPU changes. | ||
94 | * 3. that version is increased whenever underlying CPU | ||
95 | * changes. | ||
96 | * | ||
97 | */ | 94 | */ |
98 | do { | 95 | do { |
99 | cpu = __getcpu() & VGETCPU_CPU_MASK; | 96 | cpu = __getcpu() & VGETCPU_CPU_MASK; |
@@ -102,20 +99,27 @@ static notrace cycle_t vread_pvclock(int *mode) | |||
102 | * __getcpu() calls (Gleb). | 99 | * __getcpu() calls (Gleb). |
103 | */ | 100 | */ |
104 | 101 | ||
105 | pvti = get_pvti(cpu); | 102 | /* Make sure migrate_count will change if we leave the VCPU. */ |
103 | do { | ||
104 | pvti = get_pvti(cpu); | ||
105 | migrate_count = pvti->migrate_count; | ||
106 | |||
107 | cpu1 = cpu; | ||
108 | cpu = __getcpu() & VGETCPU_CPU_MASK; | ||
109 | } while (unlikely(cpu != cpu1)); | ||
106 | 110 | ||
107 | version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags); | 111 | version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags); |
108 | 112 | ||
109 | /* | 113 | /* |
110 | * Test we're still on the cpu as well as the version. | 114 | * Test we're still on the cpu as well as the version. |
111 | * We could have been migrated just after the first | 115 | * - We must read TSC of pvti's VCPU. |
112 | * vgetcpu but before fetching the version, so we | 116 | * - KVM doesn't follow the versioning protocol, so data could |
113 | * wouldn't notice a version change. | 117 | * change before version if we left the VCPU. |
114 | */ | 118 | */ |
115 | cpu1 = __getcpu() & VGETCPU_CPU_MASK; | 119 | smp_rmb(); |
116 | } while (unlikely(cpu != cpu1 || | 120 | } while (unlikely((pvti->pvti.version & 1) || |
117 | (pvti->pvti.version & 1) || | 121 | pvti->pvti.version != version || |
118 | pvti->pvti.version != version)); | 122 | pvti->migrate_count != migrate_count)); |
119 | 123 | ||
120 | if (unlikely(!(flags & PVCLOCK_TSC_STABLE_BIT))) | 124 | if (unlikely(!(flags & PVCLOCK_TSC_STABLE_BIT))) |
121 | *mode = VCLOCK_NONE; | 125 | *mode = VCLOCK_NONE; |