spinlock_t *ptl;
 
        if (walk->no_vma) {
-               pte = pte_offset_map(pmd, addr);
-               err = walk_pte_range_inner(pte, addr, end, walk);
-               pte_unmap(pte);
+               /*
+                * pte_offset_map() might apply user-specific validation.
+                */
+               if (walk->mm == &init_mm)
+                       pte = pte_offset_kernel(pmd, addr);
+               else
+                       pte = pte_offset_map(pmd, addr);
+               if (pte) {
+                       err = walk_pte_range_inner(pte, addr, end, walk);
+                       if (walk->mm != &init_mm)
+                               pte_unmap(pte);
+               }
        } else {
                pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
-               err = walk_pte_range_inner(pte, addr, end, walk);
-               pte_unmap_unlock(pte, ptl);
+               if (pte) {
+                       err = walk_pte_range_inner(pte, addr, end, walk);
+                       pte_unmap_unlock(pte, ptl);
+               }
        }
-
+       if (!pte)
+               walk->action = ACTION_AGAIN;
        return err;
 }
 
                    !(ops->pte_entry))
                        continue;
 
-               if (walk->vma) {
+               if (walk->vma)
                        split_huge_pmd(walk->vma, pmd, addr);
-                       if (pmd_trans_unstable(pmd))
-                               goto again;
-               }
 
                if (is_hugepd(__hugepd(pmd_val(*pmd))))
                        err = walk_hugepd_range((hugepd_t *)pmd, addr, next, walk, PMD_SHIFT);
                        err = walk_pte_range(pmd, addr, next, walk);
                if (err)
                        break;
+
+               if (walk->action == ACTION_AGAIN)
+                       goto again;
+
        } while (pmd++, addr = next, addr != end);
 
        return err;