diff options
author | David Rientjes <rientjes@google.com> | 2016-07-14 15:06:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-15 01:54:27 -0400 |
commit | a46cbf3bc53b6a93fb84a5ffb288c354fa807954 (patch) | |
tree | 9f9c1029e2291f6b366c881175f1a2894d246666 /mm/compaction.c | |
parent | f97d10454e4da2aceb44dfa7c59bb43ba9f50199 (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.c | 36 |
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 | ||