mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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:
parent
681f3b68f4
commit
ad06cf5338
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user