aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Rientjes2014-08-28 13:35:02 -0500
committerJiri Slaby2014-09-26 04:51:59 -0500
commitb264e9ab205b3038b032a18df181fd6ed7a77ce3 (patch)
tree6978ea90bfbdf79a58853ab49ce44b38f4702f1b
parentee92d4d6d28561c5019da10ed62c5bb8bdcd3c1e (diff)
downloadti-linux-kernel-b264e9ab205b3038b032a18df181fd6ed7a77ce3.tar.gz
ti-linux-kernel-b264e9ab205b3038b032a18df181fd6ed7a77ce3.tar.xz
ti-linux-kernel-b264e9ab205b3038b032a18df181fd6ed7a77ce3.zip
mm, compaction: return failed migration target pages back to freelist
commit d53aea3d46d64e95da9952887969f7533b9ab25e upstream. 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> Signed-off-by: Mel Gorman <mgorman@suse.de> Signed-off-by: Jiri Slaby <jslaby@suse.cz>
-rw-r--r--mm/compaction.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/mm/compaction.c b/mm/compaction.c
index fae59eae87ec..e4add4214028 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -788,23 +788,32 @@ static struct page *compaction_alloc(struct page *migratepage,
788} 788}
789 789
790/* 790/*
791 * We cannot control nr_migratepages and nr_freepages fully when migration is 791 * This is a migrate-callback that "frees" freepages back to the isolated
792 * running as migrate_pages() has no knowledge of compact_control. When 792 * freelist. All pages on the freelist are from the same zone, so there is no
793 * migration is complete, we count the number of pages on the lists by hand. 793 * special handling needed for NUMA.
794 */
795static void compaction_free(struct page *page, unsigned long data)
796{
797 struct compact_control *cc = (struct compact_control *)data;
798
799 list_add(&page->lru, &cc->freepages);
800 cc->nr_freepages++;
801}
802
803/*
804 * We cannot control nr_migratepages fully when migration is running as
805 * migrate_pages() has no knowledge of of compact_control. When migration is
806 * complete, we count the number of pages on the list by hand.
794 */ 807 */
795static void update_nr_listpages(struct compact_control *cc) 808static void update_nr_listpages(struct compact_control *cc)
796{ 809{
797 int nr_migratepages = 0; 810 int nr_migratepages = 0;
798 int nr_freepages = 0;
799 struct page *page; 811 struct page *page;
800 812
801 list_for_each_entry(page, &cc->migratepages, lru) 813 list_for_each_entry(page, &cc->migratepages, lru)
802 nr_migratepages++; 814 nr_migratepages++;
803 list_for_each_entry(page, &cc->freepages, lru)
804 nr_freepages++;
805 815
806 cc->nr_migratepages = nr_migratepages; 816 cc->nr_migratepages = nr_migratepages;
807 cc->nr_freepages = nr_freepages;
808} 817}
809 818
810/* possible outcome of isolate_migratepages */ 819/* possible outcome of isolate_migratepages */
@@ -1014,8 +1023,8 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
1014 } 1023 }
1015 1024
1016 nr_migrate = cc->nr_migratepages; 1025 nr_migrate = cc->nr_migratepages;
1017 err = migrate_pages(&cc->migratepages, compaction_alloc, NULL, 1026 err = migrate_pages(&cc->migratepages, compaction_alloc,
1018 (unsigned long)cc, 1027 compaction_free, (unsigned long)cc,
1019 cc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC, 1028 cc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC,
1020 MR_COMPACTION); 1029 MR_COMPACTION);
1021 update_nr_listpages(cc); 1030 update_nr_listpages(cc);