|
@@ -671,16 +671,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 = ALIGN(cc->migrate_pfn + 1, pageblock_nr_pages);
|
|
|
|
|
|
/*
|
|
@@ -700,6 +704,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;
|
|
|
|
|
|
/*
|
|
|
* This can iterate a massively long zone without finding any
|
|
@@ -734,13 +739,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;
|