diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 80 |
1 files changed, 71 insertions, 9 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 4edb4b74eb7e..8388bc99f2ee 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -47,6 +47,8 @@ struct fgraph_data { | |||
47 | #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 | 47 | #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 |
48 | #define TRACE_GRAPH_PRINT_IRQS 0x40 | 48 | #define TRACE_GRAPH_PRINT_IRQS 0x40 |
49 | 49 | ||
50 | static unsigned int max_depth; | ||
51 | |||
50 | static struct tracer_opt trace_opts[] = { | 52 | static struct tracer_opt trace_opts[] = { |
51 | /* Display overruns? (for self-debug purpose) */ | 53 | /* Display overruns? (for self-debug purpose) */ |
52 | { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) }, | 54 | { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) }, |
@@ -189,10 +191,16 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer) | |||
189 | 191 | ||
190 | ftrace_pop_return_trace(&trace, &ret, frame_pointer); | 192 | ftrace_pop_return_trace(&trace, &ret, frame_pointer); |
191 | trace.rettime = trace_clock_local(); | 193 | trace.rettime = trace_clock_local(); |
192 | ftrace_graph_return(&trace); | ||
193 | barrier(); | 194 | barrier(); |
194 | current->curr_ret_stack--; | 195 | current->curr_ret_stack--; |
195 | 196 | ||
197 | /* | ||
198 | * The trace should run after decrementing the ret counter | ||
199 | * in case an interrupt were to come in. We don't want to | ||
200 | * lose the interrupt if max_depth is set. | ||
201 | */ | ||
202 | ftrace_graph_return(&trace); | ||
203 | |||
196 | if (unlikely(!ret)) { | 204 | if (unlikely(!ret)) { |
197 | ftrace_graph_stop(); | 205 | ftrace_graph_stop(); |
198 | WARN_ON(1); | 206 | WARN_ON(1); |
@@ -210,7 +218,7 @@ int __trace_graph_entry(struct trace_array *tr, | |||
210 | { | 218 | { |
211 | struct ftrace_event_call *call = &event_funcgraph_entry; | 219 | struct ftrace_event_call *call = &event_funcgraph_entry; |
212 | struct ring_buffer_event *event; | 220 | struct ring_buffer_event *event; |
213 | struct ring_buffer *buffer = tr->buffer; | 221 | struct ring_buffer *buffer = tr->trace_buffer.buffer; |
214 | struct ftrace_graph_ent_entry *entry; | 222 | struct ftrace_graph_ent_entry *entry; |
215 | 223 | ||
216 | if (unlikely(__this_cpu_read(ftrace_cpu_disabled))) | 224 | if (unlikely(__this_cpu_read(ftrace_cpu_disabled))) |
@@ -250,13 +258,14 @@ int trace_graph_entry(struct ftrace_graph_ent *trace) | |||
250 | return 0; | 258 | return 0; |
251 | 259 | ||
252 | /* trace it when it is-nested-in or is a function enabled. */ | 260 | /* trace it when it is-nested-in or is a function enabled. */ |
253 | if (!(trace->depth || ftrace_graph_addr(trace->func)) || | 261 | if ((!(trace->depth || ftrace_graph_addr(trace->func)) || |
254 | ftrace_graph_ignore_irqs()) | 262 | ftrace_graph_ignore_irqs()) || |
263 | (max_depth && trace->depth >= max_depth)) | ||
255 | return 0; | 264 | return 0; |
256 | 265 | ||
257 | local_irq_save(flags); | 266 | local_irq_save(flags); |
258 | cpu = raw_smp_processor_id(); | 267 | cpu = raw_smp_processor_id(); |
259 | data = tr->data[cpu]; | 268 | data = per_cpu_ptr(tr->trace_buffer.data, cpu); |
260 | disabled = atomic_inc_return(&data->disabled); | 269 | disabled = atomic_inc_return(&data->disabled); |
261 | if (likely(disabled == 1)) { | 270 | if (likely(disabled == 1)) { |
262 | pc = preempt_count(); | 271 | pc = preempt_count(); |
@@ -314,7 +323,7 @@ void __trace_graph_return(struct trace_array *tr, | |||
314 | { | 323 | { |
315 | struct ftrace_event_call *call = &event_funcgraph_exit; | 324 | struct ftrace_event_call *call = &event_funcgraph_exit; |
316 | struct ring_buffer_event *event; | 325 | struct ring_buffer_event *event; |
317 | struct ring_buffer *buffer = tr->buffer; | 326 | struct ring_buffer *buffer = tr->trace_buffer.buffer; |
318 | struct ftrace_graph_ret_entry *entry; | 327 | struct ftrace_graph_ret_entry *entry; |
319 | 328 | ||
320 | if (unlikely(__this_cpu_read(ftrace_cpu_disabled))) | 329 | if (unlikely(__this_cpu_read(ftrace_cpu_disabled))) |
@@ -341,7 +350,7 @@ void trace_graph_return(struct ftrace_graph_ret *trace) | |||
341 | 350 | ||
342 | local_irq_save(flags); | 351 | local_irq_save(flags); |
343 | cpu = raw_smp_processor_id(); | 352 | cpu = raw_smp_processor_id(); |
344 | data = tr->data[cpu]; | 353 | data = per_cpu_ptr(tr->trace_buffer.data, cpu); |
345 | disabled = atomic_inc_return(&data->disabled); | 354 | disabled = atomic_inc_return(&data->disabled); |
346 | if (likely(disabled == 1)) { | 355 | if (likely(disabled == 1)) { |
347 | pc = preempt_count(); | 356 | pc = preempt_count(); |
@@ -551,9 +560,9 @@ get_return_for_leaf(struct trace_iterator *iter, | |||
551 | * We need to consume the current entry to see | 560 | * We need to consume the current entry to see |
552 | * the next one. | 561 | * the next one. |
553 | */ | 562 | */ |
554 | ring_buffer_consume(iter->tr->buffer, iter->cpu, | 563 | ring_buffer_consume(iter->trace_buffer->buffer, iter->cpu, |
555 | NULL, NULL); | 564 | NULL, NULL); |
556 | event = ring_buffer_peek(iter->tr->buffer, iter->cpu, | 565 | event = ring_buffer_peek(iter->trace_buffer->buffer, iter->cpu, |
557 | NULL, NULL); | 566 | NULL, NULL); |
558 | } | 567 | } |
559 | 568 | ||
@@ -1457,6 +1466,59 @@ static struct tracer graph_trace __read_mostly = { | |||
1457 | #endif | 1466 | #endif |
1458 | }; | 1467 | }; |
1459 | 1468 | ||
1469 | |||
1470 | static ssize_t | ||
1471 | graph_depth_write(struct file *filp, const char __user *ubuf, size_t cnt, | ||
1472 | loff_t *ppos) | ||
1473 | { | ||
1474 | unsigned long val; | ||
1475 | int ret; | ||
1476 | |||
1477 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); | ||
1478 | if (ret) | ||
1479 | return ret; | ||
1480 | |||
1481 | max_depth = val; | ||
1482 | |||
1483 | *ppos += cnt; | ||
1484 | |||
1485 | return cnt; | ||
1486 | } | ||
1487 | |||
1488 | static ssize_t | ||
1489 | graph_depth_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
1490 | loff_t *ppos) | ||
1491 | { | ||
1492 | char buf[15]; /* More than enough to hold UINT_MAX + "\n"*/ | ||
1493 | int n; | ||
1494 | |||
1495 | n = sprintf(buf, "%d\n", max_depth); | ||
1496 | |||
1497 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, n); | ||
1498 | } | ||
1499 | |||
1500 | static const struct file_operations graph_depth_fops = { | ||
1501 | .open = tracing_open_generic, | ||
1502 | .write = graph_depth_write, | ||
1503 | .read = graph_depth_read, | ||
1504 | .llseek = generic_file_llseek, | ||
1505 | }; | ||
1506 | |||
1507 | static __init int init_graph_debugfs(void) | ||
1508 | { | ||
1509 | struct dentry *d_tracer; | ||
1510 | |||
1511 | d_tracer = tracing_init_dentry(); | ||
1512 | if (!d_tracer) | ||
1513 | return 0; | ||
1514 | |||
1515 | trace_create_file("max_graph_depth", 0644, d_tracer, | ||
1516 | NULL, &graph_depth_fops); | ||
1517 | |||
1518 | return 0; | ||
1519 | } | ||
1520 | fs_initcall(init_graph_debugfs); | ||
1521 | |||
1460 | static __init int init_graph_trace(void) | 1522 | static __init int init_graph_trace(void) |
1461 | { | 1523 | { |
1462 | max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1); | 1524 | max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1); |