Skip to content

Commit dd47ac4

Browse files
xzpeterakpm00
authored andcommitted
mm/khugepaged: check again on anon uffd-wp during isolation
Khugepaged collapse an anonymous thp in two rounds of scans. The 2nd round done in __collapse_huge_page_isolate() after hpage_collapse_scan_pmd(), during which all the locks will be released temporarily. It means the pgtable can change during this phase before 2nd round starts. It's logically possible some ptes got wr-protected during this phase, and we can errornously collapse a thp without noticing some ptes are wr-protected by userfault. e1e267c wanted to avoid it but it only did that for the 1st phase, not the 2nd phase. Since __collapse_huge_page_isolate() happens after a round of small page swapins, we don't need to worry on any !present ptes - if it existed khugepaged will already bail out. So we only need to check present ptes with uffd-wp bit set there. This is something I found only but never had a reproducer, I thought it was one caused a bug in Muhammad's recent pagemap new ioctl work, but it turns out it's not the cause of that but an userspace bug. However this seems to still be a real bug even with a very small race window, still worth to have it fixed and copy stable. Link: https://lkml.kernel.org/r/[email protected] Fixes: e1e267c ("khugepaged: skip collapse if uffd-wp detected") Signed-off-by: Peter Xu <[email protected]> Reviewed-by: David Hildenbrand <[email protected]> Reviewed-by: Yang Shi <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: Axel Rasmussen <[email protected]> Cc: Mike Rapoport <[email protected]> Cc: Nadav Amit <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 24bf08c commit dd47ac4

File tree

1 file changed

+4
-0
lines changed

1 file changed

+4
-0
lines changed

mm/khugepaged.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,10 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
572572
result = SCAN_PTE_NON_PRESENT;
573573
goto out;
574574
}
575+
if (pte_uffd_wp(pteval)) {
576+
result = SCAN_PTE_UFFD_WP;
577+
goto out;
578+
}
575579
page = vm_normal_page(vma, address, pteval);
576580
if (unlikely(!page) || unlikely(is_zone_device_page(page))) {
577581
result = SCAN_PAGE_NULL;

0 commit comments

Comments
 (0)