Where arch_needs_pgtable_deposit() is true, every huge PMD needs a deposited page table. ppc64 in hash mode keeps the hash slot array of the huge page in it, so vmf_insert_pfn_pmd() deposits one for each special PMD it maps. copy_huge_pmd() copies a special PMD into the child without a table. The child then dereferences a NULL table: - on the first hash fault on the PMD, in __hash_page_thp(); - on the zap at munmap() or exit, in hash__pmdp_huge_get_and_clear(). Allocate a table before taking the page table locks and deposit it with the copy, as insert_pmd() does. Fixes: d1503aa9ab805 ("powerpc/64s: Add support for huge pfnmaps") Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/20261014-b4-prep-vstor-149847-copy_huge_pmd-recheck-special-pmd-v1-1-d225c60bc316@virtuozzo.com?part=1 Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Konstantin Khorenko --- mm/huge_memory.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index fcea98f0d8865..d53db73f52676 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1961,6 +1961,11 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, pmd = pmdp_get_lockless(src_pmd); if (unlikely(pmd_present(pmd) && pmd_special(pmd) && !is_huge_zero_pmd(pmd))) { + if (arch_needs_pgtable_deposit()) { + pgtable = pte_alloc_one(dst_mm); + if (unlikely(!pgtable)) + goto out; + } dst_ptl = pmd_lock(dst_mm, dst_pmd); src_ptl = pmd_lockptr(src_mm, src_pmd); spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING); @@ -1974,6 +1979,8 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, if (unlikely(!pmd_present(pmd) || !pmd_special(pmd))) { spin_unlock(src_ptl); spin_unlock(dst_ptl); + if (pgtable) + pte_free(dst_mm, pgtable); return -EAGAIN; } /* @@ -1983,6 +1990,10 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, * wrongly write to the backend MMIO. */ VM_WARN_ON_ONCE(vma_is_cow_mapping(src_vma) && pmd_write(pmd)); + if (pgtable) { + mm_inc_nr_ptes(dst_mm); + pgtable_trans_huge_deposit(dst_mm, dst_pmd, pgtable); + } goto set_pmd; } -- 2.43.0