diff options
author | Kirill A. Shutemov <kirill.shutemov@linux.intel.com> | 2020-06-03 16:00:17 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-03 20:09:46 -0700 |
commit | ae2c5d8042426b69c5f4a74296d1a20bb769a8ad (patch) | |
tree | d439332de05fb8f9a73cc7778d2b2a552ca0d02c /mm/khugepaged.c | |
parent | a980df33e9351e5474c06ec0fd96b2f409e2ff22 (diff) | |
download | lwn-ae2c5d8042426b69c5f4a74296d1a20bb769a8ad.tar.gz lwn-ae2c5d8042426b69c5f4a74296d1a20bb769a8ad.zip |
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.
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Tested-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: William Kucharski <william.kucharski@oracle.com>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Acked-by: Yang Shi <yang.shi@linux.alibaba.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Ralph Campbell <rcampbell@nvidia.com>
Link: http://lkml.kernel.org/r/20200416160026.16538-5-kirill.shutemov@linux.intel.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/khugepaged.c')
-rw-r--r-- | mm/khugepaged.c | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 8a74b9705a65..37d6c4be632f 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -931,6 +931,11 @@ static bool __collapse_huge_page_swapin(struct mm_struct *mm, } 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; } |