aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorMel Gorman <mgorman@suse.de>2011-06-15 18:08:52 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-06-15 23:04:02 -0400
commitf9e35b3b41f47c4e17d8132edbcab305a6aaa4b0 (patch)
treed489fff3885bb7c4df0eebd2f074a398420740e6 /mm
parentd179e84ba5da1d0024087d1759a2938817a00f3f (diff)
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: Ury Stankevich <urykhy@gmail.com> Signed-off-by: Mel Gorman <mgorman@suse.de> Reviewed-by: Minchan Kim <minchan.kim@gmail.com> Reviewed-by: Michal Hocko <mhocko@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/compaction.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/mm/compaction.c b/mm/compaction.c
index 9b94eaf537e4..6cc604bd5649 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -251,11 +251,18 @@ static bool too_many_isolated(struct zone *zone)
251 return isolated > (inactive + active) / 2; 251 return isolated > (inactive + active) / 2;
252} 252}
253 253
254/* possible outcome of isolate_migratepages */
255typedef enum {
256 ISOLATE_ABORT, /* Abort compaction now */
257 ISOLATE_NONE, /* No pages isolated, continue scanning */
258 ISOLATE_SUCCESS, /* Pages isolated, migrate */
259} isolate_migrate_t;
260
254/* 261/*
255 * Isolate all pages that can be migrated from the block pointed to by 262 * Isolate all pages that can be migrated from the block pointed to by
256 * the migrate scanner within compact_control. 263 * the migrate scanner within compact_control.
257 */ 264 */
258static unsigned long isolate_migratepages(struct zone *zone, 265static isolate_migrate_t isolate_migratepages(struct zone *zone,
259 struct compact_control *cc) 266 struct compact_control *cc)
260{ 267{
261 unsigned long low_pfn, end_pfn; 268 unsigned long low_pfn, end_pfn;
@@ -272,7 +279,7 @@ static unsigned long isolate_migratepages(struct zone *zone,
272 /* Do not cross the free scanner or scan within a memory hole */ 279 /* Do not cross the free scanner or scan within a memory hole */
273 if (end_pfn > cc->free_pfn || !pfn_valid(low_pfn)) { 280 if (end_pfn > cc->free_pfn || !pfn_valid(low_pfn)) {
274 cc->migrate_pfn = end_pfn; 281 cc->migrate_pfn = end_pfn;
275 return 0; 282 return ISOLATE_NONE;
276 } 283 }
277 284
278 /* 285 /*
@@ -281,10 +288,14 @@ static unsigned long isolate_migratepages(struct zone *zone,
281 * delay for some time until fewer pages are isolated 288 * delay for some time until fewer pages are isolated
282 */ 289 */
283 while (unlikely(too_many_isolated(zone))) { 290 while (unlikely(too_many_isolated(zone))) {
291 /* async migration should just abort */
292 if (!cc->sync)
293 return ISOLATE_ABORT;
294
284 congestion_wait(BLK_RW_ASYNC, HZ/10); 295 congestion_wait(BLK_RW_ASYNC, HZ/10);
285 296
286 if (fatal_signal_pending(current)) 297 if (fatal_signal_pending(current))
287 return 0; 298 return ISOLATE_ABORT;
288 } 299 }
289 300
290 /* Time to isolate some pages for migration */ 301 /* Time to isolate some pages for migration */
@@ -369,7 +380,7 @@ static unsigned long isolate_migratepages(struct zone *zone,
369 380
370 trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated); 381 trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated);
371 382
372 return cc->nr_migratepages; 383 return ISOLATE_SUCCESS;
373} 384}
374 385
375/* 386/*
@@ -535,8 +546,15 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
535 unsigned long nr_migrate, nr_remaining; 546 unsigned long nr_migrate, nr_remaining;
536 int err; 547 int err;
537 548
538 if (!isolate_migratepages(zone, cc)) 549 switch (isolate_migratepages(zone, cc)) {
550 case ISOLATE_ABORT:
551 ret = COMPACT_PARTIAL;
552 goto out;
553 case ISOLATE_NONE:
539 continue; 554 continue;
555 case ISOLATE_SUCCESS:
556 ;
557 }
540 558
541 nr_migrate = cc->nr_migratepages; 559 nr_migrate = cc->nr_migratepages;
542 err = migrate_pages(&cc->migratepages, compaction_alloc, 560 err = migrate_pages(&cc->migratepages, compaction_alloc,
@@ -560,6 +578,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
560 578
561 } 579 }
562 580
581out:
563 /* Release free pages and check accounting */ 582 /* Release free pages and check accounting */
564 cc->nr_freepages -= release_freepages(&cc->freepages); 583 cc->nr_freepages -= release_freepages(&cc->freepages);
565 VM_BUG_ON(cc->nr_freepages != 0); 584 VM_BUG_ON(cc->nr_freepages != 0);