Skip to content

Commit 803de90

Browse files
tehcasterakpm00
authored andcommitted
mm, vmscan: prevent infinite loop for costly GFP_NOIO | __GFP_RETRY_MAYFAIL allocations
Sven reports an infinite loop in __alloc_pages_slowpath() for costly order __GFP_RETRY_MAYFAIL allocations that are also GFP_NOIO. Such combination can happen in a suspend/resume context where a GFP_KERNEL allocation can have __GFP_IO masked out via gfp_allowed_mask. Quoting Sven: 1. try to do a "costly" allocation (order > PAGE_ALLOC_COSTLY_ORDER) with __GFP_RETRY_MAYFAIL set. 2. page alloc's __alloc_pages_slowpath tries to get a page from the freelist. This fails because there is nothing free of that costly order. 3. page alloc tries to reclaim by calling __alloc_pages_direct_reclaim, which bails out because a zone is ready to be compacted; it pretends to have made a single page of progress. 4. page alloc tries to compact, but this always bails out early because __GFP_IO is not set (it's not passed by the snd allocator, and even if it were, we are suspending so the __GFP_IO flag would be cleared anyway). 5. page alloc believes reclaim progress was made (because of the pretense in item 3) and so it checks whether it should retry compaction. The compaction retry logic thinks it should try again, because: a) reclaim is needed because of the early bail-out in item 4 b) a zonelist is suitable for compaction 6. goto 2. indefinite stall. (end quote) The immediate root cause is confusing the COMPACT_SKIPPED returned from __alloc_pages_direct_compact() (step 4) due to lack of __GFP_IO to be indicating a lack of order-0 pages, and in step 5 evaluating that in should_compact_retry() as a reason to retry, before incrementing and limiting the number of retries. There are however other places that wrongly assume that compaction can happen while we lack __GFP_IO. To fix this, introduce gfp_compaction_allowed() to abstract the __GFP_IO evaluation and switch the open-coded test in try_to_compact_pages() to use it. Also use the new helper in: - compaction_ready(), which will make reclaim not bail out in step 3, so there's at least one attempt to actually reclaim, even if chances are small for a costly order - in_reclaim_compaction() which will make should_continue_reclaim() return false and we don't over-reclaim unnecessarily - in __alloc_pages_slowpath() to set a local variable can_compact, which is then used to avoid retrying reclaim/compaction for costly allocations (step 5) if we can't compact and also to skip the early compaction attempt that we do in some cases Link: https://lkml.kernel.org/r/[email protected] Fixes: 3250845 ("Revert "mm, oom: prevent premature OOM killer invocation for high order request"") Signed-off-by: Vlastimil Babka <[email protected]> Reported-by: Sven van Ashbrook <[email protected]> Closes: https://lore.kernel.org/all/CAG-rBihs_xMKb3wrMO1%2B-%2Bp4fowP9oy1pa_OTkfxBzPUVOZF%[email protected]/ Tested-by: Karthikeyan Ramasubramanian <[email protected]> Cc: Brian Geffon <[email protected]> Cc: Curtis Malainey <[email protected]> Cc: Jaroslav Kysela <[email protected]> Cc: Mel Gorman <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Takashi Iwai <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 720da1e commit 803de90

File tree

4 files changed

+20
-11
lines changed

4 files changed

+20
-11
lines changed

include/linux/gfp.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,15 @@ static inline bool gfp_has_io_fs(gfp_t gfp)
353353
return (gfp & (__GFP_IO | __GFP_FS)) == (__GFP_IO | __GFP_FS);
354354
}
355355

356+
/*
357+
* Check if the gfp flags allow compaction - GFP_NOIO is a really
358+
* tricky context because the migration might require IO.
359+
*/
360+
static inline bool gfp_compaction_allowed(gfp_t gfp_mask)
361+
{
362+
return IS_ENABLED(CONFIG_COMPACTION) && (gfp_mask & __GFP_IO);
363+
}
364+
356365
extern gfp_t vma_thp_gfp_mask(struct vm_area_struct *vma);
357366

