@@ -219,17 +219,28 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
219
219
}
220
220
}
221
221
222
+ static inline pmd_t pmdp_establish (struct vm_area_struct * vma ,
223
+ unsigned long address , pmd_t * pmdp , pmd_t pmd )
224
+ {
225
+ pmd_t old ;
226
+
227
+ do {
228
+ old = * pmdp ;
229
+ } while (cmpxchg64 (& pmdp -> pmd , old .pmd , pmd .pmd ) != old .pmd );
230
+
231
+ return old ;
232
+ }
233
+
222
234
/*
223
235
* This routine is only called when splitting a THP
224
236
*/
225
- void pmdp_invalidate (struct vm_area_struct * vma , unsigned long address ,
237
+ pmd_t pmdp_invalidate (struct vm_area_struct * vma , unsigned long address ,
226
238
pmd_t * pmdp )
227
239
{
228
- pmd_t entry = * pmdp ;
229
-
230
- pmd_val (entry ) &= ~_PAGE_VALID ;
240
+ pmd_t old , entry ;
231
241
232
- set_pmd_at (vma -> vm_mm , address , pmdp , entry );
242
+ entry = __pmd (pmd_val (* pmdp ) & ~_PAGE_VALID );
243
+ old = pmdp_establish (vma , address , pmdp , entry );
233
244
flush_tlb_range (vma , address , address + HPAGE_PMD_SIZE );
234
245
235
246
/*
@@ -240,6 +251,8 @@ void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
240
251
if ((pmd_val (entry ) & _PAGE_PMD_HUGE ) &&
241
252
!is_huge_zero_page (pmd_page (entry )))
242
253
(vma -> vm_mm )-> context .thp_pte_count -- ;
254
+
255
+ return old ;
243
256
}
244
257
245
258
void pgtable_trans_huge_deposit (struct mm_struct * mm , pmd_t * pmdp ,
0 commit comments