From: "Kirill A. Shutemov" <kirill.shutemov@xxxxxxxxxxxxxxx> Subject: khugepaged: drain LRU add pagevec after swapin collapse_huge_page() tries to swap in pages that are part of the PMD range. Just swapped in page goes though LRU add cache. The cache gets extra reference on the page. The extra reference can lead to the collapse fail: the following __collapse_huge_page_isolate() would check refcount and abort collapse seeing unexpected refcount. The fix is to drain local LRU add cache in __collapse_huge_page_swapin() if we successfully swapped in any pages. Link: http://lkml.kernel.org/r/20200416160026.16538-5-kirill.shutemov@xxxxxxxxxxxxxxx Signed-off-by: Kirill A. Shutemov <kirill.shutemov@xxxxxxxxxxxxxxx> Reviewed-by: William Kucharski <william.kucharski@xxxxxxxxxx> Reviewed-by: Zi Yan <ziy@xxxxxxxxxx> Tested-by: Zi Yan <ziy@xxxxxxxxxx> Acked-by: Yang Shi <yang.shi@xxxxxxxxxxxxxxxxx> Cc: Andrea Arcangeli <aarcange@xxxxxxxxxx> Cc: John Hubbard <jhubbard@xxxxxxxxxx> Cc: Mike Kravetz <mike.kravetz@xxxxxxxxxx> Cc: Ralph Campbell <rcampbell@xxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- mm/khugepaged.c | 5 +++++ 1 file changed, 5 insertions(+) --- a/mm/khugepaged.c~khugepaged-drain-lru-add-pagevec-after-swapin +++ a/mm/khugepaged.c @@ -931,6 +931,11 @@ static bool __collapse_huge_page_swapin( } vmf.pte--; pte_unmap(vmf.pte); + + /* Drain LRU add pagevec to remove extra pin on the swapped in pages */ + if (swapped_in) + lru_add_drain(); + trace_mm_collapse_huge_page_swapin(mm, swapped_in, referenced, 1); return true; } _