nmi_backtrace: allow excluding an arbitrary CPU
authorDouglas Anderson <dianders@chromium.org>
Fri, 4 Aug 2023 14:00:42 +0000 (07:00 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Fri, 18 Aug 2023 17:19:00 +0000 (10:19 -0700)
The APIs that allow backtracing across CPUs have always had a way to
exclude the current CPU.  This convenience means callers didn't need to
find a place to allocate a CPU mask just to handle the common case.

Let's extend the API to take a CPU ID to exclude instead of just a
boolean.  This isn't any more complex for the API to handle and allows the
hardlockup detector to exclude a different CPU (the one it already did a
trace for) without needing to find space for a CPU mask.

Arguably, this new API also encourages safer behavior.  Specifically if
the caller wants to avoid tracing the current CPU (maybe because they
already traced the current CPU) this makes it more obvious to the caller
that they need to make sure that the current CPU ID can't change.

[akpm@linux-foundation.org: fix trigger_allbutcpu_cpu_backtrace() stub]
Link: https://lkml.kernel.org/r/20230804065935.v4.1.Ia35521b91fc781368945161d7b28538f9996c182@changeid
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Acked-by: Michal Hocko <mhocko@suse.com>
Cc: kernel test robot <lkp@intel.com>
Cc: Lecopzer Chen <lecopzer.chen@mediatek.com>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Pingfan Liu <kernelfans@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
16 files changed:
arch/arm/include/asm/irq.h
arch/arm/kernel/smp.c
arch/loongarch/include/asm/irq.h
arch/loongarch/kernel/process.c
arch/mips/include/asm/irq.h
arch/mips/kernel/process.c
arch/powerpc/include/asm/irq.h
arch/powerpc/kernel/stacktrace.c
arch/powerpc/kernel/watchdog.c
arch/sparc/include/asm/irq_64.h
arch/sparc/kernel/process_64.c
arch/x86/include/asm/irq.h
arch/x86/kernel/apic/hw_nmi.c
include/linux/nmi.h
kernel/watchdog.c
lib/nmi_backtrace.c

index 18605f1b3580715a7e90cffdab75e454eb972b29..26c1d2ced4ce18f85ae3f0e33a7a931072f4e4ff 100644 (file)
@@ -32,7 +32,7 @@ void handle_IRQ(unsigned int, struct pt_regs *);
 #include <linux/cpumask.h>
 
 extern void arch_trigger_cpumask_backtrace(const cpumask_t *mask,
-                                          bool exclude_self);
+                                          int exclude_cpu);
 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
 #endif
 
index 6756203e45f3d0b7780d2144ab21a0a80e048883..3431c0553f45cdf5f0b1b8dbb59bf38003da9995 100644 (file)
@@ -846,7 +846,7 @@ static void raise_nmi(cpumask_t *mask)
        __ipi_send_mask(ipi_desc[IPI_CPU_BACKTRACE], mask);
 }
 
-void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
 {
-       nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_nmi);
+       nmi_trigger_cpumask_backtrace(mask, exclude_cpu, raise_nmi);
 }
index a115e8999c69e3e0e67e6da7c05f350f013c4d1a..218b4da0ea90d012199fe65f47eceae810a0a300 100644 (file)
@@ -40,7 +40,7 @@ void spurious_interrupt(void);
 #define NR_IRQS_LEGACY 16
 
 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
-void arch_trigger_cpumask_backtrace(const struct cpumask *mask, bool exclude_self);
+void arch_trigger_cpumask_backtrace(const struct cpumask *mask, int exclude_cpu);
 
 #define MAX_IO_PICS 2
 #define NR_IRQS        (64 + (256 * MAX_IO_PICS))
index 2e04eb07abb6e0e13f0887580eb264affbfdc7bb..778e8d09953e3ffaff7828f91aac188782af2493 100644 (file)
@@ -345,9 +345,9 @@ static void raise_backtrace(cpumask_t *mask)
        }
 }
 
-void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
 {
-       nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_backtrace);
+       nmi_trigger_cpumask_backtrace(mask, exclude_cpu, raise_backtrace);
 }
 
 #ifdef CONFIG_64BIT
