Skip to content

Commit 79ad784

Browse files
thejhgregkh
authored andcommitted
mm/khugepaged: fix GUP-fast interaction by sending IPI
commit 2ba99c5 upstream. Since commit 70cbc3c ("mm: gup: fix the fast GUP race against THP collapse"), the lockless_pages_from_mm() fastpath rechecks the pmd_t to ensure that the page table was not removed by khugepaged in between. However, lockless_pages_from_mm() still requires that the page table is not concurrently freed. Fix it by sending IPIs (if the architecture uses semi-RCU-style page table freeing) before freeing/reusing page tables. Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Fixes: ba76149 ("thp: khugepaged") Signed-off-by: Jann Horn <[email protected]> Reviewed-by: Yang Shi <[email protected]> Acked-by: David Hildenbrand <[email protected]> Cc: John Hubbard <[email protected]> Cc: Peter Xu <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> [manual backport: two of the three places in khugepaged that can free ptes were refactored into a common helper between 5.15 and 6.0] Signed-off-by: Jann Horn <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent d15cd6d commit 79ad784

File tree

3 files changed

+8
-3
lines changed

3 files changed

+8
-3
lines changed

include/asm-generic/tlb.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,16 @@ extern void tlb_remove_table(struct mmu_gather *tlb, void *table);
207207
#define tlb_needs_table_invalidate() (true)
208208
#endif
209209

210+
void tlb_remove_table_sync_one(void);
211+
210212
#else
211213

212214
#ifdef tlb_needs_table_invalidate
213215
#error tlb_needs_table_invalidate() requires MMU_GATHER_RCU_TABLE_FREE
214216
#endif
215217

218+
static inline void tlb_remove_table_sync_one(void) { }
219+
216220
#endif /* CONFIG_MMU_GATHER_RCU_TABLE_FREE */
217221

218222

mm/khugepaged.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,7 @@ static void collapse_huge_page(struct mm_struct *mm,
11561156
_pmd = pmdp_collapse_flush(vma, address, pmd);
11571157
spin_unlock(pmd_ptl);
11581158
mmu_notifier_invalidate_range_end(&range);
1159+
tlb_remove_table_sync_one();
11591160

11601161
spin_lock(pte_ptl);
11611162
isolated = __collapse_huge_page_isolate(vma, address, pte,
@@ -1537,6 +1538,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr)
15371538
/* step 4: collapse pmd */
15381539
_pmd = pmdp_collapse_flush(vma, haddr, pmd);
15391540
mm_dec_nr_ptes(mm);
1541+
tlb_remove_table_sync_one();
15401542
pte_free(mm, pmd_pgtable(_pmd));
15411543

15421544
i_mmap_unlock_write(vma->vm_file->f_mapping);
@@ -1623,6 +1625,7 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
16231625
/* assume page table is clear */
16241626
_pmd = pmdp_collapse_flush(vma, addr, pmd);
16251627
mm_dec_nr_ptes(mm);
1628+
tlb_remove_table_sync_one();
16261629
pte_free(mm, pmd_pgtable(_pmd));
16271630
}
16281631
mmap_write_unlock(mm);

mm/mmu_gather.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ static void tlb_remove_table_smp_sync(void *arg)
139139
/* Simply deliver the interrupt */
140140
}
141141

142-
static void tlb_remove_table_sync_one(void)
142+
void tlb_remove_table_sync_one(void)
143143
{
144144
/*
145145
* This isn't an RCU grace period and hence the page-tables cannot be
@@ -163,8 +163,6 @@ static void tlb_remove_table_free(struct mmu_table_batch *batch)
163163

164164
#else /* !CONFIG_MMU_GATHER_RCU_TABLE_FREE */
165165

166-
static void tlb_remove_table_sync_one(void) { }
167-
168166
static void tlb_remove_table_free(struct mmu_table_batch *batch)
169167
{
170168
__tlb_remove_table_free(batch);

0 commit comments

Comments
 (0)