EM( SCAN_PMD_NULL,              "pmd_null")                     \
        EM( SCAN_EXCEED_NONE_PTE,       "exceed_none_pte")              \
        EM( SCAN_PTE_NON_PRESENT,       "pte_non_present")              \
+       EM( SCAN_PTE_UFFD_WP,           "pte_uffd_wp")                  \
        EM( SCAN_PAGE_RO,               "no_writable_page")             \
        EM( SCAN_LACK_REFERENCED_PAGE,  "lack_referenced_page")         \
        EM( SCAN_PAGE_NULL,             "page_null")                    \
 
        SCAN_PMD_NULL,
        SCAN_EXCEED_NONE_PTE,
        SCAN_PTE_NON_PRESENT,
+       SCAN_PTE_UFFD_WP,
        SCAN_PAGE_RO,
        SCAN_LACK_REFERENCED_PAGE,
        SCAN_PAGE_NULL,
                pte_t pteval = *_pte;
                if (is_swap_pte(pteval)) {
                        if (++unmapped <= khugepaged_max_ptes_swap) {
+                               /*
+                                * Always be strict with uffd-wp
+                                * enabled swap entries.  Please see
+                                * comment below for pte_uffd_wp().
+                                */
+                               if (pte_swp_uffd_wp(pteval)) {
+                                       result = SCAN_PTE_UFFD_WP;
+                                       goto out_unmap;
+                               }
                                continue;
                        } else {
                                result = SCAN_EXCEED_SWAP_PTE;
                        result = SCAN_PTE_NON_PRESENT;
                        goto out_unmap;
                }
+               if (pte_uffd_wp(pteval)) {
+                       /*
+                        * Don't collapse the page if any of the small
+                        * PTEs are armed with uffd write protection.
+                        * Here we can also mark the new huge pmd as
+                        * write protected if any of the small ones is
+                        * marked but that could bring uknown
+                        * userfault messages that falls outside of
+                        * the registered range.  So, just be simple.
+                        */
+                       result = SCAN_PTE_UFFD_WP;
+                       goto out_unmap;
+               }
                if (pte_write(pteval))
                        writable = true;