[Devel] [PATCH RHEL7 COMMIT] ms/mm, compaction: return failed migration target pages back to freelist

Konstantin Khorenko khorenko at virtuozzo.com
Wed Jan 31 18:21:59 MSK 2018


The commit is pushed to "branch-rh7-3.10.0-693.11.6.vz7.42.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.11.6.vz7.42.4
------>
commit de2f34677c1370b39e7cff0ae77f21215585d14f
Author: David Rientjes <rientjes at google.com>
Date:   Wed Jan 31 18:21:59 2018 +0300

    ms/mm, compaction: return failed migration target pages back to freelist
    
    Greg reported that he found isolated free pages were returned back to the
    VM rather than the compaction freelist.  This will cause holes behind the
    free scanner and cause it to reallocate additional memory if necessary
    later.
    
    He detected the problem at runtime seeing that ext4 metadata pages (esp
    the ones read by "sbi->s_group_desc[i] = sb_bread(sb, block)") were
    constantly visited by compaction calls of migrate_pages().  These pages
    had a non-zero b_count which caused fallback_migrate_page() ->
    try_to_release_page() -> try_to_free_buffers() to fail.
    
    Memory compaction works by having a "freeing scanner" scan from one end of
    a zone which isolates pages as migration targets while another "migrating
    scanner" scans from the other end of the same zone which isolates pages
    for migration.
    
    When page migration fails for an isolated page, the target page is
    returned to the system rather than the freelist built by the freeing
    scanner.  This may require the freeing scanner to continue scanning memory
    after suitable migration targets have already been returned to the system
    needlessly.
    
    This patch returns destination pages to the freeing scanner freelist when
    page migration fails.  This prevents unnecessary work done by the freeing
    scanner but also encourages memory to be as compacted as possible at the
    end of the zone.
    
    Signed-off-by: David Rientjes <rientjes at google.com>
    Reported-by: Greg Thelen <gthelen at google.com>
    Acked-by: Mel Gorman <mgorman at suse.de>
    Acked-by: Vlastimil Babka <vbabka at suse.cz>
    Reviewed-by: Naoya Horiguchi <n-horiguchi at ah.jp.nec.com>
    Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
    (cherry picked from commit d53aea3d46d64e95da9952887969f7533b9ab25e)
    Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>
---
 mm/compaction.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/mm/compaction.c b/mm/compaction.c
index 7e74add6b9c2..109647df914d 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -794,23 +794,32 @@ static struct page *compaction_alloc(struct page *migratepage,
 }
 
 /*
- * We cannot control nr_migratepages and nr_freepages fully when migration is
- * running as migrate_pages() has no knowledge of compact_control. When
- * migration is complete, we count the number of pages on the lists by hand.
+ * This is a migrate-callback that "frees" freepages back to the isolated
+ * freelist.  All pages on the freelist are from the same zone, so there is no
+ * special handling needed for NUMA.
+ */
+static void compaction_free(struct page *page, unsigned long data)
+{
+	struct compact_control *cc = (struct compact_control *)data;
+
+	list_add(&page->lru, &cc->freepages);
+	cc->nr_freepages++;
+}
+
+/*
+ * We cannot control nr_migratepages fully when migration is running as
+ * migrate_pages() has no knowledge of of compact_control.  When migration is
+ * complete, we count the number of pages on the list by hand.
  */
 static void update_nr_listpages(struct compact_control *cc)
 {
 	int nr_migratepages = 0;
-	int nr_freepages = 0;
 	struct page *page;
 
 	list_for_each_entry(page, &cc->migratepages, lru)
 		nr_migratepages++;
-	list_for_each_entry(page, &cc->freepages, lru)
-		nr_freepages++;
 
 	cc->nr_migratepages = nr_migratepages;
-	cc->nr_freepages = nr_freepages;
 }
 
 /* possible outcome of isolate_migratepages */
@@ -1020,8 +1029,8 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
 		}
 
 		nr_migrate = cc->nr_migratepages;
-		err = migrate_pages(&cc->migratepages, compaction_alloc, NULL,
-				(unsigned long)cc,
+		err = migrate_pages(&cc->migratepages, compaction_alloc,
+				compaction_free, (unsigned long)cc,
 				cc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC,
 				MR_COMPACTION);
 		update_nr_listpages(cc);


More information about the Devel mailing list