static inline int
copy_present_page(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,
		  pte_t *dst_pte, pte_t *src_pte, unsigned long addr, int *rss,
		  struct page **prealloc, pte_t pte, struct page *page)
{
	struct mm_struct *src_mm = src_vma->vm_mm;
	struct page *new_page;

	if (!is_cow_mapping(src_vma->vm_flags))
		return 1;

	/*
	 * What we want to do is to check whether this page may
	 * have been pinned by the parent process.  If so,
	 * instead of wrprotect the pte on both sides, we copy
	 * the page immediately so that we'll always guarantee
	 * the pinned page won't be randomly replaced in the
	 * future.
	 *
	 * The page pinning checks are just "has this mm ever
	 * seen pinning", along with the (inexact) check of
	 * the page count. That might give false positives for
	 * for pinning, but it will work correctly.
	 */
	if (likely(!atomic_read(&src_mm->has_pinned)))
		return 1;
	if (likely(!page_maybe_dma_pinned(page)))
		return 1;

	/*
	 * The vma->anon_vma of the child process may be NULL
	 * because the entire vma does not contain anonymous pages.
	 * A BUG will occur when the copy_present_page() passes
	 * a copy of a non-anonymous page of that vma to the
	 * page_add_new_anon_rmap() to set up new anonymous rmap.
	 * Return 1 if the page is not an anonymous page.
	 */
	if (!PageAnon(page))
		return 1;

	new_page = *prealloc;
	if (!new_page)
		return -EAGAIN;

	/*
	 * We have a prealloc page, all good!  Take it
	 * over and copy the page & arm it.
	 */
	*prealloc = NULL;
	copy_user_highpage(new_page, page, addr, src_vma);
	__SetPageUptodate(new_page);
	reliable_page_counter(new_page, dst_vma->vm_mm, 1);
	page_add_new_anon_rmap(new_page, dst_vma, addr, false);
	lru_cache_add_inactive_or_unevictable(new_page, dst_vma);
	rss[mm_counter(new_page)]++;

	/* All done, just insert the new page copy in the child */
	pte = mk_pte(new_page, dst_vma->vm_page_prot);
	pte = maybe_mkwrite(pte_mkdirty(pte), dst_vma);
	if (userfaultfd_pte_wp(dst_vma, *src_pte))
		/* Uffd-wp needs to be delivered to dest pte as well */
		pte = pte_wrprotect(pte_mkuffd_wp(pte));
	set_pte_at(dst_vma->vm_mm, addr, dst_pte, pte);
	return 0;
}