index 75abfa834ab7ac7dc9caa66a7ec2da62acc020df..3a848e7e69f71102c925df2dd2be1003419a9bfd 100644 (file)
@@ -77,7 +77,7 @@ extern int cp0_fdc_irq;
 extern int get_c0_fdc_int(void);
 
 void arch_trigger_cpumask_backtrace(const struct cpumask *mask,
-                                   bool exclude_self);
+                                   int exclude_cpu);
 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
 
 #endif /* _ASM_IRQ_H */
index a3225912c862da7bbe3bd315950f5073006f99e9..5387ed0a51862b66609d990cb039b27261a5c234 100644 (file)
@@ -750,9 +750,9 @@ static void raise_backtrace(cpumask_t *mask)
        }
 }
 
-void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
 {
-       nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_backtrace);
+       nmi_trigger_cpumask_backtrace(mask, exclude_cpu, raise_backtrace);
 }
 
 int mips_get_process_fp_mode(struct task_struct *task)
index f257cacb49a9c2fc9fc577abf4049a93da076ed7..ba1a5974e714364cecba82311271c3fc22ea4998 100644 (file)
@@ -55,7 +55,7 @@ int irq_choose_cpu(const struct cpumask *mask);
 
 #if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_NMI_IPI)
 extern void arch_trigger_cpumask_backtrace(const cpumask_t *mask,
-                                          bool exclude_self);
+                                          int exclude_cpu);
 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
 #endif
 
index 5de8597eaab8dc428828abb0c6fba244e62fe23b..b15f15dcacb5c42a5b26645460c45e1e5f29340f 100644 (file)
@@ -221,8 +221,8 @@ static void raise_backtrace_ipi(cpumask_t *mask)
        }
 }
 
-void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
 {
-       nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_backtrace_ipi);
+       nmi_trigger_cpumask_backtrace(mask, exclude_cpu, raise_backtrace_ipi);
 }
 #endif /* defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_NMI_IPI) */
index edb2dd1f53ebc8370a921636e1243f12ee1983b9..8c464a5d82469fd85b51e412eafc788366eba96b 100644 (file)
@@ -245,7 +245,7 @@ static void watchdog_smp_panic(int cpu)
                        __cpumask_clear_cpu(c, &wd_smp_cpus_ipi);
                }
        } else {
-               trigger_allbutself_cpu_backtrace();
+               trigger_allbutcpu_cpu_backtrace(cpu);
                cpumask_clear(&wd_smp_cpus_ipi);
        }
 
@@ -416,7 +416,7 @@ DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt)
                xchg(&__wd_nmi_output, 1); // see wd_lockup_ipi
 
                if (sysctl_hardlockup_all_cpu_backtrace)
-                       trigger_allbutself_cpu_backtrace();
+                       trigger_allbutcpu_cpu_backtrace(cpu);
 
                if (hardlockup_panic)
                        nmi_panic(regs, "Hard LOCKUP");
index b436029f1ced2c15a58cd22e1c6d271977b7cfad..8c4c0c87f99808356b20a0c7172c5096fd7201e5 100644 (file)
@@ -87,7 +87,7 @@ static inline unsigned long get_softint(void)
 }
 
 void arch_trigger_cpumask_backtrace(const struct cpumask *mask,
-                                   bool exclude_self);
+                                   int exclude_cpu);
 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
 
 extern void *hardirq_stack[NR_CPUS];
index b51d8fb0ecdc2d693b3e30fb0b908a074df362e3..1ea3f37fa9851495fc0db812477c07c73c160fa8 100644 (file)
@@ -236,7 +236,7 @@ static void __global_reg_poll(struct global_reg_snapshot *gp)
        }
 }
 
-void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
 {
        struct thread_info *tp = current_thread_info();
        struct pt_regs *regs = get_irq_regs();
@@ -252,7 +252,7 @@ void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
 
        memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
 
-       if (cpumask_test_cpu(this_cpu, mask) && !exclude_self)
+       if (cpumask_test_cpu(this_cpu, mask) && this_cpu != exclude_cpu)
                __global_reg_self(tp, regs, this_cpu);
 
        smp_fetch_global_regs();
@@ -260,7 +260,7 @@ void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
        for_each_cpu(cpu, mask) {
                struct global_reg_snapshot *gp;
 
-               if (exclude_self && cpu == this_cpu)
+               if (cpu == exclude_cpu)
                        continue;
 
                gp = &global_cpu_snapshot[cpu].reg;
index 29e083b92813c345fece77a30b5f98bdbb2403f4..836c170d308755fe205b802e34b51c7ffd592017 100644 (file)
@@ -42,7 +42,7 @@ extern void init_ISA_irqs(void);
 
 #ifdef CONFIG_X86_LOCAL_APIC
 void arch_trigger_cpumask_backtrace(const struct cpumask *mask,
-                                   bool exclude_self);
+                                   int exclude_cpu);
 
 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
 #endif
index 34a992e275ef42b94e6f0fb057ff160617cd972a..d6e01f924299678e2d649c002936cfbade67dced 100644 (file)
@@ -34,9 +34,9 @@ static void nmi_raise_cpu_backtrace(cpumask_t *mask)
        apic->send_IPI_mask(mask, NMI_VECTOR);
 }
 
