Merge tag 'for-linus-20140507' of git://git.infradead.org/linux-mtd
[firefly-linux-kernel-4.4.55.git] / mm / compaction.c
index 3a1828541dc0ba4861f0827e1479d4fef5cb31cf..627dc2e4320fdf976895e9b96c2c54d91b2b2760 100644 (file)
@@ -460,12 +460,13 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
        unsigned long last_pageblock_nr = 0, pageblock_nr;
        unsigned long nr_scanned = 0, nr_isolated = 0;
        struct list_head *migratelist = &cc->migratepages;
-       isolate_mode_t mode = 0;
        struct lruvec *lruvec;
        unsigned long flags;
        bool locked = false;
        struct page *page = NULL, *valid_page = NULL;
        bool skipped_async_unsuitable = false;
+       const isolate_mode_t mode = (!cc->sync ? ISOLATE_ASYNC_MIGRATE : 0) |
+                                   (unevictable ? ISOLATE_UNEVICTABLE : 0);
 
        /*
         * Ensure that there are not too many pages isolated from the LRU
@@ -487,7 +488,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
        cond_resched();
        for (; low_pfn < end_pfn; low_pfn++) {
                /* give a chance to irqs before checking need_resched() */
-               if (locked && !((low_pfn+1) % SWAP_CLUSTER_MAX)) {
+               if (locked && !(low_pfn % SWAP_CLUSTER_MAX)) {
                        if (should_release_lock(&zone->lru_lock)) {
                                spin_unlock_irqrestore(&zone->lru_lock, flags);
                                locked = false;
@@ -526,8 +527,25 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
 
                /* If isolation recently failed, do not retry */
                pageblock_nr = low_pfn >> pageblock_order;
-               if (!isolation_suitable(cc, page))
-                       goto next_pageblock;
+               if (last_pageblock_nr != pageblock_nr) {
+                       int mt;
+
+                       last_pageblock_nr = pageblock_nr;
+                       if (!isolation_suitable(cc, page))
+                               goto next_pageblock;
+
+                       /*
+                        * For async migration, also only scan in MOVABLE
+                        * blocks. Async migration is optimistic to see if
+                        * the minimum amount of work satisfies the allocation
+                        */
+                       mt = get_pageblock_migratetype(page);
+                       if (!cc->sync && !migrate_async_suitable(mt)) {
+                               cc->finished_update_migrate = true;
+                               skipped_async_unsuitable = true;
+                               goto next_pageblock;
+                       }
+               }
 
                /*
                 * Skip if free. page_order cannot be used without zone->lock
@@ -536,18 +554,6 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
                if (PageBuddy(page))
                        continue;
 
-               /*
-                * For async migration, also only scan in MOVABLE blocks. Async
-                * migration is optimistic to see if the minimum amount of work
-                * satisfies the allocation
-                */
-               if (!cc->sync && last_pageblock_nr != pageblock_nr &&
-                   !migrate_async_suitable(get_pageblock_migratetype(page))) {
-                       cc->finished_update_migrate = true;
-                       skipped_async_unsuitable = true;
-                       goto next_pageblock;
-               }
-
                /*
                 * Check may be lockless but that's ok as we recheck later.
                 * It's possible to migrate LRU pages and balloon pages
@@ -557,11 +563,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
                        if (unlikely(balloon_page_movable(page))) {
                                if (locked && balloon_page_isolate(page)) {
                                        /* Successfully isolated */
-                                       cc->finished_update_migrate = true;
-                                       list_add(&page->lru, migratelist);
-                                       cc->nr_migratepages++;
-                                       nr_isolated++;
-                                       goto check_compact_cluster;
+                                       goto isolate_success;
                                }
                        }
                        continue;
@@ -607,12 +609,6 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
                        continue;
                }
 
-               if (!cc->sync)
-                       mode |= ISOLATE_ASYNC_MIGRATE;
-
-               if (unevictable)
-                       mode |= ISOLATE_UNEVICTABLE;
-
                lruvec = mem_cgroup_page_lruvec(page, zone);
 
                /* Try isolate the page */
@@ -622,13 +618,14 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
                VM_BUG_ON_PAGE(PageTransCompound(page), page);
 
                /* Successfully isolated */
-               cc->finished_update_migrate = true;
                del_page_from_lru_list(page, lruvec, page_lru(page));
+
+isolate_success:
+               cc->finished_update_migrate = true;
                list_add(&page->lru, migratelist);
                cc->nr_migratepages++;
                nr_isolated++;
 
-check_compact_cluster:
                /* Avoid isolating too much */
                if (cc->nr_migratepages == COMPACT_CLUSTER_MAX) {
                        ++low_pfn;
@@ -639,7 +636,6 @@ check_compact_cluster:
 
 next_pageblock:
                low_pfn = ALIGN(low_pfn + 1, pageblock_nr_pages) - 1;
-               last_pageblock_nr = pageblock_nr;
        }
 
        acct_isolated(zone, locked, cc);
@@ -675,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);
 
        /*
@@ -704,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
@@ -738,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;