Skip to content

Commit fe0756d

Browse files
Barry Songgregkh
Barry Song
authored andcommitted
mm: userfaultfd: correct dirty flags set for both present and swap pte
commit 75cb1cc upstream. As David pointed out, what truly matters for mremap and userfaultfd move operations is the soft dirty bit. The current comment and implementation—which always sets the dirty bit for present PTEs and fails to set the soft dirty bit for swap PTEs—are incorrect. This could break features like Checkpoint-Restore in Userspace (CRIU). This patch updates the behavior to correctly set the soft dirty bit for both present and swap PTEs in accordance with mremap. Link: https://lkml.kernel.org/r/[email protected] Fixes: adef440 ("userfaultfd: UFFDIO_MOVE uABI") Signed-off-by: Barry Song <[email protected]> Reported-by: David Hildenbrand <[email protected]> Closes: https://lore.kernel.org/linux-mm/[email protected]/ Acked-by: Peter Xu <[email protected]> Reviewed-by: Suren Baghdasaryan <[email protected]> Cc: Lokesh Gidra <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent d005c81 commit fe0756d

File tree

1 file changed

+10
-2
lines changed

1 file changed

+10
-2
lines changed

mm/userfaultfd.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,8 +1059,13 @@ static int move_present_pte(struct mm_struct *mm,
10591059
src_folio->index = linear_page_index(dst_vma, dst_addr);
10601060

10611061
orig_dst_pte = mk_pte(&src_folio->page, dst_vma->vm_page_prot);
1062-
/* Follow mremap() behavior and treat the entry dirty after the move */
1063-
orig_dst_pte = pte_mkwrite(pte_mkdirty(orig_dst_pte), dst_vma);
1062+
/* Set soft dirty bit so userspace can notice the pte was moved */
1063+
#ifdef CONFIG_MEM_SOFT_DIRTY
1064+
orig_dst_pte = pte_mksoft_dirty(orig_dst_pte);
1065+
#endif
1066+
if (pte_dirty(orig_src_pte))
1067+
orig_dst_pte = pte_mkdirty(orig_dst_pte);
1068+
orig_dst_pte = pte_mkwrite(orig_dst_pte, dst_vma);
10641069

10651070
set_pte_at(mm, dst_addr, dst_pte, orig_dst_pte);
10661071
out:
@@ -1094,6 +1099,9 @@ static int move_swap_pte(struct mm_struct *mm, struct vm_area_struct *dst_vma,
10941099
}
10951100

10961101
orig_src_pte = ptep_get_and_clear(mm, src_addr, src_pte);
1102+
#ifdef CONFIG_MEM_SOFT_DIRTY
1103+
orig_src_pte = pte_swp_mksoft_dirty(orig_src_pte);
1104+
#endif
10971105
set_pte_at(mm, dst_addr, dst_pte, orig_src_pte);
10981106
double_pt_unlock(dst_ptl, src_ptl);
10991107

0 commit comments

Comments
 (0)