Merge tag 'perf-tools-fixes-for-v6.3-1-2023-03-09' of git://git.kernel.org/pub/scm...
[linux-2.6-microblaze.git] / mm / compaction.c
index 8238e83..5a9501e 100644 (file)
@@ -122,7 +122,6 @@ bool PageMovable(struct page *page)
 
        return false;
 }
-EXPORT_SYMBOL(PageMovable);
 
 void __SetPageMovable(struct page *page, const struct movable_operations *mops)
 {
@@ -977,7 +976,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                                        locked = NULL;
                                }
 
-                               if (!isolate_movable_page(page, mode))
+                               if (isolate_movable_page(page, mode))
                                        goto isolate_success;
                        }
 
@@ -1102,12 +1101,12 @@ isolate_success_no_list:
 
                /*
                 * Avoid isolating too much unless this block is being
-                * rescanned (e.g. dirty/writeback pages, parallel allocation)
+                * fully scanned (e.g. dirty/writeback pages, parallel allocation)
                 * or a lock is contended. For contention, isolate quickly to
                 * potentially remove one source of contention.
                 */
                if (cc->nr_migratepages >= COMPACT_CLUSTER_MAX &&
-                   !cc->rescan && !cc->contended) {
+                   !cc->finish_pageblock && !cc->contended) {
                        ++low_pfn;
                        break;
                }
@@ -1172,14 +1171,14 @@ isolate_abort:
        }
 
        /*
-        * Updated the cached scanner pfn once the pageblock has been scanned
+        * Update the cached scanner pfn once the pageblock has been scanned.
         * Pages will either be migrated in which case there is no point
         * scanning in the near future or migration failed in which case the
         * failure reason may persist. The block is marked for skipping if
         * there were no pages isolated in the block or if the block is
         * rescanned twice in a row.
         */
-       if (low_pfn == end_pfn && (!nr_isolated || cc->rescan)) {
+       if (low_pfn == end_pfn && (!nr_isolated || cc->finish_pageblock)) {
                if (valid_page && !skip_updated)
                        set_pageblock_skip(valid_page);
                update_cached_migrate(cc, low_pfn);
@@ -1762,6 +1761,13 @@ static unsigned long fast_find_migrateblock(struct compact_control *cc)
        if (cc->ignore_skip_hint)
                return pfn;
 
+       /*
+        * If the pageblock should be finished then do not select a different
+        * pageblock.
+        */
+       if (cc->finish_pageblock)
+               return pfn;
+
        /*
         * If the migrate_pfn is not at the start of a zone or the start
         * of a pageblock then assume this is a continuation of a previous
@@ -2027,6 +2033,8 @@ static unsigned int fragmentation_score_node(pg_data_t *pgdat)
                struct zone *zone;
 
                zone = &pgdat->node_zones[zoneid];
+               if (!populated_zone(zone))
+                       continue;
                score += fragmentation_score_zone_weighted(zone);
        }
 
@@ -2315,9 +2323,6 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)
        if (ret == COMPACT_SUCCESS || ret == COMPACT_SKIPPED)
                return ret;
 
-       /* huh, compaction_suitable is returning something unexpected */
-       VM_BUG_ON(ret != COMPACT_CONTINUE);
-
        /*
         * Clear pageblock skip if there were failures recently and compaction
         * is about to be retried after being deferred.
@@ -2375,19 +2380,20 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)
                unsigned long iteration_start_pfn = cc->migrate_pfn;
 
                /*
-                * Avoid multiple rescans which can happen if a page cannot be
-                * isolated (dirty/writeback in async mode) or if the migrated
-                * pages are being allocated before the pageblock is cleared.
-                * The first rescan will capture the entire pageblock for
-                * migration. If it fails, it'll be marked skip and scanning
-                * will proceed as normal.
+                * Avoid multiple rescans of the same pageblock which can
+                * happen if a page cannot be isolated (dirty/writeback in
+                * async mode) or if the migrated pages are being allocated
+                * before the pageblock is cleared.  The first rescan will
+                * capture the entire pageblock for migration. If it fails,
+                * it'll be marked skip and scanning will proceed as normal.
                 */
-               cc->rescan = false;
+               cc->finish_pageblock = false;
                if (pageblock_start_pfn(last_migrated_pfn) ==
                    pageblock_start_pfn(iteration_start_pfn)) {
-                       cc->rescan = true;
+                       cc->finish_pageblock = true;
                }
 
+rescan:
                switch (isolate_migratepages(cc)) {
                case ISOLATE_ABORT:
                        ret = COMPACT_CONTENDED;
@@ -2430,18 +2436,37 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)
                                goto out;
                        }
                        /*
-                        * We failed to migrate at least one page in the current
-                        * order-aligned block, so skip the rest of it.
+                        * If an ASYNC or SYNC_LIGHT fails to migrate a page
+                        * within the current order-aligned block, scan the
+                        * remainder of the pageblock. This will mark the
+                        * pageblock "skip" to avoid rescanning in the near
+                        * future. This will isolate more pages than necessary
+                        * for the request but avoid loops due to
+                        * fast_find_migrateblock revisiting blocks that were
+                        * recently partially scanned.
                         */
-                       if (cc->direct_compaction &&
-                                               (cc->mode == MIGRATE_ASYNC)) {
-                               cc->migrate_pfn = block_end_pfn(
-                                               cc->migrate_pfn - 1, cc->order);
-                               /* Draining pcplists is useless in this case */
-                               last_migrated_pfn = 0;
+                       if (cc->direct_compaction && !cc->finish_pageblock &&
+                                               (cc->mode < MIGRATE_SYNC)) {
+                               cc->finish_pageblock = true;
+
+                               /*
+                                * Draining pcplists does not help THP if
+                                * any page failed to migrate. Even after
+                                * drain, the pageblock will not be free.
+                                */
+                               if (cc->order == COMPACTION_HPAGE_ORDER)
+                                       last_migrated_pfn = 0;
+
+                               goto rescan;
                        }
                }
 
+               /* Stop if a page has been captured */
+               if (capc && capc->page) {
+                       ret = COMPACT_SUCCESS;
+                       break;
+               }
+
 check_drain:
                /*
                 * Has the migration scanner moved away from the previous
@@ -2460,12 +2485,6 @@ check_drain:
                                last_migrated_pfn = 0;
                        }
                }
-
-               /* Stop if a page has been captured */
-               if (capc && capc->page) {
-                       ret = COMPACT_SUCCESS;
-                       break;
-               }
        }
 
 out:
