linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1] userfaultfd: do not block on locking a large folio with raised refcount
@ 2025-02-25 20:46 Suren Baghdasaryan
  2025-02-25 20:56 ` Lokesh Gidra
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Suren Baghdasaryan @ 2025-02-25 20:46 UTC (permalink / raw)
  To: akpm
  Cc: lokeshgidra, aarcange, 21cnbao, v-songbaohua, david, peterx,
	willy, Liam.Howlett, lorenzo.stoakes, hughd, jannh, kaleshsingh,
	surenb, linux-mm, linux-kernel

Lokesh recently raised an issue about UFFDIO_MOVE getting into a deadlock
state when it goes into split_folio() with raised folio refcount.
split_folio() expects the reference count to be exactly
mapcount + num_pages_in_folio + 1 (see can_split_folio()) and fails with
EAGAIN otherwise. If multiple processes are trying to move the same
large folio, they raise the refcount (all tasks succeed in that) then
one of them succeeds in locking the folio, while others will block in
folio_lock() while keeping the refcount raised. The winner of this
race will proceed with calling split_folio() and will fail returning
EAGAIN to the caller and unlocking the folio. The next competing process
will get the folio locked and will go through the same flow. In the
meantime the original winner will be retried and will block in
folio_lock(), getting into the queue of waiting processes only to repeat
the same path. All this results in a livelock.
An easy fix would be to avoid waiting for the folio lock while holding
folio refcount, similar to madvise_free_huge_pmd() where folio lock is
acquired before raising the folio refcount.
Modify move_pages_pte() to try locking the folio first and if that fails
and the folio is large then return EAGAIN without touching the folio
refcount. If the folio is single-page then split_folio() is not called,
so we don't have this issue.
Lokesh has a reproducer [1] and I verified that this change fixes the
issue.

[1] https://github.com/lokeshgidra/uffd_move_ioctl_deadlock

Reported-by: Lokesh Gidra <lokeshgidra@google.com>
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
---
 mm/userfaultfd.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 867898c4e30b..f17f8290c523 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -1236,6 +1236,7 @@ static int move_pages_pte(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd,
 		 */
 		if (!src_folio) {
 			struct folio *folio;
+			bool locked;
 
 			/*
 			 * Pin the page while holding the lock to be sure the
@@ -1255,12 +1256,26 @@ static int move_pages_pte(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd,
 				goto out;
 			}
 
+			locked = folio_trylock(folio);
+			/*
+			 * We avoid waiting for folio lock with a raised refcount
+			 * for large folios because extra refcounts will result in
+			 * split_folio() failing later and retrying. If multiple
+			 * tasks are trying to move a large folio we can end
+			 * livelocking.
+			 */
+			if (!locked && folio_test_large(folio)) {
+				spin_unlock(src_ptl);
+				err = -EAGAIN;
+				goto out;
+			}
+
 			folio_get(folio);
 			src_folio = folio;
 			src_folio_pte = orig_src_pte;
 			spin_unlock(src_ptl);
 
-			if (!folio_trylock(src_folio)) {
+			if (!locked) {
 				pte_unmap(&orig_src_pte);
 				pte_unmap(&orig_dst_pte);
 				src_pte = dst_pte = NULL;

base-commit: 801d47bd96ce22acd43809bc09e004679f707c39
-- 
2.48.1.658.g4767266eb4-goog



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2025-02-26 18:59 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-02-25 20:46 [PATCH 1/1] userfaultfd: do not block on locking a large folio with raised refcount Suren Baghdasaryan
2025-02-25 20:56 ` Lokesh Gidra
2025-02-25 21:32 ` Peter Xu
2025-02-25 22:12   ` Suren Baghdasaryan
2025-02-25 22:21     ` Suren Baghdasaryan
2025-02-25 22:48       ` Peter Xu
2025-02-25 23:01         ` Suren Baghdasaryan
2025-02-26 14:59 ` Liam R. Howlett
2025-02-26 16:11   ` Suren Baghdasaryan
2025-02-26 16:16     ` Matthew Wilcox
2025-02-26 16:22       ` Suren Baghdasaryan
2025-02-26 18:59         ` Suren Baghdasaryan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox