Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: protect concurrent make_all_cpus_request

make_all_cpus_request contains a race condition which can
trigger false request completed status, as follows:

CPU0 CPU1

if (test_and_set_bit(req,&vcpu->requests))
.... if (test_and_set_bit(req,&vcpu->requests))
.. return
proceed to smp_call_function_many(wait=1)

Use a spinlock to serialize concurrent CPUs.

Cc: stable@kernel.org
Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>

authored by

Marcelo Tosatti and committed by
Avi Kivity
84261923 29a4b933

+4
+1
include/linux/kvm_host.h
··· 125 125 struct kvm { 126 126 struct mutex lock; /* protects the vcpus array and APIC accesses */ 127 127 spinlock_t mmu_lock; 128 + spinlock_t requests_lock; 128 129 struct rw_semaphore slots_lock; 129 130 struct mm_struct *mm; /* userspace tied to this vm */ 130 131 int nmemslots;
+3
virt/kvm/kvm_main.c
··· 746 746 cpumask_clear(cpus); 747 747 748 748 me = get_cpu(); 749 + spin_lock(&kvm->requests_lock); 749 750 for (i = 0; i < KVM_MAX_VCPUS; ++i) { 750 751 vcpu = kvm->vcpus[i]; 751 752 if (!vcpu) ··· 763 762 smp_call_function_many(cpus, ack_flush, NULL, 1); 764 763 else 765 764 called = false; 765 + spin_unlock(&kvm->requests_lock); 766 766 put_cpu(); 767 767 free_cpumask_var(cpus); 768 768 return called; ··· 984 982 kvm->mm = current->mm; 985 983 atomic_inc(&kvm->mm->mm_count); 986 984 spin_lock_init(&kvm->mmu_lock); 985 + spin_lock_init(&kvm->requests_lock); 987 986 kvm_io_bus_init(&kvm->pio_bus); 988 987 mutex_init(&kvm->lock); 989 988 kvm_io_bus_init(&kvm->mmio_bus);