diff mbox series

[v5,10/17] mm/gup: Trigger break COW PTE before calling follow_pfn_pte()

Message ID 20230414142341.354556-11-shiyn.lin@gmail.com (mailing list archive)
State Changes Requested
Headers show
Series Introduce Copy-On-Write to Page Table | expand

Commit Message

Chih-En Lin April 14, 2023, 2:23 p.m. UTC
In most of cases, GUP will not modify the page table, excluding
follow_pfn_pte(). To deal with COW PTE, Trigger the break COW
PTE fault before calling follow_pfn_pte().

Signed-off-by: Chih-En Lin <shiyn.lin@gmail.com>
---
 mm/gup.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/mm/gup.c b/mm/gup.c
index eab18ba045db..325424c02ca6 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -544,7 +544,8 @@  static struct page *follow_page_pte(struct vm_area_struct *vma,
 	if (WARN_ON_ONCE((flags & (FOLL_PIN | FOLL_GET)) ==
 			 (FOLL_PIN | FOLL_GET)))
 		return ERR_PTR(-EINVAL);
-	if (unlikely(pmd_bad(*pmd)))
+	/* COW-ed PTE has write protection which can trigger pmd_bad(). */
+	if (unlikely(pmd_write(*pmd) && pmd_bad(*pmd)))
 		return no_page_table(vma, flags);
 
 	ptep = pte_offset_map_lock(mm, pmd, address, &ptl);
@@ -587,6 +588,11 @@  static struct page *follow_page_pte(struct vm_area_struct *vma,
 		if (is_zero_pfn(pte_pfn(pte))) {
 			page = pte_page(pte);
 		} else {
+			if (test_bit(MMF_COW_PTE, &mm->flags) &&
+			    !pmd_write(*pmd)) {
+				page = ERR_PTR(-EMLINK);
+				goto out;
+			}
 			ret = follow_pfn_pte(vma, address, ptep, flags);
 			page = ERR_PTR(ret);
 			goto out;