[PATCH v4 2/3] mm/memfd: Reserve hugetlb folios before allocation

Vivek Kasireddy vivek.kasireddy at intel.com
Wed Jun 18 05:30:54 UTC 2025


When we try to allocate a folio via alloc_hugetlb_folio_reserve(),
we need to ensure that there is an active reservation associated
with the allocation. Otherwise, our allocation request would fail
if there are no active reservations made at that moment against any
other allocations. This is because alloc_hugetlb_folio_reserve()
checks h->resv_huge_pages before proceeding with the allocation.

Therefore, to address this issue, we just need to make a reservation
(by calling hugetlb_reserve_pages()) before we try to allocate the
folio. This will also ensure that proper region/subpool accounting is
done associated with our allocation.

Cc: Steve Sistare <steven.sistare at oracle.com>
Cc: Muchun Song <muchun.song at linux.dev>
Cc: David Hildenbrand <david at redhat.com>
Cc: Andrew Morton <akpm at linux-foundation.org>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy at intel.com>
---
 include/linux/hugetlb.h |  5 +++++
 mm/hugetlb.c            |  5 -----
 mm/memfd.c              | 17 ++++++++++++++---
 3 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index d8310b0f36dd..c6c87eae4a8d 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -740,6 +740,11 @@ extern unsigned int default_hstate_idx;
 
 #define default_hstate (hstates[default_hstate_idx])
 
+static inline struct hugepage_subpool *subpool_inode(struct inode *inode)
+{
+	return HUGETLBFS_SB(inode->i_sb)->spool;
+}
+
 static inline struct hugepage_subpool *hugetlb_folio_subpool(struct folio *folio)
 {
 	return folio->_hugetlb_subpool;
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 6b34152744cc..57d85af6db3f 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -284,11 +284,6 @@ static long hugepage_subpool_put_pages(struct hugepage_subpool *spool,
 	return ret;
 }
 
-static inline struct hugepage_subpool *subpool_inode(struct inode *inode)
-{
-	return HUGETLBFS_SB(inode->i_sb)->spool;
-}
-
 static inline struct hugepage_subpool *subpool_vma(struct vm_area_struct *vma)
 {
 	return subpool_inode(file_inode(vma->vm_file));
diff --git a/mm/memfd.c b/mm/memfd.c
index ab367e61553d..2c861a7ac345 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -71,7 +71,6 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx)
 #ifdef CONFIG_HUGETLB_PAGE
 	struct folio *folio;
 	gfp_t gfp_mask;
-	int err;
 
 	if (is_file_hugepages(memfd)) {
 		/*
@@ -80,12 +79,19 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx)
 		 * alloc from. Also, the folio will be pinned for an indefinite
 		 * amount of time, so it is not expected to be migrated away.
 		 */
+		struct inode *inode = file_inode(memfd);
 		struct hstate *h = hstate_file(memfd);
+		int err = -ENOMEM;
+		long nr_resv;
 
 		gfp_mask = htlb_alloc_mask(h);
 		gfp_mask &= ~(__GFP_HIGHMEM | __GFP_MOVABLE);
 		idx >>= huge_page_order(h);
 
+		nr_resv = hugetlb_reserve_pages(inode, idx, idx + 1, NULL, 0);
+		if (nr_resv < 0)
+			return ERR_PTR(nr_resv);
+
 		folio = alloc_hugetlb_folio_reserve(h,
 						    numa_node_id(),
 						    NULL,
@@ -96,12 +102,17 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx)
 							idx);
 			if (err) {
 				folio_put(folio);
-				return ERR_PTR(err);
+				goto err_unresv;
 			}
+
+			hugetlb_set_folio_subpool(folio, subpool_inode(inode));
 			folio_unlock(folio);
 			return folio;
 		}
-		return ERR_PTR(-ENOMEM);
+err_unresv:
+		if (nr_resv > 0)
+			hugetlb_unreserve_pages(inode, idx, idx + 1, 0);
+		return ERR_PTR(err);
 	}
 #endif
 	return shmem_read_folio(memfd->f_mapping, idx);
-- 
2.49.0



More information about the dri-devel mailing list