-void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
 {
-       nmi_trigger_cpumask_backtrace(mask, exclude_self,
+       nmi_trigger_cpumask_backtrace(mask, exclude_cpu,
                                      nmi_raise_cpu_backtrace);
 }
 
index e3e6a64b98e09069b2f8c763f47aee97612a9d49..e92e378df000fb1eca1e082ebc889fe7849a19d2 100644 (file)
@@ -157,31 +157,31 @@ static inline void touch_nmi_watchdog(void)
 #ifdef arch_trigger_cpumask_backtrace
 static inline bool trigger_all_cpu_backtrace(void)
 {
-       arch_trigger_cpumask_backtrace(cpu_online_mask, false);
+       arch_trigger_cpumask_backtrace(cpu_online_mask, -1);
        return true;
 }
 
-static inline bool trigger_allbutself_cpu_backtrace(void)
+static inline bool trigger_allbutcpu_cpu_backtrace(int exclude_cpu)
 {
-       arch_trigger_cpumask_backtrace(cpu_online_mask, true);
+       arch_trigger_cpumask_backtrace(cpu_online_mask, exclude_cpu);
        return true;
 }
 
 static inline bool trigger_cpumask_backtrace(struct cpumask *mask)
 {
-       arch_trigger_cpumask_backtrace(mask, false);
+       arch_trigger_cpumask_backtrace(mask, -1);
        return true;
 }
 
 static inline bool trigger_single_cpu_backtrace(int cpu)
 {
-       arch_trigger_cpumask_backtrace(cpumask_of(cpu), false);
+       arch_trigger_cpumask_backtrace(cpumask_of(cpu), -1);
        return true;
 }
 
 /* generic implementation */
 void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
-                                  bool exclude_self,
+                                  int exclude_cpu,
                                   void (*raise)(cpumask_t *mask));
 bool nmi_cpu_backtrace(struct pt_regs *regs);
 
@@ -190,7 +190,7 @@ static inline bool trigger_all_cpu_backtrace(void)
 {
        return false;
 }
-static inline bool trigger_allbutself_cpu_backtrace(void)
+static inline bool trigger_allbutcpu_cpu_backtrace(int exclude_cpu)
 {
        return false;
 }
index be38276a365f344b976a7a86fb3c6d99bb68345f..085d7a78f62f012213692cfe855a914122d47b22 100644 (file)
@@ -523,7 +523,7 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
                        dump_stack();
 
                if (softlockup_all_cpu_backtrace) {
-                       trigger_allbutself_cpu_backtrace();
+                       trigger_allbutcpu_cpu_backtrace(smp_processor_id());
                        clear_bit_unlock(0, &soft_lockup_nmi_warn);
                }
 
index 5274bbb026d7933b535f6cfb3883d140101bddb1..33c154264bfe2e9afee85df470574f1a1efe6aa3 100644 (file)
@@ -34,7 +34,7 @@ static unsigned long backtrace_flag;
  * they are passed being updated as a side effect of this call.
  */
 void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
-                                  bool exclude_self,
+                                  int exclude_cpu,
                                   void (*raise)(cpumask_t *mask))
 {
        int i, this_cpu = get_cpu();
@@ -49,8 +49,8 @@ void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
        }
 
        cpumask_copy(to_cpumask(backtrace_mask), mask);
-       if (exclude_self)
-               cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask));
+       if (exclude_cpu != -1)
+               cpumask_clear_cpu(exclude_cpu, to_cpumask(backtrace_mask));
 
        /*
         * Don't try to send an NMI to this cpu; it may work on some