diff mbox series

[3/6] mm/userfaultfd: Fix a few thp pmd missing uffd-wp bit

Message ID 20210428225030.9708-4-peterx@redhat.com (mailing list archive)
State New, archived
Headers show
Series mm/uffd: Misc fix for uffd-wp and one more test | expand

Commit Message

Peter Xu April 28, 2021, 10:50 p.m. UTC
These include:

  1. When remove migration pmd entry, should keep the uffd-wp bit from swap
     pte.  Note that we need to do this after setting write bit just in case we
     need to remove it.

  2. When change huge pmd and convert write -> read migration entry, persist
     the same uffd-wp bit.

  3. When convert pmd to swap entry, should drop the uffd-wp bit always.

Signed-off-by: Peter Xu <peterx@redhat.com>
---
 include/linux/swapops.h | 2 ++
 mm/huge_memory.c        | 4 ++++
 2 files changed, 6 insertions(+)
diff mbox series

Patch

diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index d9b7c9132c2f6..7dd57303bb0c3 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -258,6 +258,8 @@  static inline swp_entry_t pmd_to_swp_entry(pmd_t pmd)
 
 	if (pmd_swp_soft_dirty(pmd))
 		pmd = pmd_swp_clear_soft_dirty(pmd);
+	if (pmd_swp_uffd_wp(pmd))
+		pmd = pmd_swp_clear_uffd_wp(pmd);
 	arch_entry = __pmd_to_swp_entry(pmd);
 	return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));
 }
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 20a4569895254..e6423fe11a8f2 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1823,6 +1823,8 @@  int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
 			newpmd = swp_entry_to_pmd(entry);
 			if (pmd_swp_soft_dirty(*pmd))
 				newpmd = pmd_swp_mksoft_dirty(newpmd);
+			if (pmd_swp_uffd_wp(*pmd))
+				newpmd = pmd_swp_mkuffd_wp(newpmd);
 			set_pmd_at(mm, addr, pmd, newpmd);
 		}
 		goto unlock;
@@ -3234,6 +3236,8 @@  void remove_migration_pmd(struct page_vma_mapped_walk *pvmw, struct page *new)
 		pmde = pmd_mksoft_dirty(pmde);
 	if (is_write_migration_entry(entry))
 		pmde = maybe_pmd_mkwrite(pmde, vma);
+	if (pmd_swp_uffd_wp(*pvmw->pmd))
+		pmde = pmd_wrprotect(pmd_mkuffd_wp(pmde));
 
 	flush_cache_range(vma, mmun_start, mmun_start + HPAGE_PMD_SIZE);
 	if (PageAnon(new))