vmemmap_remap_range() currently walks vmemmap page tables under init_mm.mmap_lock. If the walk reaches a leaf PMD, vmemmap_split_pmd() allocates a PTE table with GFP_KERNEL and can enter direct reclaim: hugetlb_vmemmap_optimize_folio() vmemmap_remap_range() mmap_read_lock(&init_mm) <-- outer read lock ... vmemmap_split_pmd() pte_alloc_one_kernel(&init_mm) /* GFP_KERNEL */ ttm_pool_shrinker_scan() ... change_page_attr_set_clr() mmap_read_lock(&init_mm) <-- self-deadlock Since commit d5d8b8662e6e ("x86/mm/pat: Acquire init_mm read lock on attribute changes to avoid UAF"), reclaim through TTM can enter CPA, which also takes init_mm.mmap_lock. If a writer is pending, the nested read blocks behind it while the outer read cannot be released, causing a self-deadlock. HVO walks vmemmap ranges whose intermediate page tables remain present. vmemmap_split_pmd() revalidates the PMD under init_mm.page_table_lock before installing the PTE table. Use the lockless page-table walker so the allocation no longer runs under init_mm.mmap_lock. Fixes: d5d8b8662e6e ("x86/mm/pat: Acquire init_mm read lock on attribute changes to avoid UAF") Cc: stable@vger.kernel.org Signed-off-by: Muchun Song Reported-by: Sashiko Closes: https://lore.kernel.org/sashiko-outbox-206969@kernel.org/ Reviewed-by: Jose A. Perez de Azpillaga --- v3: - Collect Reviewed-by from Jose A. Perez de Azpillaga --- mm/hugetlb_vmemmap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c index 6fba3184356c..5852b0a1c479 100644 --- a/mm/hugetlb_vmemmap.c +++ b/mm/hugetlb_vmemmap.c @@ -161,10 +161,8 @@ static int vmemmap_remap_range(unsigned long start, unsigned long end, VM_BUG_ON(!PAGE_ALIGNED(start | end)); - mmap_read_lock(&init_mm); - ret = walk_kernel_page_table_range(start, end, &vmemmap_remap_ops, - NULL, walk); - mmap_read_unlock(&init_mm); + ret = walk_kernel_page_table_range_lockless(start, end, &vmemmap_remap_ops, + NULL, walk); if (ret) return ret; -- 2.54.0