nmi_backtrace: generate one-line reports for idle cpus
[cascardo/linux.git] / mm / compaction.c
index 335eeee..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 */
@@ -1316,7 +1320,7 @@ static enum compact_result __compact_finished(struct zone *zone, struct compact_
                return COMPACT_CONTINUE;
 
        /* Compaction run is not finished if the watermark is not met */
-       watermark = low_wmark_pages(zone);
+       watermark = zone->watermark[cc->alloc_flags & ALLOC_WMARK_MASK];
 
        if (!zone_watermark_ok(zone, cc->order, watermark, cc->classzone_idx,
                                                        cc->alloc_flags))
@@ -1375,13 +1379,12 @@ 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))
                return COMPACT_CONTINUE;
 
-       watermark = low_wmark_pages(zone);
+       watermark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK];
        /*
         * If watermarks for high-order allocation are already met, there
         * should be no need for compaction at all.
@@ -1391,30 +1394,26 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
                return COMPACT_SUCCESS;
 
        /*
-        * 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
+        * Watermarks for order-0 must be met for compaction to be able to
+        * isolate free pages for migration targets. This means that the
+        * watermark and alloc_flags have to match, or be more pessimistic than
+        * the check in __isolate_free_page(). We don't use the direct
+        * compactor's alloc_flags, as they are not relevant for freepage
+        * 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 += (2UL << 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_flags, wmark_target))
+                                               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;
 }
 
@@ -1423,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;
@@ -1458,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;
        }
 
@@ -1644,6 +1665,9 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,
                .alloc_flags = alloc_flags,
                .classzone_idx = classzone_idx,
                .direct_compaction = true,
+               .whole_zone = (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);
@@ -1689,7 +1713,8 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
                                                                ac->nodemask) {
                enum compact_result status;
 
-               if (compaction_deferred(zone, order)) {
+               if (prio > MIN_COMPACT_PRIORITY
+                                       && compaction_deferred(zone, order)) {
                        rc = max_t(enum compact_result, COMPACT_DEFERRED, rc);
                        continue;
                }
@@ -1698,9 +1723,8 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
                                        alloc_flags, ac_classzone_idx(ac));
                rc = max(status, rc);
 
-               /* If a normal allocation would succeed, stop compacting */
-               if (zone_watermark_ok(zone, order, low_wmark_pages(zone),
-                                       ac_classzone_idx(ac), alloc_flags)) {
+               /* The allocation should succeed, stop compacting */
+               if (status == COMPACT_SUCCESS) {
                        /*
                         * We think the allocation will succeed in this zone,
                         * but it is not certain, hence the false. The caller
@@ -1873,8 +1897,6 @@ static void kcompactd_do_work(pg_data_t *pgdat)
                .ignore_skip_hint = true,
 
        };
-       bool success = false;
-
        trace_mm_compaction_kcompactd_wake(pgdat->node_id, cc.order,
                                                        cc.classzone_idx);
        count_vm_event(KCOMPACTD_WAKE);
@@ -1903,9 +1925,7 @@ static void kcompactd_do_work(pg_data_t *pgdat)
                        return;
                status = compact_zone(zone, &cc);
 
-               if (zone_watermark_ok(zone, cc.order, low_wmark_pages(zone),
-                                               cc.classzone_idx, 0)) {
-                       success = true;
+               if (status == COMPACT_SUCCESS) {
                        compaction_defer_reset(zone, cc.order, false);
                } else if (status == COMPACT_PARTIAL_SKIPPED || status == COMPACT_COMPLETE) {
                        /*