summaryrefslogtreecommitdiffstats
path: root/mm/compaction.c
diff options
context:
space:
mode:
authorDavid Rientjes <rientjes@google.com>2014-06-04 19:08:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-04 19:54:06 -0400
commitd53aea3d46d64e95da9952887969f7533b9ab25e (patch)
tree08274ccc497045f40b2d14d9306be3ccf4aa549a /mm/compaction.c
parent68711a746345c44ae00c64d8dbac6a9ce13ac54a (diff)
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@google.com> Reported-by: Greg Thelen <gthelen@google.com> Acked-by: Mel Gorman <mgorman@suse.de> Acked-by: Vlastimil Babka <vbabka@suse.cz> Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/compaction.c')
-rw-r--r--mm/compaction.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/mm/compaction.c b/mm/compaction.c
index f74a362d2e28..d0c7c994e11b 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -790,23 +790,32 @@ static struct page *compaction_alloc(struct page *migratepage,
790} 790}
791 791
792/* 792/*
793 * We cannot control nr_migratepages and nr_freepages fully when migration is 793 * This is a migrate-callback that "frees" freepages back to the isolated
794 * running as migrate_pages() has no knowledge of compact_control. When 794 * freelist. All pages on the freelist are from the same zone, so there is no
795 * migration is complete, we count the number of pages on the lists by hand. 795 * special handling needed for NUMA.
796 */
797static void compaction_free(struct page *page, unsigned long data)
798{
799 struct compact_control *cc = (struct compact_control *)data;
800
801 list_add(&page->lru, &cc->freepages);
802 cc->nr_freepages++;
803}
804
805/*
806 * We cannot control nr_migratepages fully when migration is running as
807 * migrate_pages() has no knowledge of of compact_control. When migration is
808 * complete, we count the number of pages on the list by hand.
796 */ 809 */
797static void update_nr_listpages(struct compact_control *cc) 810static void update_nr_listpages(struct compact_control *cc)
798{ 811{
799 int nr_migratepages = 0; 812 int nr_migratepages = 0;
800 int nr_freepages = 0;
801 struct page *page; 813 struct page *page;
802 814
803 list_for_each_entry(page, &cc->migratepages, lru) 815 list_for_each_entry(page, &cc->migratepages, lru)
804 nr_migratepages++; 816 nr_migratepages++;
805 list_for_each_entry(page, &cc->freepages, lru)
806 nr_freepages++;
807 817
808 cc->nr_migratepages = nr_migratepages; 818 cc->nr_migratepages = nr_migratepages;
809 cc->nr_freepages = nr_freepages;
810} 819}
811 820
812/* possible outcome of isolate_migratepages */ 821/* possible outcome of isolate_migratepages */
@@ -1016,8 +1025,8 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
1016 } 1025 }
1017 1026
1018 nr_migrate = cc->nr_migratepages; 1027 nr_migrate = cc->nr_migratepages;
1019 err = migrate_pages(&cc->migratepages, compaction_alloc, NULL, 1028 err = migrate_pages(&cc->migratepages, compaction_alloc,
1020 (unsigned long)cc, 1029 compaction_free, (unsigned long)cc,
1021 cc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC, 1030 cc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC,
1022 MR_COMPACTION); 1031 MR_COMPACTION);
1023 update_nr_listpages(cc); 1032 update_nr_listpages(cc);