@@ -219,17 +219,28 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
219219 }
220220}
221221
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+
222234/*
223235 * This routine is only called when splitting a THP
224236 */
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 ,
226238 pmd_t * pmdp )
227239{
228- pmd_t entry = * pmdp ;
229-
230- pmd_val (entry ) &= ~_PAGE_VALID ;
240+ pmd_t old , entry ;
231241
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 );
233244 flush_tlb_range (vma , address , address + HPAGE_PMD_SIZE );
234245
235246 /*
@@ -240,6 +251,8 @@ void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
240251 if ((pmd_val (entry ) & _PAGE_PMD_HUGE ) &&
241252 !is_huge_zero_page (pmd_page (entry )))
242253 (vma -> vm_mm )-> context .thp_pte_count -- ;
254+
255+ return old ;
243256}
244257
245258void pgtable_trans_huge_deposit (struct mm_struct * mm , pmd_t * pmdp ,
0 commit comments