summaryrefslogtreecommitdiffstats
path: root/mm/compaction.c
diff options
context:
space:
mode:
authorDavid Rientjes <rientjes@google.com>2016-07-14 15:06:50 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-15 01:54:27 -0400
commita46cbf3bc53b6a93fb84a5ffb288c354fa807954 (patch)
tree9f9c1029e2291f6b366c881175f1a2894d246666 /mm/compaction.c
parentf97d10454e4da2aceb44dfa7c59bb43ba9f50199 (diff)
mm, compaction: prevent VM_BUG_ON when terminating freeing scanner
It's possible to isolate some freepages in a pageblock and then fail split_free_page() due to the low watermark check. In this case, we hit VM_BUG_ON() because the freeing scanner terminated early without a contended lock or enough freepages. This should never have been a VM_BUG_ON() since it's not a fatal condition. It should have been a VM_WARN_ON() at best, or even handled gracefully. Regardless, we need to terminate anytime the full pageblock scan was not done. The logic belongs in isolate_freepages_block(), so handle its state gracefully by terminating the pageblock loop and making a note to restart at the same pageblock next time since it was not possible to complete the scan this time. [rientjes@google.com: don't rescan pages in a pageblock] Link: http://lkml.kernel.org/r/alpine.DEB.2.10.1607111244150.83138@chino.kir.corp.google.com Link: http://lkml.kernel.org/r/alpine.DEB.2.10.1606291436300.145590@chino.kir.corp.google.com Signed-off-by: David Rientjes <rientjes@google.com> Reported-by: Minchan Kim <minchan@kernel.org> Tested-by: Minchan Kim <minchan@kernel.org> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Cc: Hugh Dickins <hughd@google.com> Cc: Mel Gorman <mgorman@techsingularity.net> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: <stable@vger.kernel.org> 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.c36
1 files changed, 14 insertions, 22 deletions
diff --git a/mm/compaction.c b/mm/compaction.c
index 79bfe0e06907..7bc04778f84d 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -1009,8 +1009,6 @@ static void isolate_freepages(struct compact_control *cc)
1009 block_end_pfn = block_start_pfn, 1009 block_end_pfn = block_start_pfn,
1010 block_start_pfn -= pageblock_nr_pages, 1010 block_start_pfn -= pageblock_nr_pages,
1011 isolate_start_pfn = block_start_pfn) { 1011 isolate_start_pfn = block_start_pfn) {
1012 unsigned long isolated;
1013
1014 /* 1012 /*
1015 * This can iterate a massively long zone without finding any 1013 * This can iterate a massively long zone without finding any
1016 * suitable migration targets, so periodically check if we need 1014 * suitable migration targets, so periodically check if we need
@@ -1034,36 +1032,30 @@ static void isolate_freepages(struct compact_control *cc)
1034 continue; 1032 continue;
1035 1033
1036 /* Found a block suitable for isolating free pages from. */ 1034 /* Found a block suitable for isolating free pages from. */
1037 isolated = isolate_freepages_block(cc, &isolate_start_pfn, 1035 isolate_freepages_block(cc, &isolate_start_pfn, block_end_pfn,
1038 block_end_pfn, freelist, false); 1036 freelist, false);
1039 /* If isolation failed early, do not continue needlessly */
1040 if (!isolated && isolate_start_pfn < block_end_pfn &&
1041 cc->nr_migratepages > cc->nr_freepages)
1042 break;
1043 1037
1044 /* 1038 /*
1045 * If we isolated enough freepages, or aborted due to async 1039 * If we isolated enough freepages, or aborted due to lock
1046 * compaction being contended, terminate the loop. 1040 * contention, terminate.
1047 * Remember where the free scanner should restart next time,
1048 * which is where isolate_freepages_block() left off.
1049 * But if it scanned the whole pageblock, isolate_start_pfn
1050 * now points at block_end_pfn, which is the start of the next
1051 * pageblock.
1052 * In that case we will however want to restart at the start
1053 * of the previous pageblock.
1054 */ 1041 */
1055 if ((cc->nr_freepages >= cc->nr_migratepages) 1042 if ((cc->nr_freepages >= cc->nr_migratepages)
1056 || cc->contended) { 1043 || cc->contended) {
1057 if (isolate_start_pfn >= block_end_pfn) 1044 if (isolate_start_pfn >= block_end_pfn) {
1045 /*
1046 * Restart at previous pageblock if more
1047 * freepages can be isolated next time.
1048 */
1058 isolate_start_pfn = 1049 isolate_start_pfn =
1059 block_start_pfn - pageblock_nr_pages; 1050 block_start_pfn - pageblock_nr_pages;
1051 }
1060 break; 1052 break;
1061 } else { 1053 } else if (isolate_start_pfn < block_end_pfn) {
1062 /* 1054 /*
1063 * isolate_freepages_block() should not terminate 1055 * If isolation failed early, do not continue
1064 * prematurely unless contended, or isolated enough 1056 * needlessly.
1065 */ 1057 */
1066 VM_BUG_ON(isolate_start_pfn < block_end_pfn); 1058 break;
1067 } 1059 }
1068 } 1060 }
1069 1061