[PATCH 08/13] KVM: x86/mmu: Zap shared-only memslots when private attribute changes

Sean Christopherson
2023-09-21T20:56:52Z

Zap all relevant memslots, including shared-only memslots, if the private
memory attribute is being changed. If userspace converts a range to
private, KVM must zap shared SPTEs to prevent the guest from accessing
the memory as shared. If userspace converts a range to shared, zapping
SPTEs for shared-only memslots isn't strictly necessary, but doing so
ensures that KVM will install a hugepage mapping if possible, e.g. if a
2MiB range that was mixed is converted to be 100% shared.

Fixes: dcde045383f3 ("KVM: x86/mmu: Handle page fault for private memory")
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/mmu/mmu.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 148931cf9dba..aa67d9d6fcf8 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -7259,10 +7259,17 @@ bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm,
struct kvm_gfn_range *range)
{
/*
- * KVM x86 currently only supports KVM_MEMORY_ATTRIBUTE_PRIVATE, skip
- * the slot if the slot will never consume the PRIVATE attribute.
+ * Zap SPTEs even if the slot can't be mapped PRIVATE. KVM x86 only
+ * supports KVM_MEMORY_ATTRIBUTE_PRIVATE, and so it *seems* like KVM
+ * can simply ignore such slots. But if userspace is making memory
+ * PRIVATE, then KVM must prevent the guest from accessing the memory
+ * as shared. And if userspace is making memory SHARED and this point
+ * is reached, then at least one page within the range was previously
+ * PRIVATE, i.e. the slot's possible hugepage ranges are changing.
+ * Zapping SPTEs in this case ensures KVM will reassess whether or not
+ * a hugepage can be used for affected ranges.
*/
- if (!kvm_slot_can_be_private(range->slot))
+ if (WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm)))
return false;

return kvm_mmu_unmap_gfn_range(kvm, range);
--
2.42.0.515.g380fc7ccd1-goog