]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mm/memfd: reserve hugetlb folios before allocation
authorVivek Kasireddy <vivek.kasireddy@intel.com>
Wed, 18 Jun 2025 05:30:54 +0000 (22:30 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 10 Jul 2025 05:42:15 +0000 (22:42 -0700)
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.

Link: https://lkml.kernel.org/r/20250618053415.1036185-3-vivek.kasireddy@intel.com
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
Cc: Steve Sistare <steven.sistare@oracle.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: David Hildenbrand <david@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Oscar Salvador <osalvador@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
include/linux/hugetlb.h
mm/hugetlb.c
mm/memfd.c

index d8310b0f36ddbbc28bfa81e30924ef334f5a1618..c6c87eae4a8dc005a75827e4f6642ecb93fa9d67 100644 (file)
@@ -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;
index e1570735012a441eec2743397b991cc3a06d1622..da9f10710c278442b56420e4be55fc6c56f141a8 100644 (file)
@@ -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));
index b558c4c3bd27b340627f36805dbbd1d82c76ce5f..32fa6bfe57d11ac132ae41548d1156c901f8e505 100644 (file)
@@ -70,7 +70,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)) {
                /*
@@ -79,12 +78,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,
@@ -95,12 +101,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);