[PATCH RFC v5 06/53] KVM: x86/mmu: Bug the VM if gmem attributes are queried to determine max mapping level

Ackerley Tng via B4 Relay
2026-04-28T23:25:17Z

When the maximum mapping level is queried, KVM's MMU lock is held, and
while the MMU lock is held, guest_memfd cannot take the
filemap_invalidate_lock() to look up the current shared/private state of
the gfn, for these reasons:

+ The MMU lock is a spinlock or rwlock and cannot be held while taking a
lock that can sleep.
+ In guest_memfd's code paths (such as truncate), the
filemap_invalidate_lock() is held while taking the MMU lock, and taking
the locks in reverse order would introduce a AB-BA deadlock.

Currently, the maximum mapping level is only queried from guest_memfd in
the process of recovering huge pages, if dirty logging is disabled on a
memslot. Dirty logging is not currently supported for guest_memfd, and
guest_memfd memslots also cannot be updated.

For now, bug the VM if guest_memfd needs to be queried to determine the
maximum mapping level. This guard can be removed if/when support is added.

Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
arch/x86/kvm/mmu/mmu.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 8276d7ca02036..2cc848bddf190 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -3364,6 +3364,15 @@ int kvm_mmu_max_mapping_level(struct kvm *kvm, struct kvm_page_fault *fault,
max_level = fault->max_level;
is_private = fault->is_private;
} else {
+ /*
+ * Memory attributes cannot be obtained from guest_memfd while
+ * the MMU lock is held.
+ */
+ if (KVM_BUG_ON(static_call_query(__kvm_get_memory_attributes) ==
+ kvm_gmem_get_memory_attributes, kvm)) {
+ return 0;
+ }
+
max_level = PG_LEVEL_NUM;
is_private = kvm_mem_is_private(kvm, gfn);
}

--
2.54.0.545.g6539524ca2-goog