memcg: turn memcg_kmem_skip_account into a bit field
[deliverable/linux.git] / mm / compaction.c
index 1fc6736815e04c3e2cd7f48c3bfedad9d616b69a..546e571e9d60d1df57155833ab0e2d6afcb33ac0 100644 (file)
@@ -41,15 +41,17 @@ static inline void count_compact_events(enum vm_event_item item, long delta)
 static unsigned long release_freepages(struct list_head *freelist)
 {
        struct page *page, *next;
-       unsigned long count = 0;
+       unsigned long high_pfn = 0;
 
        list_for_each_entry_safe(page, next, freelist, lru) {
+               unsigned long pfn = page_to_pfn(page);
                list_del(&page->lru);
                __free_page(page);
-               count++;
+               if (pfn > high_pfn)
+                       high_pfn = pfn;
        }
 
-       return count;
+       return high_pfn;
 }
 
 static void map_pages(struct list_head *list)
@@ -195,16 +197,12 @@ static void update_pageblock_skip(struct compact_control *cc,
 
        /* Update where async and sync compaction should restart */
        if (migrate_scanner) {
-               if (cc->finished_update_migrate)
-                       return;
                if (pfn > zone->compact_cached_migrate_pfn[0])
                        zone->compact_cached_migrate_pfn[0] = pfn;
                if (cc->mode != MIGRATE_ASYNC &&
                    pfn > zone->compact_cached_migrate_pfn[1])
                        zone->compact_cached_migrate_pfn[1] = pfn;
        } else {
-               if (cc->finished_update_free)
-                       return;
                if (pfn < zone->compact_cached_free_pfn)
                        zone->compact_cached_free_pfn = pfn;
        }
@@ -715,7 +713,6 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                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++;
@@ -888,15 +885,6 @@ static void isolate_freepages(struct compact_control *cc)
                                isolate_start_pfn :
                                block_start_pfn - pageblock_nr_pages;
 
-               /*
-                * Set a flag that we successfully isolated in this pageblock.
-                * In the next loop iteration, zone->compact_cached_free_pfn
-                * will not be updated and thus it will effectively contain the
-                * highest pageblock we isolated pages from.
-                */
-               if (isolated)
-                       cc->finished_update_free = true;
-
                /*
                 * isolate_freepages_block() might have aborted due to async
                 * compaction being contended
@@ -1170,6 +1158,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
        unsigned long end_pfn = zone_end_pfn(zone);
        const int migratetype = gfpflags_to_migratetype(cc->gfp_mask);
        const bool sync = cc->mode != MIGRATE_ASYNC;
+       unsigned long last_migrated_pfn = 0;
 
        ret = compaction_suitable(zone, cc->order, cc->alloc_flags,
                                                        cc->classzone_idx);
@@ -1215,6 +1204,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
        while ((ret = compact_finished(zone, cc, migratetype)) ==
                                                COMPACT_CONTINUE) {
                int err;
+               unsigned long isolate_start_pfn = cc->migrate_pfn;
 
                switch (isolate_migratepages(zone, cc)) {
                case ISOLATE_ABORT:
@@ -1223,7 +1213,12 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
                        cc->nr_migratepages = 0;
                        goto out;
                case ISOLATE_NONE:
-                       continue;
+                       /*
+                        * We haven't isolated and migrated anything, but
+                        * there might still be unflushed migrations from
+                        * previous cc->order aligned block.
+                        */
+                       goto check_drain;
                case ISOLATE_SUCCESS:
                        ;
                }
@@ -1248,12 +1243,61 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
                                goto out;
                        }
                }
+
+               /*
+                * Record where we could have freed pages by migration and not
+                * yet flushed them to buddy allocator. We use the pfn that
+                * isolate_migratepages() started from in this loop iteration
+                * - this is the lowest page that could have been isolated and
+                * then freed by migration.
+                */
+               if (!last_migrated_pfn)
+                       last_migrated_pfn = isolate_start_pfn;
+
+check_drain:
+               /*
+                * Has the migration scanner moved away from the previous
+                * cc->order aligned block where we migrated from? If yes,
+                * flush the pages that were freed, so that they can merge and
+                * compact_finished() can detect immediately if allocation
+                * would succeed.
+                */
+               if (cc->order > 0 && last_migrated_pfn) {
+                       int cpu;
+                       unsigned long current_block_start =
+                               cc->migrate_pfn & ~((1UL << cc->order) - 1);
+
+                       if (last_migrated_pfn < current_block_start) {
+                               cpu = get_cpu();
+                               lru_add_drain_cpu(cpu);
+                               drain_local_pages(zone);
+                               put_cpu();
+                               /* No more flushing until we migrate again */
+                               last_migrated_pfn = 0;
+                       }
+               }
+
        }
 
 out:
-       /* Release free pages and check accounting */
-       cc->nr_freepages -= release_freepages(&cc->freepages);
-       VM_BUG_ON(cc->nr_freepages != 0);
+       /*
+        * Release free pages and update where the free scanner should restart,
+        * so we don't leave any returned pages behind in the next attempt.
+        */
+       if (cc->nr_freepages > 0) {
+               unsigned long free_pfn = release_freepages(&cc->freepages);
+
+               cc->nr_freepages = 0;
+               VM_BUG_ON(free_pfn == 0);
+               /* The cached pfn is always the first in a pageblock */
+               free_pfn &= ~(pageblock_nr_pages-1);
+               /*
+                * Only go back, not forward. The cached pfn might have been
+                * already reset to zone end in compact_finished()
+                */
+               if (free_pfn > zone->compact_cached_free_pfn)
+                       zone->compact_cached_free_pfn = free_pfn;
+       }
 
        trace_mm_compaction_end(ret);
 
@@ -1298,15 +1342,13 @@ int sysctl_extfrag_threshold = 500;
  * @mode: The migration mode for async, sync light, or sync migration
  * @contended: Return value that determines if compaction was aborted due to
  *            need_resched() or lock contention
- * @candidate_zone: Return the zone where we think allocation should succeed
  *
  * This is the main entry point for direct page compaction.
  */
 unsigned long try_to_compact_pages(struct zonelist *zonelist,
                        int order, gfp_t gfp_mask, nodemask_t *nodemask,
                        enum migrate_mode mode, int *contended,
-                       int alloc_flags, int classzone_idx,
-                       struct zone **candidate_zone)
+                       int alloc_flags, int classzone_idx)
 {
        enum zone_type high_zoneidx = gfp_zone(gfp_mask);
        int may_enter_fs = gfp_mask & __GFP_FS;
@@ -1343,7 +1385,6 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
                /* If a normal allocation would succeed, stop compacting */
                if (zone_watermark_ok(zone, order, low_wmark_pages(zone),
                                        classzone_idx, alloc_flags)) {
-                       *candidate_zone = zone;
                        /*
                         * We think the allocation will succeed in this zone,
                         * but it is not certain, hence the false. The caller
@@ -1365,7 +1406,7 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
                        goto break_loop;
                }
 
-               if (mode != MIGRATE_ASYNC) {
+               if (mode != MIGRATE_ASYNC && status == COMPACT_COMPLETE) {
                        /*
                         * We think that allocation won't succeed in this zone
                         * so we defer compaction there. If it ends up
This page took 0.025797 seconds and 5 git commands to generate.