linux/arch/x86/mm
Mikhail Gavrilov e3ee38c1bc x86/mm: Drop unnecessary PMD page copy when freeing
On a box with a discrete GPU, lockdep reports a possible deadlock as
soon as kswapd shrinks the TTM page pool. The immediate cause is an
x86 commit that added an mmap_read_lock() to kernel page protection
munging code.

The huge vmap code holds the same lock over a GFP_KERNEL allocation,
which is a no-no now that reclaim can take it. That allocation is in a
page table *free* path and ends up being for dubious purposes[1].
Basically, it tries to avoid hardware setting Accessed=1 in page table
entries that are unreachable by the hardware, a non-issue.

Remove the PMD copy. Detach the original PMD page at the PUD, flush
the mid-level caches, and free the PTE tables straight from the
detached PMD page. With no allocation left, the locking issue is gone.

Lockdep splat/analysis:

  WARNING: possible circular locking dependency detected
  7.3.0-rc3-f6e7b42bf05b+ #183 Tainted: G     U
  ------------------------------------------------------
  kswapd0/269 is trying to acquire lock:
  ((init_mm).mmap_lock){++++}-{4:4}, at: change_page_attr_set_clr+0x29a/0x4a0
  but task is already holding lock:
  (pool_shrink_rwsem){.+.+}-{4:4}, at: ttm_pool_shrink+0xb2/0x330 [ttm]
  Chain exists of:
    (init_mm).mmap_lock --> fs_reclaim --> pool_shrink_rwsem

The cycle is built from three edges:

  1) pool_shrink_rwsem -> (init_mm).mmap_lock

     The TTM shrinker restores the caching attribute of every page it
     frees, while holding pool_shrink_rwsem:

       ttm_pool_shrink()
       -> ttm_pool_dispose_list()
       -> ttm_pool_free_page()
       -> set_pages_wb()
       -> change_page_attr_set_clr()   [ init_mm mmap read lock ]

  2) fs_reclaim -> pool_shrink_rwsem

     The same shrinker, called from reclaim.

  3) (init_mm).mmap_lock -> fs_reclaim

     ioremap() installing a huge PUD mapping over an existing PMD table:

       ioremap_page_range()
       -> vmap_range_noflush()
       -> vmap_try_huge_pud()          [ init_mm mmap read lock ]
       -> pud_free_pmd_page()
       -> __get_free_page(GFP_KERNEL)  [ enters reclaim ]

[ dhansen: Lots of changelog munging/trimming and merged comments from my
	   version of the fix. ]

