hc
2025-02-14 bbb9540dc49f70f6b703d1c8d1b85fa5f602d86e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// SPDX-License-Identifier: GPL-2.0
/*
 * Provide a default dump_stack() function for architectures
 * which don't implement their own.
 */
 
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/smp.h>
#include <linux/irqstage.h>
#include <linux/atomic.h>
#include <linux/kexec.h>
#include <linux/utsname.h>
#include <linux/hardirq.h>
 
static char dump_stack_arch_desc_str[128];
 
/**
 * dump_stack_set_arch_desc - set arch-specific str to show with task dumps
 * @fmt: printf-style format string
 * @...: arguments for the format string
 *
 * The configured string will be printed right after utsname during task
 * dumps.  Usually used to add arch-specific system identifiers.  If an
 * arch wants to make use of such an ID string, it should initialize this
 * as soon as possible during boot.
 */
void __init dump_stack_set_arch_desc(const char *fmt, ...)
{
   va_list args;
 
   va_start(args, fmt);
   vsnprintf(dump_stack_arch_desc_str, sizeof(dump_stack_arch_desc_str),
         fmt, args);
   va_end(args);
}
 
/**
 * dump_stack_print_info - print generic debug info for dump_stack()
 * @log_lvl: log level
 *
 * Arch-specific dump_stack() implementations can use this function to
 * print out the same debug information as the generic dump_stack().
 */
void dump_stack_print_info(const char *log_lvl)
{
   printk("%sCPU: %d PID: %d Comm: %.20s %s%s %s %.*s\n",
          log_lvl, raw_smp_processor_id(), current->pid, current->comm,
          kexec_crash_loaded() ? "Kdump: loaded " : "",
          print_tainted(),
          init_utsname()->release,
          (int)strcspn(init_utsname()->version, " "),
          init_utsname()->version);
 
   if (dump_stack_arch_desc_str[0] != '\0')
       printk("%sHardware name: %s\n",
              log_lvl, dump_stack_arch_desc_str);
 
#ifdef CONFIG_IRQ_PIPELINE
   printk("%sIRQ stage: %s\n",
          log_lvl, current_irq_stage->name);
#endif
 
   print_worker_info(log_lvl, current);
}
 
/**
 * show_regs_print_info - print generic debug info for show_regs()
 * @log_lvl: log level
 *
 * show_regs() implementations can use this function to print out generic
 * debug information.
 */
void show_regs_print_info(const char *log_lvl)
{
   dump_stack_print_info(log_lvl);
}
 
static void __dump_stack(const char *log_lvl)
{
   dump_stack_print_info(log_lvl);
   show_stack(NULL, NULL, log_lvl);
}
 
/**
 * dump_stack - dump the current task information and its stack trace
 *
 * Architectures can override this implementation by implementing its own.
 */
#ifdef CONFIG_SMP
static atomic_t dump_lock = ATOMIC_INIT(-1);
 
static unsigned long disable_local_irqs(void)
{
   unsigned long flags = 0; /* only to trick the UMR detection */
 
   /*
    * We neither need nor want to disable in-band IRQs over the
    * oob stage, where CPU migration can't happen. Conversely, we
    * neither need nor want to disable hard IRQs from the oob
    * stage, so that latency won't skyrocket as a result of
    * dumping the stack backtrace.
    */
   if (running_inband() && !on_pipeline_entry())
       local_irq_save(flags);
 
   return flags;
}
 
static void restore_local_irqs(unsigned long flags)
{
   if (running_inband() && !on_pipeline_entry())
       local_irq_restore(flags);
}
 
asmlinkage __visible void dump_stack_lvl(const char *log_lvl)
{
   unsigned long flags;
   int was_locked;
   int old;
   int cpu;
 
   /*
    * Permit this cpu to perform nested stack dumps while serialising
    * against other CPUs
    */
retry:
   flags = disable_local_irqs();
   cpu = smp_processor_id();
   old = atomic_cmpxchg(&dump_lock, -1, cpu);
   if (old == -1) {
       was_locked = 0;
   } else if (old == cpu) {
       was_locked = 1;
   } else {
       restore_local_irqs(flags);
       /*
        * Wait for the lock to release before jumping to
        * atomic_cmpxchg() in order to mitigate the thundering herd
        * problem.
        */
       do { cpu_relax(); } while (atomic_read(&dump_lock) != -1);
       goto retry;
   }
 
   __dump_stack(log_lvl);
 
   if (!was_locked)
       atomic_set(&dump_lock, -1);
 
   restore_local_irqs(flags);
}
#else
asmlinkage __visible void dump_stack_lvl(const char *log_lvl)
{
   __dump_stack(log_lvl);
}
#endif
EXPORT_SYMBOL(dump_stack_lvl);
 
asmlinkage __visible void dump_stack(void)
{
   dump_stack_lvl(KERN_DEFAULT);
}
EXPORT_SYMBOL(dump_stack);