return folio;
 }
 
-/**
- * try_grab_folio() - Attempt to get or pin a folio.
- * @page:  pointer to page to be grabbed
- * @refs:  the value to (effectively) add to the folio's refcount
- * @flags: gup flags: these are the FOLL_* flag values.
- *
- * "grab" names in this file mean, "look at flags to decide whether to use
- * FOLL_PIN or FOLL_GET behavior, when incrementing the folio's refcount.
- *
- * Either FOLL_PIN or FOLL_GET (or neither) must be set, but not both at the
- * same time. (That's true throughout the get_user_pages*() and
- * pin_user_pages*() APIs.) Cases:
- *
- *    FOLL_GET: folio's refcount will be incremented by @refs.
- *
- *    FOLL_PIN on large folios: folio's refcount will be incremented by
- *    @refs, and its pincount will be incremented by @refs.
- *
- *    FOLL_PIN on single-page folios: folio's refcount will be incremented by
- *    @refs * GUP_PIN_COUNTING_BIAS.
- *
- * Return: The folio containing @page (with refcount appropriately
- * incremented) for success, or NULL upon failure. If neither FOLL_GET
- * nor FOLL_PIN was set, that's considered failure, and furthermore,
- * a likely bug in the caller, so a warning is also emitted.
- */
-struct folio *try_grab_folio(struct page *page, int refs, unsigned int flags)
-{
-       struct folio *folio;
-
-       if (WARN_ON_ONCE((flags & (FOLL_GET | FOLL_PIN)) == 0))
-               return NULL;
-
-       if (unlikely(!(flags & FOLL_PCI_P2PDMA) && is_pci_p2pdma_page(page)))
-               return NULL;
-
-       if (flags & FOLL_GET)
-               return try_get_folio(page, refs);
-
-       /* FOLL_PIN is set */
-
-       /*
-        * Don't take a pin on the zero page - it's not going anywhere
-        * and it is used in a *lot* of places.
-        */
-       if (is_zero_page(page))
-               return page_folio(page);
-
-       folio = try_get_folio(page, refs);
-       if (!folio)
-               return NULL;
-
-       /*
-        * Can't do FOLL_LONGTERM + FOLL_PIN gup fast path if not in a
-        * right zone, so fail and let the caller fall back to the slow
-        * path.
-        */
-       if (unlikely((flags & FOLL_LONGTERM) &&
-                    !folio_is_longterm_pinnable(folio))) {
-               if (!put_devmap_managed_folio_refs(folio, refs))
-                       folio_put_refs(folio, refs);
-               return NULL;
-       }
-
-       /*
-        * When pinning a large folio, use an exact count to track it.
-        *
-        * However, be sure to *also* increment the normal folio
-        * refcount field at least once, so that the folio really
-        * is pinned.  That's why the refcount from the earlier
-        * try_get_folio() is left intact.
-        */
-       if (folio_test_large(folio))
-               atomic_add(refs, &folio->_pincount);
-       else
-               folio_ref_add(folio,
-                               refs * (GUP_PIN_COUNTING_BIAS - 1));
-       /*
-        * Adjust the pincount before re-checking the PTE for changes.
-        * This is essentially a smp_mb() and is paired with a memory
-        * barrier in folio_try_share_anon_rmap_*().
-        */
-       smp_mb__after_atomic();
-
-       node_stat_mod_folio(folio, NR_FOLL_PIN_ACQUIRED, refs);
-
-       return folio;
-}
-
 static void gup_put_folio(struct folio *folio, int refs, unsigned int flags)
 {
        if (flags & FOLL_PIN) {
 }
 
 /**
- * try_grab_page() - elevate a page's refcount by a flag-dependent amount
- * @page:    pointer to page to be grabbed
- * @flags:   gup flags: these are the FOLL_* flag values.
+ * try_grab_folio() - add a folio's refcount by a flag-dependent amount
+ * @folio:    pointer to folio to be grabbed
+ * @refs:     the value to (effectively) add to the folio's refcount
+ * @flags:    gup flags: these are the FOLL_* flag values
  *
  * This might not do anything at all, depending on the flags argument.
  *
  * "grab" names in this file mean, "look at flags to decide whether to use
- * FOLL_PIN or FOLL_GET behavior, when incrementing the page's refcount.
+ * FOLL_PIN or FOLL_GET behavior, when incrementing the folio's refcount.
  *
  * Either FOLL_PIN or FOLL_GET (or neither) may be set, but not both at the same
- * time. Cases: please see the try_grab_folio() documentation, with
- * "refs=1".
+ * time.
  *
  * Return: 0 for success, or if no action was required (if neither FOLL_PIN
  * nor FOLL_GET was set, nothing is done). A negative error code for failure:
  *
- *   -ENOMEM           FOLL_GET or FOLL_PIN was set, but the page could not
+ *   -ENOMEM           FOLL_GET or FOLL_PIN was set, but the folio could not
  *                     be grabbed.
+ *
+ * It is called when we have a stable reference for the folio, typically in
+ * GUP slow path.
  */
-int __must_check try_grab_page(struct page *page, unsigned int flags)
+int __must_check try_grab_folio(struct folio *folio, int refs,
+                               unsigned int flags)
 {
-       struct folio *folio = page_folio(page);
-
        if (WARN_ON_ONCE(folio_ref_count(folio) <= 0))
                return -ENOMEM;
 
-       if (unlikely(!(flags & FOLL_PCI_P2PDMA) && is_pci_p2pdma_page(page)))
+       if (unlikely(!(flags & FOLL_PCI_P2PDMA) && is_pci_p2pdma_page(&folio->page)))
                return -EREMOTEIO;
 
        if (flags & FOLL_GET)
-               folio_ref_inc(folio);
+               folio_ref_add(folio, refs);
        else if (flags & FOLL_PIN) {
                /*
                 * Don't take a pin on the zero page - it's not going anywhere
                 * and it is used in a *lot* of places.
                 */
-               if (is_zero_page(page))
+               if (is_zero_folio(folio))
                        return 0;
 
                /*
-                * Similar to try_grab_folio(): be sure to *also*
-                * increment the normal page refcount field at least once,
+                * Increment the normal page refcount field at least once,
                 * so that the page really is pinned.
                 */
                if (folio_test_large(folio)) {
-                       folio_ref_add(folio, 1);
-                       atomic_add(1, &folio->_pincount);
+                       folio_ref_add(folio, refs);
+                       atomic_add(refs, &folio->_pincount);
                } else {
-                       folio_ref_add(folio, GUP_PIN_COUNTING_BIAS);
+                       folio_ref_add(folio, refs * GUP_PIN_COUNTING_BIAS);
                }
 
-               node_stat_mod_folio(folio, NR_FOLL_PIN_ACQUIRED, 1);
+               node_stat_mod_folio(folio, NR_FOLL_PIN_ACQUIRED, refs);
        }
 
        return 0;
 
        return nr;
 }
+
+/**
+ * try_grab_folio_fast() - Attempt to get or pin a folio in fast path.
+ * @page:  pointer to page to be grabbed
+ * @refs:  the value to (effectively) add to the folio's refcount
+ * @flags: gup flags: these are the FOLL_* flag values.
+ *
+ * "grab" names in this file mean, "look at flags to decide whether to use
+ * FOLL_PIN or FOLL_GET behavior, when incrementing the folio's refcount.
+ *
+ * Either FOLL_PIN or FOLL_GET (or neither) must be set, but not both at the
+ * same time. (That's true throughout the get_user_pages*() and
+ * pin_user_pages*() APIs.) Cases:
+ *
+ *    FOLL_GET: folio's refcount will be incremented by @refs.
+ *
+ *    FOLL_PIN on large folios: folio's refcount will be incremented by
+ *    @refs, and its pincount will be incremented by @refs.
+ *
+ *    FOLL_PIN on single-page folios: folio's refcount will be incremented by
+ *    @refs * GUP_PIN_COUNTING_BIAS.
+ *
+ * Return: The folio containing @page (with refcount appropriately
+ * incremented) for success, or NULL upon failure. If neither FOLL_GET
+ * nor FOLL_PIN was set, that's considered failure, and furthermore,
+ * a likely bug in the caller, so a warning is also emitted.
+ *
+ * It uses add ref unless zero to elevate the folio refcount and must be called
+ * in fast path only.
+ */
+static struct folio *try_grab_folio_fast(struct page *page, int refs,
+                                        unsigned int flags)
+{
+       struct folio *folio;
+
+       /* Raise warn if it is not called in fast GUP */
+       VM_WARN_ON_ONCE(!irqs_disabled());
+
+       if (WARN_ON_ONCE((flags & (FOLL_GET | FOLL_PIN)) == 0))
+               return NULL;
+
+       if (unlikely(!(flags & FOLL_PCI_P2PDMA) && is_pci_p2pdma_page(page)))
+               return NULL;
+
+       if (flags & FOLL_GET)
+               return try_get_folio(page, refs);
+
+       /* FOLL_PIN is set */
+
+       /*
+        * Don't take a pin on the zero page - it's not going anywhere
+        * and it is used in a *lot* of places.
+        */
+       if (is_zero_page(page))
+               return page_folio(page);
+
+       folio = try_get_folio(page, refs);
+       if (!folio)
+               return NULL;
+
+       /*
+        * Can't do FOLL_LONGTERM + FOLL_PIN gup fast path if not in a
+        * right zone, so fail and let the caller fall back to the slow
+        * path.
+        */
+       if (unlikely((flags & FOLL_LONGTERM) &&
+                    !folio_is_longterm_pinnable(folio))) {
+               if (!put_devmap_managed_folio_refs(folio, refs))
+                       folio_put_refs(folio, refs);
+               return NULL;
+       }
+
+       /*
+        * When pinning a large folio, use an exact count to track it.
+        *
+        * However, be sure to *also* increment the normal folio
+        * refcount field at least once, so that the folio really
+        * is pinned.  That's why the refcount from the earlier
+        * try_get_folio() is left intact.
+        */
+       if (folio_test_large(folio))
+               atomic_add(refs, &folio->_pincount);
+       else
+               folio_ref_add(folio,
+                               refs * (GUP_PIN_COUNTING_BIAS - 1));
+       /*
+        * Adjust the pincount before re-checking the PTE for changes.
+        * This is essentially a smp_mb() and is paired with a memory
+        * barrier in folio_try_share_anon_rmap_*().
+        */
+       smp_mb__after_atomic();
+
+       node_stat_mod_folio(folio, NR_FOLL_PIN_ACQUIRED, refs);
+
+       return folio;
+}
 #endif /* CONFIG_ARCH_HAS_HUGEPD || CONFIG_HAVE_GUP_FAST */
 
 #ifdef CONFIG_ARCH_HAS_HUGEPD
  */
 static int gup_hugepte(struct vm_area_struct *vma, pte_t *ptep, unsigned long sz,
                       unsigned long addr, unsigned long end, unsigned int flags,
-                      struct page **pages, int *nr)
+                      struct page **pages, int *nr, bool fast)
 {
        unsigned long pte_end;
        struct page *page;
        page = pte_page(pte);
        refs = record_subpages(page, sz, addr, end, pages + *nr);
 
-       folio = try_grab_folio(page, refs, flags);
-       if (!folio)
-               return 0;
+       if (fast) {
+               folio = try_grab_folio_fast(page, refs, flags);
+               if (!folio)
+                       return 0;
+       } else {
+               folio = page_folio(page);
+               if (try_grab_folio(folio, refs, flags))
+                       return 0;
+       }
 
        if (unlikely(pte_val(pte) != pte_val(ptep_get(ptep)))) {
                gup_put_folio(folio, refs, flags);
 static int gup_hugepd(struct vm_area_struct *vma, hugepd_t hugepd,
                      unsigned long addr, unsigned int pdshift,
                      unsigned long end, unsigned int flags,
-                     struct page **pages, int *nr)
+                     struct page **pages, int *nr, bool fast)
 {
        pte_t *ptep;
        unsigned long sz = 1UL << hugepd_shift(hugepd);
        ptep = hugepte_offset(hugepd, addr, pdshift);
        do {
                next = hugepte_addr_end(addr, end, sz);
-               ret = gup_hugepte(vma, ptep, sz, addr, end, flags, pages, nr);
+               ret = gup_hugepte(vma, ptep, sz, addr, end, flags, pages, nr,
+                                 fast);
                if (ret != 1)
                        return ret;
        } while (ptep++, addr = next, addr != end);
        ptep = hugepte_offset(hugepd, addr, pdshift);
        ptl = huge_pte_lock(h, vma->vm_mm, ptep);
        ret = gup_hugepd(vma, hugepd, addr, pdshift, addr + PAGE_SIZE,
-                        flags, &page, &nr);
+                        flags, &page, &nr, false);
        spin_unlock(ptl);
 
        if (ret == 1) {
 static inline int gup_hugepd(struct vm_area_struct *vma, hugepd_t hugepd,
                             unsigned long addr, unsigned int pdshift,
                             unsigned long end, unsigned int flags,
-                            struct page **pages, int *nr)
+                            struct page **pages, int *nr, bool fast)
 {
        return 0;
 }
            gup_must_unshare(vma, flags, page))
                return ERR_PTR(-EMLINK);
 
