atl1e: Use setup_timer
[cascardo/linux.git] / mm / compaction.c
index f9792ba..546e571 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
@@ -1086,9 +1074,9 @@ static int compact_finished(struct zone *zone, struct compact_control *cc,
 
        /* Compaction run is not finished if the watermark is not met */
        watermark = low_wmark_pages(zone);
-       watermark += (1 << cc->order);
 
-       if (!zone_watermark_ok(zone, cc->order, watermark, 0, 0))
+       if (!zone_watermark_ok(zone, cc->order, watermark, cc->classzone_idx,
+                                                       cc->alloc_flags))
                return COMPACT_CONTINUE;
 
        /* Direct compactor: Is a suitable page free? */
@@ -1114,7 +1102,8 @@ static int compact_finished(struct zone *zone, struct compact_control *cc,
  *   COMPACT_PARTIAL  - If the allocation would succeed without compaction
  *   COMPACT_CONTINUE - If compaction should run now
  */
-unsigned long compaction_suitable(struct zone *zone, int order)
+unsigned long compaction_suitable(struct zone *zone, int order,
+                                       int alloc_flags, int classzone_idx)
 {
        int fragindex;
        unsigned long watermark;
@@ -1126,21 +1115,30 @@ unsigned long compaction_suitable(struct zone *zone, int order)
        if (order == -1)
                return COMPACT_CONTINUE;
 
+       watermark = low_wmark_pages(zone);
+       /*
+        * If watermarks for high-order allocation are already met, there
+        * should be no need for compaction at all.
+        */
+       if (zone_watermark_ok(zone, order, watermark, classzone_idx,
+                                                               alloc_flags))
+               return COMPACT_PARTIAL;
+
        /*
         * Watermarks for order-0 must be met for compaction. Note the 2UL.
         * This is because during migration, copies of pages need to be
         * allocated and for a short time, the footprint is higher
         */
-       watermark = low_wmark_pages(zone) + (2UL << order);
-       if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
+       watermark += (2UL << order);
+       if (!zone_watermark_ok(zone, 0, watermark, classzone_idx, alloc_flags))
                return COMPACT_SKIPPED;
 
        /*
         * fragmentation index determines if allocation failures are due to
         * low memory or external fragmentation
         *
-        * index of -1000 implies allocations might succeed depending on
-        * watermarks
+        * index of -1000 would imply allocations might succeed depending on
+        * watermarks, but we already failed the high-order watermark check
         * index towards 0 implies failure is due to lack of memory
         * index towards 1000 implies failure is due to fragmentation
         *
@@ -1150,10 +1148,6 @@ unsigned long compaction_suitable(struct zone *zone, int order)
        if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold)
                return COMPACT_SKIPPED;
 
-       if (fragindex == -1000 && zone_watermark_ok(zone, order, watermark,
-           0, 0))
-               return COMPACT_PARTIAL;
-
        return COMPACT_CONTINUE;
 }
 
@@ -1164,8 +1158,10 @@ 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);
+       ret = compaction_suitable(zone, cc->order, cc->alloc_flags,
+                                                       cc->classzone_idx);
        switch (ret) {
        case COMPACT_PARTIAL:
        case COMPACT_SKIPPED:
@@ -1208,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:
@@ -1216,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:
                        ;
                }
@@ -1241,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);
 
@@ -1254,7 +1305,8 @@ out:
 }
 
 static unsigned long compact_zone_order(struct zone *zone, int order,
-               gfp_t gfp_mask, enum migrate_mode mode, int *contended)
+               gfp_t gfp_mask, enum migrate_mode mode, int *contended,
+               int alloc_flags, int classzone_idx)
 {
        unsigned long ret;
        struct compact_control cc = {
@@ -1264,6 +1316,8 @@ static unsigned long compact_zone_order(struct zone *zone, int order,
                .gfp_mask = gfp_mask,
                .zone = zone,
                .mode = mode,
+               .alloc_flags = alloc_flags,
+               .classzone_idx = classzone_idx,
        };
        INIT_LIST_HEAD(&cc.freepages);
        INIT_LIST_HEAD(&cc.migratepages);
@@ -1288,14 +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,
-                       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;
@@ -1303,7 +1356,6 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
        struct zoneref *z;
        struct zone *zone;
        int rc = COMPACT_DEFERRED;
-       int alloc_flags = 0;
        int all_zones_contended = COMPACT_CONTENDED_LOCK; /* init for &= op */
 
        *contended = COMPACT_CONTENDED_NONE;
@@ -1312,10 +1364,6 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
        if (!order || !may_enter_fs || !may_perform_io)
                return COMPACT_SKIPPED;
 
-#ifdef CONFIG_CMA
-       if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
-               alloc_flags |= ALLOC_CMA;
-#endif
        /* Compact each zone in the list */
        for_each_zone_zonelist_nodemask(zone, z, zonelist, high_zoneidx,
                                                                nodemask) {
@@ -1326,7 +1374,7 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
                        continue;
 
                status = compact_zone_order(zone, order, gfp_mask, mode,
-                                                       &zone_contended);
+                               &zone_contended, alloc_flags, classzone_idx);
                rc = max(status, rc);
                /*
                 * It takes at least one zone that wasn't lock contended
@@ -1335,9 +1383,8 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
                all_zones_contended &= zone_contended;
 
                /* If a normal allocation would succeed, stop compacting */
-               if (zone_watermark_ok(zone, order, low_wmark_pages(zone), 0,
-                                     alloc_flags)) {
-                       *candidate_zone = zone;
+               if (zone_watermark_ok(zone, order, low_wmark_pages(zone),
+                                       classzone_idx, alloc_flags)) {
                        /*
                         * We think the allocation will succeed in this zone,
                         * but it is not certain, hence the false. The caller
@@ -1359,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