@@ -545,7 +545,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);
@@ -588,6 +589,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;
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(-)