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: 0a4e6be9ca ("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>
This commit is contained in:
Radim Krčmář 2015-04-02 20:44:23 +02:00 committed by Paolo Bonzini
parent 3180a7fcbc
commit 80f7fdb1c7
1 changed files with 12 additions and 8 deletions

View File

@ -99,21 +99,25 @@ static notrace cycle_t vread_pvclock(int *mode)
* __getcpu() calls (Gleb).
*/
pvti = get_pvti(cpu);
/* Make sure migrate_count will change if we leave the VCPU. */
do {
pvti = get_pvti(cpu);
migrate_count = pvti->migrate_count;
migrate_count = pvti->migrate_count;
cpu1 = cpu;
cpu = __getcpu() & VGETCPU_CPU_MASK;
} while (unlikely(cpu != cpu1));
version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags);
/*
* Test we're still on the cpu as well as the version.
* We could have been migrated just after the first
* vgetcpu but before fetching the version, so we
* wouldn't notice a version change.
* - We must read TSC of pvti's VCPU.
* - KVM doesn't follow the versioning protocol, so data could
* change before version if we left the VCPU.
*/
cpu1 = __getcpu() & VGETCPU_CPU_MASK;
} while (unlikely(cpu != cpu1 ||
(pvti->pvti.version & 1) ||
smp_rmb();
} while (unlikely((pvti->pvti.version & 1) ||
pvti->pvti.version != version ||
pvti->migrate_count != migrate_count));