Skip to content

Commit fe5c2bd

Browse files
Michal Hockogregkh
authored andcommitted
mm, vmalloc: fix high order __GFP_NOFAIL allocations
[ Upstream commit e9c3cda ] Gao Xiang has reported that the page allocator complains about high order __GFP_NOFAIL request coming from the vmalloc core: __alloc_pages+0x1cb/0x5b0 mm/page_alloc.c:5549 alloc_pages+0x1aa/0x270 mm/mempolicy.c:2286 vm_area_alloc_pages mm/vmalloc.c:2989 [inline] __vmalloc_area_node mm/vmalloc.c:3057 [inline] __vmalloc_node_range+0x978/0x13c0 mm/vmalloc.c:3227 kvmalloc_node+0x156/0x1a0 mm/util.c:606 kvmalloc include/linux/slab.h:737 [inline] kvmalloc_array include/linux/slab.h:755 [inline] kvcalloc include/linux/slab.h:760 [inline] it seems that I have completely missed high order allocation backing vmalloc areas case when implementing __GFP_NOFAIL support. This means that [k]vmalloc at al. can allocate higher order allocations with __GFP_NOFAIL which can trigger OOM killer for non-costly orders easily or cause a lot of reclaim/compaction activity if those requests cannot be satisfied. Fix the issue by falling back to zero order allocations for __GFP_NOFAIL requests if the high order request fails. Link: https://lkml.kernel.org/r/[email protected] Fixes: 9376130 ("mm/vmalloc: add support for __GFP_NOFAIL") Reported-by: Gao Xiang <[email protected]> Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Michal Hocko <[email protected]> Reviewed-by: Uladzislau Rezki (Sony) <[email protected]> Acked-by: Vlastimil Babka <[email protected]> Cc: Baoquan He <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: Mel Gorman <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Stable-dep-of: 8e0545c ("mm/vmalloc: fix vmalloc which may return null if called with __GFP_NOFAIL") Signed-off-by: Sasha Levin <[email protected]>
1 parent b1574c8 commit fe5c2bd

File tree

1 file changed

+23
-5
lines changed

1 file changed

+23
-5
lines changed

mm/vmalloc.c

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2923,6 +2923,8 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
29232923
unsigned int order, unsigned int nr_pages, struct page **pages)
29242924
{
29252925
unsigned int nr_allocated = 0;
2926+
gfp_t alloc_gfp = gfp;
2927+
bool nofail = false;
29262928
struct page *page;
29272929
int i;
29282930

@@ -2933,6 +2935,7 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
29332935
* more permissive.
29342936
*/
29352937
if (!order) {
2938+
/* bulk allocator doesn't support nofail req. officially */
29362939
gfp_t bulk_gfp = gfp & ~__GFP_NOFAIL;
29372940

29382941
while (nr_allocated < nr_pages) {
@@ -2971,20 +2974,35 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
29712974
if (nr != nr_pages_request)
29722975
break;
29732976
}
2977+
} else if (gfp & __GFP_NOFAIL) {
2978+
/*
2979+
* Higher order nofail allocations are really expensive and
2980+
* potentially dangerous (pre-mature OOM, disruptive reclaim
2981+
* and compaction etc.
2982+
*/
2983+
alloc_gfp &= ~__GFP_NOFAIL;
2984+
nofail = true;
29742985
}
29752986

29762987
/* High-order pages or fallback path if "bulk" fails. */
2977-
29782988
while (nr_allocated < nr_pages) {
29792989
if (fatal_signal_pending(current))
29802990
break;
29812991

29822992
if (nid == NUMA_NO_NODE)
2983-
page = alloc_pages(gfp, order);
2993+
page = alloc_pages(alloc_gfp, order);
29842994
else
2985-
page = alloc_pages_node(nid, gfp, order);
2986-
if (unlikely(!page))
2987-
break;
2995+
page = alloc_pages_node(nid, alloc_gfp, order);
2996+
if (unlikely(!page)) {
2997+
if (!nofail)
2998+
break;
2999+
3000+
/* fall back to the zero order allocations */
3001+
alloc_gfp |= __GFP_NOFAIL;
3002+
order = 0;
3003+
continue;
3004+
}
3005+
29883006
/*
29893007
* Higher order allocations must be able to be treated as
29903008
* indepdenent small pages by callers (as they can with

0 commit comments

Comments
 (0)