Skip to content

Commit 19f0423

Browse files
Huang Yiweirostedt
authored andcommitted
tracing: Support to dump instance traces by ftrace_dump_on_oops
Currently ftrace only dumps the global trace buffer on an OOPs. For debugging a production usecase, instance trace will be helpful to check specific problems since global trace buffer may be used for other purposes. This patch extend the ftrace_dump_on_oops parameter to dump a specific or multiple trace instances: - ftrace_dump_on_oops=0: as before -- don't dump - ftrace_dump_on_oops[=1]: as before -- dump the global trace buffer on all CPUs - ftrace_dump_on_oops=2 or =orig_cpu: as before -- dump the global trace buffer on CPU that triggered the oops - ftrace_dump_on_oops=<instance_name>: new behavior -- dump the tracing instance matching <instance_name> - ftrace_dump_on_oops[=2/orig_cpu],<instance1_name>[=2/orig_cpu], <instrance2_name>[=2/orig_cpu]: new behavior -- dump the global trace buffer and multiple instance buffer on all CPUs, or only dump on CPU that triggered the oops if =2 or =orig_cpu is given Also, the sysctl node can handle the input accordingly. Link: https://lore.kernel.org/linux-trace-kernel/[email protected] Cc: Ross Zwisler <[email protected]> Cc: <[email protected]> Cc: <[email protected]> Cc: <[email protected]> Cc: <[email protected]> Cc: <[email protected]> Cc: <[email protected]> Cc: <[email protected]> Signed-off-by: Huang Yiwei <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 0bdfb68 commit 19f0423

File tree

7 files changed

+168
-55
lines changed

7 files changed

+168
-55
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,12 +1572,28 @@
15721572
The above will cause the "foo" tracing instance to trigger
15731573
a snapshot at the end of boot up.
15741574

1575-
ftrace_dump_on_oops[=orig_cpu]
1575+
ftrace_dump_on_oops[=2(orig_cpu) | =<instance>][,<instance> |
1576+
,<instance>=2(orig_cpu)]
15761577
[FTRACE] will dump the trace buffers on oops.
1577-
If no parameter is passed, ftrace will dump
1578-
buffers of all CPUs, but if you pass orig_cpu, it will
1579-
dump only the buffer of the CPU that triggered the
1580-
oops.
1578+
If no parameter is passed, ftrace will dump global
1579+
buffers of all CPUs, if you pass 2 or orig_cpu, it
1580+
will dump only the buffer of the CPU that triggered
1581+
the oops, or the specific instance will be dumped if
1582+
its name is passed. Multiple instance dump is also
1583+
supported, and instances are separated by commas. Each
1584+
instance supports only dump on CPU that triggered the
1585+
oops by passing 2 or orig_cpu to it.
1586+
1587+
ftrace_dump_on_oops=foo=orig_cpu
1588+
1589+
The above will dump only the buffer of "foo" instance
1590+
on CPU that triggered the oops.
1591+
1592+
ftrace_dump_on_oops,foo,bar=orig_cpu
1593+
1594+
The above will dump global buffer on all CPUs, the
1595+
buffer of "foo" instance on all CPUs and the buffer
1596+
of "bar" instance on CPU that triggered the oops.
15811597

15821598
ftrace_filter=[function-list]
15831599
[FTRACE] Limit the functions traced by the function

Documentation/admin-guide/sysctl/kernel.rst

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,30 @@ kernel panic). This will output the contents of the ftrace buffers to
296296
the console. This is very useful for capturing traces that lead to
297297
crashes and outputting them to a serial console.
298298

299-
= ===================================================
300-
0 Disabled (default).
301-
1 Dump buffers of all CPUs.
302-
2 Dump the buffer of the CPU that triggered the oops.
303-
= ===================================================
304-
299+
======================= ===========================================
300+
0 Disabled (default).
301+
1 Dump buffers of all CPUs.
302+
2(orig_cpu) Dump the buffer of the CPU that triggered the
303+
oops.
304+
<instance> Dump the specific instance buffer on all CPUs.
305+
<instance>=2(orig_cpu) Dump the specific instance buffer on the CPU
306+
that triggered the oops.
307+
======================= ===========================================
308+
309+
Multiple instance dump is also supported, and instances are separated
310+
by commas. If global buffer also needs to be dumped, please specify
311+
the dump mode (1/2/orig_cpu) first for global buffer.
312+
313+
So for example to dump "foo" and "bar" instance buffer on all CPUs,
314+
user can::
315+
316+
echo "foo,bar" > /proc/sys/kernel/ftrace_dump_on_oops
317+
318+
To dump global buffer and "foo" instance buffer on all
319+
CPUs along with the "bar" instance buffer on CPU that triggered the
320+
oops, user can::
321+
322+
echo "1,foo,bar=2" > /proc/sys/kernel/ftrace_dump_on_oops
305323

