diff options
author | Vlastimil Babka <vbabka@suse.cz> | 2014-05-06 15:50:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-05-06 16:04:59 -0400 |
commit | 49e068f0b73dd042c186ffa9b420a9943e90389a (patch) | |
tree | defb673f5ac84bdc9824fb3200fee1933b28aea9 | |
parent | 0e3b7e5402cbec4cee58895a00945356ee26a720 (diff) |
mm/compaction: make isolate_freepages start at pageblock boundary
The compaction freepage scanner implementation in isolate_freepages()
starts by taking the current cc->free_pfn value as the first pfn. In a
for loop, it scans from this first pfn to the end of the pageblock, and
then subtracts pageblock_nr_pages from the first pfn to obtain the first
pfn for the next for loop iteration.
This means that when cc->free_pfn starts at offset X rather than being
aligned on pageblock boundary, the scanner will start at offset X in all
scanned pageblock, ignoring potentially many free pages. Currently this
can happen when
a) zone's end pfn is not pageblock aligned, or
b) through zone->compact_cached_free_pfn with CONFIG_HOLES_IN_ZONE
enabled and a hole spanning the beginning of a pageblock
This patch fixes the problem by aligning the initial pfn in
isolate_freepages() to pageblock boundary. This also permits replacing
the end-of-pageblock alignment within the for loop with a simple
pageblock_nr_pages increment.
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Reported-by: Heesub Shin <heesub.shin@samsung.com>
Acked-by: Minchan Kim <minchan@kernel.org>
Cc: Mel Gorman <mgorman@suse.de>
Acked-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Cc: Michal Nazarewicz <mina86@mina86.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Christoph Lameter <cl@linux.com>
Acked-by: Rik van Riel <riel@redhat.com>
Cc: Dongjun Shin <d.j.shin@samsung.com>
Cc: Sunghwan Yun <sunghwan.yun@samsung.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | mm/compaction.c | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/mm/compaction.c b/mm/compaction.c index 37f976287068..627dc2e4320f 100644 --- a/mm/compaction.c +++ b/mm/compaction.c | |||
@@ -671,16 +671,20 @@ static void isolate_freepages(struct zone *zone, | |||
671 | struct compact_control *cc) | 671 | struct compact_control *cc) |
672 | { | 672 | { |
673 | struct page *page; | 673 | struct page *page; |
674 | unsigned long high_pfn, low_pfn, pfn, z_end_pfn, end_pfn; | 674 | unsigned long high_pfn, low_pfn, pfn, z_end_pfn; |
675 | int nr_freepages = cc->nr_freepages; | 675 | int nr_freepages = cc->nr_freepages; |
676 | struct list_head *freelist = &cc->freepages; | 676 | struct list_head *freelist = &cc->freepages; |
677 | 677 | ||
678 | /* | 678 | /* |
679 | * Initialise the free scanner. The starting point is where we last | 679 | * Initialise the free scanner. The starting point is where we last |
680 | * scanned from (or the end of the zone if starting). The low point | 680 | * successfully isolated from, zone-cached value, or the end of the |
681 | * is the end of the pageblock the migration scanner is using. | 681 | * zone when isolating for the first time. We need this aligned to |
682 | * the pageblock boundary, because we do pfn -= pageblock_nr_pages | ||
683 | * in the for loop. | ||
684 | * The low boundary is the end of the pageblock the migration scanner | ||
685 | * is using. | ||
682 | */ | 686 | */ |
683 | pfn = cc->free_pfn; | 687 | pfn = cc->free_pfn & ~(pageblock_nr_pages-1); |
684 | low_pfn = ALIGN(cc->migrate_pfn + 1, pageblock_nr_pages); | 688 | low_pfn = ALIGN(cc->migrate_pfn + 1, pageblock_nr_pages); |
685 | 689 | ||
686 | /* | 690 | /* |
@@ -700,6 +704,7 @@ static void isolate_freepages(struct zone *zone, | |||
700 | for (; pfn >= low_pfn && cc->nr_migratepages > nr_freepages; | 704 | for (; pfn >= low_pfn && cc->nr_migratepages > nr_freepages; |
701 | pfn -= pageblock_nr_pages) { | 705 | pfn -= pageblock_nr_pages) { |
702 | unsigned long isolated; | 706 | unsigned long isolated; |
707 | unsigned long end_pfn; | ||
703 | 708 | ||
704 | /* | 709 | /* |
705 | * This can iterate a massively long zone without finding any | 710 | * This can iterate a massively long zone without finding any |
@@ -734,13 +739,10 @@ static void isolate_freepages(struct zone *zone, | |||
734 | isolated = 0; | 739 | isolated = 0; |
735 | 740 | ||
736 | /* | 741 | /* |
737 | * As pfn may not start aligned, pfn+pageblock_nr_page | 742 | * Take care when isolating in last pageblock of a zone which |
738 | * may cross a MAX_ORDER_NR_PAGES boundary and miss | 743 | * ends in the middle of a pageblock. |
739 | * a pfn_valid check. Ensure isolate_freepages_block() | ||
740 | * only scans within a pageblock | ||
741 | */ | 744 | */ |
742 | end_pfn = ALIGN(pfn + 1, pageblock_nr_pages); | 745 | end_pfn = min(pfn + pageblock_nr_pages, z_end_pfn); |
743 | end_pfn = min(end_pfn, z_end_pfn); | ||
744 | isolated = isolate_freepages_block(cc, pfn, end_pfn, | 746 | isolated = isolate_freepages_block(cc, pfn, end_pfn, |
745 | freelist, false); | 747 | freelist, false); |
746 | nr_freepages += isolated; | 748 | nr_freepages += isolated; |