Commit 49e068f0 authored by Vlastimil Babka's avatar Vlastimil Babka Committed by Linus Torvalds

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: default avatarVlastimil Babka <vbabka@suse.cz>
Reported-by: default avatarHeesub Shin <heesub.shin@samsung.com>
Acked-by: default avatarMinchan Kim <minchan@kernel.org>
Cc: Mel Gorman <mgorman@suse.de>
Acked-by: default avatarJoonsoo 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: default avatarRik 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 0e3b7e54
...@@ -671,16 +671,20 @@ static void isolate_freepages(struct zone *zone, ...@@ -671,16 +671,20 @@ static void isolate_freepages(struct zone *zone,
struct compact_control *cc) struct compact_control *cc)
{ {
struct page *page; struct page *page;
unsigned long high_pfn, low_pfn, pfn, z_end_pfn, end_pfn; unsigned long high_pfn, low_pfn, pfn, z_end_pfn;
int nr_freepages = cc->nr_freepages; int nr_freepages = cc->nr_freepages;
struct list_head *freelist = &cc->freepages; struct list_head *freelist = &cc->freepages;
/* /*
* Initialise the free scanner. The starting point is where we last * Initialise the free scanner. The starting point is where we last
* scanned from (or the end of the zone if starting). The low point * successfully isolated from, zone-cached value, or the end of the
* is the end of the pageblock the migration scanner is using. * zone when isolating for the first time. We need this aligned to
* the pageblock boundary, because we do pfn -= pageblock_nr_pages
* in the for loop.
* The low boundary is the end of the pageblock the migration scanner
* is using.
*/ */
pfn = cc->free_pfn; pfn = cc->free_pfn & ~(pageblock_nr_pages-1);
low_pfn = ALIGN(cc->migrate_pfn + 1, pageblock_nr_pages); low_pfn = ALIGN(cc->migrate_pfn + 1, pageblock_nr_pages);
/* /*
...@@ -700,6 +704,7 @@ static void isolate_freepages(struct zone *zone, ...@@ -700,6 +704,7 @@ static void isolate_freepages(struct zone *zone,
for (; pfn >= low_pfn && cc->nr_migratepages > nr_freepages; for (; pfn >= low_pfn && cc->nr_migratepages > nr_freepages;
pfn -= pageblock_nr_pages) { pfn -= pageblock_nr_pages) {
unsigned long isolated; unsigned long isolated;
unsigned long end_pfn;
/* /*
* This can iterate a massively long zone without finding any * This can iterate a massively long zone without finding any
...@@ -734,13 +739,10 @@ static void isolate_freepages(struct zone *zone, ...@@ -734,13 +739,10 @@ static void isolate_freepages(struct zone *zone,
isolated = 0; isolated = 0;
/* /*
* As pfn may not start aligned, pfn+pageblock_nr_page * Take care when isolating in last pageblock of a zone which
* may cross a MAX_ORDER_NR_PAGES boundary and miss * ends in the middle of a pageblock.
* a pfn_valid check. Ensure isolate_freepages_block()
* only scans within a pageblock
*/ */
end_pfn = ALIGN(pfn + 1, pageblock_nr_pages); end_pfn = min(pfn + pageblock_nr_pages, z_end_pfn);
end_pfn = min(end_pfn, z_end_pfn);
isolated = isolate_freepages_block(cc, pfn, end_pfn, isolated = isolate_freepages_block(cc, pfn, end_pfn,
freelist, false); freelist, false);
nr_freepages += isolated; nr_freepages += isolated;
......
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