On Wed, 4 Sep 2019 at 01:59, Jia He <justin.he@xxxxxxx> wrote: > @@ -2152,20 +2153,30 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo > */ > if (unlikely(!src)) { > void *kaddr = kmap_atomic(dst); > - void __user *uaddr = (void __user *)(va & PAGE_MASK); > + void __user *uaddr = (void __user *)(vmf->address & PAGE_MASK); > + pte_t entry; > > /* > * This really shouldn't fail, because the page is there > * in the page tables. But it might just be unreadable, > * in which case we just give up and fill the result with > - * zeroes. > + * zeroes. If PTE_AF is cleared on arm64, it might > + * cause double page fault here. so makes pte young here > */ > + if (!pte_young(vmf->orig_pte)) { > + entry = pte_mkyoung(vmf->orig_pte); > + if (ptep_set_access_flags(vmf->vma, vmf->address, > + vmf->pte, entry, vmf->flags & FAULT_FLAG_WRITE)) I think you need to pass dirty = 0 to ptep_set_access_flags() rather than the vmf->flags & FAULT_FLAG_WRITE. This is copying from the user address into a kernel mapping and the fault you want to prevent is a read access on uaddr via __copy_from_user_inatomic(). The pte will be made writable in the wp_page_copy() function. -- Catalin