[PATCH] mips: mm: Call rcutree_report_cpu_starting() even earlier

Stefan Wiehler posted 1 patch 2 months, 1 week ago
There is a newer version of this series
arch/mips/mm/tlb-r4k.c | 7 +++++++
1 file changed, 7 insertions(+)
[PATCH] mips: mm: Call rcutree_report_cpu_starting() even earlier
Posted by Stefan Wiehler 2 months, 1 week ago
rcutree_report_cpu_starting() must be called on secondary CPUs before
allocating memory to avoid the following Lockdep-RCU splat when
CONFIG_PROVE_RCU_LIST=y:

  WARNING: suspicious RCU usage
  6.6.119-00d46e15c416-fct #1 Not tainted
  -----------------------------
  /kernel/locking/lockdep.c:3762 RCU-list traversed in non-reader section!!

  other info that might help us debug this:

  RCU used illegally from offline CPU!
  rcu_scheduler_active = 1, debug_locks = 1
  no locks held by swapper/1/0.

  stack backtrace:
  CPU: 1 PID: 0 Comm: swapper/1 Not tainted 6.6.119-00d46e15c416-fct #1
  Stack : 80000000029e37d8 0000000000000000 0000000000000008 80000000029e37e8
          80000000029e37e8 80000000029e3978 0000000000000000 0000000000000000
          0000000000000000 0000000000000001 ffffffff80d9df38 ffffffff810e19c0
          0000000000000000 0000000000000010 ffffffff80a7d140 0000000000000000
          ffffffff81c20814 0000000000000000 ffffffff80da0000 0000000000000000
          ffffffff80cadf38 0000000000000000 0000000000000000 80000000029ab680
          72f093276415c1f3 ffffffff81c2084f ffffffff80da0000 ffffffffc0149ed8
          fffffffffffffffe 80000000029e0000 80000000029e37e0 80000000029abf58
          ffffffff80129fb0 0000000000000000 0000000000000000 0000000000000000
          0000000000000000 0000000000000000 ffffffff80129fd0 0000000000000000
          ...
  Call Trace:
  [<ffffffff80129fd0>] show_stack+0x60/0x158
  [<ffffffff80a8cd84>] dump_stack_lvl+0x88/0xbc
  [<ffffffff801c78f8>] lockdep_rcu_suspicious+0x1c0/0x240
  [<ffffffff801cc80c>] __lock_acquire+0x121c/0x29d8
  [<ffffffff801ce14c>] lock_acquire+0x184/0x448
  [<ffffffff80a9ba30>] _raw_spin_lock_irqsave+0x50/0x90
  [<ffffffff80367038>] ___slab_alloc+0xa08/0x1808
  [<ffffffff80367e70>] __slab_alloc.isra.0+0x38/0x78
  [<ffffffff8036b7d4>] __kmem_cache_alloc_node+0x35c/0x370
  [<ffffffff80308ed8>] __kmalloc+0x58/0xd0
  [<ffffffff80a8f064>] r4k_tlb_uniquify+0x7c/0x428
  [<ffffffff80143e8c>] tlb_init+0x7c/0x110
  [<ffffffff8012bdb4>] per_cpu_trap_init+0x16c/0x1d0
  [<ffffffff80133258>] start_secondary+0x28/0x128

raw_smp_processor_id() is required in order to avoid calling into
lockdep before RCU has declared the CPU to be watched for readers.

See also commit 55702ec9603e ("mips/smp: Call
rcutree_report_cpu_starting() earlier").

Fixes: 231ac951faba ("MIPS: mm: kmalloc tlb_vpn array to avoid stack overflow")
Signed-off-by: Stefan Wiehler <stefan.wiehler@nokia.com>
Cc: stable@vger.kernel.org
---
 arch/mips/mm/tlb-r4k.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 24fe85fa169d..49cb5262df1e 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -18,6 +18,7 @@
 #include <linux/hugetlb.h>
 #include <linux/export.h>
 #include <linux/sort.h>
+#include <linux/rcutree.h>
 
 #include <asm/cpu.h>
 #include <asm/cpu-type.h>
@@ -744,12 +745,18 @@ static void __ref r4k_tlb_uniquify_write(struct tlbent *tlb_vpns, int tlbsize)
  */
 static void __ref r4k_tlb_uniquify(void)
 {
+	unsigned int cpu = raw_smp_processor_id();
 	int tlbsize = current_cpu_data.tlbsize;
 	bool use_slab = slab_is_available();
+	static bool secondary = false;
 	phys_addr_t tlb_vpn_size;
 	struct tlbent *tlb_vpns;
 
 	tlb_vpn_size = tlbsize * sizeof(*tlb_vpns);
+	if (secondary)
+		rcu_cpu_starting(cpu);
+	else
+		secondary = true;
 	tlb_vpns = (use_slab ?
 		    kmalloc(tlb_vpn_size, GFP_ATOMIC) :
 		    memblock_alloc_raw(tlb_vpn_size, sizeof(*tlb_vpns)));
-- 
2.42.0
Re: [PATCH] mips: mm: Call rcutree_report_cpu_starting() even earlier
Posted by Maciej W. Rozycki 2 months, 1 week ago
On Tue, 7 Apr 2026, Stefan Wiehler wrote:

> diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
> index 24fe85fa169d..49cb5262df1e 100644
> --- a/arch/mips/mm/tlb-r4k.c
> +++ b/arch/mips/mm/tlb-r4k.c
> @@ -744,12 +745,18 @@ static void __ref r4k_tlb_uniquify_write(struct tlbent *tlb_vpns, int tlbsize)
>   */
>  static void __ref r4k_tlb_uniquify(void)
>  {
> +	unsigned int cpu = raw_smp_processor_id();
>  	int tlbsize = current_cpu_data.tlbsize;
>  	bool use_slab = slab_is_available();
> +	static bool secondary = false;
>  	phys_addr_t tlb_vpn_size;
>  	struct tlbent *tlb_vpns;
>  
>  	tlb_vpn_size = tlbsize * sizeof(*tlb_vpns);
> +	if (secondary)
> +		rcu_cpu_starting(cpu);
> +	else
> +		secondary = true;

 You could use `use_slab' to figure out whether it is a secondary CPU, but 
the right fix AFAICT is to reorder the `rcutree_report_cpu_starting' ahead 
of `per_cpu_trap_init' in `start_secondary', possibly even to the start of 
the function (does it rely on any of the initialisation done earlier on?).

 NB is `rcu_cpu_starting' the right function call to make, and where does 
`cpu' come from here?

 Thanks for the report!

  Maciej
Re: [PATCH] mips: mm: Call rcutree_report_cpu_starting() even earlier
Posted by Stefan Wiehler 2 months ago
>  You could use `use_slab' to figure out whether it is a secondary CPU, but
> the right fix AFAICT is to reorder the `rcutree_report_cpu_starting' ahead
> of `per_cpu_trap_init' in `start_secondary', possibly even to the start of
> the function (does it rely on any of the initialisation done earlier on?).

Thanks, reordering the rcutree_report_cpu_starting() call in start_secondary()
is indeed much better; funny that I forgot my own change in commit 55702ec9603e
("mips/smp: Call rcutree_report_cpu_starting() earlier") from some years ago.
Will sent out a v2 shortly.

>  NB is `rcu_cpu_starting' the right function call to make, and where does
> `cpu' come from here?

Sorry, rcu_cpu_starting() has been renamed to rcutree_report_cpu_starting() at
some point, and I accidentally sent out the patch for our LTS kernel; also
fixed in v2.

Kind regards,

Stefan