mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
mm, vmalloc: fix high order __GFP_NOFAIL allocations
[ Upstream commite9c3cda4d8] 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/ZAXynvdNqcI0f6Us@dhcp22.suse.cz Fixes:9376130c39("mm/vmalloc: add support for __GFP_NOFAIL") Reported-by: Gao Xiang <hsiangkao@linux.alibaba.com> Link: https://lkml.kernel.org/r/20230305053035.1911-1-hsiangkao@linux.alibaba.com Signed-off-by: Michal Hocko <mhocko@suse.com> Reviewed-by: Uladzislau Rezki (Sony) <urezki@gmail.com> Acked-by: Vlastimil Babka <vbabka@suse.cz> Cc: Baoquan He <bhe@redhat.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Mel Gorman <mgorman@techsingularity.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Stable-dep-of: 8e0545c83d67 ("mm/vmalloc: fix vmalloc which may return null if called with __GFP_NOFAIL") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
b1574c8c0a
commit
fe5c2bdcb1
28
mm/vmalloc.c
28
mm/vmalloc.c
@@ -2923,6 +2923,8 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
|
|||||||
unsigned int order, unsigned int nr_pages, struct page **pages)
|
unsigned int order, unsigned int nr_pages, struct page **pages)
|
||||||
{
|
{
|
||||||
unsigned int nr_allocated = 0;
|
unsigned int nr_allocated = 0;
|
||||||
|
gfp_t alloc_gfp = gfp;
|
||||||
|
bool nofail = false;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -2933,6 +2935,7 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
|
|||||||
* more permissive.
|
* more permissive.
|
||||||
*/
|
*/
|
||||||
if (!order) {
|
if (!order) {
|
||||||
|
/* bulk allocator doesn't support nofail req. officially */
|
||||||
gfp_t bulk_gfp = gfp & ~__GFP_NOFAIL;
|
gfp_t bulk_gfp = gfp & ~__GFP_NOFAIL;
|
||||||
|
|
||||||
while (nr_allocated < nr_pages) {
|
while (nr_allocated < nr_pages) {
|
||||||
@@ -2971,20 +2974,35 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
|
|||||||
if (nr != nr_pages_request)
|
if (nr != nr_pages_request)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (gfp & __GFP_NOFAIL) {
|
||||||
|
/*
|
||||||
|
* Higher order nofail allocations are really expensive and
|
||||||
|
* potentially dangerous (pre-mature OOM, disruptive reclaim
|
||||||
|
* and compaction etc.
|
||||||
|
*/
|
||||||
|
alloc_gfp &= ~__GFP_NOFAIL;
|
||||||
|
nofail = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* High-order pages or fallback path if "bulk" fails. */
|
/* High-order pages or fallback path if "bulk" fails. */
|
||||||
|
|
||||||
while (nr_allocated < nr_pages) {
|
while (nr_allocated < nr_pages) {
|
||||||
if (fatal_signal_pending(current))
|
if (fatal_signal_pending(current))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (nid == NUMA_NO_NODE)
|
if (nid == NUMA_NO_NODE)
|
||||||
page = alloc_pages(gfp, order);
|
page = alloc_pages(alloc_gfp, order);
|
||||||
else
|
else
|
||||||
page = alloc_pages_node(nid, gfp, order);
|
page = alloc_pages_node(nid, alloc_gfp, order);
|
||||||
if (unlikely(!page))
|
if (unlikely(!page)) {
|
||||||
break;
|
if (!nofail)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* fall back to the zero order allocations */
|
||||||
|
alloc_gfp |= __GFP_NOFAIL;
|
||||||
|
order = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Higher order allocations must be able to be treated as
|
* Higher order allocations must be able to be treated as
|
||||||
* indepdenent small pages by callers (as they can with
|
* indepdenent small pages by callers (as they can with
|
||||||
|
|||||||
Reference in New Issue
Block a user