From: Ackerley Tng <[email protected]> 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 <[email protected]> --- 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
