Skip to content

Commit 99fa8a4

Browse files
Hugh Dickinstorvalds
authored andcommitted
mm/thp: fix __split_huge_pmd_locked() on shmem migration entry
Patch series "mm/thp: fix THP splitting unmap BUGs and related", v10. Here is v2 batch of long-standing THP bug fixes that I had not got around to sending before, but prompted now by Wang Yugui's report https://lore.kernel.org/linux-mm/[email protected]/ Wang Yugui has tested a rollup of these fixes applied to 5.10.39, and they have done no harm, but have *not* fixed that issue: something more is needed and I have no idea of what. This patch (of 7): Stressing huge tmpfs page migration racing hole punch often crashed on the VM_BUG_ON(!pmd_present) in pmdp_huge_clear_flush(), with DEBUG_VM=y kernel; or shortly afterwards, on a bad dereference in __split_huge_pmd_locked() when DEBUG_VM=n. They forgot to allow for pmd migration entries in the non-anonymous case. Full disclosure: those particular experiments were on a kernel with more relaxed mmap_lock and i_mmap_rwsem locking, and were not repeated on the vanilla kernel: it is conceivable that stricter locking happens to avoid those cases, or makes them less likely; but __split_huge_pmd_locked() already allowed for pmd migration entries when handling anonymous THPs, so this commit brings the shmem and file THP handling into line. And while there: use old_pmd rather than _pmd, as in the following blocks; and make it clearer to the eye that the !vma_is_anonymous() block is self-contained, making an early return after accounting for unmapping. Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Fixes: e71769a ("mm: enable thp migration for shmem thp") Signed-off-by: Hugh Dickins <[email protected]> Cc: Kirill A. Shutemov <[email protected]> Cc: Yang Shi <[email protected]> Cc: Wang Yugui <[email protected]> Cc: "Matthew Wilcox (Oracle)" <[email protected]> Cc: Naoya Horiguchi <[email protected]> Cc: Alistair Popple <[email protected]> Cc: Ralph Campbell <[email protected]> Cc: Zi Yan <[email protected]> Cc: Miaohe Lin <[email protected]> Cc: Minchan Kim <[email protected]> Cc: Jue Wang <[email protected]> Cc: Peter Xu <[email protected]> Cc: Jan Kara <[email protected]> Cc: Shakeel Butt <[email protected]> Cc: Oscar Salvador <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent ffc90cb commit 99fa8a4

File tree

2 files changed

+20
-12
lines changed

2 files changed

+20
-12
lines changed

mm/huge_memory.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,7 +2044,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
20442044
count_vm_event(THP_SPLIT_PMD);
20452045

20462046
if (!vma_is_anonymous(vma)) {
2047-
_pmd = pmdp_huge_clear_flush_notify(vma, haddr, pmd);
2047+
old_pmd = pmdp_huge_clear_flush_notify(vma, haddr, pmd);
20482048
/*
20492049
* We are going to unmap this huge page. So
20502050
* just go ahead and zap it
@@ -2053,16 +2053,25 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
20532053
zap_deposited_table(mm, pmd);
20542054
if (vma_is_special_huge(vma))
20552055
return;
2056-
page = pmd_page(_pmd);
2057-
if (!PageDirty(page) && pmd_dirty(_pmd))
2058-
set_page_dirty(page);
2059-
if (!PageReferenced(page) && pmd_young(_pmd))
2060-
SetPageReferenced(page);
2061-
page_remove_rmap(page, true);
2062-
put_page(page);
2056+
if (unlikely(is_pmd_migration_entry(old_pmd))) {
2057+
swp_entry_t entry;
2058+
2059+
entry = pmd_to_swp_entry(old_pmd);
2060+
page = migration_entry_to_page(entry);
2061+
} else {
2062+
page = pmd_page(old_pmd);
2063+
if (!PageDirty(page) && pmd_dirty(old_pmd))
2064+
set_page_dirty(page);
2065+
if (!PageReferenced(page) && pmd_young(old_pmd))
2066+
SetPageReferenced(page);
2067+
page_remove_rmap(page, true);
2068+
put_page(page);
2069+
}
20632070
add_mm_counter(mm, mm_counter_file(page), -HPAGE_PMD_NR);
20642071
return;
2065-
} else if (pmd_trans_huge(*pmd) && is_huge_zero_pmd(*pmd)) {
2072+
}
2073+
2074+
if (pmd_trans_huge(*pmd) && is_huge_zero_pmd(*pmd)) {
20662075
/*
20672076
* FIXME: Do we want to invalidate secondary mmu by calling
20682077
* mmu_notifier_invalidate_range() see comments below inside

mm/pgtable-generic.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,8 @@ pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, unsigned long address,
135135
{
136136
pmd_t pmd;
137137
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
138-
VM_BUG_ON(!pmd_present(*pmdp));
139-
/* Below assumes pmd_present() is true */
140-
VM_BUG_ON(!pmd_trans_huge(*pmdp) && !pmd_devmap(*pmdp));
138+
VM_BUG_ON(pmd_present(*pmdp) && !pmd_trans_huge(*pmdp) &&
139+
!pmd_devmap(*pmdp));
141140
pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
142141
flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
143142
return pmd;

0 commit comments

Comments
 (0)