}
 #endif /* CONFIG_NUMA_BALANCING */
 
+static inline bool pte_hw_valid(pte_t pte)
+{
+       return (pte_raw(pte) & cpu_to_be64(_PAGE_PRESENT | _PAGE_PTE)) ==
+               cpu_to_be64(_PAGE_PRESENT | _PAGE_PTE);
+}
+
 static inline int pte_present(pte_t pte)
 {
        /*
         * invalid during ptep_set_access_flags. Hence we look for _PAGE_INVALID
         * if we find _PAGE_PRESENT cleared.
         */
-       return !!(pte_raw(pte) & cpu_to_be64(_PAGE_PRESENT | _PAGE_INVALID));
-}
 
-static inline bool pte_hw_valid(pte_t pte)
-{
-       return !!(pte_raw(pte) & cpu_to_be64(_PAGE_PRESENT));
+       if (pte_hw_valid(pte))
+               return true;
+       return (pte_raw(pte) & cpu_to_be64(_PAGE_INVALID | _PAGE_PTE)) ==
+               cpu_to_be64(_PAGE_INVALID | _PAGE_PTE);
 }
 
 #ifdef CONFIG_PPC_MEM_KEYS
 
                goto bail;
        }
 
-       /* Add _PAGE_PRESENT to the required access perm */
-       access |= _PAGE_PRESENT;
+       /*
+        * Add _PAGE_PRESENT to the required access perm. If there are parallel
+        * updates to the pte that can possibly clear _PAGE_PTE, catch that too.
+        *
+        * We can safely use the return pte address in rest of the function
+        * because we do set H_PAGE_BUSY which prevents further updates to pte
+        * from generic code.
+        */
+       access |= _PAGE_PRESENT | _PAGE_PTE;
 
        /*
         * Pre-check access permissions (will be re-checked atomically