From 3f5cde74b0a58fd3d1ec27b276ac73507faf8d3d Mon Sep 17 00:00:00 2001 From: Cho KyongHo Date: Thu, 7 Feb 2019 16:52:12 +0900 Subject: [PATCH] [RAMEN9610-12171] mm/hpa: fix possible inifinite page isolation If HPA starts isolating pages in a page block that is currently isolated in another thread, the page block possibly remains isolated infinitely because HPA decides the target migratetype of the page block from the current migratetype of it. Once it gets migratetype of a page block as MT_ISOLATE and passes it to alloc_contig_range(), the final migratetype of the page block becomes MT_ISOLATE which is not expected. See the following race condition described by Jaewon Kim. CPU0 CPU1 get_pageblock_migratetype -> get MT_NON_ISOLATE as previous MT alloc_contig_range_fast __alloc_contig_range start_isolate_page_range -> set to MT_ISOALTE get_pageblock_migratetype -> get MT_ISOLATE as previous MT alloc_contig_range_fast __alloc_contig_range start_isolate_page_range -> set to MT_ISOALTE undo_isolate_page_range to the -> recover to MT_NON_ISOLATE undo_isolate_page_range -> recover to MT_ISOLATE He observed a page block is remained isolated for a log time. Change-Id: I933b5c1a281ee32f400d63913c52301bb01cb550 Reported-by: Jaewon Kim Signed-off-by: Cho KyongHo --- mm/hpa.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/mm/hpa.c b/mm/hpa.c index 0d7af5fcaaa5..28aebe88d677 100644 --- a/mm/hpa.c +++ b/mm/hpa.c @@ -309,6 +309,8 @@ retry: (total_scanned < (end_pfn - start_pfn) * MAX_SCAN_TRY) && (remained > 0); pfn += nr_pages, total_scanned += nr_pages) { + int mt; + if (pfn + nr_pages > end_pfn) { pfn = start_pfn; continue; @@ -324,8 +326,14 @@ retry: if (tmp < (pfn + nr_pages)) continue; - /* CMA pages should not be reclaimed */ - if (is_migrate_cma_page(pfn_to_page(pfn))) { + mt = get_pageblock_migratetype(pfn_to_page(pfn)); + /* + * CMA pages should not be reclaimed. + * Isolated page blocks should not be tried again because it + * causes isolated page block remained in isolated state + * forever. + */ + if (is_migrate_cma(mt) || is_migrate_isolate(mt)) { /* nr_pages is added before next iteration */ pfn = ALIGN(pfn + 1, pageblock_nr_pages) - nr_pages; continue; @@ -342,8 +350,7 @@ retry: if (!is_movable_chunk(pfn, order)) continue; - ret = alloc_contig_range_fast(pfn, pfn + nr_pages, - get_pageblock_migratetype(pfn_to_page(pfn))); + ret = alloc_contig_range_fast(pfn, pfn + nr_pages, mt); if (ret == 0) prep_highorder_pages(pfn, order); else -- 2.20.1