KVM: guest_memfd: Avoid deadlock in error_remove_folio()

memory_failure() invokes ->error_remove_folio() while holding the
poisoned folio lock.  KVM's guest_memfd callback then takes
mapping->invalidate_lock for read before invalidating guest mappings.

This can deadlock with paths that hold mapping->invalidate_lock for write
and then try to lock the same folio, e.g. truncation from MADV_REMOVE or
FALLOC_FL_PUNCH_HOLE.  Because rwsems are fair, the problem is not limited
to guest_memfd punch-hole: a pending writer can also block future readers,
so ->error_remove_folio() must not block on the invalidate lock while
holding the poisoned folio lock.

Use filemap_invalidate_trylock_shared() in kvm_gmem_error_folio().  If the
invalidate lock is contended, fail the recovery instead of potentially
deadlocking the memory-failure path.

Fixes: a7800aa80e ("KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for guest-specific backing memory")
Signed-off-by: Hao Zhang <zhanghao1@kylinos.cn>
Link: https://lore.kernel.org/all/tencent_7DA064CAC9B463EB9B651801011E2CE4230A@qq.com/
Link: https://patch.msgid.link/ambEdSPjerZIVN0b@192.168.1.215
Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
Hao Zhang 2026-07-27 10:37:41 +08:00 committed by Sean Christopherson
parent 681f3b68f4
commit ad06cf5338

View File

@ -828,7 +828,17 @@ static int kvm_gmem_error_folio(struct address_space *mapping, struct folio *fol
enum kvm_gfn_range_filter filter;
pgoff_t start, end;
filemap_invalidate_lock_shared(mapping);
/*
* memory_failure() invokes ->error_remove_folio() while holding the
* poisoned folio lock. Do not block on mapping->invalidate_lock, as
* a writer that already holds the invalidate lock can be waiting for
* the same folio, e.g. truncation from MADV_REMOVE/FALLOC_FL_PUNCH_HOLE.
*
* If the invalidate lock is contended, fail the recovery instead of
* risking a deadlock in the memory-failure path.
*/
if (!filemap_invalidate_trylock_shared(mapping))
return -EBUSY;
start = folio->index;
end = start + folio_nr_pages(folio);