summaryrefslogtreecommitdiff
path: root/virt
diff options
context:
space:
mode:
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/kvm_main.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index ee1005cb99e1..2d6203ecab88 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -5167,15 +5167,26 @@ static void hardware_disable_all_nolock(void)
static void hardware_disable_all(void)
{
+ cpus_read_lock();
raw_spin_lock(&kvm_count_lock);
hardware_disable_all_nolock();
raw_spin_unlock(&kvm_count_lock);
+ cpus_read_unlock();
}
static int hardware_enable_all(void)
{
int r = 0;
+ /*
+ * When onlining a CPU, cpu_online_mask is set before kvm_online_cpu()
+ * is called, and so on_each_cpu() between them includes the CPU that
+ * is being onlined. As a result, hardware_enable_nolock() may get
+ * invoked before kvm_online_cpu(), which also enables hardware if the
+ * usage count is non-zero. Disable CPU hotplug to avoid attempting to
+ * enable hardware multiple times.
+ */
+ cpus_read_lock();
raw_spin_lock(&kvm_count_lock);
kvm_usage_count++;
@@ -5190,6 +5201,7 @@ static int hardware_enable_all(void)
}
raw_spin_unlock(&kvm_count_lock);
+ cpus_read_unlock();
return r;
}