Merge tag 'staging-4.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[cascardo/linux.git] / mm / compaction.c
index 658c009..0409a4a 100644 (file)
@@ -997,8 +997,12 @@ isolate_migratepages_range(struct compact_control *cc, unsigned long start_pfn,
 #ifdef CONFIG_COMPACTION
 
 /* Returns true if the page is within a block suitable for migration to */
-static bool suitable_migration_target(struct page *page)
+static bool suitable_migration_target(struct compact_control *cc,
+                                                       struct page *page)
 {
+       if (cc->ignore_block_suitable)
+               return true;
+
        /* If the page is a large free page, then disallow migration */
        if (PageBuddy(page)) {
                /*
@@ -1083,7 +1087,7 @@ static void isolate_freepages(struct compact_control *cc)
                        continue;
 
                /* Check the block is suitable for migration */
-               if (!suitable_migration_target(page))
+               if (!suitable_migration_target(cc, page))
                        continue;
 
                /* If isolation recently failed, do not retry */
@@ -1375,7 +1379,6 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
                                        int classzone_idx,
                                        unsigned long wmark_target)
 {
-       int fragindex;
        unsigned long watermark;
 
        if (is_via_compact_memory(order))
@@ -1399,29 +1402,18 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
         * isolation. We however do use the direct compactor's classzone_idx to
         * skip over zones where lowmem reserves would prevent allocation even
         * if compaction succeeds.
+        * For costly orders, we require low watermark instead of min for
+        * compaction to proceed to increase its chances.
         * ALLOC_CMA is used, as pages in CMA pageblocks are considered
         * suitable migration targets
         */
-       watermark = low_wmark_pages(zone) + compact_gap(order);
+       watermark = (order > PAGE_ALLOC_COSTLY_ORDER) ?
+                               low_wmark_pages(zone) : min_wmark_pages(zone);
+       watermark += compact_gap(order);
        if (!__zone_watermark_ok(zone, 0, watermark, classzone_idx,
                                                ALLOC_CMA, wmark_target))
                return COMPACT_SKIPPED;
 
-       /*
-        * fragmentation index determines if allocation failures are due to
-        * low memory or external fragmentation
-        *
-        * 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
-        *
-        * Only compact if a failure would be due to fragmentation.
-        */
-       fragindex = fragmentation_index(zone, order);
-       if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold)
-               return COMPACT_NOT_SUITABLE_ZONE;
-
        return COMPACT_CONTINUE;
 }
 
@@ -1430,9 +1422,32 @@ enum compact_result compaction_suitable(struct zone *zone, int order,
                                        int classzone_idx)
 {
        enum compact_result ret;
+       int fragindex;
 
        ret = __compaction_suitable(zone, order, alloc_flags, classzone_idx,
                                    zone_page_state(zone, NR_FREE_PAGES));
+       /*
+        * fragmentation index determines if allocation failures are due to
+        * low memory or external fragmentation
+        *
+        * 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
+        *
+        * Only compact if a failure would be due to fragmentation. Also
+        * ignore fragindex for non-costly orders where the alternative to
+        * a successful reclaim/compaction is OOM. Fragindex and the
+        * vm.extfrag_threshold sysctl is meant as a heuristic to prevent
+        * excessive compaction for costly orders, but it should not be at the
+        * expense of system stability.
+        */
+       if (ret == COMPACT_CONTINUE && (order > PAGE_ALLOC_COSTLY_ORDER)) {
+               fragindex = fragmentation_index(zone, order);
+               if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold)
+                       ret = COMPACT_NOT_SUITABLE_ZONE;
+       }
+
        trace_mm_compaction_suitable(zone, order, ret);
        if (ret == COMPACT_NOT_SUITABLE_ZONE)
                ret = COMPACT_SKIPPED;
@@ -1465,8 +1480,7 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
                available += zone_page_state_snapshot(zone, NR_FREE_PAGES);
                compact_result = __compaction_suitable(zone, order, alloc_flags,
                                ac_classzone_idx(ac), available);
-               if (compact_result != COMPACT_SKIPPED &&
-                               compact_result != COMPACT_NOT_SUITABLE_ZONE)
+               if (compact_result != COMPACT_SKIPPED)
                        return true;
        }
 
@@ -1652,7 +1666,8 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,
                .classzone_idx = classzone_idx,
                .direct_compaction = true,
                .whole_zone = (prio == MIN_COMPACT_PRIORITY),
-               .ignore_skip_hint = (prio == MIN_COMPACT_PRIORITY)
+               .ignore_skip_hint = (prio == MIN_COMPACT_PRIORITY),
+               .ignore_block_suitable = (prio == MIN_COMPACT_PRIORITY)
        };
        INIT_LIST_HEAD(&cc.freepages);
        INIT_LIST_HEAD(&cc.migratepages);