[PATCH 5/6] KVM: x86/mmu: Protect kvm->memslots with a mutex

From: Ben Gardon
Date: Tue Apr 27 2021 - 18:36:58 EST


Adds a lock around memslots changes. Currently this lock does not have
any effect on the syncronization model, but it will be used in a future
commit to facilitate lazy rmap allocation.

Signed-off-by: Ben Gardon <bgardon@xxxxxxxxxx>
---
arch/x86/include/asm/kvm_host.h | 5 +++++
arch/x86/kvm/x86.c | 11 +++++++++++
include/linux/kvm_host.h | 2 ++
virt/kvm/kvm_main.c | 9 ++++++++-
4 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 3900dcf2439e..bce7fa152473 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1124,6 +1124,11 @@ struct kvm_arch {
#endif /* CONFIG_X86_64 */

bool shadow_mmu_active;
+
+ /*
+ * Protects kvm->memslots.
+ */
+ struct mutex memslot_assignment_lock;
};

struct kvm_vm_stat {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index fc32a7dbe4c4..30234fe96f48 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10649,6 +10649,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
raw_spin_lock_init(&kvm->arch.tsc_write_lock);
mutex_init(&kvm->arch.apic_map_lock);
spin_lock_init(&kvm->arch.pvclock_gtod_sync_lock);
+ mutex_init(&kvm->arch.memslot_assignment_lock);

kvm->arch.kvmclock_offset = -get_kvmclock_base_ns();
pvclock_update_vm_gtod_copy(kvm);
@@ -10868,6 +10869,16 @@ static int alloc_memslot_rmap(struct kvm_memory_slot *slot,
return -ENOMEM;
}

+
+void kvm_arch_assign_memslots(struct kvm *kvm, int as_id,
+ struct kvm_memslots *slots)
+{
+ mutex_lock(&kvm->arch.memslot_assignment_lock);
+ rcu_assign_pointer(kvm->memslots[as_id], slots);
+ mutex_unlock(&kvm->arch.memslot_assignment_lock);
+}
+
+
static int kvm_alloc_memslot_metadata(struct kvm_memory_slot *slot,
unsigned long npages)
{
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 8895b95b6a22..146bb839c754 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -720,6 +720,8 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
const struct kvm_userspace_memory_region *mem,
enum kvm_mr_change change);
+void kvm_arch_assign_memslots(struct kvm *kvm, int as_id,
+ struct kvm_memslots *slots);
void kvm_arch_commit_memory_region(struct kvm *kvm,
const struct kvm_userspace_memory_region *mem,
struct kvm_memory_slot *old,
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 2799c6660cce..e62a37bc5b90 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1270,6 +1270,12 @@ static int check_memory_region_flags(const struct kvm_userspace_memory_region *m
return 0;
}

+__weak void kvm_arch_assign_memslots(struct kvm *kvm, int as_id,
+ struct kvm_memslots *slots)
+{
+ rcu_assign_pointer(kvm->memslots[as_id], slots);
+}
+
static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
int as_id, struct kvm_memslots *slots)
{
@@ -1279,7 +1285,8 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
WARN_ON(gen & KVM_MEMSLOT_GEN_UPDATE_IN_PROGRESS);
slots->generation = gen | KVM_MEMSLOT_GEN_UPDATE_IN_PROGRESS;

- rcu_assign_pointer(kvm->memslots[as_id], slots);
+ kvm_arch_assign_memslots(kvm, as_id, slots);
+
synchronize_srcu_expedited(&kvm->srcu);

/*
--
2.31.1.498.g6c1eba8ee3d-goog