Skip to content

Commit a65ad6c

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 adb5c2e commit a65ad6c

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
@@ -1068,8 +1068,13 @@ static int move_present_pte(struct mm_struct *mm,
10681068
src_folio->index = linear_page_index(dst_vma, dst_addr);
10691069

10701070
orig_dst_pte = mk_pte(&src_folio->page, dst_vma->vm_page_prot);
1071-
/* Follow mremap() behavior and treat the entry dirty after the move */
1072-
orig_dst_pte = pte_mkwrite(pte_mkdirty(orig_dst_pte), dst_vma);
1071+
/* Set soft dirty bit so userspace can notice the pte was moved */
1072+
#ifdef CONFIG_MEM_SOFT_DIRTY
1073+
orig_dst_pte = pte_mksoft_dirty(orig_dst_pte);
1074+
#endif
1075+
if (pte_dirty(orig_src_pte))
1076+
orig_dst_pte = pte_mkdirty(orig_dst_pte);
1077+
orig_dst_pte = pte_mkwrite(orig_dst_pte, dst_vma);
10731078

10741079
set_pte_at(mm, dst_addr, dst_pte, orig_dst_pte);
10751080
out:
@@ -1104,6 +1109,9 @@ static int move_swap_pte(struct mm_struct *mm, struct vm_area_struct *dst_vma,
11041109
}
11051110

11061111
orig_src_pte = ptep_get_and_clear(mm, src_addr, src_pte);
1112+
#ifdef CONFIG_MEM_SOFT_DIRTY
1113+
orig_src_pte = pte_swp_mksoft_dirty(orig_src_pte);
1114+
#endif
11071115
set_pte_at(mm, dst_addr, dst_pte, orig_src_pte);
11081116
double_pt_unlock(dst_ptl, src_ptl);
11091117

0 commit comments

Comments
 (0)