-       ret = try_grab_page(page, flags);
+       ret = try_grab_folio(page_folio(page), 1, flags);
        if (ret)
                page = ERR_PTR(ret);
        else
        VM_BUG_ON_PAGE((flags & FOLL_PIN) && PageAnon(page) &&
                        !PageAnonExclusive(page), page);
 
-       ret = try_grab_page(page, flags);
+       ret = try_grab_folio(page_folio(page), 1, flags);
        if (ret)
                return ERR_PTR(ret);
 
        VM_BUG_ON_PAGE((flags & FOLL_PIN) && PageAnon(page) &&
                       !PageAnonExclusive(page), page);
 
-       /* try_grab_page() does nothing unless FOLL_GET or FOLL_PIN is set. */
-       ret = try_grab_page(page, flags);
+       /* try_grab_folio() does nothing unless FOLL_GET or FOLL_PIN is set. */
+       ret = try_grab_folio(page_folio(page), 1, flags);
        if (unlikely(ret)) {
                page = ERR_PTR(ret);
                goto out;
                        goto unmap;
                *page = pte_page(entry);
        }
-       ret = try_grab_page(*page, gup_flags);
+       ret = try_grab_folio(page_folio(*page), 1, gup_flags);
        if (unlikely(ret))
                goto unmap;
 out:
                         * pages.
                         */
                        if (page_increm > 1) {
-                               struct folio *folio;
+                               struct folio *folio = page_folio(page);
 
                                /*
                                 * Since we already hold refcount on the
                                 * large folio, this should never fail.
                                 */
-                               folio = try_grab_folio(page, page_increm - 1,
-                                                      foll_flags);
-                               if (WARN_ON_ONCE(!folio)) {
+                               if (try_grab_folio(folio, page_increm - 1,
+                                                  foll_flags)) {
                                        /*
                                         * Release the 1st page ref if the
                                         * folio is problematic, fail hard.
                                         */
-                                       gup_put_folio(page_folio(page), 1,
+                                       gup_put_folio(folio, 1,
                                                      foll_flags);
                                        ret = -EFAULT;
                                        goto out;
  * This code is based heavily on the PowerPC implementation by Nick Piggin.
  */
 #ifdef CONFIG_HAVE_GUP_FAST
-
 /*
  * Used in the GUP-fast path to determine whether GUP is permitted to work on
  * a specific folio.
                VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
                page = pte_page(pte);
 
-               folio = try_grab_folio(page, 1, flags);
+               folio = try_grab_folio_fast(page, 1, flags);
                if (!folio)
                        goto pte_unmap;
 
                        break;
                }
 
-               folio = try_grab_folio(page, 1, flags);
+               folio = try_grab_folio_fast(page, 1, flags);
                if (!folio) {
                        gup_fast_undo_dev_pagemap(nr, nr_start, flags, pages);
                        break;
        page = pmd_page(orig);
        refs = record_subpages(page, PMD_SIZE, addr, end, pages + *nr);
 
-       folio = try_grab_folio(page, refs, flags);
+       folio = try_grab_folio_fast(page, refs, flags);
        if (!folio)
                return 0;
 
        page = pud_page(orig);
        refs = record_subpages(page, PUD_SIZE, addr, end, pages + *nr);
 
-       folio = try_grab_folio(page, refs, flags);
+       folio = try_grab_folio_fast(page, refs, flags);
        if (!folio)
                return 0;
 
        page = pgd_page(orig);
        refs = record_subpages(page, PGDIR_SIZE, addr, end, pages + *nr);
 
-       folio = try_grab_folio(page, refs, flags);
+       folio = try_grab_folio_fast(page, refs, flags);
        if (!folio)
                return 0;
 
                         * pmd format and THP pmd format
                         */
                        if (gup_hugepd(NULL, __hugepd(pmd_val(pmd)), addr,
-                                      PMD_SHIFT, next, flags, pages, nr) != 1)
+                                      PMD_SHIFT, next, flags, pages, nr,
+                                      true) != 1)
                                return 0;
                } else if (!gup_fast_pte_range(pmd, pmdp, addr, next, flags,
                                               pages, nr))
                                return 0;
                } else if (unlikely(is_hugepd(__hugepd(pud_val(pud))))) {
                        if (gup_hugepd(NULL, __hugepd(pud_val(pud)), addr,
-                                      PUD_SHIFT, next, flags, pages, nr) != 1)
+                                      PUD_SHIFT, next, flags, pages, nr,
+                                      true) != 1)
                                return 0;
                } else if (!gup_fast_pmd_range(pudp, pud, addr, next, flags,
                                               pages, nr))
                BUILD_BUG_ON(p4d_leaf(p4d));
                if (unlikely(is_hugepd(__hugepd(p4d_val(p4d))))) {
                        if (gup_hugepd(NULL, __hugepd(p4d_val(p4d)), addr,
-                                      P4D_SHIFT, next, flags, pages, nr) != 1)
+                                      P4D_SHIFT, next, flags, pages, nr,
+                                      true) != 1)
                                return 0;
                } else if (!gup_fast_pud_range(p4dp, p4d, addr, next, flags,
                                               pages, nr))
                                return;
                } else if (unlikely(is_hugepd(__hugepd(pgd_val(pgd))))) {
                        if (gup_hugepd(NULL, __hugepd(pgd_val(pgd)), addr,
-                                      PGDIR_SHIFT, next, flags, pages, nr) != 1)
+                                      PGDIR_SHIFT, next, flags, pages, nr,
+                                      true) != 1)
                                return;
                } else if (!gup_fast_p4d_range(pgdp, pgd, addr, next, flags,
                                               pages, nr))