Patchwork [3.11.y.z,extended,stable] Patch "mm/compaction: make isolate_freepages start at pageblock boundary" has been added to staging queue

mail settings
Submitter Luis Henriques
Date May 14, 2014, 2:57 p.m.
Message ID <>
Download mbox | patch
Permalink /patch/349190/
State New
Headers show


Luis Henriques - May 14, 2014, 2:57 p.m.
This is a note to let you know that I have just added a patch titled

    mm/compaction: make isolate_freepages start at pageblock boundary

to the linux-3.11.y-queue branch of the 3.11.y.z extended stable tree 
which can be found at:;a=shortlog;h=refs/heads/linux-3.11.y-queue

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.11.y.z tree, see



From d3cf1fbe9a0de6e049a39168c4f38fafcec86fd3 Mon Sep 17 00:00:00 2001
From: Vlastimil Babka <>
Date: Tue, 6 May 2014 12:50:03 -0700
Subject: mm/compaction: make isolate_freepages start at pageblock boundary

commit 49e068f0b73dd042c186ffa9b420a9943e90389a upstream.

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 <>
Reported-by: Heesub Shin <>
Acked-by: Minchan Kim <>
Cc: Mel Gorman <>
Acked-by: Joonsoo Kim <>
Cc: Bartlomiej Zolnierkiewicz <>
Cc: Michal Nazarewicz <>
Cc: Naoya Horiguchi <>
Cc: Christoph Lameter <>
Acked-by: Rik van Riel <>
Cc: Dongjun Shin <>
Cc: Sunghwan Yun <>
Signed-off-by: Andrew Morton <>
Signed-off-by: Linus Torvalds <>
Signed-off-by: Luis Henriques <>
 mm/compaction.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)



diff --git a/mm/compaction.c b/mm/compaction.c
index 18a90b4..46e2f96 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -657,16 +657,20 @@  static void isolate_freepages(struct zone *zone,
 				struct compact_control *cc)
 	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;
 	struct list_head *freelist = &cc->freepages;

 	 * Initialise the free scanner. The starting point is where we last
-	 * scanned from (or the end of the zone if starting). The low point
-	 * is the end of the pageblock the migration scanner is using.
+	 * successfully isolated from, zone-cached value, or the end of the
+	 * 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 = cc->migrate_pfn + pageblock_nr_pages;

@@ -686,6 +690,7 @@  static void isolate_freepages(struct zone *zone,
 	for (; pfn > low_pfn && cc->nr_migratepages > nr_freepages;
 					pfn -= pageblock_nr_pages) {
 		unsigned long isolated;
+		unsigned long end_pfn;

 		if (!pfn_valid(pfn))
@@ -713,13 +718,10 @@  static void isolate_freepages(struct zone *zone,
 		isolated = 0;

-		 * As pfn may not start aligned, pfn+pageblock_nr_page
-		 * may cross a MAX_ORDER_NR_PAGES boundary and miss
-		 * a pfn_valid check. Ensure isolate_freepages_block()
-		 * only scans within a pageblock
+		 * Take care when isolating in last pageblock of a zone which
+		 * ends in the middle of a pageblock.
-		end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
-		end_pfn = min(end_pfn, z_end_pfn);
+		end_pfn = min(pfn + pageblock_nr_pages, z_end_pfn);
 		isolated = isolate_freepages_block(cc, pfn, end_pfn,
 						   freelist, false);
 		nr_freepages += isolated;