306324
ftrace_enabled, stack_tracer_enabled
307325
====================================

include/linux/ftrace.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,9 @@ static inline void unpause_graph_tracing(void) { }
11511151
#ifdef CONFIG_TRACING
11521152
enum ftrace_dump_mode;
11531153

1154-
extern enum ftrace_dump_mode ftrace_dump_on_oops;
1154+
#define MAX_TRACER_SIZE 100
1155+
extern char ftrace_dump_on_oops[];
1156+
extern int ftrace_dump_on_oops_enabled(void);
11551157
extern int tracepoint_printk;
11561158

11571159
extern void disable_trace_on_warning(void);

include/linux/kernel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ enum ftrace_dump_mode {
215215
DUMP_NONE,
216216
DUMP_ALL,
217217
DUMP_ORIG,
218+
DUMP_PARAM,
218219
};
219220

220221
#ifdef CONFIG_TRACING

kernel/sysctl.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,9 +1710,9 @@ static struct ctl_table kern_table[] = {
17101710
{
17111711
.procname = "ftrace_dump_on_oops",
17121712
.data = &ftrace_dump_on_oops,
1713-
.maxlen = sizeof(int),
1713+
.maxlen = MAX_TRACER_SIZE,
17141714
.mode = 0644,
1715-
.proc_handler = proc_dointvec,
1715+
.proc_handler = proc_dostring,
17161716
},
17171717
{
17181718
.procname = "traceoff_on_warning",

kernel/trace/trace.c

Lines changed: 116 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,12 @@ cpumask_var_t __read_mostly tracing_buffer_mask;
130130
* /proc/sys/kernel/ftrace_dump_on_oops
131131
* Set 1 if you want to dump buffers of all CPUs
132132
* Set 2 if you want to dump the buffer of the CPU that triggered oops
133+
* Set instance name if you want to dump the specific trace instance
134+
* Multiple instance dump is also supported, and instances are seperated
135+
* by commas.
133136
*/
134-
135-
enum ftrace_dump_mode ftrace_dump_on_oops;
137+
/* Set to string format zero to disable by default */
138+
char ftrace_dump_on_oops[MAX_TRACER_SIZE] = "0";
136139

137140
/* When set, tracing will stop when a WARN*() is hit */
138141
int __disable_trace_on_warning;
@@ -178,7 +181,6 @@ static void ftrace_trace_userstack(struct trace_array *tr,
178181
struct trace_buffer *buffer,
179182
unsigned int trace_ctx);
180183

181-
#define MAX_TRACER_SIZE 100
182184
static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata;
183185
static char *default_bootup_tracer;
184186

@@ -201,19 +203,33 @@ static int __init set_cmdline_ftrace(char *str)
201203
}
202204
__setup("ftrace=", set_cmdline_ftrace);
203205

206+
int ftrace_dump_on_oops_enabled(void)
207+
{
208+
if (!strcmp("0", ftrace_dump_on_oops))
209+
return 0;
210+
else
211+
return 1;
212+
}
213+
204214
static int __init set_ftrace_dump_on_oops(char *str)
205215
{
206-
if (*str++ != '=' || !*str || !strcmp("1", str)) {
207-
ftrace_dump_on_oops = DUMP_ALL;
216+
if (!*str) {
217+
strscpy(ftrace_dump_on_oops, "1", MAX_TRACER_SIZE);
208218
return 1;
209219
}
210220

211-
if (!strcmp("orig_cpu", str) || !strcmp("2", str)) {
212-
ftrace_dump_on_oops = DUMP_ORIG;
213-
return 1;
214-
}
221+
if (*str == ',') {
222+
strscpy(ftrace_dump_on_oops, "1", MAX_TRACER_SIZE);
223+
strscpy(ftrace_dump_on_oops + 1, str, MAX_TRACER_SIZE - 1);
224+
return 1;
225+
}
226+
227+
if (*str++ == '=') {
228+
strscpy(ftrace_dump_on_oops, str, MAX_TRACER_SIZE);
229+
return 1;
230+
}
215231

216-
return 0;
232+
return 0;
217233
}
218234
__setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops);
219235

@@ -9832,14 +9848,14 @@ static struct notifier_block trace_die_notifier = {
98329848
static int trace_die_panic_handler(struct notifier_block *self,
98339849
unsigned long ev, void *unused)
98349850
{
9835-
if (!ftrace_dump_on_oops)
9851+
if (!ftrace_dump_on_oops_enabled())
98369852
return NOTIFY_DONE;
98379853

98389854
/* The die notifier requires DIE_OOPS to trigger */
98399855
if (self == &trace_die_notifier && ev != DIE_OOPS)
98409856
return NOTIFY_DONE;
98419857

9842-
ftrace_dump(ftrace_dump_on_oops);
9858+
ftrace_dump(DUMP_PARAM);
98439859

98449860
return NOTIFY_DONE;
98459861
}
@@ -9880,12 +9896,12 @@ trace_printk_seq(struct trace_seq *s)
98809896
trace_seq_init(s);
98819897
}
98829898

9883-
void trace_init_global_iter(struct trace_iterator *iter)
9899+
static void trace_init_iter(struct trace_iterator *iter, struct trace_array *tr)
98849900
{
9885-
iter->tr = &global_trace;
9901+
iter->tr = tr;
98869902
iter->trace = iter->tr->current_trace;
98879903
iter->cpu_file = RING_BUFFER_ALL_CPUS;
9888-
iter->array_buffer = &global_trace.array_buffer;
9904+
iter->array_buffer = &tr->array_buffer;
98899905

98909906
if (iter->trace && iter->trace->open)
98919907
iter->trace->open(iter);
@@ -9905,22 +9921,19 @@ void trace_init_global_iter(struct trace_iterator *iter)
99059921
iter->fmt_size = STATIC_FMT_BUF_SIZE;
99069922
}
99079923

9908-
void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
9924+
void trace_init_global_iter(struct trace_iterator *iter)
9925+
{
9926+
trace_init_iter(iter, &global_trace);
9927+
}
9928+
9929+
static void ftrace_dump_one(struct trace_array *tr, enum ftrace_dump_mode dump_mode)
99099930
{
99109931
/* use static because iter can be a bit big for the stack */
99119932
static struct trace_iterator iter;
9912-
static atomic_t dump_running;
9913-
struct trace_array *tr = &global_trace;
99149933
unsigned int old_userobj;
99159934
unsigned long flags;
99169935
int cnt = 0, cpu;
99179936

9918-
/* Only allow one dump user at a time. */
9919-
if (atomic_inc_return(&dump_running) != 1) {
9920-
atomic_dec(&dump_running);
9921-
return;
9922-
}
9923-
99249937
/*
99259938
* Always turn off tracing when we dump.
99269939
* We don't need to show trace output of what happens
@@ -9929,12 +9942,12 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
99299942
* If the user does a sysrq-z, then they can re-enable
99309943
* tracing with echo 1 > tracing_on.
99319944
*/
9932-
tracing_off();
9945+
tracer_tracing_off(tr);
99339946

99349947
local_irq_save(flags);
99359948

99369949
/* Simulate the iterator */
9937-
trace_init_global_iter(&iter);
9950+
trace_init_iter(&iter, tr);
99389951

99399952
for_each_tracing_cpu(cpu) {
99409953
atomic_inc(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled);
@@ -9945,21 +9958,15 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
99459958
/* don't look at user memory in panic mode */
99469959
tr->trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
99479960

9948-
switch (oops_dump_mode) {
9949-
case DUMP_ALL:
9950-
iter.cpu_file = RING_BUFFER_ALL_CPUS;
9951-
break;
9952-
case DUMP_ORIG:
9961+
if (dump_mode == DUMP_ORIG)
99539962
iter.cpu_file = raw_smp_processor_id();
9954-
break;
9955-
case DUMP_NONE:
9956-
goto out_enable;
9957-
default:
9958-
printk(KERN_TRACE "Bad dumping mode, switching to all CPUs dump\n");
9963+
else
99599964
iter.cpu_file = RING_BUFFER_ALL_CPUS;
9960-
}
99619965

9962-
printk(KERN_TRACE "Dumping ftrace buffer:\n");
9966+
if (tr == &global_trace)
9967+
printk(KERN_TRACE "Dumping ftrace buffer:\n");
9968+
else
9969+
printk(KERN_TRACE "Dumping ftrace instance %s buffer:\n", tr->name);
99639970

99649971
/* Did function tracer already get disabled? */
99659972
if (ftrace_is_dead()) {
@@ -10001,15 +10008,84 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
1000110008
else
1000210009
printk(KERN_TRACE "---------------------------------\n");
1000310010

10004-
out_enable:
1000510011
tr->trace_flags |= old_userobj;
1000610012

1000710013
for_each_tracing_cpu(cpu) {
1000810014
atomic_dec(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled);
1000910015
}
10010-
atomic_dec(&dump_running);
1001110016
local_irq_restore(flags);
1001210017
}
10018+
10019+
static void ftrace_dump_by_param(void)
10020+
{
10021+
bool first_param = true;
10022+
char dump_param[MAX_TRACER_SIZE];
10023+
char *buf, *token, *inst_name;
10024+
struct trace_array *tr;
10025+
10026+
strscpy(dump_param, ftrace_dump_on_oops, MAX_TRACER_SIZE);
10027+
buf = dump_param;
10028+
10029+
while ((token = strsep(&buf, ",")) != NULL) {
10030+
if (first_param) {
10031+
first_param = false;
10032+
if (!strcmp("0", token))
10033+
continue;
10034+
else if (!strcmp("1", token)) {
10035+
ftrace_dump_one(&global_trace, DUMP_ALL);
10036+
continue;
10037+
}
10038+
else if (!strcmp("2", token) ||
10039+
!strcmp("orig_cpu", token)) {
10040+
ftrace_dump_one(&global_trace, DUMP_ORIG);
10041+
continue;
10042+
}
10043+
}
10044+
10045+
inst_name = strsep(&token, "=");
10046+
tr = trace_array_find(inst_name);
10047+
if (!tr) {
10048+
printk(KERN_TRACE "Instance %s not found\n", inst_name);
10049+
continue;
10050+
}
10051+
10052+
if (token && (!strcmp("2", token) ||
10053+
!strcmp("orig_cpu", token)))
10054+
ftrace_dump_one(tr, DUMP_ORIG);
10055+
else
10056+
ftrace_dump_one(tr, DUMP_ALL);
10057+
}
10058+
}
10059+
10060+
void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
10061+
{
10062+
static atomic_t dump_running;
10063+
10064+
/* Only allow one dump user at a time. */
10065+
if (atomic_inc_return(&dump_running) != 1) {
10066+
atomic_dec(&dump_running);
10067+
return;
10068+
}
10069+
10070+
switch (oops_dump_mode) {
10071+
case DUMP_ALL:
10072+
ftrace_dump_one(&global_trace, DUMP_ALL);
10073+
break;
10074+
case DUMP_ORIG:
10075+
ftrace_dump_one(&global_trace, DUMP_ORIG);
10076+
break;
10077+
case DUMP_PARAM:
10078+
ftrace_dump_by_param();
10079+
break;
10080+
case DUMP_NONE:
10081+
break;
10082+
default:
10083+
printk(KERN_TRACE "Bad dumping mode, switching to all CPUs dump\n");
10084+
ftrace_dump_one(&global_trace, DUMP_ALL);
10085+
}
10086+
10087+
atomic_dec(&dump_running);
10088+
}
1001310089
EXPORT_SYMBOL_GPL(ftrace_dump);
1001410090

1001510091
#define WRITE_BUFSIZE 4096

kernel/trace/trace_selftest.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace)
768768
if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) {
769769
ftrace_graph_stop();
770770
printk(KERN_WARNING "BUG: Function graph tracer hang!\n");
771-
if (ftrace_dump_on_oops) {
771+
if (ftrace_dump_on_oops_enabled()) {
772772
ftrace_dump(DUMP_ALL);
773773
/* ftrace_dump() disables tracing */
774774
tracing_on();

0 commit comments

Comments
 (0)