@@ -2493,6 +2512,9 @@ out:
 
        trace_mm_compaction_end(cc, start_pfn, end_pfn, sync, ret);
 
+       VM_BUG_ON(!list_empty(&cc->freepages));
+       VM_BUG_ON(!list_empty(&cc->migratepages));
+
        return ret;
 }
 
@@ -2531,9 +2553,6 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,
 
        ret = compact_zone(&cc, &capc);
 
-       VM_BUG_ON(!list_empty(&cc.freepages));
-       VM_BUG_ON(!list_empty(&cc.migratepages));
-
        /*
         * Make sure we hide capture control first before we read the captured
         * page pointer, otherwise an interrupt could free and capture a page
@@ -2665,8 +2684,10 @@ static void proactive_compact_node(pg_data_t *pgdat)
 
                compact_zone(&cc, NULL);
 
-               VM_BUG_ON(!list_empty(&cc.freepages));
-               VM_BUG_ON(!list_empty(&cc.migratepages));
+               count_compact_events(KCOMPACTD_MIGRATE_SCANNED,
+                                    cc.total_migrate_scanned);
+               count_compact_events(KCOMPACTD_FREE_SCANNED,
+                                    cc.total_free_scanned);
        }
 }
 
@@ -2694,9 +2715,6 @@ static void compact_node(int nid)
                cc.zone = zone;
 
                compact_zone(&cc, NULL);
-
-               VM_BUG_ON(!list_empty(&cc.freepages));
-               VM_BUG_ON(!list_empty(&cc.migratepages));
        }
 }
 
@@ -2736,6 +2754,8 @@ int compaction_proactiveness_sysctl_handler(struct ctl_table *table, int write,
                                continue;
 
                        pgdat->proactive_compact_trigger = true;
+                       trace_mm_compaction_wakeup_kcompactd(pgdat->node_id, -1,
+                                                            pgdat->nr_zones - 1);
                        wake_up_interruptible(&pgdat->kcompactd_wait);
                }
        }
@@ -2873,9 +2893,6 @@ static void kcompactd_do_work(pg_data_t *pgdat)
                                     cc.total_migrate_scanned);
                count_compact_events(KCOMPACTD_FREE_SCANNED,
                                     cc.total_free_scanned);
-
-               VM_BUG_ON(!list_empty(&cc.freepages));
-               VM_BUG_ON(!list_empty(&cc.migratepages));
        }
 
        /*