Linux s390 Architecture development
 help / color / mirror / Atom feed
* [PATCH 00/12] mm: make userland page table freeing RCU-safe
@ 2026-09-01 11:01 Lorenzo Stoakes (ARM)
  2026-09-01 11:01 ` [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period Lorenzo Stoakes (ARM)
                   ` (11 more replies)
  0 siblings, 12 replies; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

The majority of architectures in the kernel defer page table freeing until
an RCU grace period has elapsed, this series converts all remaining
architectures to do so too and eliminates CONFIG_MMU_GATHER_RCU_TABLE_FREE
altogether.

This is important because it enables safe lockless page table walking under
RCU alone.

Doing so allows for reduced lock contention, avoids lock ordering concerns
and enables fast, efficient and correct page table walking as a result.

Additionally it removes a bunch of code and architecture-specific behaviour
which is always a beneficial thing to do.

There has been much recent work on this:

* In 2023 Hugh Dickins RCU-deferred khugepaged page table retraction in
  commit 13cf577e6b66 ("mm/pgtable: add pte_free_defer() for pgtable as
  page").

* Qi Zheng has done most of the work that made this possible starting with
  the critical commit 718b13861d22 ("x86: mm: free page table pages by RCU
  instead of semi RCU").

* Qi then went on to convert a large number of architectures in commit
  e3ecf7c7d082 ("mm: pgtable: convert some architectures to use
  tlb_remove_ptdesc()"), commit 44b079583f7d ("alpha: mm: enable
  MMU_GATHER_RCU_TABLE_FREE") and the series to which it belongs.

* Qi then introduced the important CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE
  option in commit 086498aed3f6 ("mm: convert __HAVE_ARCH_TLB_REMOVE_TABLE
  to CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE config").

* Finally, and critically, Lance Yang then converted the batch allocation
  fallback case to be RCU-safe in commit 1fb3d8c20bfa ("mm/mmu_gather:
  replace IPI with synchronize_rcu() when batch allocation fails").

The work I do here is only possible due to the work Hugh, Qi, Lance and
others have done previously.

An initial task this series addresses is to zap deposited page tables after
an RCU grace period. Not doing so is currently safe, but for page table
walkers relying on RCU alone, it would not be.

The changes are largely mechanical - the majority of arches already have
the machinery required to support CONFIG_MMU_GATHER_RCU_TABLE_FREE and
simply needed configuration changes or small implementation changes to
switch over.

However some arches required extra attention - sh-X2, m68k-motorola and
sparc32.

sh-X2 allocates PMDs from the slab allocator and PTEs as normal. Therefore
CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE is set to customise page table freeing
and the LSB is used to encode which page table level is used, with
__tlb_remove_table() doing the right thing depending on this.

This pattern is repeated for m68k-motorola and sparc32 to account for
different page table levels. In each case, the page tables are aligned such
that sufficient bits are available in each case for encoding this
information.

m68k-motorola required the biggest change - since RCU page table freeing
uses call_rcu(), this means page table freeing can arise from softirq
context.

This was fixed with an IRQ-safe spin lock used in both get_pointer_table()
and free_pointer_table().

As part of this change, the logic for allocation of a new pointer table was
separated out into add_pointer_table() to make the locking more obviously
correct.

Finally, sparc32 was similar to m68k-motorola in that locking was required,
however this was already implemented via a spinlock, and only had to be
updated to be IRQ-safe.

Additionally, the nocache pool's bit_map lock was updated to be IRQ-safe
for softirq frees.

Separately, the PTE path can't take mm->page_table_lock from softirq (no mm
there), which is fine because the page reference count transitions are
atomic and fully ordered.

The series finally removes CONFIG_MMU_GATHER_RCU_TABLE_FREE and all related
configurations and code that supported !CONFIG_MMU_GATHER_RCU_TABLE_FREE.

As a result, page table walks can now be performed safely under RCU without
any risk of page tables being freed underneath a walker.

However, this is the only guarantee that this work provides - page table
walkers must still ensure that page table entries are as expected
throughout.

All changes have been build tested. As most of the conversions are simply
utilising existing mechanics that are known to work, this suffices for most
cases.

However those arches where significant changes have been made -
m68k-motorola, sparc32 and sh-X2 - have been tested further.

For each of these a boot test and stress test has been performed - fork 400
children, each mmap()'ing 2 MiB and touching every page then partially
munmap()'ing then exiting to trigger as much page table freeing as
possible.

All were found to be working correctly.

Note that sparc32 LEON SMP is not emulated, Andreas - do you have a means
of testing this?

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
Lorenzo Stoakes (ARM) (12):
      mm/huge_memory: zap deposited page tables after an RCU grace period
      mm: enable MMU_GATHER_RCU_TABLE_FREE for most 2-level architectures
      mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU riscv
      mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU arm
      mm: enable MMU_GATHER_RCU_TABLE_FREE for arc, microblaze, xtensa
      mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc64
      mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-coldfire
      mm: enable MMU_GATHER_RCU_TABLE_FREE for sh-X2
      mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-motorola
      mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc32
      mm: make userland page table freeing RCU-safe
      mm: change the contract for free_pgtables(), update docs

 Documentation/mm/process_addrs.rst       |   6 ++
 arch/Kconfig                             |   8 --
 arch/alpha/Kconfig                       |   1 -
 arch/arc/include/asm/pgalloc.h           |   6 +-
 arch/arm/Kconfig                         |   1 -
 arch/arm64/Kconfig                       |   1 -
 arch/loongarch/Kconfig                   |   1 -
 arch/m68k/Kconfig                        |   1 +
 arch/m68k/include/asm/mcf_pgalloc.h      |   5 +-
 arch/m68k/include/asm/motorola_pgalloc.h |   9 ++-
 arch/m68k/mm/motorola.c                  | 121 ++++++++++++++++++++-----------
 arch/microblaze/include/asm/pgalloc.h    |   2 +-
 arch/mips/Kconfig                        |   1 -
 arch/parisc/Kconfig                      |   1 -
 arch/powerpc/Kconfig                     |   1 -
 arch/riscv/Kconfig                       |   1 -
 arch/s390/Kconfig                        |   1 -
 arch/sh/Kconfig                          |   1 +
 arch/sh/include/asm/pgalloc.h            |   6 +-
 arch/sh/mm/pgtable.c                     |  20 +++++
 arch/sparc/Kconfig                       |   4 +-
 arch/sparc/include/asm/pgalloc_32.h      |   7 +-
 arch/sparc/include/asm/pgalloc_64.h      |   8 --
 arch/sparc/include/asm/tlb_64.h          |   2 -
 arch/sparc/lib/bitext.c                  |  14 ++--
 arch/sparc/mm/srmmu.c                    |  26 ++++++-
 arch/um/Kconfig                          |   1 -
 arch/x86/Kconfig                         |   1 -
 arch/xtensa/include/asm/tlb.h            |   2 +-
 include/asm-generic/tlb.h                |  66 +++--------------
 mm/Kconfig                               |   2 +-
 mm/gup.c                                 |   5 +-
 mm/huge_memory.c                         |   2 +-
 mm/mmu_gather.c                          |  30 ++------
 mm/pgtable-generic.c                     |  18 ++++-
 35 files changed, 194 insertions(+), 188 deletions(-)
---
base-commit: 88297631d4d42f6004cb39c0ba3da7d2d10a616f
change-id: 20260831-rcu-pagetable-freeing-84b6be830e20

Cheers,
-- 
Lorenzo Stoakes (ARM) <ljs@kernel.org>


^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:18   ` sashiko-bot
  2026-09-01 13:19   ` Kiryl Shutsemau
  2026-09-01 11:01 ` [PATCH 02/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for most 2-level architectures Lorenzo Stoakes (ARM)
                   ` (10 subsequent siblings)
  11 siblings, 2 replies; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

When an anonymous mapping is collapsed for THP, a PTE page table is
'deposited' with the installed PMD entry.

This is done in order that a split can be performed without needing to
allocate additional memory.

The freeing occurs in zap_deposited_table() and is done directly without
any delay via pte_free().

This is currently not a problem as existing page table walks are protected
by the mmap or anon rmap lock.

However this becomes problematic in a future where RCU-only page table
walkers exist, as there is nothing to prevent a page table walker that
started the walk prior to collapse having its PTE table freed underneath
it.

Commit 13cf577e6b66 ("mm/pgtable: add pte_free_defer() for pgtable as
page") already provides us the mechanism by which to solve this -
pte_free_defer().

Therefore, as a prerequisite to a future commit which will permit fully RCU
page table walks, update zap_deposited_table() to use pte_free_defer()
rather than pte_free().

Note that the IPI sync in collapse_huge_page() is still required to ensure
refcount correctness against a GUP-fast operation.

This is because GUP-fast might increment refcount, but
__collapse_huge_page_isolate() determines whether it is safe to proceed by
checking folio_ref_count() against folio_expected_ref_count(), so the two
must be mutually excluded.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 mm/huge_memory.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 54494c3fa983..505f7b62ff28 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2476,7 +2476,7 @@ static inline void zap_deposited_table(struct mm_struct *mm, pmd_t *pmd)
 	pgtable_t pgtable;
 
 	pgtable = pgtable_trans_huge_withdraw(mm, pmd);
-	pte_free(mm, pgtable);
+	pte_free_defer(mm, pgtable);
 	mm_dec_nr_ptes(mm);
 }
 

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 02/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for most 2-level architectures
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
  2026-09-01 11:01 ` [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:22   ` sashiko-bot
  2026-09-01 11:01 ` [PATCH 03/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU riscv Lorenzo Stoakes (ARM)
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

Commit e3ecf7c7d082 ("mm: pgtable: convert some architectures to use
tlb_remove_ptdesc()") updated a number of architectures from using
pagetable_dtor() + tlb_remove_page_ptdesc() to using tlb_remove_ptdesc() in
__pte_free_tlb().

This is meaningful as tlb_remove_ptdesc() allows for RCU page table
freeing if CONFIG_MMU_GATHER_RCU_TABLE_FREE is specified.

The csky, hexagon, nios2, openrisc, sh (except X2) and m68k-sun3
architectures all have 2 levels of page tables, so the only page tables
ever freed by mmu_gather are PTEs, so this update suffices to ensure that
every page table freed by the mmu_gather mechanism is freed under RCU.

Therefore, update all of these architectures to select
CONFIG_MMU_GATHER_RCU_TABLE_FREE.

This forms part of an overall effort to switch every architecture to this
mode.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 arch/csky/Kconfig     | 1 +
 arch/hexagon/Kconfig  | 1 +
 arch/m68k/Kconfig     | 1 +
 arch/nios2/Kconfig    | 1 +
 arch/openrisc/Kconfig | 1 +
 arch/sh/Kconfig       | 1 +
 6 files changed, 6 insertions(+)

diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig
index 4331313a42ff..80f89ef1d962 100644
--- a/arch/csky/Kconfig
+++ b/arch/csky/Kconfig
@@ -96,6 +96,7 @@ config CSKY
 	select HAVE_SYSCALL_TRACEPOINTS
 	select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU
 	select LOCK_MM_AND_FIND_VMA
+	select MMU_GATHER_RCU_TABLE_FREE
 	select MAY_HAVE_SPARSE_IRQ
 	select MODULES_USE_ELF_RELA if MODULES
 	select OF
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig
index b48491140013..d9b3fb86556b 100644
--- a/arch/hexagon/Kconfig
+++ b/arch/hexagon/Kconfig
@@ -23,6 +23,7 @@ config HEXAGON
 	# select HAVE_CLK
 	select GENERIC_ATOMIC64
 	select HAVE_PERF_EVENTS
+	select MMU_GATHER_RCU_TABLE_FREE
 	# GENERIC_ALLOCATOR is used by dma_alloc_coherent()
 	select GENERIC_ALLOCATOR
 	select GENERIC_IRQ_PROBE
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 11835eb59d94..e29610fd1240 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -36,6 +36,7 @@ config M68K
 	select HAVE_MOD_ARCH_SPECIFIC
 	select HAVE_UID16
 	select MMU_GATHER_NO_RANGE if MMU
+	select MMU_GATHER_RCU_TABLE_FREE if MMU && SUN3
 	select MODULES_USE_ELF_REL
 	select MODULES_USE_ELF_RELA
 	select NO_DMA if !MMU && !COLDFIRE
diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig
index 9c0e6eaeb005..b0ccfc3b7a7e 100644
--- a/arch/nios2/Kconfig
+++ b/arch/nios2/Kconfig
@@ -19,6 +19,7 @@ config NIOS2
 	select HAVE_PAGE_SIZE_4KB
 	select IRQ_DOMAIN
 	select LOCK_MM_AND_FIND_VMA
+	select MMU_GATHER_RCU_TABLE_FREE
 	select MODULES_USE_ELF_RELA
 	select OF
 	select OF_EARLY_FLATTREE
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 5eb995c13074..d90b24dd3bce 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -35,6 +35,7 @@ config OPENRISC
 	select GENERIC_ATOMIC64
 	select GENERIC_CLOCKEVENTS_BROADCAST
 	select GENERIC_SMP_IDLE_THREAD
+	select MMU_GATHER_RCU_TABLE_FREE
 	select MODULES_USE_ELF_RELA
 	select HAVE_DEBUG_STACKOVERFLOW
 	select OR1K_PIC
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index d60f1d5a94c0..204f64912f0e 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -61,6 +61,7 @@ config SUPERH
 	select HAVE_SYSCALL_TRACEPOINTS
 	select IRQ_FORCED_THREADING
 	select LOCK_MM_AND_FIND_VMA
+	select MMU_GATHER_RCU_TABLE_FREE if MMU && !X2TLB
 	select MODULES_USE_ELF_RELA
 	select NEED_SG_DMA_LENGTH
 	select NO_DMA if !MMU && !DMA_COHERENT

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 03/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU riscv
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
  2026-09-01 11:01 ` [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period Lorenzo Stoakes (ARM)
  2026-09-01 11:01 ` [PATCH 02/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for most 2-level architectures Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:14   ` sashiko-bot
  2026-09-01 11:01 ` [PATCH 04/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU arm Lorenzo Stoakes (ARM)
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

Currently riscv gates MMU_GATHER_RCU_TABLE_FREE on CONFIG_SMP and
CONFIG_MMU.

Commit 69be3fb111e7 ("riscv: enable MMU_GATHER_RCU_TABLE_FREE for SMP &&
MMU") enabled CONFIG_MMU_GATHER_RCU_TABLE_FREE for CONFIG_SMP, CONFIG_MMU
riscv builds.

This is expressly for the safety of GUP-fast walkers (CONFIG_HAVE_GUP_FAST
is enabled if CONFIG_MMU is enabled).

Naturally a single core system does not encounter issues with software page
table walkers being correctly synchronised across cores, as there is only a
single core.

However, CONFIG_PREEMPT_RCU is still available on a riscv UP system, so for
a future RCU-only page table walker, this guarantee is required to prevent
concurrent page table teardown.

All page table freeing is already done via tlb_remove_ptdesc() so the
conditions of CONFIG_MMU_GATHER_RCU_TABLE_FREE are already met.

This forms part of an overall effort to switch every architecture to this
mode.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 arch/riscv/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 505eed4af932..3529ed1861ce 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -208,7 +208,7 @@ config RISCV
 	select IRQ_FORCED_THREADING
 	select KASAN_VMALLOC if KASAN
 	select LOCK_MM_AND_FIND_VMA
-	select MMU_GATHER_RCU_TABLE_FREE if SMP && MMU
+	select MMU_GATHER_RCU_TABLE_FREE if MMU
 	select MODULES_USE_ELF_RELA if MODULES
 	select OF
 	select OF_EARLY_FLATTREE

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 04/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU arm
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
                   ` (2 preceding siblings ...)
  2026-09-01 11:01 ` [PATCH 03/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU riscv Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:18   ` sashiko-bot
  2026-09-01 11:01 ` [PATCH 05/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for arc, microblaze, xtensa Lorenzo Stoakes (ARM)
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

Commit a0ad5496b2b3 ("arm: mm: enable HAVE_RCU_TABLE_FREE logic") enabled
CONFIG_MMU_GATHER_RCU_TABLE_FREE (then named HAVE_RCU_TABLE_FREE) for SMP
arm architectures with LPAE enabled.

Regardless of whether CONFIG_ARM_LPAE is enabled or not, the same page
table freeing functions __pte_free_tlb() and __pmd_free_tlb() are used.

Non-LPAE PMD page tables are folded into the PGD and freed by
pgd_free() (PGD freeing is not part of mmu_gather page table freeing in any
case), so this is a noop in this case.

Since commit 358d1c39c82a ("arm: convert various functions to use ptdescs")
both LPAE and non-LPAE PTE page table freeing uses tlb_remove_ptdesc().

Thus all page table freeing is performed under RCU with
CONFIG_MMU_GATHER_RCU_TABLE_FREE enabled for LPAE and non-LPAE and thus it
need not be gated on LPAE.

A UP arm system can set CONFIG_PREEMPT_RCU, so a future pure RCU page
table walker requires MMU_GATHER_RCU_TABLE_FREE to be enabled on UP as
well, even if concurrent GUP fast is not possible there.

Therefore, it is both safe and desirable to set
CONFIG_MMU_GATHER_RCU_TABLE_FREE for all MMU arm architectures (nommu does
not perform mmu_gather operations).

This forms part of an overall effort to switch every architecture to this
mode.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 arch/arm/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 408aa58a2a5b..72b9afc6ae10 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -134,7 +134,7 @@ config ARM
 	select HAVE_PERF_REGS
 	select HAVE_PERF_USER_STACK_DUMP
 	select HAVE_POSIX_CPU_TIMERS_TASK_WORK
-	select MMU_GATHER_RCU_TABLE_FREE if SMP && ARM_LPAE
+	select MMU_GATHER_RCU_TABLE_FREE if MMU
 	select HAVE_REGS_AND_STACK_ACCESS_API
 	select HAVE_RSEQ
 	select HAVE_RUST if CPU_LITTLE_ENDIAN && CPU_32v7 && !KASAN

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 05/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for arc, microblaze, xtensa
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
                   ` (3 preceding siblings ...)
  2026-09-01 11:01 ` [PATCH 04/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU arm Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:28   ` sashiko-bot
  2026-09-01 11:01 ` [PATCH 06/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc64 Lorenzo Stoakes (ARM)
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

Each of these architectures directly free page tables without routing these
changes through tlb_remove_ptdesc().

The use of tlb_remove_ptdesc() is required for
CONFIG_MMU_GATHER_RCU_TABLE_FREE to correctly free page tables under RCU,
so simply update these architectures to use these functions.

Since none of the architectures share page tables or do anything unusual,
nothing complicated is required here.

Therefore this is simply a mechanical change - convert __pud_free_tlb(),
__pmd_free_tlb() and __pte_free_tlb() to use tlb_remove_ptdesc() as
required.

At the point this is in place, all mmu_gather page table freeing is
performed under RCU, and thus MMU_GATHER_RCU_TABLE_FREE is selected for
each architecture.

This forms part of an overall effort to switch every architecture to this
mode.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 arch/arc/Kconfig                      | 1 +
 arch/arc/include/asm/pgalloc.h        | 6 +++---
 arch/microblaze/Kconfig               | 1 +
 arch/microblaze/include/asm/pgalloc.h | 2 +-
 arch/xtensa/Kconfig                   | 1 +
 arch/xtensa/include/asm/tlb.h         | 2 +-
 6 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 2ed7186c81c5..7a7542b61823 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -47,6 +47,7 @@ config ARC
 	select HAVE_SYSCALL_TRACEPOINTS
 	select IRQ_DOMAIN
 	select LOCK_MM_AND_FIND_VMA
+	select MMU_GATHER_RCU_TABLE_FREE
 	select MODULES_USE_ELF_RELA
 	select OF
 	select OF_EARLY_FLATTREE
diff --git a/arch/arc/include/asm/pgalloc.h b/arch/arc/include/asm/pgalloc.h
index dfae070fe8d5..9b6c37f92e97 100644
--- a/arch/arc/include/asm/pgalloc.h
+++ b/arch/arc/include/asm/pgalloc.h
@@ -72,7 +72,7 @@ static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4dp, pud_t *pudp)
 	set_p4d(p4dp, __p4d((unsigned long)pudp));
 }
 
-#define __pud_free_tlb(tlb, pmd, addr)  pud_free((tlb)->mm, pmd)
+#define __pud_free_tlb(tlb, pmd, addr)  tlb_remove_ptdesc((tlb), virt_to_ptdesc(pmd))
 
 #endif
 
@@ -83,10 +83,10 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp)
 	set_pud(pudp, __pud((unsigned long)pmdp));
 }
 
-#define __pmd_free_tlb(tlb, pmd, addr)  pmd_free((tlb)->mm, pmd)
+#define __pmd_free_tlb(tlb, pmd, addr)  tlb_remove_ptdesc((tlb), virt_to_ptdesc(pmd))
 
 #endif
 
-#define __pte_free_tlb(tlb, pte, addr)  pte_free((tlb)->mm, pte)
+#define __pte_free_tlb(tlb, pte, addr)  tlb_remove_ptdesc((tlb), page_ptdesc(pte))
 
 #endif /* _ASM_ARC_PGALLOC_H */
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 484ebb3baedf..af7e821e96c1 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -41,6 +41,7 @@ config MICROBLAZE
 	select PCI_SYSCALL if PCI
 	select CPU_NO_EFFICIENT_FFS
 	select MMU_GATHER_NO_RANGE
+	select MMU_GATHER_RCU_TABLE_FREE
 	select SPARSE_IRQ
 	select ZONE_DMA
 	select TRACE_IRQFLAGS_SUPPORT
diff --git a/arch/microblaze/include/asm/pgalloc.h b/arch/microblaze/include/asm/pgalloc.h
index 084a8a0dc239..ffee6a009219 100644
--- a/arch/microblaze/include/asm/pgalloc.h
+++ b/arch/microblaze/include/asm/pgalloc.h
@@ -25,7 +25,7 @@ extern void __bad_pte(pmd_t *pmd);
 
 extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm);
 
-#define __pte_free_tlb(tlb, pte, addr)	pte_free((tlb)->mm, (pte))
+#define __pte_free_tlb(tlb, pte, addr)	tlb_remove_ptdesc((tlb), page_ptdesc(pte))
 
 #define pmd_populate(mm, pmd, pte) \
 			(pmd_val(*(pmd)) = (unsigned long)page_address(pte))
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index f2f9cd9cde50..33c4caee30e2 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -55,6 +55,7 @@ config XTENSA
 	select HAVE_VIRT_CPU_ACCOUNTING_GEN
 	select IRQ_DOMAIN
 	select LOCK_MM_AND_FIND_VMA
+	select MMU_GATHER_RCU_TABLE_FREE if MMU
 	select MODULES_USE_ELF_RELA
 	select PERF_USE_VMALLOC
 	select TRACE_IRQFLAGS_SUPPORT
diff --git a/arch/xtensa/include/asm/tlb.h b/arch/xtensa/include/asm/tlb.h
index 8c3ceb427018..6fb7b78154f6 100644
--- a/arch/xtensa/include/asm/tlb.h
+++ b/arch/xtensa/include/asm/tlb.h
@@ -16,7 +16,7 @@
 
 #include <asm-generic/tlb.h>
 
-#define __pte_free_tlb(tlb, pte, address)	pte_free((tlb)->mm, pte)
+#define __pte_free_tlb(tlb, pte, address)	tlb_remove_ptdesc((tlb), page_ptdesc(pte))
 
 void check_tlb_sanity(void);
 

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 06/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc64
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
                   ` (4 preceding siblings ...)
  2026-09-01 11:01 ` [PATCH 05/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for arc, microblaze, xtensa Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:23   ` sashiko-bot
  2026-09-01 11:01 ` [PATCH 07/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-coldfire Lorenzo Stoakes (ARM)
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

Commit 4a0100f7546f ("sparc64: use RCU page table freeing") enabled
CONFIG_MMU_GATHER_RCU_TABLE_FREE for SMP sparc64 architectures, expressly
for GUP-fast page table walkers.

Naturally, UP systems do not have to worry about concurrent GUP fast
operations.

However, CONFIG_PREEMPT_RCU is also available even on a UP system, so a
future pure-RCU page table walker requires MMU_GATHER_RCU_TABLE_FREE to be
enabled on UP, even if concurrent GUP fast is not possible there.

To enable future pure-RCU page table walkers, enable
MMU_GATHER_RCU_TABLE_FREE unconditionally.

With this change, it is no longer necessary to have !CONFIG_SMP
pgtable_free_tlb(), so also remove this now dead code.

This forms part of an overall effort to switch every architecture to this
mode.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 arch/sparc/Kconfig                  | 4 ++--
 arch/sparc/include/asm/pgalloc_64.h | 8 --------
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index ab77d3f2536e..8d42ebc6d302 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -75,8 +75,8 @@ config SPARC64
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_KRETPROBES
 	select HAVE_KPROBES
-	select MMU_GATHER_RCU_TABLE_FREE if SMP
-	select HAVE_ARCH_TLB_REMOVE_TABLE if SMP
+	select MMU_GATHER_RCU_TABLE_FREE
+	select HAVE_ARCH_TLB_REMOVE_TABLE
 	select MMU_GATHER_MERGE_VMAS
 	select MMU_GATHER_NO_FLUSH_CACHE
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
diff --git a/arch/sparc/include/asm/pgalloc_64.h b/arch/sparc/include/asm/pgalloc_64.h
index caa7632be4c2..b5055d259b74 100644
--- a/arch/sparc/include/asm/pgalloc_64.h
+++ b/arch/sparc/include/asm/pgalloc_64.h
@@ -74,8 +74,6 @@ void pte_free_defer(struct mm_struct *mm, pgtable_t pgtable);
 
 void pgtable_free(void *table, bool is_page);
 
-#ifdef CONFIG_SMP
-
 struct mmu_gather;
 void tlb_remove_table(struct mmu_gather *, void *);
 
@@ -96,12 +94,6 @@ static inline void __tlb_remove_table(void *_table)
 		is_page = true;
 	pgtable_free(table, is_page);
 }
-#else /* CONFIG_SMP */
-static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, bool is_page)
-{
-	pgtable_free(table, is_page);
-}
-#endif /* !CONFIG_SMP */
 
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pte_t *pte,
 				  unsigned long address)

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 07/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-coldfire
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
                   ` (5 preceding siblings ...)
  2026-09-01 11:01 ` [PATCH 06/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc64 Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:23   ` sashiko-bot
  2026-09-01 11:01 ` [PATCH 08/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sh-X2 Lorenzo Stoakes (ARM)
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

Similar to sun3, the coldfire variant of m68k uses 2-level page tables.

Update its __pte_free_tlb() function to use tlb_remove_ptdesc() in order
that, with CONFIG_MMU_GATHER_RCU_TABLE_FREE, page tables are freed under
RCU.

The page tables occupy a page each and have no odd semantics, so this
change suffices to allow enabling of CONFIG_MMU_GATHER_RCU_TABLE_FREE for
m68k-coldfire, so do so.

This forms part of an overall effort to switch every architecture to this
mode.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 arch/m68k/Kconfig                   | 2 +-
 arch/m68k/include/asm/mcf_pgalloc.h | 5 +----
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index e29610fd1240..6b8ec67c86fd 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -36,7 +36,7 @@ config M68K
 	select HAVE_MOD_ARCH_SPECIFIC
 	select HAVE_UID16
 	select MMU_GATHER_NO_RANGE if MMU
-	select MMU_GATHER_RCU_TABLE_FREE if MMU && SUN3
+	select MMU_GATHER_RCU_TABLE_FREE if MMU && (SUN3 || COLDFIRE)
 	select MODULES_USE_ELF_REL
 	select MODULES_USE_ELF_RELA
 	select NO_DMA if !MMU && !COLDFIRE
diff --git a/arch/m68k/include/asm/mcf_pgalloc.h b/arch/m68k/include/asm/mcf_pgalloc.h
index fc5454d37da3..b53ff0950db2 100644
--- a/arch/m68k/include/asm/mcf_pgalloc.h
+++ b/arch/m68k/include/asm/mcf_pgalloc.h
@@ -39,10 +39,7 @@ extern inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pgtable,
 				  unsigned long address)
 {
-	struct ptdesc *ptdesc = virt_to_ptdesc(pgtable);
-
-	pagetable_dtor(ptdesc);
-	pagetable_free(ptdesc);
+	tlb_remove_ptdesc(tlb, virt_to_ptdesc(pgtable));
 }
 
 static inline pgtable_t pte_alloc_one(struct mm_struct *mm)

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 08/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sh-X2
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
                   ` (6 preceding siblings ...)
  2026-09-01 11:01 ` [PATCH 07/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-coldfire Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:30   ` sashiko-bot
  2026-09-01 11:01 ` [PATCH 09/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-motorola Lorenzo Stoakes (ARM)
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

Currently, non-x2 sh specifies CONFIG_MMU_GATHER_RCU_TABLE_FREE allowing
RCU page table freeing.

sh-X2 is problematic because it utilises slab-allocated PMD page tables,
and thus tlb_remove_ptdesc() cannot be used in these cases.

All other sh variants are fine as commit e3ecf7c7d082 ("mm: pgtable:
convert some architectures to use tlb_remove_ptdesc()") already converted
page table freeing to use tlb_remove_ptdesc(), which does so after an RCU
grace period when CONFIG_MMU_GATHER_RCU_TABLE_FREE is specified.

Resolve this issue by firstly specifying CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE
for sh-X2, so the arch can provide its own __tlb_remove_table()
implementation (called after the RCU grace period).

Then, convert __pmd_free_tlb() to tag the pointer to the PMD, and have
__tlb_remove_table() check this tag to determine whether to free via the
slab or to use pagetable_dtor_free().

This follows the pattern used by sparc64 as implemented in commit
4a0100f7546f ("sparc64: use RCU page table freeing").

Previously __pmd_free_tlb() freed PMD page tables immediately, before any
TLB flush IPI. This seems to be a pre-existing bug, which this change also
resolves.

CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE is only specified for sh-X2, as setting
it disables CONFIG_PT_RECLAIM and causes __tlb_remove_table_one() to call
tlb_remove_table_sync_rcu() and synchronize_rcu() in turn, and this is not
necessary for other sh variants.

This forms part of an overall effort to switch every architecture to this
mode.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 arch/sh/Kconfig               |  3 ++-
 arch/sh/include/asm/pgalloc.h |  6 +++++-
 arch/sh/mm/pgtable.c          | 20 ++++++++++++++++++++
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 204f64912f0e..75236bef6f16 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -33,6 +33,7 @@ config SUPERH
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_ARCH_KGDB
 	select HAVE_ARCH_SECCOMP_FILTER
+	select HAVE_ARCH_TLB_REMOVE_TABLE if X2TLB
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_DEBUG_BUGVERBOSE
 	select HAVE_DEBUG_KMEMLEAK
@@ -61,7 +62,7 @@ config SUPERH
 	select HAVE_SYSCALL_TRACEPOINTS
 	select IRQ_FORCED_THREADING
 	select LOCK_MM_AND_FIND_VMA
-	select MMU_GATHER_RCU_TABLE_FREE if MMU && !X2TLB
+	select MMU_GATHER_RCU_TABLE_FREE if MMU
 	select MODULES_USE_ELF_RELA
 	select NEED_SG_DMA_LENGTH
 	select NO_DMA if !MMU && !DMA_COHERENT
diff --git a/arch/sh/include/asm/pgalloc.h b/arch/sh/include/asm/pgalloc.h
index 6fe7123d38fa..67ce7fa23fa1 100644
--- a/arch/sh/include/asm/pgalloc.h
+++ b/arch/sh/include/asm/pgalloc.h
@@ -17,7 +17,11 @@ extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
 extern void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd);
 extern pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address);
 extern void pmd_free(struct mm_struct *mm, pmd_t *pmd);
-#define __pmd_free_tlb(tlb, pmdp, addr)		pmd_free((tlb)->mm, (pmdp))
+extern void __tlb_remove_table(void *table);
+
+/* PMDs are slab-allocated, tag so they are freed correctly. */
+#define __pmd_free_tlb(tlb, pmdp, addr)					\
+	tlb_remove_table((tlb), (void *)((unsigned long)(pmdp) | 1))
 #endif
 
 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
diff --git a/arch/sh/mm/pgtable.c b/arch/sh/mm/pgtable.c
index 3a4085ea0161..f6184b86b89c 100644
--- a/arch/sh/mm/pgtable.c
+++ b/arch/sh/mm/pgtable.c
@@ -56,4 +56,24 @@ void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
 	kmem_cache_free(pmd_cachep, pmd);
 }
+
+static void __tlb_remove_table_slab(void *table)
+{
+	kmem_cache_free(pmd_cachep, table);
+}
+
+static void __tlb_remove_table_pgtable(void *table)
+{
+	pagetable_dtor_free(table);
+}
+
+void __tlb_remove_table(void *table)
+{
+	const unsigned long addr = (unsigned long)table;
+
+	if (addr & 1)
+		__tlb_remove_table_slab((void *)(addr & ~1UL));
+	else
+		__tlb_remove_table_pgtable(table);
+}
 #endif /* PAGETABLE_LEVELS > 2 */

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 09/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-motorola
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
                   ` (7 preceding siblings ...)
  2026-09-01 11:01 ` [PATCH 08/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sh-X2 Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:30   ` sashiko-bot
  2026-09-01 11:01 ` [PATCH 10/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc32 Lorenzo Stoakes (ARM)
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

sun3 and coldfire are already supported, however motorola requires a little
more care.

Here, custom table removal logic is required, so
CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE is enabled for m68k-motorola.

Firstly as part of this change, the page table level must be communicated
to the underlying __tlb_remove_table() implementation.

Take advantage of the fact that page tables are aligned by more than enough
to permit setting TABLE_PTE or TABLE_PMD in the low bits of the pointer,
and store this there.

Then update __pte_free_tlb() and __pmd_free_tlb() to pass this through,
then have __tlb_remove_table() decode this and pass it to
free_pointer_table().

The page table freeing is performed via call_rcu(), so free_pointer_table()
now will be invoked from softirq context, and as such may be re-entrant.

Introduce an irq save/restore spinlock to handle this, and hold it over the
time a given ptable entry is being referenced in both get_pointer_table()
and free_pointer_table().

In order to make things a little easier in this respect, separate out the
logic for adding a new ptable entry into add_pointer_table() and only hold
the lock during ptable entry insertion in this case.

Note that original list_add_tail(new, dp) added new prior to dp, which is
ptable_list[type].next, i.e. after ptable_list[type].

The equivalent therefore is list_add(new, &ptable_list[type]), which adds
new after ptable_list[type], only without needing to make reference to dp.

Note that, as m68k-motorola specifies CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE, it
does not enable CONFIG_PT_RECLAIM. This isn't meaningfully impactful.

With this applied, all of m68k implements CONFIG_MMU_GATHER_RCU_TABLE_FREE.

This forms part of an overall effort to switch every architecture to this
mode.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 arch/m68k/Kconfig                        |   3 +-
 arch/m68k/include/asm/motorola_pgalloc.h |   9 ++-
 arch/m68k/mm/motorola.c                  | 121 ++++++++++++++++++++-----------
 3 files changed, 86 insertions(+), 47 deletions(-)

diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 6b8ec67c86fd..fa5d39549da9 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -29,6 +29,7 @@ config M68K
 	select HAVE_ARCH_LIBGCC_H
 	select HAVE_ARCH_SECCOMP
 	select HAVE_ARCH_SECCOMP_FILTER
+	select HAVE_ARCH_TLB_REMOVE_TABLE if MMU_MOTOROLA
 	select HAVE_ASM_MODVERSIONS
 	select HAVE_DEBUG_BUGVERBOSE
 	select HAVE_EFFICIENT_UNALIGNED_ACCESS if !CPU_HAS_NO_UNALIGNED
@@ -36,7 +37,7 @@ config M68K
 	select HAVE_MOD_ARCH_SPECIFIC
 	select HAVE_UID16
 	select MMU_GATHER_NO_RANGE if MMU
-	select MMU_GATHER_RCU_TABLE_FREE if MMU && (SUN3 || COLDFIRE)
+	select MMU_GATHER_RCU_TABLE_FREE if MMU
 	select MODULES_USE_ELF_REL
 	select MODULES_USE_ELF_RELA
 	select NO_DMA if !MMU && !COLDFIRE
diff --git a/arch/m68k/include/asm/motorola_pgalloc.h b/arch/m68k/include/asm/motorola_pgalloc.h
index 1091fb0affbe..dcde40e8b5c6 100644
--- a/arch/m68k/include/asm/motorola_pgalloc.h
+++ b/arch/m68k/include/asm/motorola_pgalloc.h
@@ -17,6 +17,7 @@ enum m68k_table_types {
 extern void init_pointer_table(void *table, int type);
 extern void *get_pointer_table(struct mm_struct *mm, int type);
 extern int free_pointer_table(void *table, int type);
+extern void __tlb_remove_table(void *table);
 
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
@@ -47,7 +48,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pgtable)
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pgtable,
 				  unsigned long address)
 {
-	free_pointer_table(pgtable, TABLE_PTE);
+	tlb_remove_table(tlb, (void *)((unsigned long)pgtable | TABLE_PTE));
 }
 
 
@@ -61,10 +62,10 @@ static inline int pmd_free(struct mm_struct *mm, pmd_t *pmd)
 	return free_pointer_table(pmd, TABLE_PMD);
 }
 
-static inline int __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
-				 unsigned long address)
+static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
+				  unsigned long address)
 {
-	return free_pointer_table(pmd, TABLE_PMD);
+	tlb_remove_table(tlb, (void *)((unsigned long)pmd | TABLE_PMD));
 }
 
 
diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c
index b30aa69a73a6..ffc80483440b 100644
--- a/arch/m68k/mm/motorola.c
+++ b/arch/m68k/mm/motorola.c
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/memblock.h>
 #include <linux/gfp.h>
+#include <linux/cleanup.h>
 
 #include <asm/setup.h>
 #include <linux/uaccess.h>
@@ -103,6 +104,8 @@ static struct list_head ptable_list[3] = {
 	LIST_HEAD_INIT(ptable_list[2]),
 };
 
+static DEFINE_SPINLOCK(ptable_lock);
+
 #define PD_PTABLE(ptdesc) ((ptable_desc *)&(virt_to_ptdesc((void *)(ptdesc))->pt_list))
 #define PD_PTDESC(ptable) (list_entry(ptable, struct ptdesc, pt_list))
 #define PD_MARKBITS(dp) (*(unsigned int *)&PD_PTDESC(dp)->pt_index)
@@ -139,52 +142,66 @@ void __init init_pointer_table(void *table, int type)
 	return;
 }
 
-void *get_pointer_table(struct mm_struct *mm, int type)
+/*
+ * For a pointer table for a user process address space, a
+ * table is taken from a ptdesc allocated for the purpose.  Each
+ * ptdesc can hold 8 pointer tables.  The ptdesc is remapped in
+ * virtual address space to be noncacheable.
+ */
+static void *add_pointer_table(struct mm_struct *mm, int type)
 {
-	ptable_desc *dp = ptable_list[type].next;
-	unsigned int mask = list_empty(&ptable_list[type]) ? 0 : PD_MARKBITS(dp);
-	unsigned int tmp, off;
+	struct ptdesc *ptdesc;
+	ptable_desc *new;
+	void *pt_addr;
 
-	/*
-	 * For a pointer table for a user process address space, a
-	 * table is taken from a ptdesc allocated for the purpose.  Each
-	 * ptdesc can hold 8 pointer tables.  The ptdesc is remapped in
-	 * virtual address space to be noncacheable.
-	 */
-	if (mask == 0) {
-		struct ptdesc *ptdesc;
-		ptable_desc *new;
-		void *pt_addr;
-
-		ptdesc = pagetable_alloc(GFP_KERNEL | __GFP_ZERO, 0);
-		if (!ptdesc)
-			return NULL;
-
-		pt_addr = ptdesc_address(ptdesc);
-
-		switch (type) {
-		case TABLE_PTE:
-			/*
-			 * m68k doesn't have SPLIT_PTE_PTLOCKS for not having
-			 * SMP.
-			 */
-			pagetable_pte_ctor(mm, ptdesc);
-			break;
-		case TABLE_PMD:
-			pagetable_pmd_ctor(mm, ptdesc);
-			break;
-		case TABLE_PGD:
-			pagetable_pgd_ctor(ptdesc);
-			break;
-		}
+	ptdesc = pagetable_alloc(GFP_KERNEL | __GFP_ZERO, 0);
+	if (!ptdesc)
+		return NULL;
+
+	pt_addr = ptdesc_address(ptdesc);
+
+	switch (type) {
+	case TABLE_PTE:
+		/*
+		 * m68k doesn't have SPLIT_PTE_PTLOCKS for not having
+		 * SMP.
+		 */
+		pagetable_pte_ctor(mm, ptdesc);
+		break;
+	case TABLE_PMD:
+		pagetable_pmd_ctor(mm, ptdesc);
+		break;
+	case TABLE_PGD:
+		pagetable_pgd_ctor(ptdesc);
+		break;
+	}
+
+	mmu_page_ctor(pt_addr);
+
+	new = PD_PTABLE(pt_addr);
 
-		mmu_page_ctor(pt_addr);
+	PD_MARKBITS(new) = ptable_mask(type) - 1;
+	scoped_guard(spinlock_irqsave, &ptable_lock)
+		list_add(new, &ptable_list[type]);
 
-		new = PD_PTABLE(pt_addr);
-		PD_MARKBITS(new) = ptable_mask(type) - 1;
-		list_add_tail(new, dp);
+	return (pmd_t *)pt_addr;
+}
+
+void *get_pointer_table(struct mm_struct *mm, int type)
+{
+	unsigned int tmp, off;
+	unsigned long mask;
+	unsigned long flags;
+	ptable_desc *dp;
+	void *ret;
 
-		return (pmd_t *)pt_addr;
+	spin_lock_irqsave(&ptable_lock, flags);
+	dp = ptable_list[type].next;
+	mask = list_empty(&ptable_list[type]) ? 0 : PD_MARKBITS(dp);
+
+	if (mask == 0) {
+		spin_unlock_irqrestore(&ptable_lock, flags);
+		return add_pointer_table(mm, type);
 	}
 
 	for (tmp = 1, off = 0; (mask & tmp) == 0; tmp <<= 1, off += ptable_size(type))
@@ -194,7 +211,10 @@ void *get_pointer_table(struct mm_struct *mm, int type)
 		/* move to end of list */
 		list_move_tail(dp, &ptable_list[type]);
 	}
-	return ptdesc_address(PD_PTDESC(dp)) + off;
+
+	ret = ptdesc_address(PD_PTDESC(dp)) + off;
+	spin_unlock_irqrestore(&ptable_lock, flags);
+	return ret;
 }
 
 int free_pointer_table(void *table, int type)
@@ -203,6 +223,9 @@ int free_pointer_table(void *table, int type)
 	unsigned long ptable = (unsigned long)table;
 	unsigned long pt_addr = ptable & PAGE_MASK;
 	unsigned int mask = 1U << ((ptable - pt_addr)/ptable_size(type));
+	unsigned long flags;
+
+	spin_lock_irqsave(&ptable_lock, flags);
 
 	dp = PD_PTABLE(pt_addr);
 	if (PD_MARKBITS (dp) & mask)
@@ -213,6 +236,8 @@ int free_pointer_table(void *table, int type)
 	if (PD_MARKBITS(dp) == ptable_mask(type)) {
 		/* all tables in ptdesc are free, free ptdesc */
 		list_del(dp);
+		spin_unlock_irqrestore(&ptable_lock, flags);
+
 		mmu_page_dtor((void *)pt_addr);
 		pagetable_dtor_free(virt_to_ptdesc((void *)pt_addr));
 		return 1;
@@ -223,9 +248,21 @@ int free_pointer_table(void *table, int type)
 		 */
 		list_move(dp, &ptable_list[type]);
 	}
+
+	spin_unlock_irqrestore(&ptable_lock, flags);
 	return 0;
 }
 
+void __tlb_remove_table(void *table)
+{
+	/* The bottom 2 bits are used to encode page table type. */
+	const unsigned long encoded = (unsigned long)table;
+	void *addr = (void *)(encoded & ~3UL);
+	const int type = encoded & 3;
+
+	free_pointer_table(addr, type);
+}
+
 /* size of memory already mapped in head.S */
 extern __initdata unsigned long m68k_init_mapped_size;
 

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 10/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc32
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
                   ` (8 preceding siblings ...)
  2026-09-01 11:01 ` [PATCH 09/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-motorola Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:37   ` sashiko-bot
  2026-09-01 11:01 ` [PATCH 11/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
  2026-09-01 11:01 ` [PATCH 12/12] mm: change the contract for free_pgtables(), update docs Lorenzo Stoakes (ARM)
  11 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

Careful handling is required for sparc32 which implements page tables as
part of a shared backing page.

To support this, a custom __tlb_remove_table() function is required, as
specified by CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE.

This allows __pte_free_tlb() and __pmd_free_tlb() to specify which page
table level is being freed, which is transmitted to __tlb_remove_table()
through setting the lowest bit of the page table to 1 for a PMD and 0 for a
PTE (the page tables are 256-byte aligned so this is safe to do).

Next, since the page table freeing is done via RCU callback, and thus might
be executed in softirq context, update the spin locks to IRQ save/restore.

Then, in __tlb_remove_table(), figure out whether to free a PMD page table
via free_pmd_fast() or a PTE via the newly introduced __pte_free()
function, using the lower bit encoded in __pte_free_tlb() or
__pmd_free_tlb() to determine which to call.

__pte_free() is identical to preexisting pte_free(), except that it
optionally allows a NULL mm pointer to be provided, in which case there is
no mm whose mm->page_table_lock can be taken.

This lock doesn't appear to have been doing quite as much as it intended,
as backing pages can contain page tables for multiple mm's, which are not
serialised by it.

But more importantly - the reference count increment in pte_alloc_one() and
decrement in __pte_free() are atomic with full ordering, so it simply isn't
possible for there to be a meaningful race here.

Note that the specification of CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE disables
CONFIG_PT_RECLAIM for sparc32, which mirrors sparc64.

This forms part of an overall effort to switch every architecture to this
mode, and with it complete, means every architecture now supports
CONFIG_MMU_GATHER_RCU_TABLE_FREE.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 arch/sparc/Kconfig                  |  2 ++
 arch/sparc/include/asm/pgalloc_32.h |  7 +++++--
 arch/sparc/lib/bitext.c             | 14 +++++++-------
 arch/sparc/mm/srmmu.c               | 26 +++++++++++++++++++++++---
 4 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 8d42ebc6d302..79c09d6ee466 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -64,6 +64,8 @@ config SPARC32
 	select HAVE_UID16
 	select HAVE_PAGE_SIZE_4KB
 	select LOCK_MM_AND_FIND_VMA
+	select MMU_GATHER_RCU_TABLE_FREE
+	select HAVE_ARCH_TLB_REMOVE_TABLE
 	select OLD_SIGACTION
 	select ZONE_DMA
 
diff --git a/arch/sparc/include/asm/pgalloc_32.h b/arch/sparc/include/asm/pgalloc_32.h
index 4f73e87b22a3..36010852ba0c 100644
--- a/arch/sparc/include/asm/pgalloc_32.h
+++ b/arch/sparc/include/asm/pgalloc_32.h
@@ -48,7 +48,9 @@ static inline void free_pmd_fast(pmd_t * pmd)
 }
 
 #define pmd_free(mm, pmd)		free_pmd_fast(pmd)
-#define __pmd_free_tlb(tlb, pmd, addr)	pmd_free((tlb)->mm, pmd)
+
+#define __pmd_free_tlb(tlb, pmd, addr)					\
+	tlb_remove_table((tlb), (void *)((unsigned long)(pmd) | 1UL))
 
 #define pmd_populate(mm, pmd, pte)	pmd_set(pmd, pte)
 
@@ -72,6 +74,7 @@ static inline void free_pte_fast(pte_t *pte)
 #define pte_free_kernel(mm, pte)	free_pte_fast(pte)
 
 void pte_free(struct mm_struct * mm, pgtable_t pte);
-#define __pte_free_tlb(tlb, pte, addr)	pte_free((tlb)->mm, pte)
+void __tlb_remove_table(void *table);
+#define __pte_free_tlb(tlb, pte, addr)	tlb_remove_table((tlb), (void *)(pte))
 
 #endif /* _SPARC_PGALLOC_H */
diff --git a/arch/sparc/lib/bitext.c b/arch/sparc/lib/bitext.c
index 32a5c1d9459c..c309e27973ce 100644
--- a/arch/sparc/lib/bitext.c
+++ b/arch/sparc/lib/bitext.c
@@ -22,8 +22,6 @@
  * @align: requested alignment
  *
  * Returns offset in the map or -1 if out of space.
- *
- * Not safe to call from an interrupt (uses spin_lock).
  */
 int bit_map_string_get(struct bit_map *t, int len, int align)
 {
@@ -31,6 +29,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
 	int off_new;
 	int align1;
 	int i, color;
+	unsigned long flags;
 
 	if (t->num_colors) {
 		/* align is overloaded to be the page color */
@@ -50,7 +49,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
 		BUG();
 	color &= align1;
 
-	spin_lock(&t->lock);
+	spin_lock_irqsave(&t->lock, flags);
 	if (len < t->last_size)
 		offset = t->first_free;
 	else
@@ -64,7 +63,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
 		if (offset >= t->size)
 			offset = 0;
 		if (count + len > t->size) {
-			spin_unlock(&t->lock);
+			spin_unlock_irqrestore(&t->lock, flags);
 /* P3 */ printk(KERN_ERR
   "bitmap out: size %d used %d off %d len %d align %d count %d\n",
   t->size, t->used, offset, len, align, count);
@@ -90,7 +89,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
 					t->last_off = 0;
 				t->used += len;
 				t->last_size = len;
-				spin_unlock(&t->lock);
+				spin_unlock_irqrestore(&t->lock, flags);
 				return offset;
 			}
 		}
@@ -103,10 +102,11 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
 void bit_map_clear(struct bit_map *t, int offset, int len)
 {
 	int i;
+	unsigned long flags;
 
 	if (t->used < len)
 		BUG();		/* Much too late to do any good, but alas... */
-	spin_lock(&t->lock);
+	spin_lock_irqsave(&t->lock, flags);
 	for (i = 0; i < len; i++) {
 		if (test_bit(offset + i, t->map) == 0)
 			BUG();
@@ -115,7 +115,7 @@ void bit_map_clear(struct bit_map *t, int offset, int len)
 	if (offset < t->first_free)
 		t->first_free = offset;
 	t->used -= len;
-	spin_unlock(&t->lock);
+	spin_unlock_irqrestore(&t->lock, flags);
 }
 
 void bit_map_init(struct bit_map *t, unsigned long *map, int size)
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 9a74902ad181..2a2c7bd21011 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -359,19 +359,39 @@ pgtable_t pte_alloc_one(struct mm_struct *mm)
 	return ptep;
 }
 
-void pte_free(struct mm_struct *mm, pgtable_t ptep)
+static void __pte_free(struct mm_struct *mm, pgtable_t ptep)
 {
+	const bool process_context = mm;
 	struct page *page;
 
 	page = pfn_to_page(__nocache_pa((unsigned long)ptep) >> PAGE_SHIFT);
-	spin_lock(&mm->page_table_lock);
+	if (process_context)
+		spin_lock(&mm->page_table_lock);
 	if (page_ref_dec_return(page) == 1)
 		pagetable_dtor(page_ptdesc(page));
-	spin_unlock(&mm->page_table_lock);
+	if (process_context)
+		spin_unlock(&mm->page_table_lock);
 
 	srmmu_free_nocache(ptep, SRMMU_PTE_TABLE_SIZE);
 }
 
+void pte_free(struct mm_struct *mm, pgtable_t ptep)
+{
+	__pte_free(mm, ptep);
+}
+
+void __tlb_remove_table(void *table)
+{
+	const unsigned long encoded = (unsigned long)table;
+	const unsigned long addr = encoded & ~1UL;
+	const bool is_pmd = encoded & 1;
+
+	if (is_pmd)
+		free_pmd_fast((pmd_t *)addr);
+	else /* Called from softirq context, no mm. */
+		__pte_free(NULL, (pgtable_t)addr);
+}
+
 /* context handling - a dynamically sized pool is used */
 #define NO_CONTEXT	-1
 

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 11/12] mm: make userland page table freeing RCU-safe
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
                   ` (9 preceding siblings ...)
  2026-09-01 11:01 ` [PATCH 10/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc32 Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:52   ` sashiko-bot
  2026-09-01 13:33   ` Kiryl Shutsemau
  2026-09-01 11:01 ` [PATCH 12/12] mm: change the contract for free_pgtables(), update docs Lorenzo Stoakes (ARM)
  11 siblings, 2 replies; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

Now every architecture has been converted to support
CONFIG_MMU_GATHER_RCU_TABLE_FREE, this configuration option no longer makes
any sense to keep around.

Therefore remove it, and remove all the dead code that existed for
!CONFIG_MMU_GATHER_RCU_TABLE_FREE architectures previously.

Additionally, CONFIG_MMU_GATHER_TABLE_FREE is no longer necessary, as all
architectures instead use CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE when a custom
__tlb_remove_table() is required, so remove this too.

A number of architectures only enabled CONFIG_MMU_GATHER_RCU_TABLE_FREE if
CONFIG_MMU was set, however the mmu_gather logic only actually does
something meaningful if CONFIG_MMU is set (mmu_gather.c is only compiled in
this case, for instance).

As a result, there's no need to gate any of this logic on CONFIG_MMU
explicitly.

CONFIG_PT_RECLAIM however does have a strict dependency on CONFIG_MMU, so
make this dependency explicit.

Additionally, correct comments to remove references to non-RCU page table
gathering and make it clear that this is not 'semi-RCU', nor has it been
since commit 1fb3d8c20bfa ("mm/mmu_gather: replace IPI with
synchronize_rcu() when batch allocation fails").

With this change in place the kernel policy is now that all page tables are
freed after an RCU grace period, and thus it is now safe to unconditionally
perform page table walks under RCU, safe in the knowledge that page tables
will not be freed underneath the walker.

This is all that is guaranteed, however, so naturally it is still incumbent
upon page table walkers to ensure that the page table entries are as
expected.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 arch/Kconfig                    |  8 -----
 arch/alpha/Kconfig              |  1 -
 arch/arc/Kconfig                |  1 -
 arch/arm/Kconfig                |  1 -
 arch/arm64/Kconfig              |  1 -
 arch/csky/Kconfig               |  1 -
 arch/hexagon/Kconfig            |  1 -
 arch/loongarch/Kconfig          |  1 -
 arch/m68k/Kconfig               |  1 -
 arch/microblaze/Kconfig         |  1 -
 arch/mips/Kconfig               |  1 -
 arch/nios2/Kconfig              |  1 -
 arch/openrisc/Kconfig           |  1 -
 arch/parisc/Kconfig             |  1 -
 arch/powerpc/Kconfig            |  1 -
 arch/riscv/Kconfig              |  1 -
 arch/s390/Kconfig               |  1 -
 arch/sh/Kconfig                 |  1 -
 arch/sparc/Kconfig              |  2 --
 arch/sparc/include/asm/tlb_64.h |  2 --
 arch/um/Kconfig                 |  1 -
 arch/x86/Kconfig                |  1 -
 arch/xtensa/Kconfig             |  1 -
 include/asm-generic/tlb.h       | 66 ++++++-----------------------------------
 mm/Kconfig                      |  2 +-
 mm/gup.c                        |  5 ++--
 mm/mmu_gather.c                 | 30 ++++---------------
 27 files changed, 18 insertions(+), 117 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 45c657772362..6f7516916797 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -526,13 +526,6 @@ config HAVE_ARCH_JUMP_LABEL
 config HAVE_ARCH_JUMP_LABEL_RELATIVE
 	bool
 
-config MMU_GATHER_TABLE_FREE
-	bool
-
-config MMU_GATHER_RCU_TABLE_FREE
-	bool
-	select MMU_GATHER_TABLE_FREE
-
 config MMU_GATHER_PAGE_SIZE
 	bool
 
@@ -548,7 +541,6 @@ config MMU_GATHER_MERGE_VMAS
 
 config MMU_GATHER_NO_GATHER
 	bool
-	depends on MMU_GATHER_TABLE_FREE
 
 config ARCH_WANT_IRQS_OFF_ACTIVATE_MM
 	bool
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index e53ef2d88463..9063c7bda4e4 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -42,7 +42,6 @@ config ALPHA
 	select ARCH_STACKWALK
 	select CPU_NO_EFFICIENT_FFS if !ALPHA_EV67
 	select MMU_GATHER_NO_RANGE
-	select MMU_GATHER_RCU_TABLE_FREE
 	select SPARSEMEM_EXTREME if SPARSEMEM
 	select ZONE_DMA
 	select TRACE_IRQFLAGS_SUPPORT
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 7a7542b61823..2ed7186c81c5 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -47,7 +47,6 @@ config ARC
 	select HAVE_SYSCALL_TRACEPOINTS
 	select IRQ_DOMAIN
 	select LOCK_MM_AND_FIND_VMA
-	select MMU_GATHER_RCU_TABLE_FREE
 	select MODULES_USE_ELF_RELA
 	select OF
 	select OF_EARLY_FLATTREE
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 72b9afc6ae10..0cc289a7184a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -134,7 +134,6 @@ config ARM
 	select HAVE_PERF_REGS
 	select HAVE_PERF_USER_STACK_DUMP
 	select HAVE_POSIX_CPU_TIMERS_TASK_WORK
-	select MMU_GATHER_RCU_TABLE_FREE if MMU
 	select HAVE_REGS_AND_STACK_ACCESS_API
 	select HAVE_RSEQ
 	select HAVE_RUST if CPU_LITTLE_ENDIAN && CPU_32v7 && !KASAN
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 2bbeded33da0..b6c2dd8b2612 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -221,7 +221,6 @@ config ARM64
 	select HAVE_RELIABLE_STACKTRACE
 	select HAVE_POSIX_CPU_TIMERS_TASK_WORK
 	select HAVE_FUNCTION_ARG_ACCESS_API
-	select MMU_GATHER_RCU_TABLE_FREE
 	select HAVE_RSEQ
 	select HAVE_RUST if RUSTC_SUPPORTS_ARM64
 	select HAVE_STACKPROTECTOR
diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig
index 80f89ef1d962..4331313a42ff 100644
--- a/arch/csky/Kconfig
+++ b/arch/csky/Kconfig
@@ -96,7 +96,6 @@ config CSKY
 	select HAVE_SYSCALL_TRACEPOINTS
 	select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU
 	select LOCK_MM_AND_FIND_VMA
-	select MMU_GATHER_RCU_TABLE_FREE
 	select MAY_HAVE_SPARSE_IRQ
 	select MODULES_USE_ELF_RELA if MODULES
 	select OF
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig
index d9b3fb86556b..b48491140013 100644
--- a/arch/hexagon/Kconfig
+++ b/arch/hexagon/Kconfig
@@ -23,7 +23,6 @@ config HEXAGON
 	# select HAVE_CLK
 	select GENERIC_ATOMIC64
 	select HAVE_PERF_EVENTS
-	select MMU_GATHER_RCU_TABLE_FREE
 	# GENERIC_ALLOCATOR is used by dma_alloc_coherent()
 	select GENERIC_ALLOCATOR
 	select GENERIC_IRQ_PROBE
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 9c5def706222..d1b23da40737 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -188,7 +188,6 @@ config LOONGARCH
 	select IRQ_LOONGARCH_CPU
 	select LOCK_MM_AND_FIND_VMA
 	select MMU_GATHER_MERGE_VMAS if MMU
-	select MMU_GATHER_RCU_TABLE_FREE
 	select MODULES_USE_ELF_RELA if MODULES
 	select NEED_PER_CPU_EMBED_FIRST_CHUNK
 	select NEED_PER_CPU_PAGE_FIRST_CHUNK
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index fa5d39549da9..eb84c3af92c0 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -37,7 +37,6 @@ config M68K
 	select HAVE_MOD_ARCH_SPECIFIC
 	select HAVE_UID16
 	select MMU_GATHER_NO_RANGE if MMU
-	select MMU_GATHER_RCU_TABLE_FREE if MMU
 	select MODULES_USE_ELF_REL
 	select MODULES_USE_ELF_RELA
 	select NO_DMA if !MMU && !COLDFIRE
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index af7e821e96c1..484ebb3baedf 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -41,7 +41,6 @@ config MICROBLAZE
 	select PCI_SYSCALL if PCI
 	select CPU_NO_EFFICIENT_FFS
 	select MMU_GATHER_NO_RANGE
-	select MMU_GATHER_RCU_TABLE_FREE
 	select SPARSE_IRQ
 	select ZONE_DMA
 	select TRACE_IRQFLAGS_SUPPORT
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index e2eb9627bd14..f0c43d118ca0 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -97,7 +97,6 @@ config MIPS
 	select IRQ_FORCED_THREADING
 	select ISA if EISA
 	select LOCK_MM_AND_FIND_VMA
-	select MMU_GATHER_RCU_TABLE_FREE
 	select MODULES_USE_ELF_REL if MODULES
 	select MODULES_USE_ELF_RELA if MODULES && 64BIT
 	select PERF_USE_VMALLOC
diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig
index b0ccfc3b7a7e..9c0e6eaeb005 100644
--- a/arch/nios2/Kconfig
+++ b/arch/nios2/Kconfig
@@ -19,7 +19,6 @@ config NIOS2
 	select HAVE_PAGE_SIZE_4KB
 	select IRQ_DOMAIN
 	select LOCK_MM_AND_FIND_VMA
-	select MMU_GATHER_RCU_TABLE_FREE
 	select MODULES_USE_ELF_RELA
 	select OF
 	select OF_EARLY_FLATTREE
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index d90b24dd3bce..5eb995c13074 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -35,7 +35,6 @@ config OPENRISC
 	select GENERIC_ATOMIC64
 	select GENERIC_CLOCKEVENTS_BROADCAST
 	select GENERIC_SMP_IDLE_THREAD
-	select MMU_GATHER_RCU_TABLE_FREE
 	select MODULES_USE_ELF_RELA
 	select HAVE_DEBUG_STACKOVERFLOW
 	select OR1K_PIC
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index d3afac2f0d9b..77f67028ad89 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -80,7 +80,6 @@ config PARISC
 	select GENERIC_CLOCKEVENTS
 	select CPU_NO_EFFICIENT_FFS
 	select THREAD_INFO_IN_TASK
-	select MMU_GATHER_RCU_TABLE_FREE
 	select NEED_DMA_MAP_STATE
 	select NEED_SG_DMA_LENGTH
 	select HAVE_ARCH_KGDB
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 2580e27e4328..0767cfcbaa42 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -307,7 +307,6 @@ config PPC
 	select KASAN_VMALLOC			if KASAN && EXECMEM
 	select LOCK_MM_AND_FIND_VMA
 	select MMU_GATHER_PAGE_SIZE
-	select MMU_GATHER_RCU_TABLE_FREE
 	select HAVE_ARCH_TLB_REMOVE_TABLE
 	select MMU_GATHER_MERGE_VMAS
 	select MMU_LAZY_TLB_SHOOTDOWN		if PPC_BOOK3S_64
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 3529ed1861ce..7741a4287498 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -208,7 +208,6 @@ config RISCV
 	select IRQ_FORCED_THREADING
 	select KASAN_VMALLOC if KASAN
 	select LOCK_MM_AND_FIND_VMA
-	select MMU_GATHER_RCU_TABLE_FREE if MMU
 	select MODULES_USE_ELF_RELA if MODULES
 	select OF
 	select OF_EARLY_FLATTREE
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index b88b85042136..a34376c05f6e 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -267,7 +267,6 @@ config S390
 	select LOCK_MM_AND_FIND_VMA
 	select MMU_GATHER_MERGE_VMAS
 	select MMU_GATHER_NO_GATHER
-	select MMU_GATHER_RCU_TABLE_FREE
 	select MODULES_USE_ELF_RELA
 	select NEED_DMA_MAP_STATE	if PCI
 	select NEED_PER_CPU_EMBED_FIRST_CHUNK
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 75236bef6f16..fe859def918c 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -62,7 +62,6 @@ config SUPERH
 	select HAVE_SYSCALL_TRACEPOINTS
 	select IRQ_FORCED_THREADING
 	select LOCK_MM_AND_FIND_VMA
-	select MMU_GATHER_RCU_TABLE_FREE if MMU
 	select MODULES_USE_ELF_RELA
 	select NEED_SG_DMA_LENGTH
 	select NO_DMA if !MMU && !DMA_COHERENT
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 79c09d6ee466..742ffff8c37f 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -64,7 +64,6 @@ config SPARC32
 	select HAVE_UID16
 	select HAVE_PAGE_SIZE_4KB
 	select LOCK_MM_AND_FIND_VMA
-	select MMU_GATHER_RCU_TABLE_FREE
 	select HAVE_ARCH_TLB_REMOVE_TABLE
 	select OLD_SIGACTION
 	select ZONE_DMA
@@ -77,7 +76,6 @@ config SPARC64
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_KRETPROBES
 	select HAVE_KPROBES
-	select MMU_GATHER_RCU_TABLE_FREE
 	select HAVE_ARCH_TLB_REMOVE_TABLE
 	select MMU_GATHER_MERGE_VMAS
 	select MMU_GATHER_NO_FLUSH_CACHE
diff --git a/arch/sparc/include/asm/tlb_64.h b/arch/sparc/include/asm/tlb_64.h
index 3037187482db..f5f9631685d5 100644
--- a/arch/sparc/include/asm/tlb_64.h
+++ b/arch/sparc/include/asm/tlb_64.h
@@ -29,9 +29,7 @@ void flush_tlb_pending(void);
  * and therefore we don't need a TLBI when freeing page-table pages.
  */
 
-#ifdef CONFIG_MMU_GATHER_RCU_TABLE_FREE
 #define tlb_needs_table_invalidate()	(false)
-#endif
 
 #include <asm-generic/tlb.h>
 
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index d9541d13d9eb..94b8ff70f578 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -44,7 +44,6 @@ config UML
 	select HAVE_SYSCALL_TRACEPOINTS
 	select THREAD_INFO_IN_TASK
 	select SPARSE_IRQ
-	select MMU_GATHER_RCU_TABLE_FREE
 
 config MMU
 	bool
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index a8c3b3d31a27..6e5e462ec059 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -283,7 +283,6 @@ config X86
 	select HAVE_PERF_REGS
 	select HAVE_PERF_USER_STACK_DUMP
 	select ASYNC_KERNEL_PGTABLE_FREE	if IOMMU_SVA
-	select MMU_GATHER_RCU_TABLE_FREE
 	select MMU_GATHER_MERGE_VMAS
 	select HAVE_POSIX_CPU_TIMERS_TASK_WORK
 	select HAVE_REGS_AND_STACK_ACCESS_API
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 33c4caee30e2..f2f9cd9cde50 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -55,7 +55,6 @@ config XTENSA
 	select HAVE_VIRT_CPU_ACCOUNTING_GEN
 	select IRQ_DOMAIN
 	select LOCK_MM_AND_FIND_VMA
-	select MMU_GATHER_RCU_TABLE_FREE if MMU
 	select MODULES_USE_ELF_RELA
 	select PERF_USE_VMALLOC
 	select TRACE_IRQFLAGS_SUPPORT
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index bdcc2778ac64..044dabc1fe9c 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -67,11 +67,8 @@
  *  - tlb_remove_table()
  *
  *    tlb_remove_table() is the basic primitive to free page-table directories
- *    (__p*_free_tlb()).  In it's most primitive form it is an alias for
- *    tlb_remove_page() below, for when page directories are pages and have no
- *    additional constraints.
- *
- *    See also MMU_GATHER_TABLE_FREE and MMU_GATHER_RCU_TABLE_FREE.
+ *    (__p*_free_tlb()).  Page directories are freed after an RCU grace
+ *    period - see the comment in mm/mmu_gather.c.
  *
  *  - tlb_remove_page() / tlb_remove_page_size()
  *  - __tlb_remove_folio_pages() / __tlb_remove_page_size()
@@ -151,24 +148,15 @@
  *  This might be useful if your architecture has size specific TLB
  *  invalidation instructions.
  *
- *  MMU_GATHER_TABLE_FREE
- *
- *  This provides tlb_remove_table(), to be used instead of tlb_remove_page()
- *  for page directores (__p*_free_tlb()).
- *
- *  Useful if your architecture has non-page page directories.
+ *  Page directories (__p*_free_tlb()) are always freed via tlb_remove_table(),
+ *  after an RCU grace period (see mm/mmu_gather.c).
  *
- *  When used, an architecture is expected to provide __tlb_remove_table() or
- *  use the generic __tlb_remove_table(), which does the actual freeing of these
- *  pages.
+ * This serialises against software page-table walkers, including architectures
+ * which do not use IPIs for remote TLB invalidates.
  *
- *  MMU_GATHER_RCU_TABLE_FREE
- *
- *  Like MMU_GATHER_TABLE_FREE, and adds semi-RCU semantics to the free (see
- *  comment below).
- *
- *  Useful if your architecture doesn't use IPIs for remote TLB invalidates
- *  and therefore doesn't naturally serialize with software page-table walkers.
+ *  An architecture is expected to provide __tlb_remove_table() (see
+ *  HAVE_ARCH_TLB_REMOVE_TABLE) or use the generic __tlb_remove_table(), which
+ *  does the actual freeing of these pages.
  *
  *  MMU_GATHER_NO_FLUSH_CACHE
  *
@@ -200,12 +188,8 @@
  *  various ptep_get_and_clear() functions.
  */
 
-#ifdef CONFIG_MMU_GATHER_TABLE_FREE
-
 struct mmu_table_batch {
-#ifdef CONFIG_MMU_GATHER_RCU_TABLE_FREE
 	struct rcu_head		rcu;
-#endif
 	unsigned int		nr;
 	void			*tables[];
 };
@@ -224,23 +208,6 @@ static inline void __tlb_remove_table(void *table)
 
 extern void tlb_remove_table(struct mmu_gather *tlb, void *table);
 
-#else /* !CONFIG_MMU_GATHER_TABLE_FREE */
-
-static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page);
-/*
- * Without MMU_GATHER_TABLE_FREE the architecture is assumed to have page based
- * page directories and we can use the normal page batching to free them.
- */
-static inline void tlb_remove_table(struct mmu_gather *tlb, void *table)
-{
-	struct ptdesc *ptdesc = (struct ptdesc *)table;
-
-	pagetable_dtor(ptdesc);
-	tlb_remove_page(tlb, ptdesc_page(ptdesc));
-}
-#endif /* CONFIG_MMU_GATHER_TABLE_FREE */
-
-#ifdef CONFIG_MMU_GATHER_RCU_TABLE_FREE
 /*
  * This allows an architecture that does not use the linux page-tables for
  * hardware to skip the TLBI when freeing page tables.
@@ -253,19 +220,6 @@ void tlb_remove_table_sync_one(void);
 
 void tlb_remove_table_sync_rcu(void);
 
-#else
-
-#ifdef tlb_needs_table_invalidate
-#error tlb_needs_table_invalidate() requires MMU_GATHER_RCU_TABLE_FREE
-#endif
-
-static inline void tlb_remove_table_sync_one(void) { }
-
-static inline void tlb_remove_table_sync_rcu(void) { }
-
-#endif /* CONFIG_MMU_GATHER_RCU_TABLE_FREE */
-
-
 #ifndef CONFIG_MMU_GATHER_NO_GATHER
 /*
  * If we can't allocate a page to make a big batch of page pointers
@@ -325,9 +279,7 @@ static inline void tlb_flush_rmaps(struct mmu_gather *tlb, struct vm_area_struct
 struct mmu_gather {
 	struct mm_struct	*mm;
 
-#ifdef CONFIG_MMU_GATHER_TABLE_FREE
 	struct mmu_table_batch	*batch;
-#endif
 
 	unsigned long		start;
 	unsigned long		end;
diff --git a/mm/Kconfig b/mm/Kconfig
index c1ddf59c0d71..bc7befafb47b 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -1465,7 +1465,7 @@ config HAVE_ARCH_TLB_REMOVE_TABLE
 
 config PT_RECLAIM
 	def_bool y
-	depends on MMU_GATHER_RCU_TABLE_FREE && !HAVE_ARCH_TLB_REMOVE_TABLE
+	depends on MMU && !HAVE_ARCH_TLB_REMOVE_TABLE
 	help
 	  Try to reclaim empty user page table pages in paths other than munmap
 	  and exit_mmap path.
diff --git a/mm/gup.c b/mm/gup.c
index eb898ea1ee22..63b435ec605c 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -2700,8 +2700,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
  * Before activating this code, please be aware that the following assumptions
  * are currently made:
  *
- *  *) Either MMU_GATHER_RCU_TABLE_FREE is enabled, and tlb_remove_table() is used to
- *  free pages containing page tables or TLB flushing requires IPI broadcast.
+ *  *) tlb_remove_table() is used to free pages containing page tables, with
+ *  the free deferred until an RCU grace period has elapsed (see
+ *  mm/mmu_gather.c).
  *
  *  *) ptes can be read atomically by the architecture.
  *
diff --git a/mm/mmu_gather.c b/mm/mmu_gather.c
index 3985d856de7f..2a72a9686773 100644
--- a/mm/mmu_gather.c
+++ b/mm/mmu_gather.c
@@ -218,8 +218,6 @@ bool __tlb_remove_page_size(struct mmu_gather *tlb, struct page *page, int page_
 
 #endif /* MMU_GATHER_NO_GATHER */
 
-#ifdef CONFIG_MMU_GATHER_TABLE_FREE
-
 static void __tlb_remove_table_free(struct mmu_table_batch *batch)
 {
 	int i;
@@ -230,10 +228,8 @@ static void __tlb_remove_table_free(struct mmu_table_batch *batch)
 	free_page((unsigned long)batch);
 }
 
-#ifdef CONFIG_MMU_GATHER_RCU_TABLE_FREE
-
 /*
- * Semi RCU freeing of the page directories.
+ * RCU freeing of the page directories.
  *
  * This is needed by some architectures to implement software pagetable walkers.
  *
@@ -259,13 +255,13 @@ static void __tlb_remove_table_free(struct mmu_table_batch *batch)
  * means.
  *
  * What we do is batch the freed directory pages (tables) and RCU free them.
- * We use the sched RCU variant, as that guarantees that IRQ/preempt disabling
- * holds off grace periods.
+ * Disabling IRQs or preemption holds off RCU grace periods, so this protects
+ * both rcu_read_lock() and IRQ-disabling walkers.
  *
  * However, in order to batch these pages we need to allocate storage, this
  * allocation is deep inside the MM code and can thus easily fail on memory
- * pressure. To guarantee progress we fall back to single table freeing, see
- * the implementation of tlb_remove_table_one().
+ * pressure. To guarantee progress we fall back to single table freeing, which
+ * is also RCU-deferred - see the implementation of tlb_remove_table_one().
  *
  */
 
@@ -315,15 +311,6 @@ void tlb_remove_table_sync_rcu(void)
 	synchronize_rcu();
 }
 
-#else /* !CONFIG_MMU_GATHER_RCU_TABLE_FREE */
-
-static void tlb_remove_table_free(struct mmu_table_batch *batch)
-{
-	__tlb_remove_table_free(batch);
-}
-
-#endif /* CONFIG_MMU_GATHER_RCU_TABLE_FREE */
-
 /*
  * If we want tlb_remove_table() to imply TLB invalidates.
  */
@@ -403,13 +390,6 @@ static inline void tlb_table_init(struct mmu_gather *tlb)
 	tlb->batch = NULL;
 }
 
-#else /* !CONFIG_MMU_GATHER_TABLE_FREE */
-
-static inline void tlb_table_flush(struct mmu_gather *tlb) { }
-static inline void tlb_table_init(struct mmu_gather *tlb) { }
-
-#endif /* CONFIG_MMU_GATHER_TABLE_FREE */
-
 static void tlb_flush_mmu_free(struct mmu_gather *tlb)
 {
 	tlb_table_flush(tlb);

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 12/12] mm: change the contract for free_pgtables(), update docs
  2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
                   ` (10 preceding siblings ...)
  2026-09-01 11:01 ` [PATCH 11/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
@ 2026-09-01 11:01 ` Lorenzo Stoakes (ARM)
  2026-09-01 11:37   ` sashiko-bot
  2026-09-01 13:57   ` Kiryl Shutsemau
  11 siblings, 2 replies; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 11:01 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Kiryl Shutsemau, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu
  Cc: linux-mm, linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng, Lorenzo Stoakes (ARM)

Now that page tables are freed after an RCU grace period, it is safe for
page table walkers to walk page table ranges that are being concurrently
torn down, provided the mm is kept alive via mmgrab().

The comment block before pte_offset_map_lock() established a contract that
this was unsafe, which was correct prior to these changes. Update it to
reflect the change.

Similarly update the process addresses documentation.

Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 Documentation/mm/process_addrs.rst |  6 ++++++
 mm/pgtable-generic.c               | 18 +++++++++++++++---
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/Documentation/mm/process_addrs.rst b/Documentation/mm/process_addrs.rst
index a7296f251799..1e65b139f355 100644
--- a/Documentation/mm/process_addrs.rst
+++ b/Documentation/mm/process_addrs.rst
@@ -537,6 +537,12 @@ We establish basic locking rules when interacting with page tables:
 * When changing a page table entry the page table lock for that page table
   **must** be held, except if you can safely assume nobody can access the page
   tables concurrently (such as on invocation of :c:func:`!free_pgtables`).
+* Page tables may be *walked* under RCU alone, as page tables are freed only
+  after an RCU grace period has elapsed. However, any entry found must be
+  revalidated after the page table lock is taken (such as the
+  :c:func:`!pmd_same` recheck performed by :c:func:`!pte_offset_map_lock`)
+  before it is acted upon. Changing an entry always requires the page table
+  lock.
 * Reads from and writes to page table entries must be *appropriately*
   atomic. See the section on atomicity below for details.
 * Populating previously empty entries requires that the mmap or VMA locks are
diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
index b91b1a98029c..ff8ff3706485 100644
--- a/mm/pgtable-generic.c
+++ b/mm/pgtable-generic.c
@@ -386,9 +386,21 @@ pte_t *pte_offset_map_rw_nolock(struct mm_struct *mm, pmd_t *pmd,
  * be read-only/read-write protected.
  *
  * Note that free_pgtables(), used after unmapping detached vmas, or when
- * exiting the whole mm, does not take page table lock before freeing a page
- * table, and may not use RCU at all: "outsiders" like khugepaged should avoid
- * pte_offset_map() and co once the vma is detached from mm or mm_users is zero.
+ * exiting the whole mm, does not take the page table lock before freeing a
+ * table.
+ *
+ * However, the PMD entry is cleared first, and the table freed only after
+ * an RCU grace period, so a walker that mapped the table under
+ * rcu_read_lock() stays safe, and the pmd_same() recheck in
+ * pte_offset_map_lock() detects the teardown.
+ *
+ * Therefore it is safe for "outsiders" like khugepaged to use
+ * pte_offset_map() and co. for VMAs that might be undergoing page table
+ * teardown.
+ *
+ * Note that the PGD itself is freed at mmdrop() time, not under RCU - so the
+ * walker must keep the mm alive via mmgrab(). With that held, walking remains
+ * safe even once mm_users has reached zero.
  */
 pte_t *pte_offset_map_lock(struct mm_struct *mm, pmd_t *pmd,
 			   unsigned long addr, spinlock_t **ptlp)

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH 03/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU riscv
  2026-09-01 11:01 ` [PATCH 03/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU riscv Lorenzo Stoakes (ARM)
@ 2026-09-01 11:14   ` sashiko-bot
  0 siblings, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:14 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Alexander Gordeev, linux-s390, Christian Borntraeger,
	Vasily Gorbik, Heiko Carstens

> Currently riscv gates MMU_GATHER_RCU_TABLE_FREE on CONFIG_SMP and
> CONFIG_MMU.
> 
> Commit 69be3fb111e7 ("riscv: enable MMU_GATHER_RCU_TABLE_FREE for SMP &&
> MMU") enabled CONFIG_MMU_GATHER_RCU_TABLE_FREE for CONFIG_SMP, CONFIG_MMU
> riscv builds.
> 
> This is expressly for the safety of GUP-fast walkers (CONFIG_HAVE_GUP_FAST
> is enabled if CONFIG_MMU is enabled).
> 
> Naturally a single core system does not encounter issues with software page
> table walkers being correctly synchronised across cores, as there is only a
> single core.
> 
> However, CONFIG_PREEMPT_RCU is still available on a riscv UP system, so for
> a future RCU-only page table walker, this guarantee is required to prevent
> concurrent page table teardown.
> 
> All page table freeing is already done via tlb_remove_ptdesc() so the
> conditions of CONFIG_MMU_GATHER_RCU_TABLE_FREE are already met.
> 
> This forms part of an overall effort to switch every architecture to this
> mode.
> 
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=3


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 04/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU arm
  2026-09-01 11:01 ` [PATCH 04/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU arm Lorenzo Stoakes (ARM)
@ 2026-09-01 11:18   ` sashiko-bot
  0 siblings, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:18 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Vasily Gorbik, linux-s390, Alexander Gordeev,
	Christian Borntraeger, Heiko Carstens

> Commit a0ad5496b2b3 ("arm: mm: enable HAVE_RCU_TABLE_FREE logic") enabled
> CONFIG_MMU_GATHER_RCU_TABLE_FREE (then named HAVE_RCU_TABLE_FREE) for SMP
> arm architectures with LPAE enabled.
> 
> Regardless of whether CONFIG_ARM_LPAE is enabled or not, the same page
> table freeing functions __pte_free_tlb() and __pmd_free_tlb() are used.
> 
> Non-LPAE PMD page tables are folded into the PGD and freed by
> pgd_free() (PGD freeing is not part of mmu_gather page table freeing in any
> case), so this is a noop in this case.
> 
> Since commit 358d1c39c82a ("arm: convert various functions to use ptdescs")
> both LPAE and non-LPAE PTE page table freeing uses tlb_remove_ptdesc().
> 
> Thus all page table freeing is performed under RCU with
> CONFIG_MMU_GATHER_RCU_TABLE_FREE enabled for LPAE and non-LPAE and thus it
> need not be gated on LPAE.
> 
> A UP arm system can set CONFIG_PREEMPT_RCU, so a future pure RCU page
> table walker requires MMU_GATHER_RCU_TABLE_FREE to be enabled on UP as
> well, even if concurrent GUP fast is not possible there.
> 
> Therefore, it is both safe and desirable to set
> CONFIG_MMU_GATHER_RCU_TABLE_FREE for all MMU arm architectures (nommu does
> not perform mmu_gather operations).
> 
> This forms part of an overall effort to switch every architecture to this
> mode.
> 
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=4


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 11:01 ` [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period Lorenzo Stoakes (ARM)
@ 2026-09-01 11:18   ` sashiko-bot
  2026-09-01 13:19   ` Kiryl Shutsemau
  1 sibling, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:18 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: linux-s390, Alexander Gordeev, Vasily Gorbik,
	Christian Borntraeger, Heiko Carstens

> When an anonymous mapping is collapsed for THP, a PTE page table is
> 'deposited' with the installed PMD entry.
> 
> This is done in order that a split can be performed without needing to
> allocate additional memory.
> 
> The freeing occurs in zap_deposited_table() and is done directly without
> any delay via pte_free().
> 
> This is currently not a problem as existing page table walks are protected
> by the mmap or anon rmap lock.
> 
> However this becomes problematic in a future where RCU-only page table
> walkers exist, as there is nothing to prevent a page table walker that
> started the walk prior to collapse having its PTE table freed underneath
> [ ... ]
> __collapse_huge_page_isolate() determines whether it is safe to proceed by
> checking folio_ref_count() against folio_expected_ref_count(), so the two
> must be mutually excluded.
> 
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=1


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 02/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for most 2-level architectures
  2026-09-01 11:01 ` [PATCH 02/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for most 2-level architectures Lorenzo Stoakes (ARM)
@ 2026-09-01 11:22   ` sashiko-bot
  0 siblings, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:22 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Heiko Carstens, Christian Borntraeger, Alexander Gordeev,
	Vasily Gorbik, linux-s390

> Commit e3ecf7c7d082 ("mm: pgtable: convert some architectures to use
> tlb_remove_ptdesc()") updated a number of architectures from using
> pagetable_dtor() + tlb_remove_page_ptdesc() to using tlb_remove_ptdesc() in
> __pte_free_tlb().
> 
> This is meaningful as tlb_remove_ptdesc() allows for RCU page table
> freeing if CONFIG_MMU_GATHER_RCU_TABLE_FREE is specified.
> 
> The csky, hexagon, nios2, openrisc, sh (except X2) and m68k-sun3
> architectures all have 2 levels of page tables, so the only page tables
> ever freed by mmu_gather are PTEs, so this update suffices to ensure that
> every page table freed by the mmu_gather mechanism is freed under RCU.
> 
> Therefore, update all of these architectures to select
> CONFIG_MMU_GATHER_RCU_TABLE_FREE.
> 
> This forms part of an overall effort to switch every architecture to this
> mode.
> 
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=2


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 07/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-coldfire
  2026-09-01 11:01 ` [PATCH 07/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-coldfire Lorenzo Stoakes (ARM)
@ 2026-09-01 11:23   ` sashiko-bot
  0 siblings, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:23 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Heiko Carstens, linux-s390, Christian Borntraeger,
	Alexander Gordeev, Vasily Gorbik

> Similar to sun3, the coldfire variant of m68k uses 2-level page tables.
> 
> Update its __pte_free_tlb() function to use tlb_remove_ptdesc() in order
> that, with CONFIG_MMU_GATHER_RCU_TABLE_FREE, page tables are freed under
> RCU.
> 
> The page tables occupy a page each and have no odd semantics, so this
> change suffices to allow enabling of CONFIG_MMU_GATHER_RCU_TABLE_FREE for
> m68k-coldfire, so do so.
> 
> This forms part of an overall effort to switch every architecture to this
> mode.
> 
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=7


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 06/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc64
  2026-09-01 11:01 ` [PATCH 06/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc64 Lorenzo Stoakes (ARM)
@ 2026-09-01 11:23   ` sashiko-bot
  0 siblings, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:23 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Christian Borntraeger, Vasily Gorbik, linux-s390, Heiko Carstens,
	Alexander Gordeev

> Commit 4a0100f7546f ("sparc64: use RCU page table freeing") enabled
> CONFIG_MMU_GATHER_RCU_TABLE_FREE for SMP sparc64 architectures, expressly
> for GUP-fast page table walkers.
> 
> Naturally, UP systems do not have to worry about concurrent GUP fast
> operations.
> 
> However, CONFIG_PREEMPT_RCU is also available even on a UP system, so a
> future pure-RCU page table walker requires MMU_GATHER_RCU_TABLE_FREE to be
> enabled on UP, even if concurrent GUP fast is not possible there.
> 
> To enable future pure-RCU page table walkers, enable
> MMU_GATHER_RCU_TABLE_FREE unconditionally.
> 
> With this change, it is no longer necessary to have !CONFIG_SMP
> pgtable_free_tlb(), so also remove this now dead code.
> 
> This forms part of an overall effort to switch every architecture to this
> mode.
> 
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=6


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 05/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for arc, microblaze, xtensa
  2026-09-01 11:01 ` [PATCH 05/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for arc, microblaze, xtensa Lorenzo Stoakes (ARM)
@ 2026-09-01 11:28   ` sashiko-bot
  0 siblings, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:28 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: linux-s390, Alexander Gordeev, Vasily Gorbik, Heiko Carstens,
	Christian Borntraeger

> Each of these architectures directly free page tables without routing these
> changes through tlb_remove_ptdesc().
> 
> The use of tlb_remove_ptdesc() is required for
> CONFIG_MMU_GATHER_RCU_TABLE_FREE to correctly free page tables under RCU,
> so simply update these architectures to use these functions.
> 
> Since none of the architectures share page tables or do anything unusual,
> nothing complicated is required here.
> 
> Therefore this is simply a mechanical change - convert __pud_free_tlb(),
> __pmd_free_tlb() and __pte_free_tlb() to use tlb_remove_ptdesc() as
> required.
> 
> At the point this is in place, all mmu_gather page table freeing is
> performed under RCU, and thus MMU_GATHER_RCU_TABLE_FREE is selected for
> each architecture.
> 
> This forms part of an overall effort to switch every architecture to this
> mode.
> 
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=5


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 08/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sh-X2
  2026-09-01 11:01 ` [PATCH 08/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sh-X2 Lorenzo Stoakes (ARM)
@ 2026-09-01 11:30   ` sashiko-bot
  0 siblings, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:30 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Christian Borntraeger, Heiko Carstens, linux-s390, Vasily Gorbik,
	Alexander Gordeev

> Currently, non-x2 sh specifies CONFIG_MMU_GATHER_RCU_TABLE_FREE allowing
> RCU page table freeing.
> 
> sh-X2 is problematic because it utilises slab-allocated PMD page tables,
> and thus tlb_remove_ptdesc() cannot be used in these cases.
> 
> All other sh variants are fine as commit e3ecf7c7d082 ("mm: pgtable:
> convert some architectures to use tlb_remove_ptdesc()") already converted
> page table freeing to use tlb_remove_ptdesc(), which does so after an RCU
> grace period when CONFIG_MMU_GATHER_RCU_TABLE_FREE is specified.
> 
> Resolve this issue by firstly specifying CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE
> for sh-X2, so the arch can provide its own __tlb_remove_table()
> implementation (called after the RCU grace period).
> 
> [ ... ]
> 
> This forms part of an overall effort to switch every architecture to this
> mode.
> 
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=8


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 09/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-motorola
  2026-09-01 11:01 ` [PATCH 09/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-motorola Lorenzo Stoakes (ARM)
@ 2026-09-01 11:30   ` sashiko-bot
  0 siblings, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:30 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Heiko Carstens, linux-s390, Vasily Gorbik, Christian Borntraeger,
	Alexander Gordeev

> sun3 and coldfire are already supported, however motorola requires a little
> more care.
> 
> Here, custom table removal logic is required, so
> CONFIG_HAVE_ARCH_TLB_REMOVE_TABLE is enabled for m68k-motorola.
> 
> Firstly as part of this change, the page table level must be communicated
> to the underlying __tlb_remove_table() implementation.
> 
> Take advantage of the fact that page tables are aligned by more than enough
> to permit setting TABLE_PTE or TABLE_PMD in the low bits of the pointer,
> and store this there.
> 
> Then update __pte_free_tlb() and __pmd_free_tlb() to pass this through,
> then have __tlb_remove_table() decode this and pass it to
> [ ... ]
> 
> This forms part of an overall effort to switch every architecture to this
> mode.
> 
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=9


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 12/12] mm: change the contract for free_pgtables(), update docs
  2026-09-01 11:01 ` [PATCH 12/12] mm: change the contract for free_pgtables(), update docs Lorenzo Stoakes (ARM)
@ 2026-09-01 11:37   ` sashiko-bot
  2026-09-01 13:57   ` Kiryl Shutsemau
  1 sibling, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:37 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Christian Borntraeger, Alexander Gordeev, Vasily Gorbik,
	linux-s390, Heiko Carstens

> Now that page tables are freed after an RCU grace period, it is safe for
> page table walkers to walk page table ranges that are being concurrently
> torn down, provided the mm is kept alive via mmgrab().
> 
> The comment block before pte_offset_map_lock() established a contract that
> this was unsafe, which was correct prior to these changes. Update it to
> reflect the change.
> 
> Similarly update the process addresses documentation.
> 
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=12


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 10/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc32
  2026-09-01 11:01 ` [PATCH 10/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc32 Lorenzo Stoakes (ARM)
@ 2026-09-01 11:37   ` sashiko-bot
  0 siblings, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:37 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Heiko Carstens, linux-s390, Vasily Gorbik, Christian Borntraeger,
	Alexander Gordeev

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Concurrent execution of pagetable_pte_ctor() and pagetable_dtor() on shared backing pages corrupts folio state.
--

commit f7114a4ac52b3be28e86c3e8ab381854e55bfcf6
Author: Lorenzo Stoakes (ARM) <ljs@kernel.org>

mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc32
    
This commit enables MMU_GATHER_RCU_TABLE_FREE for sparc32 by using an RCU
callback to free page tables. It introduces __tlb_remove_table() and modifies
__pte_free() to handle NULL mm pointers when called from softirq context.

> But more importantly - the reference count increment in pte_alloc_one() and
> decrement in __pte_free() are atomic with full ordering, so it simply isn't
> possible for there to be a meaningful race here.

[Severity: High]
Does this actually prevent concurrent execution of the page table constructor
and destructor?

The atomic refcount ensures the reference count itself is safe, but it does
not serialize the execution of the constructor and destructor bodies.

If a process unmaps memory and queues PTE pages for RCU free, a softirq could
begin executing __pte_free() and drop the page refcount to 1, entering
pagetable_dtor().

If a process concurrently page faults and allocates a new PTE table in the same
4KB physical page, it increments the refcount to 2 and enters
pagetable_pte_ctor(). 

Could both threads execute the constructor and destructor concurrently,
corrupting the folio state?

> diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
> index 9a74902ad1814..2a2c7bd210114 100644
> --- a/arch/sparc/mm/srmmu.c
> +++ b/arch/sparc/mm/srmmu.c
[ ... ]
> @@ -359,19 +359,39 @@ pgtable_t pte_alloc_one(struct mm_struct *mm)
>  	return ptep;
>  }
>  
> -void pte_free(struct mm_struct *mm, pgtable_t ptep)
> +static void __pte_free(struct mm_struct *mm, pgtable_t ptep)
>  {
> +	const bool process_context = mm;
>  	struct page *page;
>  
>  	page = pfn_to_page(__nocache_pa((unsigned long)ptep) >> PAGE_SHIFT);
> -	spin_lock(&mm->page_table_lock);
> +	if (process_context)
> +		spin_lock(&mm->page_table_lock);
>  	if (page_ref_dec_return(page) == 1)
>  		pagetable_dtor(page_ptdesc(page));
        ^^^^

[Severity: High]
Can this page table destructor run concurrently with the page table
constructor in pte_alloc_one()?

Since process_context is false when called from softirq context via RCU, this
executes without a lock protecting the physical page.

If pte_alloc_one() concurrently allocates another PTE table in the same
backing page, increments the refcount to 2, and calls
pagetable_pte_ctor(mm, page_ptdesc(page)), could this lead to non-atomic
modifications to folio->page.page_type?

Concurrent execution of __folio_clear_pgtable() in the destructor and
initialization in the constructor could corrupt the page state, which may
lead to kernel crashes when pages are returned to the buddy allocator.

> -	spin_unlock(&mm->page_table_lock);
> +	if (process_context)
> +		spin_unlock(&mm->page_table_lock);
>  
>  	srmmu_free_nocache(ptep, SRMMU_PTE_TABLE_SIZE);
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=10

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 11/12] mm: make userland page table freeing RCU-safe
  2026-09-01 11:01 ` [PATCH 11/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
@ 2026-09-01 11:52   ` sashiko-bot
  2026-09-01 13:33   ` Kiryl Shutsemau
  1 sibling, 0 replies; 43+ messages in thread
From: sashiko-bot @ 2026-09-01 11:52 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Christian Borntraeger, Alexander Gordeev, Heiko Carstens,
	linux-s390, Vasily Gorbik

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [Critical] try_collapse_pte_mapped_thp accesses page tables under mmap_read_lock without excluding per-VMA locks, allowing concurrent MADV_DONTNEED to clear PMDs, leading to a UAF/Panic.
- [High] Page walk callbacks return ACTION_AGAIN infinitely when encountering migration entries.
--

commit 2921a41442d23274b78e2a0ab1dcfe01ec2fff5f
Author: Lorenzo Stoakes (ARM) <ljs@kernel.org>
mm: make userland page table freeing RCU-safe

This commit removes the configuration option for RCU table freeing, as all
architectures now support it, and cleans up dead code. It establishes a
kernel policy that all page tables are freed after an RCU grace period,
ensuring safe unconditional page table walks under RCU.

> With this change in place the kernel policy is now that all page tables are
> freed after an RCU grace period, and thus it is now safe to unconditionally
> perform page table walks under RCU, safe in the knowledge that page tables
> will not be freed underneath the walker.
> 
> This is all that is guaranteed, however, so naturally it is still incumbent
> upon page table walkers to ensure that the page table entries are as
> expected.

[Severity: High]
This is a pre-existing issue, but will these page walk callbacks spin
forever if they encounter a migration entry?

For example, in fs/proc/task_mmu.c:clear_refs_pte_range():

	pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
	if (!pte) {
		walk->action = ACTION_AGAIN;
		return 0;
	}

Since pte_offset_map_lock() returns NULL non-transiently for migration
entries, walk_pmd_range() handles ACTION_AGAIN by looping back to again:
immediately without a scheduling point. Could an unprivileged user
triggering THP migration concurrently with a /proc/pid/clear_refs read
cause a CPU soft lockup here?

The same pattern appears to exist in smaps_pte_range() in the same file,
and queue_folios_pte_range() in mm/mempolicy.c.

[Severity: Critical]
This is a pre-existing issue, but does try_collapse_pte_mapped_thp() in
mm/khugepaged.c properly exclude per-VMA locks to prevent concurrent
MADV_DONTNEED from clearing PMDs?

When checking the page tables under mmap_read_lock(), the pmd_same() check
is nested inside the if (ptl != pml) block:

mm/khugepaged.c:try_collapse_pte_mapped_thp() {
	...
	/* step 4: remove empty page table */
	if (!pml) {
		pml = pmd_lock(mm, pmd);
		if (ptl != pml) {
			spin_lock_nested(ptl, SINGLE_DEPTH_NESTING);
			if (unlikely(!pmd_same(pgt_pmd, pmdp_get_lockless(pmd)))) {
				flush_tlb_mm(mm);
				goto unlock;
			}
		}
	}
	...
}

If the system has ptl == pml, this bypasses the pmd_same() check entirely.
A concurrent MADV_DONTNEED running under the VMA lock could trigger
PT_RECLAIM and clear the PMD, freeing the PTE page.

Later in the same function:

mm/khugepaged.c:try_collapse_pte_mapped_thp() {
	...
	pgt_pmd = pmdp_collapse_flush(vma, haddr, pmd);
	pmdp_get_lockless_sync();
	pte_unmap_unlock(start_pte, ptl);
	if (ptl != pml)
		spin_unlock(pml);

	mmu_notifier_invalidate_range_end(&range);

	mm_dec_nr_ptes(mm);
	page_table_check_pte_clear_range(mm, haddr, pgt_pmd);
	pte_free_defer(mm, pmd_pgtable(pgt_pmd));
	...
}

Does this result in pmdp_collapse_flush() being called on a cleared PMD,
passing a garbage PFN to pte_free_defer() and potentially causing a kernel
panic?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-rcu-pagetable-freeing-v1-0-5456a81c8212@kernel.org?part=11

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 11:01 ` [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period Lorenzo Stoakes (ARM)
  2026-09-01 11:18   ` sashiko-bot
@ 2026-09-01 13:19   ` Kiryl Shutsemau
  2026-09-01 14:12     ` Lorenzo Stoakes (ARM)
  1 sibling, 1 reply; 43+ messages in thread
From: Kiryl Shutsemau @ 2026-09-01 13:19 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Guo Ren, Brian Cain, Geert Uytterhoeven,
	Dinh Nguyen, Simon Schuster, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu, linux-mm,
	linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 12:01:21PM +0100, Lorenzo Stoakes (ARM) wrote:
> When an anonymous mapping is collapsed for THP, a PTE page table is
> 'deposited' with the installed PMD entry.
> 
> This is done in order that a split can be performed without needing to
> allocate additional memory.
> 
> The freeing occurs in zap_deposited_table() and is done directly without
> any delay via pte_free().
> 
> This is currently not a problem as existing page table walks are protected
> by the mmap or anon rmap lock.
> 
> However this becomes problematic in a future where RCU-only page table
> walkers exist, as there is nothing to prevent a page table walker that
> started the walk prior to collapse having its PTE table freed underneath
> it.
> 
> Commit 13cf577e6b66 ("mm/pgtable: add pte_free_defer() for pgtable as
> page") already provides us the mechanism by which to solve this -
> pte_free_defer().
> 
> Therefore, as a prerequisite to a future commit which will permit fully RCU
> page table walks, update zap_deposited_table() to use pte_free_defer()
> rather than pte_free().
> 
> Note that the IPI sync in collapse_huge_page() is still required to ensure
> refcount correctness against a GUP-fast operation.
> 
> This is because GUP-fast might increment refcount, but
> __collapse_huge_page_isolate() determines whether it is safe to proceed by
> checking folio_ref_count() against folio_expected_ref_count(), so the two
> must be mutually excluded.
> 
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> ---
>  mm/huge_memory.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 54494c3fa983..505f7b62ff28 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -2476,7 +2476,7 @@ static inline void zap_deposited_table(struct mm_struct *mm, pmd_t *pmd)
>  	pgtable_t pgtable;
>  
>  	pgtable = pgtable_trans_huge_withdraw(mm, pmd);
> -	pte_free(mm, pgtable);
> +	pte_free_defer(mm, pgtable);

Hm. So it is call_rcu() on each PMD. It might be costly, especially for
zap_huge_pmd() path: 512 call_rcu() per-GB of unmapped THPs.

Do we want leverage mmu_gather if caller has it?

>  	mm_dec_nr_ptes(mm);
>  }
>  
> 
> -- 
> 2.55.0
> 

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 11/12] mm: make userland page table freeing RCU-safe
  2026-09-01 11:01 ` [PATCH 11/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
  2026-09-01 11:52   ` sashiko-bot
@ 2026-09-01 13:33   ` Kiryl Shutsemau
  2026-09-01 14:03     ` Lorenzo Stoakes (ARM)
  1 sibling, 1 reply; 43+ messages in thread
From: Kiryl Shutsemau @ 2026-09-01 13:33 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Guo Ren, Brian Cain, Geert Uytterhoeven,
	Dinh Nguyen, Simon Schuster, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu, linux-mm,
	linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 12:01:31PM +0100, Lorenzo Stoakes (ARM) wrote:
> With this change in place the kernel policy is now that all page tables are

s/all/userspace/ as subject implies?

BTW, what is your take on kernel page tables? Do we want the same policy
there. pagetable_free_kernel() is not RCU-safe as it is.

> freed after an RCU grace period, and thus it is now safe to unconditionally
> perform page table walks under RCU, safe in the knowledge that page tables
> will not be freed underneath the walker.

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 12/12] mm: change the contract for free_pgtables(), update docs
  2026-09-01 11:01 ` [PATCH 12/12] mm: change the contract for free_pgtables(), update docs Lorenzo Stoakes (ARM)
  2026-09-01 11:37   ` sashiko-bot
@ 2026-09-01 13:57   ` Kiryl Shutsemau
  2026-09-01 14:31     ` Lorenzo Stoakes (ARM)
  1 sibling, 1 reply; 43+ messages in thread
From: Kiryl Shutsemau @ 2026-09-01 13:57 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Guo Ren, Brian Cain, Geert Uytterhoeven,
	Dinh Nguyen, Simon Schuster, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu, linux-mm,
	linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 12:01:32PM +0100, Lorenzo Stoakes (ARM) wrote:
> diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
> index b91b1a98029c..ff8ff3706485 100644
> --- a/mm/pgtable-generic.c
> +++ b/mm/pgtable-generic.c
> @@ -386,9 +386,21 @@ pte_t *pte_offset_map_rw_nolock(struct mm_struct *mm, pmd_t *pmd,
>   * be read-only/read-write protected.
>   *
>   * Note that free_pgtables(), used after unmapping detached vmas, or when
> - * exiting the whole mm, does not take page table lock before freeing a page
> - * table, and may not use RCU at all: "outsiders" like khugepaged should avoid
> - * pte_offset_map() and co once the vma is detached from mm or mm_users is zero.
> + * exiting the whole mm, does not take the page table lock before freeing a
> + * table.
> + *
> + * However, the PMD entry is cleared first, and the table freed only after
> + * an RCU grace period, so a walker that mapped the table under
> + * rcu_read_lock() stays safe, and the pmd_same() recheck in
> + * pte_offset_map_lock() detects the teardown.
> + *
> + * Therefore it is safe for "outsiders" like khugepaged to use
> + * pte_offset_map() and co. for VMAs that might be undergoing page table
> + * teardown.

Is it strictly true?

free_pte_range() clears the pmd without taking the PTL, so the
pmd_same() recheck in pte_offset_map_lock() can pass and the pmd gets
cleared right after.

Readers are fine -- __pte_offset_map() holds rcu_read_lock() until
pte_unmap(), so the table cannot go away.

khugepaged is an odd example here. collapse_pte_mapped_thp() and
retract_page_tables() don't rely on this recheck -- they take pmd_lock()
plus the ptl and do their own pmd_same() under both.

Can we say walks are safe and leave the write rule where it is?

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 11/12] mm: make userland page table freeing RCU-safe
  2026-09-01 13:33   ` Kiryl Shutsemau
@ 2026-09-01 14:03     ` Lorenzo Stoakes (ARM)
  0 siblings, 0 replies; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 14:03 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Guo Ren, Brian Cain, Geert Uytterhoeven,
	Dinh Nguyen, Simon Schuster, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu, linux-mm,
	linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 02:33:14PM +0100, Kiryl Shutsemau wrote:
> On Tue, Sep 01, 2026 at 12:01:31PM +0100, Lorenzo Stoakes (ARM) wrote:
> > With this change in place the kernel policy is now that all page tables are
>
> s/all/userspace/ as subject implies?

Right yeah :) I hoped that the summary line would clarify that but can edit that
also.

>
> BTW, what is your take on kernel page tables? Do we want the same policy
> there. pagetable_free_kernel() is not RCU-safe as it is.

Yeah I think so too. I may follow up with a series to that effect also!

>
> > freed after an RCU grace period, and thus it is now safe to unconditionally
> > perform page table walks under RCU, safe in the knowledge that page tables
> > will not be freed underneath the walker.
>
> --
>   Kiryl Shutsemau / Kirill A. Shutemov

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 13:19   ` Kiryl Shutsemau
@ 2026-09-01 14:12     ` Lorenzo Stoakes (ARM)
  2026-09-01 14:24       ` Jason Gunthorpe
  0 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 14:12 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Guo Ren, Brian Cain, Geert Uytterhoeven,
	Dinh Nguyen, Simon Schuster, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu, linux-mm,
	linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 02:19:36PM +0100, Kiryl Shutsemau wrote:
> On Tue, Sep 01, 2026 at 12:01:21PM +0100, Lorenzo Stoakes (ARM) wrote:
> > When an anonymous mapping is collapsed for THP, a PTE page table is
> > 'deposited' with the installed PMD entry.
> >
> > This is done in order that a split can be performed without needing to
> > allocate additional memory.
> >
> > The freeing occurs in zap_deposited_table() and is done directly without
> > any delay via pte_free().
> >
> > This is currently not a problem as existing page table walks are protected
> > by the mmap or anon rmap lock.
> >
> > However this becomes problematic in a future where RCU-only page table
> > walkers exist, as there is nothing to prevent a page table walker that
> > started the walk prior to collapse having its PTE table freed underneath
> > it.
> >
> > Commit 13cf577e6b66 ("mm/pgtable: add pte_free_defer() for pgtable as
> > page") already provides us the mechanism by which to solve this -
> > pte_free_defer().
> >
> > Therefore, as a prerequisite to a future commit which will permit fully RCU
> > page table walks, update zap_deposited_table() to use pte_free_defer()
> > rather than pte_free().
> >
> > Note that the IPI sync in collapse_huge_page() is still required to ensure
> > refcount correctness against a GUP-fast operation.
> >
> > This is because GUP-fast might increment refcount, but
> > __collapse_huge_page_isolate() determines whether it is safe to proceed by
> > checking folio_ref_count() against folio_expected_ref_count(), so the two
> > must be mutually excluded.
> >
> > Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> > ---
> >  mm/huge_memory.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> > index 54494c3fa983..505f7b62ff28 100644
> > --- a/mm/huge_memory.c
> > +++ b/mm/huge_memory.c
> > @@ -2476,7 +2476,7 @@ static inline void zap_deposited_table(struct mm_struct *mm, pmd_t *pmd)
> >  	pgtable_t pgtable;
> >
> >  	pgtable = pgtable_trans_huge_withdraw(mm, pmd);
> > -	pte_free(mm, pgtable);
> > +	pte_free_defer(mm, pgtable);
>
> Hm. So it is call_rcu() on each PMD. It might be costly, especially for
> zap_huge_pmd() path: 512 call_rcu() per-GB of unmapped THPs.
>
> Do we want leverage mmu_gather if caller has it?

I mean, I'm not sure in which respect that'd be costly, 512 is not a big number
to a computer, and repeated call_rcu() invocations should just queue more
operations no?

It won't be costly at the time of the calls obviously as its deferred. Maybe
increase some time spent in softirq but again is 512x that big of a deal?

I'm not sure how you'd both defer the free and somehow utilise mmu_gather here
either really, certainly not without it becoming extremely messy.

But yeah I'd want to see hard data on that before I really believe that's a
problem :)

>
> >  	mm_dec_nr_ptes(mm);
> >  }
> >
> >
> > --
> > 2.55.0
> >
>
> --
>   Kiryl Shutsemau / Kirill A. Shutemov

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 14:12     ` Lorenzo Stoakes (ARM)
@ 2026-09-01 14:24       ` Jason Gunthorpe
  2026-09-01 14:41         ` Lorenzo Stoakes (ARM)
  0 siblings, 1 reply; 43+ messages in thread
From: Jason Gunthorpe @ 2026-09-01 14:24 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Kiryl Shutsemau, Andrew Morton, David Hildenbrand, Zi Yan,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Lance Yang, Usama Arif, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, John Hubbard, Peter Xu, linux-mm, linux-kernel,
	linux-csky, linux-hexagon, linux-m68k, linux-openrisc, linux-sh,
	linux-riscv, linux-arm-kernel, linux-snps-arc, linux-arch,
	sparclinux, linux-alpha, loongarch, linux-mips, linux-parisc,
	linuxppc-dev, linux-s390, linux-um, Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 03:12:45PM +0100, Lorenzo Stoakes (ARM) wrote:

> It won't be costly at the time of the calls obviously as its deferred. Maybe
> increase some time spent in softirq but again is 512x that big of a deal?
> 
> I'm not sure how you'd both defer the free and somehow utilise mmu_gather here
> either really, certainly not without it becoming extremely messy.

The less costly version is to thread the page to be freed onto the
mmu_gather through a linked list in the struct page memory. This is
super cheap since it is just a singly linked list operation.

Then when the mmu_gather is flushed it does a single call_rcu using
the rcu head of the struct page of the head of the list. The callback
clears the entire linked list of pages.

Since you have to tlb flush anyhow, it makes sense to always use the
mmu_gather. For example the design I ended up with for iommupt
accumulates all the invalidations and all the free-able memory into a
gather then invalidates and frees.

This allows maximizing the tlbi efficiency too. You can't do call_srcu
until you flush the tlb and if you call once per table then you are
also tlb flushing once per table too.

So if the kernel really does want to clear out 512 leaf tables the
optimal implementation is one range tlbi for 512 entries followed by
one call_rcu to free the memory. Hence the gather..

Jason

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 12/12] mm: change the contract for free_pgtables(), update docs
  2026-09-01 13:57   ` Kiryl Shutsemau
@ 2026-09-01 14:31     ` Lorenzo Stoakes (ARM)
  2026-09-01 17:15       ` Kiryl Shutsemau
  0 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 14:31 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Guo Ren, Brian Cain, Geert Uytterhoeven,
	Dinh Nguyen, Simon Schuster, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu, linux-mm,
	linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 02:57:13PM +0100, Kiryl Shutsemau wrote:
> On Tue, Sep 01, 2026 at 12:01:32PM +0100, Lorenzo Stoakes (ARM) wrote:
> > diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
> > index b91b1a98029c..ff8ff3706485 100644
> > --- a/mm/pgtable-generic.c
> > +++ b/mm/pgtable-generic.c
> > @@ -386,9 +386,21 @@ pte_t *pte_offset_map_rw_nolock(struct mm_struct *mm, pmd_t *pmd,
> >   * be read-only/read-write protected.
> >   *
> >   * Note that free_pgtables(), used after unmapping detached vmas, or when
> > - * exiting the whole mm, does not take page table lock before freeing a page
> > - * table, and may not use RCU at all: "outsiders" like khugepaged should avoid
> > - * pte_offset_map() and co once the vma is detached from mm or mm_users is zero.
> > + * exiting the whole mm, does not take the page table lock before freeing a
> > + * table.
> > + *
> > + * However, the PMD entry is cleared first, and the table freed only after
> > + * an RCU grace period, so a walker that mapped the table under
> > + * rcu_read_lock() stays safe, and the pmd_same() recheck in
> > + * pte_offset_map_lock() detects the teardown.
> > + *
> > + * Therefore it is safe for "outsiders" like khugepaged to use
> > + * pte_offset_map() and co. for VMAs that might be undergoing page table
> > + * teardown.
>
> Is it strictly true?
>
> free_pte_range() clears the pmd without taking the PTL, so the
> pmd_same() recheck in pte_offset_map_lock() can pass and the pmd gets
> cleared right after.
>
> Readers are fine -- __pte_offset_map() holds rcu_read_lock() until
> pte_unmap(), so the table cannot go away.
>
> khugepaged is an odd example here. collapse_pte_mapped_thp() and
> retract_page_tables() don't rely on this recheck -- they take pmd_lock()
> plus the ptl and do their own pmd_same() under both.
>
> Can we say walks are safe and leave the write rule where it is?

Hmm yeah, ah page tables, what a rabbit hole of horror :)

I guess this is effectively a reflection of the 'write lock on write, RCU load
on read' pattern in RCU itself generally.

So, maybe something like:

 * Note that free_pgtables(), used after unampping detached vmas, or when
 * exiting the whoel mm, does not take a page table lock before freeing a page
 * table.
 *
 * As page table freeing itself is RCU-safe, page table readers can safely run
 * concurrently with page table teardown. However, writers cannot, as without
 * a lock nothing prevents concurrent teardown.
 */

Instead? What do you think?

>
> --
>   Kiryl Shutsemau / Kirill A. Shutemov

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 14:24       ` Jason Gunthorpe
@ 2026-09-01 14:41         ` Lorenzo Stoakes (ARM)
  2026-09-01 15:28           ` Kiryl Shutsemau
  0 siblings, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 14:41 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Kiryl Shutsemau, Andrew Morton, David Hildenbrand, Zi Yan,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Lance Yang, Usama Arif, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, John Hubbard, Peter Xu, linux-mm, linux-kernel,
	linux-csky, linux-hexagon, linux-m68k, linux-openrisc, linux-sh,
	linux-riscv, linux-arm-kernel, linux-snps-arc, linux-arch,
	sparclinux, linux-alpha, loongarch, linux-mips, linux-parisc,
	linuxppc-dev, linux-s390, linux-um, Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 11:24:08AM -0300, Jason Gunthorpe wrote:
> On Tue, Sep 01, 2026 at 03:12:45PM +0100, Lorenzo Stoakes (ARM) wrote:
>
> > It won't be costly at the time of the calls obviously as its deferred. Maybe
> > increase some time spent in softirq but again is 512x that big of a deal?
> >
> > I'm not sure how you'd both defer the free and somehow utilise mmu_gather here
> > either really, certainly not without it becoming extremely messy.
>
> The less costly version is to thread the page to be freed onto the
> mmu_gather through a linked list in the struct page memory. This is
> super cheap since it is just a singly linked list operation.
>
> Then when the mmu_gather is flushed it does a single call_rcu using
> the rcu head of the struct page of the head of the list. The callback
> clears the entire linked list of pages.
>
> Since you have to tlb flush anyhow, it makes sense to always use the
> mmu_gather. For example the design I ended up with for iommupt
> accumulates all the invalidations and all the free-able memory into a
> gather then invalidates and frees.
>
> This allows maximizing the tlbi efficiency too. You can't do call_srcu
> until you flush the tlb and if you call once per table then you are
> also tlb flushing once per table too.
>
> So if the kernel really does want to clear out 512 leaf tables the
> optimal implementation is one range tlbi for 512 entries followed by
> one call_rcu to free the memory. Hence the gather..

I think there's some confusion here.

This isn't the path in which a page table is being freed, the _deposited_
table is zapped, in zap_deposited_table().

That is, the page table kept in reserve for THP split, that is not
currently mapped.

It amounts to a __free_pages() call.

The TLB operations are in e.g. zap_huge_pmd() etc. and nobody has
complained about inefficiencies there.

So, unless I'm missing something here, TLB flushes play no role in this
whatsoever.

The issue Kiryl raised was that instead of immediately freeing page tables,
they are now batched up individually by call_rcu().

I personally find it difficult to imagine the numbers here would be
problematic or certainly cause anything observable beyond what is
observable now.

So I'm going to have to say, unless it can be clearly demonstrated this is
problematic, I don't think there's any reason to add additional complexity
here.

>
> Jason

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 14:41         ` Lorenzo Stoakes (ARM)
@ 2026-09-01 15:28           ` Kiryl Shutsemau
  2026-09-01 15:45             ` Lorenzo Stoakes (ARM)
  2026-09-01 15:54             ` Liam R. Howlett
  0 siblings, 2 replies; 43+ messages in thread
From: Kiryl Shutsemau @ 2026-09-01 15:28 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Jason Gunthorpe, Andrew Morton, David Hildenbrand, Zi Yan,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Lance Yang, Usama Arif, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, John Hubbard, Peter Xu, linux-mm, linux-kernel,
	linux-csky, linux-hexagon, linux-m68k, linux-openrisc, linux-sh,
	linux-riscv, linux-arm-kernel, linux-snps-arc, linux-arch,
	sparclinux, linux-alpha, loongarch, linux-mips, linux-parisc,
	linuxppc-dev, linux-s390, linux-um, Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 03:41:17PM +0100, Lorenzo Stoakes (ARM) wrote:
> On Tue, Sep 01, 2026 at 11:24:08AM -0300, Jason Gunthorpe wrote:
> > On Tue, Sep 01, 2026 at 03:12:45PM +0100, Lorenzo Stoakes (ARM) wrote:
> >
> > > It won't be costly at the time of the calls obviously as its deferred. Maybe
> > > increase some time spent in softirq but again is 512x that big of a deal?
> > >
> > > I'm not sure how you'd both defer the free and somehow utilise mmu_gather here
> > > either really, certainly not without it becoming extremely messy.
> >
> > The less costly version is to thread the page to be freed onto the
> > mmu_gather through a linked list in the struct page memory. This is
> > super cheap since it is just a singly linked list operation.
> >
> > Then when the mmu_gather is flushed it does a single call_rcu using
> > the rcu head of the struct page of the head of the list. The callback
> > clears the entire linked list of pages.
> >
> > Since you have to tlb flush anyhow, it makes sense to always use the
> > mmu_gather. For example the design I ended up with for iommupt
> > accumulates all the invalidations and all the free-able memory into a
> > gather then invalidates and frees.
> >
> > This allows maximizing the tlbi efficiency too. You can't do call_srcu
> > until you flush the tlb and if you call once per table then you are
> > also tlb flushing once per table too.
> >
> > So if the kernel really does want to clear out 512 leaf tables the
> > optimal implementation is one range tlbi for 512 entries followed by
> > one call_rcu to free the memory. Hence the gather..
> 
> I think there's some confusion here.
> 
> This isn't the path in which a page table is being freed, the _deposited_
> table is zapped, in zap_deposited_table().
> 
> That is, the page table kept in reserve for THP split, that is not
> currently mapped.
> 
> It amounts to a __free_pages() call.
> 
> The TLB operations are in e.g. zap_huge_pmd() etc. and nobody has
> complained about inefficiencies there.
> 
> So, unless I'm missing something here, TLB flushes play no role in this
> whatsoever.
> 
> The issue Kiryl raised was that instead of immediately freeing page tables,
> they are now batched up individually by call_rcu().
> 
> I personally find it difficult to imagine the numbers here would be
> problematic or certainly cause anything observable beyond what is
> observable now.
> 
> So I'm going to have to say, unless it can be clearly demonstrated this is
> problematic, I don't think there's any reason to add additional complexity
> here.

It would be nice to measure munmap() overhead here.

I am worried about hitting DEFAULT_MAX_RCU_BLIMIT and trigger
rcu_force_quiescent_state() which can be disruptive to the system.

DEFAULT_MAX_RCU_BLIMIT is 10K, so it is ~20G of THP unmapped on x86.

munmap() of 64G worth of THP should be enough to demonstrate the
problem.

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 15:28           ` Kiryl Shutsemau
@ 2026-09-01 15:45             ` Lorenzo Stoakes (ARM)
  2026-09-01 17:11               ` Kiryl Shutsemau
  2026-09-01 15:54             ` Liam R. Howlett
  1 sibling, 1 reply; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 15:45 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: Jason Gunthorpe, Andrew Morton, David Hildenbrand, Zi Yan,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Lance Yang, Usama Arif, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, John Hubbard, Peter Xu, linux-mm, linux-kernel,
	linux-csky, linux-hexagon, linux-m68k, linux-openrisc, linux-sh,
	linux-riscv, linux-arm-kernel, linux-snps-arc, linux-arch,
	sparclinux, linux-alpha, loongarch, linux-mips, linux-parisc,
	linuxppc-dev, linux-s390, linux-um, Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 04:28:48PM +0100, Kiryl Shutsemau wrote:
> On Tue, Sep 01, 2026 at 03:41:17PM +0100, Lorenzo Stoakes (ARM) wrote:
> > On Tue, Sep 01, 2026 at 11:24:08AM -0300, Jason Gunthorpe wrote:
> > > On Tue, Sep 01, 2026 at 03:12:45PM +0100, Lorenzo Stoakes (ARM) wrote:
> > >
> > > > It won't be costly at the time of the calls obviously as its deferred. Maybe
> > > > increase some time spent in softirq but again is 512x that big of a deal?
> > > >
> > > > I'm not sure how you'd both defer the free and somehow utilise mmu_gather here
> > > > either really, certainly not without it becoming extremely messy.
> > >
> > > The less costly version is to thread the page to be freed onto the
> > > mmu_gather through a linked list in the struct page memory. This is
> > > super cheap since it is just a singly linked list operation.
> > >
> > > Then when the mmu_gather is flushed it does a single call_rcu using
> > > the rcu head of the struct page of the head of the list. The callback
> > > clears the entire linked list of pages.
> > >
> > > Since you have to tlb flush anyhow, it makes sense to always use the
> > > mmu_gather. For example the design I ended up with for iommupt
> > > accumulates all the invalidations and all the free-able memory into a
> > > gather then invalidates and frees.
> > >
> > > This allows maximizing the tlbi efficiency too. You can't do call_srcu
> > > until you flush the tlb and if you call once per table then you are
> > > also tlb flushing once per table too.
> > >
> > > So if the kernel really does want to clear out 512 leaf tables the
> > > optimal implementation is one range tlbi for 512 entries followed by
> > > one call_rcu to free the memory. Hence the gather..
> >
> > I think there's some confusion here.
> >
> > This isn't the path in which a page table is being freed, the _deposited_
> > table is zapped, in zap_deposited_table().
> >
> > That is, the page table kept in reserve for THP split, that is not
> > currently mapped.
> >
> > It amounts to a __free_pages() call.
> >
> > The TLB operations are in e.g. zap_huge_pmd() etc. and nobody has
> > complained about inefficiencies there.
> >
> > So, unless I'm missing something here, TLB flushes play no role in this
> > whatsoever.
> >
> > The issue Kiryl raised was that instead of immediately freeing page tables,
> > they are now batched up individually by call_rcu().
> >
> > I personally find it difficult to imagine the numbers here would be
> > problematic or certainly cause anything observable beyond what is
> > observable now.
> >
> > So I'm going to have to say, unless it can be clearly demonstrated this is
> > problematic, I don't think there's any reason to add additional complexity
> > here.
>
> It would be nice to measure munmap() overhead here.
>
> I am worried about hitting DEFAULT_MAX_RCU_BLIMIT and trigger
> rcu_force_quiescent_state() which can be disruptive to the system.
>
> DEFAULT_MAX_RCU_BLIMIT is 10K, so it is ~20G of THP unmapped on x86.
>
> munmap() of 64G worth of THP should be enough to demonstrate the
> problem.

I mean you're going to hit that from RCU freeing page tables already, which
most architectures already do right?

So if RCU saturation is a problem, that problem already exists, but I've
not heard of that being a problem at all?

So you're going to have to demonstrate why this situation is markedly
different from that. And it's the same scale.

Overall I think freeing 64 GiB of mapped memory all at once will inevitably
be a slow operation, freeing them directly will also be a lengthily process.

And also it seems to me that RCU mishandling heavy load to the point of
causing system instability should a bug filed with RCU no?

Also note pte_free_defer() is already used in retract_page_tables() so a large
collapse could also hit this problem?

I'm not sure I'm convinced there's an issue here.

>
> --
>   Kiryl Shutsemau / Kirill A. Shutemov

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 15:28           ` Kiryl Shutsemau
  2026-09-01 15:45             ` Lorenzo Stoakes (ARM)
@ 2026-09-01 15:54             ` Liam R. Howlett
  2026-09-01 16:06               ` Jason Gunthorpe
  2026-09-01 17:13               ` Kiryl Shutsemau
  1 sibling, 2 replies; 43+ messages in thread
From: Liam R. Howlett @ 2026-09-01 15:54 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: Lorenzo Stoakes (ARM), Jason Gunthorpe, Andrew Morton,
	David Hildenbrand, Zi Yan, Baolin Wang, Nico Pache, Ryan Roberts,
	Dev Jain, Barry Song, Lance Yang, Usama Arif, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, John Hubbard, Peter Xu, linux-mm, linux-kernel,
	linux-csky, linux-hexagon, linux-m68k, linux-openrisc, linux-sh,
	linux-riscv, linux-arm-kernel, linux-snps-arc, linux-arch,
	sparclinux, linux-alpha, loongarch, linux-mips, linux-parisc,
	linuxppc-dev, linux-s390, linux-um, Hugh Dickins, Qi Zheng

On 26/09/01 04:28PM, Kiryl Shutsemau wrote:
> On Tue, Sep 01, 2026 at 03:41:17PM +0100, Lorenzo Stoakes (ARM) wrote:
> > On Tue, Sep 01, 2026 at 11:24:08AM -0300, Jason Gunthorpe wrote:
> > > On Tue, Sep 01, 2026 at 03:12:45PM +0100, Lorenzo Stoakes (ARM) wrote:
> > >
> > > > It won't be costly at the time of the calls obviously as its deferred. Maybe
> > > > increase some time spent in softirq but again is 512x that big of a deal?
> > > >
> > > > I'm not sure how you'd both defer the free and somehow utilise mmu_gather here
> > > > either really, certainly not without it becoming extremely messy.
> > >
> > > The less costly version is to thread the page to be freed onto the
> > > mmu_gather through a linked list in the struct page memory. This is
> > > super cheap since it is just a singly linked list operation.
> > >
> > > Then when the mmu_gather is flushed it does a single call_rcu using
> > > the rcu head of the struct page of the head of the list. The callback
> > > clears the entire linked list of pages.

If you are going through the trouble of doing this on your side with a
custom rcu callback, it might be better to pack the pointers in a way
that does not need to pointer chase through a linked list.

> > >
> > > Since you have to tlb flush anyhow, it makes sense to always use the
> > > mmu_gather. For example the design I ended up with for iommupt
> > > accumulates all the invalidations and all the free-able memory into a
> > > gather then invalidates and frees.
> > >
> > > This allows maximizing the tlbi efficiency too. You can't do call_srcu
> > > until you flush the tlb and if you call once per table then you are
> > > also tlb flushing once per table too.
> > >
> > > So if the kernel really does want to clear out 512 leaf tables the
> > > optimal implementation is one range tlbi for 512 entries followed by
> > > one call_rcu to free the memory. Hence the gather..
> > 
> > I think there's some confusion here.
> > 
> > This isn't the path in which a page table is being freed, the _deposited_
> > table is zapped, in zap_deposited_table().
> > 
> > That is, the page table kept in reserve for THP split, that is not
> > currently mapped.
> > 
> > It amounts to a __free_pages() call.
> > 
> > The TLB operations are in e.g. zap_huge_pmd() etc. and nobody has
> > complained about inefficiencies there.
> > 
> > So, unless I'm missing something here, TLB flushes play no role in this
> > whatsoever.
> > 
> > The issue Kiryl raised was that instead of immediately freeing page tables,
> > they are now batched up individually by call_rcu().
> > 
> > I personally find it difficult to imagine the numbers here would be
> > problematic or certainly cause anything observable beyond what is
> > observable now.
> > 
> > So I'm going to have to say, unless it can be clearly demonstrated this is
> > problematic, I don't think there's any reason to add additional complexity
> > here.
> 
> It would be nice to measure munmap() overhead here.
> 
> I am worried about hitting DEFAULT_MAX_RCU_BLIMIT and trigger
> rcu_force_quiescent_state() which can be disruptive to the system.
> 
> DEFAULT_MAX_RCU_BLIMIT is 10K, so it is ~20G of THP unmapped on x86.
> 
> munmap() of 64G worth of THP should be enough to demonstrate the
> problem.

I'm not sure what that would prove besides checking if your number is
correct?  You'll see a slow down once you hit 10K of objects in the rcu
linked list.  And that will depend on what the system is doing as well,
so there will be a slow down since other things are happening on the
system before 20GB of THP is unleashed towards munmap().

One of these does use 5.12% of the RCU items that need to wait for a
grace period to be released, but testing it would be rather tricky and
the numbers won't really show much..?

Form my understanding and experience with rcu and freeing massive
numbers of objects, you gain more from the lower lock contention than
you lose when you hit 10K objects.

The trade off is in the Android setup, where they have restricted RCU to
a slower core.  Combined with another RCU setting, it was causing slow
down when we overwhelmed the queue multiple times.

So this should actually be faster unless you are doing 20GB of THP
unmapping on Android or a device configured the same way.  Considering
the cost of RAM, we should be okay for a few phone iterations.

Do you have munmap() performance dependent workload that you are
concerned about regressing?

Thanks,
Liam




^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 15:54             ` Liam R. Howlett
@ 2026-09-01 16:06               ` Jason Gunthorpe
  2026-09-01 17:13               ` Kiryl Shutsemau
  1 sibling, 0 replies; 43+ messages in thread
From: Jason Gunthorpe @ 2026-09-01 16:06 UTC (permalink / raw)
  To: Liam R. Howlett
  Cc: Kiryl Shutsemau, Lorenzo Stoakes (ARM), Andrew Morton,
	David Hildenbrand, Zi Yan, Baolin Wang, Nico Pache, Ryan Roberts,
	Dev Jain, Barry Song, Lance Yang, Usama Arif, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, John Hubbard, Peter Xu, linux-mm, linux-kernel,
	linux-csky, linux-hexagon, linux-m68k, linux-openrisc, linux-sh,
	linux-riscv, linux-arm-kernel, linux-snps-arc, linux-arch,
	sparclinux, linux-alpha, loongarch, linux-mips, linux-parisc,
	linuxppc-dev, linux-s390, linux-um, Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 11:54:47AM -0400, Liam R. Howlett wrote:
> On 26/09/01 04:28PM, Kiryl Shutsemau wrote:
> > On Tue, Sep 01, 2026 at 03:41:17PM +0100, Lorenzo Stoakes (ARM) wrote:
> > > On Tue, Sep 01, 2026 at 11:24:08AM -0300, Jason Gunthorpe wrote:
> > > > On Tue, Sep 01, 2026 at 03:12:45PM +0100, Lorenzo Stoakes (ARM) wrote:
> > > >
> > > > > It won't be costly at the time of the calls obviously as its deferred. Maybe
> > > > > increase some time spent in softirq but again is 512x that big of a deal?
> > > > >
> > > > > I'm not sure how you'd both defer the free and somehow utilise mmu_gather here
> > > > > either really, certainly not without it becoming extremely messy.
> > > >
> > > > The less costly version is to thread the page to be freed onto the
> > > > mmu_gather through a linked list in the struct page memory. This is
> > > > super cheap since it is just a singly linked list operation.
> > > >
> > > > Then when the mmu_gather is flushed it does a single call_rcu using
> > > > the rcu head of the struct page of the head of the list. The callback
> > > > clears the entire linked list of pages.
> 
> If you are going through the trouble of doing this on your side with a
> custom rcu callback, it might be better to pack the pointers in a way
> that does not need to pointer chase through a linked list.

Well, I have 8 bytes of memory in a struct page and can't allocate in
these paths, so IDK there is another option..

Jason

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 15:45             ` Lorenzo Stoakes (ARM)
@ 2026-09-01 17:11               ` Kiryl Shutsemau
  2026-09-01 17:14                 ` Lorenzo Stoakes (ARM)
  0 siblings, 1 reply; 43+ messages in thread
From: Kiryl Shutsemau @ 2026-09-01 17:11 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Jason Gunthorpe, Andrew Morton, David Hildenbrand, Zi Yan,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Lance Yang, Usama Arif, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, John Hubbard, Peter Xu, linux-mm, linux-kernel,
	linux-csky, linux-hexagon, linux-m68k, linux-openrisc, linux-sh,
	linux-riscv, linux-arm-kernel, linux-snps-arc, linux-arch,
	sparclinux, linux-alpha, loongarch, linux-mips, linux-parisc,
	linuxppc-dev, linux-s390, linux-um, Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 04:45:14PM +0100, Lorenzo Stoakes (ARM) wrote:
> > munmap() of 64G worth of THP should be enough to demonstrate the
> > problem.
> 
> I mean you're going to hit that from RCU freeing page tables already, which
> most architectures already do right?

Not at the same rate -- tlb_remove_table() batches into struct
mmu_table_batch. One call_rcu() per MAX_TABLE_BATCH.

> So if RCU saturation is a problem, that problem already exists, but I've
> not heard of that being a problem at all?

I did quick test and I don't see a measurable difference in munmap()
wall time of 40G of THPs. I see ~17x more softirqs, but this is
expected.

The objection is retracted.

We can return to this later if it is going to be visible anywhere.

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 15:54             ` Liam R. Howlett
  2026-09-01 16:06               ` Jason Gunthorpe
@ 2026-09-01 17:13               ` Kiryl Shutsemau
  2026-09-01 17:47                 ` Liam R. Howlett
  1 sibling, 1 reply; 43+ messages in thread
From: Kiryl Shutsemau @ 2026-09-01 17:13 UTC (permalink / raw)
  To: Liam R. Howlett
  Cc: Lorenzo Stoakes (ARM), Jason Gunthorpe, Andrew Morton,
	David Hildenbrand, Zi Yan, Baolin Wang, Nico Pache, Ryan Roberts,
	Dev Jain, Barry Song, Lance Yang, Usama Arif, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, John Hubbard, Peter Xu, linux-mm, linux-kernel,
	linux-csky, linux-hexagon, linux-m68k, linux-openrisc, linux-sh,
	linux-riscv, linux-arm-kernel, linux-snps-arc, linux-arch,
	sparclinux, linux-alpha, loongarch, linux-mips, linux-parisc,
	linuxppc-dev, linux-s390, linux-um, Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 11:54:47AM -0400, Liam R. Howlett wrote:
> Do you have munmap() performance dependent workload that you are
> concerned about regressing?

exit(2) path is performance critical for many workloads. Like, if you
need to restart VM.

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 17:11               ` Kiryl Shutsemau
@ 2026-09-01 17:14                 ` Lorenzo Stoakes (ARM)
  0 siblings, 0 replies; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 17:14 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: Jason Gunthorpe, Andrew Morton, David Hildenbrand, Zi Yan,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Lance Yang, Usama Arif, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, John Hubbard, Peter Xu, linux-mm, linux-kernel,
	linux-csky, linux-hexagon, linux-m68k, linux-openrisc, linux-sh,
	linux-riscv, linux-arm-kernel, linux-snps-arc, linux-arch,
	sparclinux, linux-alpha, loongarch, linux-mips, linux-parisc,
	linuxppc-dev, linux-s390, linux-um, Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 06:11:57PM +0100, Kiryl Shutsemau wrote:
> On Tue, Sep 01, 2026 at 04:45:14PM +0100, Lorenzo Stoakes (ARM) wrote:
> > > munmap() of 64G worth of THP should be enough to demonstrate the
> > > problem.
> >
> > I mean you're going to hit that from RCU freeing page tables already, which
> > most architectures already do right?
>
> Not at the same rate -- tlb_remove_table() batches into struct
> mmu_table_batch. One call_rcu() per MAX_TABLE_BATCH.
>
> > So if RCU saturation is a problem, that problem already exists, but I've
> > not heard of that being a problem at all?
>
> I did quick test and I don't see a measurable difference in munmap()
> wall time of 40G of THPs. I see ~17x more softirqs, but this is
> expected.
>
> The objection is retracted.
>
> We can return to this later if it is going to be visible anywhere.

Great thanks! :)

>
> --
>   Kiryl Shutsemau / Kirill A. Shutemov

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 12/12] mm: change the contract for free_pgtables(), update docs
  2026-09-01 14:31     ` Lorenzo Stoakes (ARM)
@ 2026-09-01 17:15       ` Kiryl Shutsemau
  2026-09-01 17:25         ` Lorenzo Stoakes (ARM)
  0 siblings, 1 reply; 43+ messages in thread
From: Kiryl Shutsemau @ 2026-09-01 17:15 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Guo Ren, Brian Cain, Geert Uytterhoeven,
	Dinh Nguyen, Simon Schuster, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu, linux-mm,
	linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 03:31:26PM +0100, Lorenzo Stoakes (ARM) wrote:
> On Tue, Sep 01, 2026 at 02:57:13PM +0100, Kiryl Shutsemau wrote:
> > On Tue, Sep 01, 2026 at 12:01:32PM +0100, Lorenzo Stoakes (ARM) wrote:
> > > diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
> > > index b91b1a98029c..ff8ff3706485 100644
> > > --- a/mm/pgtable-generic.c
> > > +++ b/mm/pgtable-generic.c
> > > @@ -386,9 +386,21 @@ pte_t *pte_offset_map_rw_nolock(struct mm_struct *mm, pmd_t *pmd,
> > >   * be read-only/read-write protected.
> > >   *
> > >   * Note that free_pgtables(), used after unmapping detached vmas, or when
> > > - * exiting the whole mm, does not take page table lock before freeing a page
> > > - * table, and may not use RCU at all: "outsiders" like khugepaged should avoid
> > > - * pte_offset_map() and co once the vma is detached from mm or mm_users is zero.
> > > + * exiting the whole mm, does not take the page table lock before freeing a
> > > + * table.
> > > + *
> > > + * However, the PMD entry is cleared first, and the table freed only after
> > > + * an RCU grace period, so a walker that mapped the table under
> > > + * rcu_read_lock() stays safe, and the pmd_same() recheck in
> > > + * pte_offset_map_lock() detects the teardown.
> > > + *
> > > + * Therefore it is safe for "outsiders" like khugepaged to use
> > > + * pte_offset_map() and co. for VMAs that might be undergoing page table
> > > + * teardown.
> >
> > Is it strictly true?
> >
> > free_pte_range() clears the pmd without taking the PTL, so the
> > pmd_same() recheck in pte_offset_map_lock() can pass and the pmd gets
> > cleared right after.
> >
> > Readers are fine -- __pte_offset_map() holds rcu_read_lock() until
> > pte_unmap(), so the table cannot go away.
> >
> > khugepaged is an odd example here. collapse_pte_mapped_thp() and
> > retract_page_tables() don't rely on this recheck -- they take pmd_lock()
> > plus the ptl and do their own pmd_same() under both.
> >
> > Can we say walks are safe and leave the write rule where it is?
> 
> Hmm yeah, ah page tables, what a rabbit hole of horror :)
> 
> I guess this is effectively a reflection of the 'write lock on write, RCU load
> on read' pattern in RCU itself generally.
> 
> So, maybe something like:
> 
>  * Note that free_pgtables(), used after unampping detached vmas, or when
>  * exiting the whoel mm, does not take a page table lock before freeing a page
>  * table.
>  *
>  * As page table freeing itself is RCU-safe, page table readers can safely run
>  * concurrently with page table teardown. However, writers cannot, as without
>  * a lock nothing prevents concurrent teardown.
>  */
> 
> Instead? What do you think?

s/whoel/whole/

Otherwise, LGTM.

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 12/12] mm: change the contract for free_pgtables(), update docs
  2026-09-01 17:15       ` Kiryl Shutsemau
@ 2026-09-01 17:25         ` Lorenzo Stoakes (ARM)
  0 siblings, 0 replies; 43+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-01 17:25 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: Andrew Morton, David Hildenbrand, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Usama Arif, Guo Ren, Brian Cain, Geert Uytterhoeven,
	Dinh Nguyen, Simon Schuster, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jason Gunthorpe, John Hubbard, Peter Xu, linux-mm,
	linux-kernel, linux-csky, linux-hexagon, linux-m68k,
	linux-openrisc, linux-sh, linux-riscv, linux-arm-kernel,
	linux-snps-arc, linux-arch, sparclinux, linux-alpha, loongarch,
	linux-mips, linux-parisc, linuxppc-dev, linux-s390, linux-um,
	Hugh Dickins, Qi Zheng

On Tue, Sep 01, 2026 at 06:15:17PM +0100, Kiryl Shutsemau wrote:
> On Tue, Sep 01, 2026 at 03:31:26PM +0100, Lorenzo Stoakes (ARM) wrote:
> > On Tue, Sep 01, 2026 at 02:57:13PM +0100, Kiryl Shutsemau wrote:
> > > On Tue, Sep 01, 2026 at 12:01:32PM +0100, Lorenzo Stoakes (ARM) wrote:
> > > > diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
> > > > index b91b1a98029c..ff8ff3706485 100644
> > > > --- a/mm/pgtable-generic.c
> > > > +++ b/mm/pgtable-generic.c
> > > > @@ -386,9 +386,21 @@ pte_t *pte_offset_map_rw_nolock(struct mm_struct *mm, pmd_t *pmd,
> > > >   * be read-only/read-write protected.
> > > >   *
> > > >   * Note that free_pgtables(), used after unmapping detached vmas, or when
> > > > - * exiting the whole mm, does not take page table lock before freeing a page
> > > > - * table, and may not use RCU at all: "outsiders" like khugepaged should avoid
> > > > - * pte_offset_map() and co once the vma is detached from mm or mm_users is zero.
> > > > + * exiting the whole mm, does not take the page table lock before freeing a
> > > > + * table.
> > > > + *
> > > > + * However, the PMD entry is cleared first, and the table freed only after
> > > > + * an RCU grace period, so a walker that mapped the table under
> > > > + * rcu_read_lock() stays safe, and the pmd_same() recheck in
> > > > + * pte_offset_map_lock() detects the teardown.
> > > > + *
> > > > + * Therefore it is safe for "outsiders" like khugepaged to use
> > > > + * pte_offset_map() and co. for VMAs that might be undergoing page table
> > > > + * teardown.
> > >
> > > Is it strictly true?
> > >
> > > free_pte_range() clears the pmd without taking the PTL, so the
> > > pmd_same() recheck in pte_offset_map_lock() can pass and the pmd gets
> > > cleared right after.
> > >
> > > Readers are fine -- __pte_offset_map() holds rcu_read_lock() until
> > > pte_unmap(), so the table cannot go away.
> > >
> > > khugepaged is an odd example here. collapse_pte_mapped_thp() and
> > > retract_page_tables() don't rely on this recheck -- they take pmd_lock()
> > > plus the ptl and do their own pmd_same() under both.
> > >
> > > Can we say walks are safe and leave the write rule where it is?
> >
> > Hmm yeah, ah page tables, what a rabbit hole of horror :)
> >
> > I guess this is effectively a reflection of the 'write lock on write, RCU load
> > on read' pattern in RCU itself generally.
> >
> > So, maybe something like:
> >
> >  * Note that free_pgtables(), used after unampping detached vmas, or when
> >  * exiting the whoel mm, does not take a page table lock before freeing a page
> >  * table.
> >  *
> >  * As page table freeing itself is RCU-safe, page table readers can safely run
> >  * concurrently with page table teardown. However, writers cannot, as without
> >  * a lock nothing prevents concurrent teardown.
> >  */
> >
> > Instead? What do you think?
>
> s/whoel/whole/

Haha yup the inevitable typo...

>
> Otherwise, LGTM.

Thanks! :)

>
> --
>   Kiryl Shutsemau / Kirill A. Shutemov

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period
  2026-09-01 17:13               ` Kiryl Shutsemau
@ 2026-09-01 17:47                 ` Liam R. Howlett
  0 siblings, 0 replies; 43+ messages in thread
From: Liam R. Howlett @ 2026-09-01 17:47 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: Lorenzo Stoakes (ARM), Jason Gunthorpe, Andrew Morton,
	David Hildenbrand, Zi Yan, Baolin Wang, Nico Pache, Ryan Roberts,
	Dev Jain, Barry Song, Lance Yang, Usama Arif, Guo Ren, Brian Cain,
	Geert Uytterhoeven, Dinh Nguyen, Simon Schuster, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Russell King, Vineet Gupta,
	Michal Simek, Chris Zankel, Max Filippov, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Peter Zijlstra, David S. Miller,
	Andreas Larsson, Richard Henderson, Matt Turner, Magnus Lindholm,
	Catalin Marinas, Mark Rutland, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman,
	Christophe Leroy (CS GROUP), Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Arnd Bergmann, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, John Hubbard, Peter Xu, linux-mm, linux-kernel,
	linux-csky, linux-hexagon, linux-m68k, linux-openrisc, linux-sh,
	linux-riscv, linux-arm-kernel, linux-snps-arc, linux-arch,
	sparclinux, linux-alpha, loongarch, linux-mips, linux-parisc,
	linuxppc-dev, linux-s390, linux-um, Hugh Dickins, Qi Zheng

On 26/09/01 06:13PM, Kiryl Shutsemau wrote:
> On Tue, Sep 01, 2026 at 11:54:47AM -0400, Liam R. Howlett wrote:
> > Do you have munmap() performance dependent workload that you are
> > concerned about regressing?
> 
> exit(2) path is performance critical for many workloads. Like, if you
> need to restart VM.
> 

That is not enough to see any impact, although less overall work would
be done during the exit call.

It would be very difficult to come up with a scenario that this would
have a measurable difference and an even harder time to come up with one
that is slower.


^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2026-09-01 17:48 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 11:01 [PATCH 00/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
2026-09-01 11:01 ` [PATCH 01/12] mm/huge_memory: zap deposited page tables after an RCU grace period Lorenzo Stoakes (ARM)
2026-09-01 11:18   ` sashiko-bot
2026-09-01 13:19   ` Kiryl Shutsemau
2026-09-01 14:12     ` Lorenzo Stoakes (ARM)
2026-09-01 14:24       ` Jason Gunthorpe
2026-09-01 14:41         ` Lorenzo Stoakes (ARM)
2026-09-01 15:28           ` Kiryl Shutsemau
2026-09-01 15:45             ` Lorenzo Stoakes (ARM)
2026-09-01 17:11               ` Kiryl Shutsemau
2026-09-01 17:14                 ` Lorenzo Stoakes (ARM)
2026-09-01 15:54             ` Liam R. Howlett
2026-09-01 16:06               ` Jason Gunthorpe
2026-09-01 17:13               ` Kiryl Shutsemau
2026-09-01 17:47                 ` Liam R. Howlett
2026-09-01 11:01 ` [PATCH 02/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for most 2-level architectures Lorenzo Stoakes (ARM)
2026-09-01 11:22   ` sashiko-bot
2026-09-01 11:01 ` [PATCH 03/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU riscv Lorenzo Stoakes (ARM)
2026-09-01 11:14   ` sashiko-bot
2026-09-01 11:01 ` [PATCH 04/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for MMU arm Lorenzo Stoakes (ARM)
2026-09-01 11:18   ` sashiko-bot
2026-09-01 11:01 ` [PATCH 05/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for arc, microblaze, xtensa Lorenzo Stoakes (ARM)
2026-09-01 11:28   ` sashiko-bot
2026-09-01 11:01 ` [PATCH 06/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc64 Lorenzo Stoakes (ARM)
2026-09-01 11:23   ` sashiko-bot
2026-09-01 11:01 ` [PATCH 07/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-coldfire Lorenzo Stoakes (ARM)
2026-09-01 11:23   ` sashiko-bot
2026-09-01 11:01 ` [PATCH 08/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sh-X2 Lorenzo Stoakes (ARM)
2026-09-01 11:30   ` sashiko-bot
2026-09-01 11:01 ` [PATCH 09/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for m68k-motorola Lorenzo Stoakes (ARM)
2026-09-01 11:30   ` sashiko-bot
2026-09-01 11:01 ` [PATCH 10/12] mm: enable MMU_GATHER_RCU_TABLE_FREE for sparc32 Lorenzo Stoakes (ARM)
2026-09-01 11:37   ` sashiko-bot
2026-09-01 11:01 ` [PATCH 11/12] mm: make userland page table freeing RCU-safe Lorenzo Stoakes (ARM)
2026-09-01 11:52   ` sashiko-bot
2026-09-01 13:33   ` Kiryl Shutsemau
2026-09-01 14:03     ` Lorenzo Stoakes (ARM)
2026-09-01 11:01 ` [PATCH 12/12] mm: change the contract for free_pgtables(), update docs Lorenzo Stoakes (ARM)
2026-09-01 11:37   ` sashiko-bot
2026-09-01 13:57   ` Kiryl Shutsemau
2026-09-01 14:31     ` Lorenzo Stoakes (ARM)
2026-09-01 17:15       ` Kiryl Shutsemau
2026-09-01 17:25         ` Lorenzo Stoakes (ARM)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox