[PATCH 09/15] mm/memfd: recheck the page cache before allocating a hugetlb folio
From: David Hildenbrand (Arm)
Date: Wed Oct 28 2026 - 16:25:46 EST
A concurrent fault or PIN request can populate the page cache
after memfd_pin_folios() misses it in the page cache but before
memfd_alloc_folio() takes the fault mutex. The latter still tries to
allocate another folio and can return -ENOMEM even though the requested
folio is already cached.
In particular, hugetlb_reserve_pages() finds the existing reservation-map
entry and reserves nothing. If no global reservations remain,
alloc_hugetlb_folio_reserve() fails even when the pool has free pages,
effectively failing memfd_pin_folios().
Recheck the page cache before reserving or allocating. If the folio is
present, drop the lookup reference and return -EEXIST so
memfd_pin_folios() retries its lookup.
This is probably not worth backporting to stable.
Fixes: 89c1905d9c14 ("mm/gup: introduce memfd_pin_folios() for pinning memfd folios")
Reported-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
---
mm/memfd.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/mm/memfd.c b/mm/memfd.c
index 4650a69aa7a6..86842c077cdd 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -102,6 +102,15 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx)
goto out_unlock;
}
+ /* Let the caller retry if we raced with population. */
+ folio = filemap_get_folio(memfd->f_mapping,
+ idx << huge_page_order(h));
+ if (!IS_ERR(folio)) {
+ folio_put(folio);
+ err = -EEXIST;
+ goto out_unlock;
+ }
+
nr_resv = hugetlb_reserve_pages(inode, idx, idx + 1, NULL, EMPTY_VMA_FLAGS);
if (nr_resv < 0) {
err = nr_resv;
--
2.43.0