diff options
author | Radim Krčmář <rkrcmar@redhat.com> | 2015-04-02 14:44:23 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2015-04-08 04:46:55 -0400 |
commit | 80f7fdb1c7f0f9266421f823964fd1962681f6ce (patch) | |
tree | 5046430395b6097984374f24d59f6616b34ae1ea /arch/x86/vdso | |
parent | 3180a7fcbc0ec7ed7cc85ed5015bdd7a8c2176e8 (diff) |
x86: vdso: fix pvclock races with task migration
If we were migrated right after __getcpu, but before reading the
migration_count, we wouldn't notice that we read TSC of a different
VCPU, nor that KVM's bug made pvti invalid, as only migration_count
on source VCPU is increased.
Change vdso instead of updating migration_count on destination.
Cc: stable@vger.kernel.org
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
Fixes: 0a4e6be9ca17 ("x86: kvm: Revert "remove sched notifier for cross-cpu migrations"")
Message-Id: <1428000263-11892-1-git-send-email-rkrcmar@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/vdso')
-rw-r--r-- | arch/x86/vdso/vclock_gettime.c | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 30933760ee5f..40d2473836c9 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c | |||
@@ -99,21 +99,25 @@ static notrace cycle_t vread_pvclock(int *mode) | |||
99 | * __getcpu() calls (Gleb). | 99 | * __getcpu() calls (Gleb). |
100 | */ | 100 | */ |
101 | 101 | ||
102 | 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; | ||
103 | 106 | ||
104 | migrate_count = pvti->migrate_count; | 107 | cpu1 = cpu; |
108 | cpu = __getcpu() & VGETCPU_CPU_MASK; | ||
109 | } while (unlikely(cpu != cpu1)); | ||
105 | 110 | ||
106 | version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags); | 111 | version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags); |
107 | 112 | ||
108 | /* | 113 | /* |
109 | * 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. |
110 | * We could have been migrated just after the first | 115 | * - We must read TSC of pvti's VCPU. |
111 | * vgetcpu but before fetching the version, so we | 116 | * - KVM doesn't follow the versioning protocol, so data could |
112 | * wouldn't notice a version change. | 117 | * change before version if we left the VCPU. |
113 | */ | 118 | */ |
114 | cpu1 = __getcpu() & VGETCPU_CPU_MASK; | 119 | smp_rmb(); |
115 | } while (unlikely(cpu != cpu1 || | 120 | } while (unlikely((pvti->pvti.version & 1) || |
116 | (pvti->pvti.version & 1) || | ||
117 | pvti->pvti.version != version || | 121 | pvti->pvti.version != version || |
118 | pvti->migrate_count != migrate_count)); | 122 | pvti->migrate_count != migrate_count)); |
119 | 123 | ||