358367
#ifdef CONFIG_CONTIG_ALLOC

mm/compaction.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2723,16 +2723,11 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
27232723
unsigned int alloc_flags, const struct alloc_context *ac,
27242724
enum compact_priority prio, struct page **capture)
27252725
{
2726-
int may_perform_io = (__force int)(gfp_mask & __GFP_IO);
27272726
struct zoneref *z;
27282727
struct zone *zone;
27292728
enum compact_result rc = COMPACT_SKIPPED;
27302729

2731-
/*
2732-
* Check if the GFP flags allow compaction - GFP_NOIO is really
2733-
* tricky context because the migration might require IO
2734-
*/
2735-
if (!may_perform_io)
2730+
if (!gfp_compaction_allowed(gfp_mask))
27362731
return COMPACT_SKIPPED;
27372732

27382733
trace_mm_compaction_try_to_compact_pages(order, gfp_mask, prio);

mm/page_alloc.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4041,6 +4041,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
40414041
struct alloc_context *ac)
40424042
{
40434043
bool can_direct_reclaim = gfp_mask & __GFP_DIRECT_RECLAIM;
4044+
bool can_compact = gfp_compaction_allowed(gfp_mask);
40444045
const bool costly_order = order > PAGE_ALLOC_COSTLY_ORDER;
40454046
struct page *page = NULL;
40464047
unsigned int alloc_flags;
@@ -4111,7 +4112,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
41114112
* Don't try this for allocations that are allowed to ignore
41124113
* watermarks, as the ALLOC_NO_WATERMARKS attempt didn't yet happen.
41134114
*/
4114-
if (can_direct_reclaim &&
4115+
if (can_direct_reclaim && can_compact &&
41154116
(costly_order ||
41164117
(order > 0 && ac->migratetype != MIGRATE_MOVABLE))
41174118
&& !gfp_pfmemalloc_allowed(gfp_mask)) {
@@ -4209,9 +4210,10 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
42094210

42104211
/*
42114212
* Do not retry costly high order allocations unless they are
4212-
* __GFP_RETRY_MAYFAIL
4213+
* __GFP_RETRY_MAYFAIL and we can compact
42134214
*/
4214-
if (costly_order && !(gfp_mask & __GFP_RETRY_MAYFAIL))
4215+
if (costly_order && (!can_compact ||
4216+
!(gfp_mask & __GFP_RETRY_MAYFAIL)))
42154217
goto nopage;
42164218

42174219
if (should_reclaim_retry(gfp_mask, order, ac, alloc_flags,
@@ -4224,7 +4226,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
42244226
* implementation of the compaction depends on the sufficient amount
42254227
* of free memory (see __compaction_suitable)
42264228
*/
4227-
if (did_some_progress > 0 &&
4229+
if (did_some_progress > 0 && can_compact &&
42284230
should_compact_retry(ac, order, alloc_flags,
42294231
compact_result, &compact_priority,
42304232
&compaction_retries))

mm/vmscan.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5753,7 +5753,7 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
57535753
/* Use reclaim/compaction for costly allocs or under memory pressure */
57545754
static bool in_reclaim_compaction(struct scan_control *sc)
57555755
{
5756-
if (IS_ENABLED(CONFIG_COMPACTION) && sc->order &&
5756+
if (gfp_compaction_allowed(sc->gfp_mask) && sc->order &&
57575757
(sc->order > PAGE_ALLOC_COSTLY_ORDER ||
57585758
sc->priority < DEF_PRIORITY - 2))
57595759
return true;
@@ -5998,6 +5998,9 @@ static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
59985998
{
59995999
unsigned long watermark;
60006000

6001+
if (!gfp_compaction_allowed(sc->gfp_mask))
6002+
return false;
6003+
60016004
/* Allocation can already succeed, nothing to do */
60026005
if (zone_watermark_ok(zone, sc->order, min_wmark_pages(zone),
60036006
sc->reclaim_idx, 0))

0 commit comments

Comments
 (0)