diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 68 |
1 files changed, 65 insertions, 3 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 4edb4b74eb7e..39ada66389cc 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); |
@@ -250,8 +258,9 @@ 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); |
@@ -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); |