[RAMEN9610-12171] mm/hpa: fix possible inifinite page isolation
authorCho KyongHo <pullip.cho@samsung.com>
Thu, 7 Feb 2019 07:52:12 +0000 (16:52 +0900)
committerhskang <hs1218.kang@samsung.com>
Thu, 14 Feb 2019 16:20:58 +0000 (01:20 +0900)
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 <jaewon31.kim@samsung.com>
Signed-off-by: Cho KyongHo <pullip.cho@samsung.com>
mm/hpa.c

index 0d7af5fcaaa5493100d8c653b3b9611929c2d0e7..28aebe88d677cfa947c1473eb501b73012bbdd37 100644 (file)
--- 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