Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nmi_backtrace: allow excluding an arbitrary CPU

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>

authored by

Douglas Anderson and committed by
Andrew Morton
8d539b84 3c9d017c

+32 -32
+1 -1
arch/arm/include/asm/irq.h
··· 32 32 #include <linux/cpumask.h> 33 33 34 34 extern void arch_trigger_cpumask_backtrace(const cpumask_t *mask, 35 - bool exclude_self); 35 + int exclude_cpu); 36 36 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace 37 37 #endif 38 38
+2 -2
arch/arm/kernel/smp.c
··· 846 846 __ipi_send_mask(ipi_desc[IPI_CPU_BACKTRACE], mask); 847 847 } 848 848 849 - void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self) 849 + void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu) 850 850 { 851 - nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_nmi); 851 + nmi_trigger_cpumask_backtrace(mask, exclude_cpu, raise_nmi); 852 852 }
+1 -1
arch/loongarch/include/asm/irq.h
··· 40 40 #define NR_IRQS_LEGACY 16 41 41 42 42 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace 43 - void arch_trigger_cpumask_backtrace(const struct cpumask *mask, bool exclude_self); 43 + void arch_trigger_cpumask_backtrace(const struct cpumask *mask, int exclude_cpu); 44 44 45 45 #define MAX_IO_PICS 2 46 46 #define NR_IRQS (64 + (256 * MAX_IO_PICS))
+2 -2
arch/loongarch/kernel/process.c
··· 345 345 } 346 346 } 347 347 348 - void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self) 348 + void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu) 349 349 { 350 - nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_backtrace); 350 + nmi_trigger_cpumask_backtrace(mask, exclude_cpu, raise_backtrace); 351 351 } 352 352 353 353 #ifdef CONFIG_64BIT
+1 -1
arch/mips/include/asm/irq.h
··· 77 77 extern int get_c0_fdc_int(void); 78 78 79 79 void arch_trigger_cpumask_backtrace(const struct cpumask *mask, 80 - bool exclude_self); 80 + int exclude_cpu); 81 81 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace 82 82 83 83 #endif /* _ASM_IRQ_H */
+2 -2
arch/mips/kernel/process.c
··· 750 750 } 751 751 } 752 752 753 - void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self) 753 + void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu) 754 754 { 755 - nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_backtrace); 755 + nmi_trigger_cpumask_backtrace(mask, exclude_cpu, raise_backtrace); 756 756 } 757 757 758 758 int mips_get_process_fp_mode(struct task_struct *task)
+1 -1
arch/powerpc/include/asm/irq.h
··· 55 55 56 56 #if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_NMI_IPI) 57 57 extern void arch_trigger_cpumask_backtrace(const cpumask_t *mask, 58 - bool exclude_self); 58 + int exclude_cpu); 59 59 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace 60 60 #endif 61 61
+2 -2
arch/powerpc/kernel/stacktrace.c
··· 221 221 } 222 222 } 223 223 224 - void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self) 224 + void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu) 225 225 { 226 - nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_backtrace_ipi); 226 + nmi_trigger_cpumask_backtrace(mask, exclude_cpu, raise_backtrace_ipi); 227 227 } 228 228 #endif /* defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_NMI_IPI) */
+2 -2
arch/powerpc/kernel/watchdog.c
··· 245 245 __cpumask_clear_cpu(c, &wd_smp_cpus_ipi); 246 246 } 247 247 } else { 248 - trigger_allbutself_cpu_backtrace(); 248 + trigger_allbutcpu_cpu_backtrace(cpu); 249 249 cpumask_clear(&wd_smp_cpus_ipi); 250 250 } 251 251 ··· 416 416 xchg(&__wd_nmi_output, 1); // see wd_lockup_ipi 417 417 418 418 if (sysctl_hardlockup_all_cpu_backtrace) 419 - trigger_allbutself_cpu_backtrace(); 419 + trigger_allbutcpu_cpu_backtrace(cpu); 420 420 421 421 if (hardlockup_panic) 422 422 nmi_panic(regs, "Hard LOCKUP");
+1 -1
arch/sparc/include/asm/irq_64.h
··· 87 87 } 88 88 89 89 void arch_trigger_cpumask_backtrace(const struct cpumask *mask, 90 - bool exclude_self); 90 + int exclude_cpu); 91 91 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace 92 92 93 93 extern void *hardirq_stack[NR_CPUS];
+3 -3
arch/sparc/kernel/process_64.c
··· 236 236 } 237 237 } 238 238 239 - void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self) 239 + void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu) 240 240 { 241 241 struct thread_info *tp = current_thread_info(); 242 242 struct pt_regs *regs = get_irq_regs(); ··· 252 252 253 253 memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); 254 254 255 - if (cpumask_test_cpu(this_cpu, mask) && !exclude_self) 255 + if (cpumask_test_cpu(this_cpu, mask) && this_cpu != exclude_cpu) 256 256 __global_reg_self(tp, regs, this_cpu); 257 257 258 258 smp_fetch_global_regs(); ··· 260 260 for_each_cpu(cpu, mask) { 261 261 struct global_reg_snapshot *gp; 262 262 263 - if (exclude_self && cpu == this_cpu) 263 + if (cpu == exclude_cpu) 264 264 continue; 265 265 266 266 gp = &global_cpu_snapshot[cpu].reg;
+1 -1
arch/x86/include/asm/irq.h
··· 42 42 43 43 #ifdef CONFIG_X86_LOCAL_APIC 44 44 void arch_trigger_cpumask_backtrace(const struct cpumask *mask, 45 - bool exclude_self); 45 + int exclude_cpu); 46 46 47 47 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace 48 48 #endif
+2 -2
arch/x86/kernel/apic/hw_nmi.c
··· 34 34 apic->send_IPI_mask(mask, NMI_VECTOR); 35 35 } 36 36 37 - void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self) 37 + void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu) 38 38 { 39 - nmi_trigger_cpumask_backtrace(mask, exclude_self, 39 + nmi_trigger_cpumask_backtrace(mask, exclude_cpu, 40 40 nmi_raise_cpu_backtrace); 41 41 } 42 42
+7 -7
include/linux/nmi.h
··· 157 157 #ifdef arch_trigger_cpumask_backtrace 158 158 static inline bool trigger_all_cpu_backtrace(void) 159 159 { 160 - arch_trigger_cpumask_backtrace(cpu_online_mask, false); 160 + arch_trigger_cpumask_backtrace(cpu_online_mask, -1); 161 161 return true; 162 162 } 163 163 164 - static inline bool trigger_allbutself_cpu_backtrace(void) 164 + static inline bool trigger_allbutcpu_cpu_backtrace(int exclude_cpu) 165 165 { 166 - arch_trigger_cpumask_backtrace(cpu_online_mask, true); 166 + arch_trigger_cpumask_backtrace(cpu_online_mask, exclude_cpu); 167 167 return true; 168 168 } 169 169 170 170 static inline bool trigger_cpumask_backtrace(struct cpumask *mask) 171 171 { 172 - arch_trigger_cpumask_backtrace(mask, false); 172 + arch_trigger_cpumask_backtrace(mask, -1); 173 173 return true; 174 174 } 175 175 176 176 static inline bool trigger_single_cpu_backtrace(int cpu) 177 177 { 178 - arch_trigger_cpumask_backtrace(cpumask_of(cpu), false); 178 + arch_trigger_cpumask_backtrace(cpumask_of(cpu), -1); 179 179 return true; 180 180 } 181 181 182 182 /* generic implementation */ 183 183 void nmi_trigger_cpumask_backtrace(const cpumask_t *mask, 184 - bool exclude_self, 184 + int exclude_cpu, 185 185 void (*raise)(cpumask_t *mask)); 186 186 bool nmi_cpu_backtrace(struct pt_regs *regs); 187 187 ··· 190 190 { 191 191 return false; 192 192 } 193 - static inline bool trigger_allbutself_cpu_backtrace(void) 193 + static inline bool trigger_allbutcpu_cpu_backtrace(int exclude_cpu) 194 194 { 195 195 return false; 196 196 }
+1 -1
kernel/watchdog.c
··· 523 523 dump_stack(); 524 524 525 525 if (softlockup_all_cpu_backtrace) { 526 - trigger_allbutself_cpu_backtrace(); 526 + trigger_allbutcpu_cpu_backtrace(smp_processor_id()); 527 527 clear_bit_unlock(0, &soft_lockup_nmi_warn); 528 528 } 529 529
+3 -3
lib/nmi_backtrace.c
··· 34 34 * they are passed being updated as a side effect of this call. 35 35 */ 36 36 void nmi_trigger_cpumask_backtrace(const cpumask_t *mask, 37 - bool exclude_self, 37 + int exclude_cpu, 38 38 void (*raise)(cpumask_t *mask)) 39 39 { 40 40 int i, this_cpu = get_cpu(); ··· 49 49 } 50 50 51 51 cpumask_copy(to_cpumask(backtrace_mask), mask); 52 - if (exclude_self) 53 - cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask)); 52 + if (exclude_cpu != -1) 53 + cpumask_clear_cpu(exclude_cpu, to_cpumask(backtrace_mask)); 54 54 55 55 /* 56 56 * Don't try to send an NMI to this cpu; it may work on some