Skip to content

Commit 26a8ea8

Browse files
Steve Sistareakpm00
authored andcommitted
mm/hugetlb: fix memfd_pin_folios resv_huge_pages leak
memfd_pin_folios followed by unpin_folios leaves resv_huge_pages elevated if the pages were not already faulted in. During a normal page fault, resv_huge_pages is consumed here: hugetlb_fault() alloc_hugetlb_folio() dequeue_hugetlb_folio_vma() dequeue_hugetlb_folio_nodemask() dequeue_hugetlb_folio_node_exact() free_huge_pages-- resv_huge_pages-- During memfd_pin_folios, the page is created by calling alloc_hugetlb_folio_nodemask instead of alloc_hugetlb_folio, and resv_huge_pages is not modified: memfd_alloc_folio() alloc_hugetlb_folio_nodemask() dequeue_hugetlb_folio_nodemask() dequeue_hugetlb_folio_node_exact() free_huge_pages-- alloc_hugetlb_folio_nodemask has other callers that must not modify resv_huge_pages. Therefore, to fix, define an alternate version of alloc_hugetlb_folio_nodemask for this call site that adjusts resv_huge_pages. Link: https://lkml.kernel.org/r/[email protected] Fixes: 89c1905 ("mm/gup: introduce memfd_pin_folios() for pinning memfd folios") Signed-off-by: Steve Sistare <[email protected]> Acked-by: Vivek Kasireddy <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Jason Gunthorpe <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Muchun Song <[email protected]> Cc: Peter Xu <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent c56b6f3 commit 26a8ea8

File tree

3 files changed

+31
-5
lines changed

3 files changed

+31
-5
lines changed

include/linux/hugetlb.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,9 @@ struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,
692692
struct folio *alloc_hugetlb_folio_nodemask(struct hstate *h, int preferred_nid,
693693
nodemask_t *nmask, gfp_t gfp_mask,
694694
bool allow_alloc_fallback);
695+
struct folio *alloc_hugetlb_folio_reserve(struct hstate *h, int preferred_nid,
696+
nodemask_t *nmask, gfp_t gfp_mask);
697+
695698
int hugetlb_add_to_page_cache(struct folio *folio, struct address_space *mapping,
696699
pgoff_t idx);
697700
void restore_reserve_on_error(struct hstate *h, struct vm_area_struct *vma,
@@ -1059,6 +1062,13 @@ static inline struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,
10591062
return NULL;
10601063
}
10611064

1065+
static inline struct folio *
1066+
alloc_hugetlb_folio_reserve(struct hstate *h, int preferred_nid,
1067+
nodemask_t *nmask, gfp_t gfp_mask)
1068+
{
1069+
return NULL;
1070+
}
1071+
10621072
static inline struct folio *
10631073
alloc_hugetlb_folio_nodemask(struct hstate *h, int preferred_nid,
10641074
nodemask_t *nmask, gfp_t gfp_mask,

mm/hugetlb.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2390,6 +2390,23 @@ struct folio *alloc_buddy_hugetlb_folio_with_mpol(struct hstate *h,
23902390
return folio;
23912391
}
23922392

2393+
struct folio *alloc_hugetlb_folio_reserve(struct hstate *h, int preferred_nid,
2394+
nodemask_t *nmask, gfp_t gfp_mask)
2395+
{
2396+
struct folio *folio;
2397+
2398+
spin_lock_irq(&hugetlb_lock);
2399+
folio = dequeue_hugetlb_folio_nodemask(h, gfp_mask, preferred_nid,
2400+
nmask);
2401+
if (folio) {
2402+
VM_BUG_ON(!h->resv_huge_pages);
2403+
h->resv_huge_pages--;
2404+
}
2405+
2406+
spin_unlock_irq(&hugetlb_lock);
2407+
return folio;
2408+
}
2409+
23932410
/* folio migration callback function */
23942411
struct folio *alloc_hugetlb_folio_nodemask(struct hstate *h, int preferred_nid,
23952412
nodemask_t *nmask, gfp_t gfp_mask, bool allow_alloc_fallback)

mm/memfd.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,10 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx)
8282
gfp_mask = htlb_alloc_mask(hstate_file(memfd));
8383
gfp_mask &= ~(__GFP_HIGHMEM | __GFP_MOVABLE);
8484

85-
folio = alloc_hugetlb_folio_nodemask(hstate_file(memfd),
86-
numa_node_id(),
87-
NULL,
88-
gfp_mask,
89-
false);
85+
folio = alloc_hugetlb_folio_reserve(hstate_file(memfd),
86+
numa_node_id(),
87+
NULL,
88+
gfp_mask);
9089
if (folio && folio_try_get(folio)) {
9190
err = hugetlb_add_to_page_cache(folio,
9291
memfd->f_mapping,

0 commit comments

Comments
 (0)