]> git.karo-electronics.de Git - linux-beck.git/blobdiff - mm/compaction.c
mm, compaction: simplify deferred compaction
[linux-beck.git] / mm / compaction.c
index edba18aed1738c752793f63ae409c22ae373342a..75f4c1206d00501094fdca3905407f2007cbea6d 100644 (file)
@@ -479,6 +479,16 @@ isolate_freepages_range(struct compact_control *cc,
 
                block_end_pfn = min(block_end_pfn, end_pfn);
 
+               /*
+                * pfn could pass the block_end_pfn if isolated freepage
+                * is more than pageblock order. In this case, we adjust
+                * scanning range to right one.
+                */
+               if (pfn >= block_end_pfn) {
+                       block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
+                       block_end_pfn = min(block_end_pfn, end_pfn);
+               }
+
                if (!pageblock_pfn_to_page(pfn, block_end_pfn, cc->zone))
                        break;
 
@@ -784,6 +794,9 @@ isolate_migratepages_range(struct compact_control *cc, unsigned long start_pfn,
                        cc->nr_migratepages = 0;
                        break;
                }
+
+               if (cc->nr_migratepages == COMPACT_CLUSTER_MAX)
+                       break;
        }
        acct_isolated(cc->zone, cc);
 
@@ -1026,8 +1039,12 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
        }
 
        acct_isolated(zone, cc);
-       /* Record where migration scanner will be restarted */
-       cc->migrate_pfn = low_pfn;
+       /*
+        * Record where migration scanner will be restarted. If we end up in
+        * the same pageblock as the free scanner, make the scanners fully
+        * meet so that compact_finished() terminates compaction.
+        */
+       cc->migrate_pfn = (end_pfn <= cc->free_pfn) ? low_pfn : cc->free_pfn;
 
        return cc->nr_migratepages ? ISOLATE_SUCCESS : ISOLATE_NONE;
 }
@@ -1069,9 +1086,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? */
@@ -1097,7 +1114,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;
@@ -1109,21 +1127,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
         *
@@ -1133,10 +1160,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;
 }
 
@@ -1148,7 +1171,8 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
        const int migratetype = gfpflags_to_migratetype(cc->gfp_mask);
        const bool sync = cc->mode != MIGRATE_ASYNC;
 
-       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:
@@ -1237,7 +1261,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 = {
@@ -1247,6 +1272,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);
@@ -1271,14 +1298,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;
@@ -1286,7 +1312,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;
@@ -1295,10 +1320,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) {
@@ -1309,7 +1330,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
@@ -1318,9 +1339,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