Fixes: d5d8b8662e ("x86/mm/pat: Acquire init_mm read lock on attribute changes to avoid UAF")
Suggested-by: Pedro Falcato <pfalcato@suse.de>
Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Link: https://lore.kernel.org/20260916062222.27347-1-mikhail.v.gavrilov@gmail.com
Link: https://lore.kernel.org/all/e11449f0-d9ad-4d1b-ab21-2be7d71fe335@intel.com/ [1]
Link: https://patch.msgid.link/20260923223116.20090-1-mikhail.v.gavrilov@gmail.com
Cc: stable@vger.kernel.org
History 2026-09-28 08:08:16 -07:00
..
pat x86/mm/pat: Allocate split page tables as kernel page tables 2026-09-09 08:39:11 +02:00
amdtopology.c x86/numa: remove redundant numa_nodes_parsed node_set() 2026-07-03 11:16:27 +03:00
cpu_entry_area.c x86/cpu_entry_area: Annotate percpu_setup_exception_stacks() as __init 2024-08-25 14:29:38 +02:00
debug_pagetables.c x86/bugs: Rename CONFIG_PAGE_TABLE_ISOLATION => CONFIG_MITIGATION_PAGE_TABLE_ISOLATION 2024-01-10 10:52:28 +01:00
dump_pagetables.c x86/mm: Drop unnecessary export of "ptdump_walk_pgd_level_debugfs" 2025-11-12 15:24:42 -08:00
extable.c x86/cpu: Hide and rename static_cpu_has() 2026-07-06 21:34:26 -07:00
fault.c x86/mm: Convert pgd_page_get_mm() to ptdescs 2026-07-13 15:55:10 -07:00
hugetlbpage.c mm, arch: consolidate hugetlb CMA reservation 2026-01-26 20:02:19 -08:00
ident_map.c x86/mm: Fix typo in comment 2026-07-01 12:43:45 -07:00
init.c x86/bpf: Enable EXECMEM_ROX_CACHE for BPF allocations 2026-07-22 17:27:15 +02:00
init_32.c arch, mm: consolidate initialization of SPARSE memory model 2026-01-26 20:02:18 -08:00
init_64.c mm.git review status for mm-hotfixes-stable..mm-stable 2026-08-20 18:17:08 -07:00
iomap_32.c io-mapping: Cleanup atomic iomap 2020-11-06 23:14:58 +01:00
ioremap.c mm, x86: use for_each_valid_pfn() from __ioremap_check_ram() 2025-05-12 23:50:44 -07:00
kasan_init_64.c kasan: call kasan_init_generic in kasan_init 2025-09-21 14:21:58 -07:00
kaslr.c x86/kaslr: Recognize all ZONE_DEVICE users as physaddr consumers 2026-01-05 18:05:55 -07:00
kmmio.c treewide: Replace kmalloc with kmalloc_obj for non-scalar types 2026-02-21 01:02:28 -08:00
kmsan_shadow.c x86: kmsan: handle CPU entry area 2022-10-03 14:03:26 -07:00
maccess.c x86/mm: Disallow vsyscall page read for copy_from_kernel_nofault() 2024-02-15 19:21:39 -08:00
Makefile x86/kexec: Disable KCOV instrumentation after load_segments() 2026-03-30 14:15:25 +02:00
mem_encrypt.c x86/mm: Don't force unencrypted DMA for IOMMU-backed devices 2026-09-11 10:30:50 +02:00
mem_encrypt_amd.c x86/sev: Avoid global variable to store virtual address of SVSM area 2025-09-03 17:58:15 +02:00
mem_encrypt_boot.S x86/boot: Create a confined code area for startup code 2025-09-03 18:00:01 +02:00
mm_internal.h arch, mm: consolidate initialization of nodes, zones and memory map 2026-01-26 20:02:18 -08:00
mmap.c mm: constify arch_pick_mmap_layout() for improved const-correctness 2025-09-21 14:22:14 -07:00
mmio-mod.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
numa.c x86/numa: remove redundant numa_nodes_parsed node_set() 2026-07-03 11:16:27 +03:00
pf_in.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 156 2019-05-30 11:26:35 -07:00
pf_in.h treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 156 2019-05-30 11:26:35 -07:00
pgprot.c mm: change vm_get_page_prot() to accept vm_flags_t argument 2025-07-09 22:42:13 -07:00
pgtable.c x86/mm: Drop unnecessary PMD page copy when freeing 2026-09-28 08:08:16 -07:00
pgtable_32.c mm: remove unneeded includes of <asm/pgalloc.h> 2020-08-07 11:33:26 -07:00
physaddr.c x86/mm: Unify __phys_addr_symbol() 2025-10-24 22:13:00 +02:00
physaddr.h License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
pkeys.c mm/pkeys: remove unused tsk parameter from arch_set_user_pkey_access() 2026-04-05 13:52:57 -07:00
pti.c treewide: Explicitly include the x86 CPUID headers 2026-05-06 14:29:59 +02:00
srat.c x86/numa: Store extra copy of numa_nodes_parsed 2026-03-04 16:35:08 +01:00
testmmiotrace.c x86/mm: add testmmiotrace MODULE_DESCRIPTION() 2024-09-01 20:43:31 -07:00
tlb.c - Get rid of static_cpu_has() - one less API to care about testing CPU 2026-08-18 19:09:42 -07:00