@@ -29,6 +29,7 @@ enum scan_result {
29
29
SCAN_PMD_NULL ,
30
30
SCAN_EXCEED_NONE_PTE ,
31
31
SCAN_PTE_NON_PRESENT ,
32
+ SCAN_PTE_UFFD_WP ,
32
33
SCAN_PAGE_RO ,
33
34
SCAN_LACK_REFERENCED_PAGE ,
34
35
SCAN_PAGE_NULL ,
@@ -1137,6 +1138,15 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
1137
1138
pte_t pteval = * _pte ;
1138
1139
if (is_swap_pte (pteval )) {
1139
1140
if (++ unmapped <= khugepaged_max_ptes_swap ) {
1141
+ /*
1142
+ * Always be strict with uffd-wp
1143
+ * enabled swap entries. Please see
1144
+ * comment below for pte_uffd_wp().
1145
+ */
1146
+ if (pte_swp_uffd_wp (pteval )) {
1147
+ result = SCAN_PTE_UFFD_WP ;
1148
+ goto out_unmap ;
1149
+ }
1140
1150
continue ;
1141
1151
} else {
1142
1152
result = SCAN_EXCEED_SWAP_PTE ;
@@ -1156,6 +1166,19 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
1156
1166
result = SCAN_PTE_NON_PRESENT ;
1157
1167
goto out_unmap ;
1158
1168
}
1169
+ if (pte_uffd_wp (pteval )) {
1170
+ /*
1171
+ * Don't collapse the page if any of the small
1172
+ * PTEs are armed with uffd write protection.
1173
+ * Here we can also mark the new huge pmd as
1174
+ * write protected if any of the small ones is
1175
+ * marked but that could bring uknown
1176
+ * userfault messages that falls outside of
1177
+ * the registered range. So, just be simple.
1178
+ */
1179
+ result = SCAN_PTE_UFFD_WP ;
1180
+ goto out_unmap ;
1181
+ }
1159
1182
if (pte_write (pteval ))
1160
1183
writable = true;
1161
1184
0 commit comments