Commit f9e35b3b authored by Mel Gorman's avatar Mel Gorman Committed by Linus Torvalds

mm: compaction: abort compaction if too many pages are isolated and caller is asynchronous V2

Asynchronous compaction is used when promoting to huge pages.  This is all
very nice but if there are a number of processes in compacting memory, a
large number of pages can be isolated.  An "asynchronous" process can
stall for long periods of time as a result with a user reporting that
firefox can stall for 10s of seconds.  This patch aborts asynchronous
compaction if too many pages are isolated as it's better to fail a
hugepage promotion than stall a process.

[minchan.kim@gmail.com: return COMPACT_PARTIAL for abort]
Reported-and-tested-by: default avatarUry Stankevich <urykhy@gmail.com>
Signed-off-by: default avatarMel Gorman <mgorman@suse.de>
Reviewed-by: default avatarMinchan Kim <minchan.kim@gmail.com>
Reviewed-by: default avatarMichal Hocko <mhocko@suse.cz>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d179e84b
...@@ -251,11 +251,18 @@ static bool too_many_isolated(struct zone *zone) ...@@ -251,11 +251,18 @@ static bool too_many_isolated(struct zone *zone)
return isolated > (inactive + active) / 2; return isolated > (inactive + active) / 2;
} }
/* possible outcome of isolate_migratepages */
typedef enum {
ISOLATE_ABORT, /* Abort compaction now */
ISOLATE_NONE, /* No pages isolated, continue scanning */
ISOLATE_SUCCESS, /* Pages isolated, migrate */
} isolate_migrate_t;
/* /*
* Isolate all pages that can be migrated from the block pointed to by * Isolate all pages that can be migrated from the block pointed to by
* the migrate scanner within compact_control. * the migrate scanner within compact_control.
*/ */
static unsigned long isolate_migratepages(struct zone *zone, static isolate_migrate_t isolate_migratepages(struct zone *zone,
struct compact_control *cc) struct compact_control *cc)
{ {
unsigned long low_pfn, end_pfn; unsigned long low_pfn, end_pfn;
...@@ -272,7 +279,7 @@ static unsigned long isolate_migratepages(struct zone *zone, ...@@ -272,7 +279,7 @@ static unsigned long isolate_migratepages(struct zone *zone,
/* Do not cross the free scanner or scan within a memory hole */ /* Do not cross the free scanner or scan within a memory hole */
if (end_pfn > cc->free_pfn || !pfn_valid(low_pfn)) { if (end_pfn > cc->free_pfn || !pfn_valid(low_pfn)) {
cc->migrate_pfn = end_pfn; cc->migrate_pfn = end_pfn;
return 0; return ISOLATE_NONE;
} }
/* /*
...@@ -281,10 +288,14 @@ static unsigned long isolate_migratepages(struct zone *zone, ...@@ -281,10 +288,14 @@ static unsigned long isolate_migratepages(struct zone *zone,
* delay for some time until fewer pages are isolated * delay for some time until fewer pages are isolated
*/ */
while (unlikely(too_many_isolated(zone))) { while (unlikely(too_many_isolated(zone))) {
/* async migration should just abort */
if (!cc->sync)
return ISOLATE_ABORT;
congestion_wait(BLK_RW_ASYNC, HZ/10); congestion_wait(BLK_RW_ASYNC, HZ/10);
if (fatal_signal_pending(current)) if (fatal_signal_pending(current))
return 0; return ISOLATE_ABORT;
} }
/* Time to isolate some pages for migration */ /* Time to isolate some pages for migration */
...@@ -369,7 +380,7 @@ static unsigned long isolate_migratepages(struct zone *zone, ...@@ -369,7 +380,7 @@ static unsigned long isolate_migratepages(struct zone *zone,
trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated); trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated);
return cc->nr_migratepages; return ISOLATE_SUCCESS;
} }
/* /*
...@@ -535,8 +546,15 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) ...@@ -535,8 +546,15 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
unsigned long nr_migrate, nr_remaining; unsigned long nr_migrate, nr_remaining;
int err; int err;
if (!isolate_migratepages(zone, cc)) switch (isolate_migratepages(zone, cc)) {
case ISOLATE_ABORT:
ret = COMPACT_PARTIAL;
goto out;
case ISOLATE_NONE:
continue; continue;
case ISOLATE_SUCCESS:
;
}
nr_migrate = cc->nr_migratepages; nr_migrate = cc->nr_migratepages;
err = migrate_pages(&cc->migratepages, compaction_alloc, err = migrate_pages(&cc->migratepages, compaction_alloc,
...@@ -560,6 +578,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) ...@@ -560,6 +578,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
} }
out:
/* Release free pages and check accounting */ /* Release free pages and check accounting */
cc->nr_freepages -= release_freepages(&cc->freepages); cc->nr_freepages -= release_freepages(&cc->freepages);
VM_BUG_ON(cc->nr_freepages != 0); VM_BUG_ON(cc->nr_freepages != 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment