aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_functions.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace_functions.c')
-rw-r--r--kernel/trace/trace_functions.c147
1 files changed, 106 insertions, 41 deletions
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 38fe1483c508..ffd56351b521 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -13,32 +13,110 @@
13#include <linux/debugfs.h> 13#include <linux/debugfs.h>
14#include <linux/uaccess.h> 14#include <linux/uaccess.h>
15#include <linux/ftrace.h> 15#include <linux/ftrace.h>
16#include <linux/slab.h>
16#include <linux/fs.h> 17#include <linux/fs.h>
17 18
18#include "trace.h" 19#include "trace.h"
19 20
20/* function tracing enabled */ 21static void tracing_start_function_trace(struct trace_array *tr);
21static int ftrace_function_enabled; 22static void tracing_stop_function_trace(struct trace_array *tr);
23static void
24function_trace_call(unsigned long ip, unsigned long parent_ip,
25 struct ftrace_ops *op, struct pt_regs *pt_regs);
26static void
27function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
28 struct ftrace_ops *op, struct pt_regs *pt_regs);
29static struct ftrace_ops trace_ops;
30static struct ftrace_ops trace_stack_ops;
31static struct tracer_flags func_flags;
32
33/* Our option */
34enum {
35 TRACE_FUNC_OPT_STACK = 0x1,
36};
37
38static int allocate_ftrace_ops(struct trace_array *tr)
39{
40 struct ftrace_ops *ops;
41
42 ops = kzalloc(sizeof(*ops), GFP_KERNEL);
43 if (!ops)
44 return -ENOMEM;
45
46 /* Currently only the non stack verision is supported */
47 ops->func = function_trace_call;
48 ops->flags = FTRACE_OPS_FL_RECURSION_SAFE;
22 49
23static struct trace_array *func_trace; 50 tr->ops = ops;
51 ops->private = tr;
52 return 0;
53}
54
55
56int ftrace_create_function_files(struct trace_array *tr,
57 struct dentry *parent)
58{
59 int ret;
60
61 /*
62 * The top level array uses the "global_ops", and the files are
63 * created on boot up.
64 */
65 if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
66 return 0;
24 67
25static void tracing_start_function_trace(void); 68 ret = allocate_ftrace_ops(tr);
26static void tracing_stop_function_trace(void); 69 if (ret)
70 return ret;
71
72 ftrace_create_filter_files(tr->ops, parent);
73
74 return 0;
75}
76
77void ftrace_destroy_function_files(struct trace_array *tr)
78{
79 ftrace_destroy_filter_files(tr->ops);
80 kfree(tr->ops);
81 tr->ops = NULL;
82}
27 83
28static int function_trace_init(struct trace_array *tr) 84static int function_trace_init(struct trace_array *tr)
29{ 85{
30 func_trace = tr; 86 struct ftrace_ops *ops;
87
88 if (tr->flags & TRACE_ARRAY_FL_GLOBAL) {
89 /* There's only one global tr */
90 if (!trace_ops.private) {
91 trace_ops.private = tr;
92 trace_stack_ops.private = tr;
93 }
94
95 if (func_flags.val & TRACE_FUNC_OPT_STACK)
96 ops = &trace_stack_ops;
97 else
98 ops = &trace_ops;
99 tr->ops = ops;
100 } else if (!tr->ops) {
101 /*
102 * Instance trace_arrays get their ops allocated
103 * at instance creation. Unless it failed
104 * the allocation.
105 */
106 return -ENOMEM;
107 }
108
31 tr->trace_buffer.cpu = get_cpu(); 109 tr->trace_buffer.cpu = get_cpu();
32 put_cpu(); 110 put_cpu();
33 111
34 tracing_start_cmdline_record(); 112 tracing_start_cmdline_record();
35 tracing_start_function_trace(); 113 tracing_start_function_trace(tr);
36 return 0; 114 return 0;
37} 115}
38 116
39static void function_trace_reset(struct trace_array *tr) 117static void function_trace_reset(struct trace_array *tr)
40{ 118{
41 tracing_stop_function_trace(); 119 tracing_stop_function_trace(tr);
42 tracing_stop_cmdline_record(); 120 tracing_stop_cmdline_record();
43} 121}
44 122
@@ -47,25 +125,18 @@ static void function_trace_start(struct trace_array *tr)
47 tracing_reset_online_cpus(&tr->trace_buffer); 125 tracing_reset_online_cpus(&tr->trace_buffer);
48} 126}
49 127
50/* Our option */
51enum {
52 TRACE_FUNC_OPT_STACK = 0x1,
53};
54
55static struct tracer_flags func_flags;
56
57static void 128static void
58function_trace_call(unsigned long ip, unsigned long parent_ip, 129function_trace_call(unsigned long ip, unsigned long parent_ip,
59 struct ftrace_ops *op, struct pt_regs *pt_regs) 130 struct ftrace_ops *op, struct pt_regs *pt_regs)
60{ 131{
61 struct trace_array *tr = func_trace; 132 struct trace_array *tr = op->private;
62 struct trace_array_cpu *data; 133 struct trace_array_cpu *data;
63 unsigned long flags; 134 unsigned long flags;
64 int bit; 135 int bit;
65 int cpu; 136 int cpu;
66 int pc; 137 int pc;
67 138
68 if (unlikely(!ftrace_function_enabled)) 139 if (unlikely(!tr->function_enabled))
69 return; 140 return;
70 141
71 pc = preempt_count(); 142 pc = preempt_count();
@@ -91,14 +162,14 @@ static void
91function_stack_trace_call(unsigned long ip, unsigned long parent_ip, 162function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
92 struct ftrace_ops *op, struct pt_regs *pt_regs) 163 struct ftrace_ops *op, struct pt_regs *pt_regs)
93{ 164{
94 struct trace_array *tr = func_trace; 165 struct trace_array *tr = op->private;
95 struct trace_array_cpu *data; 166 struct trace_array_cpu *data;
96 unsigned long flags; 167 unsigned long flags;
97 long disabled; 168 long disabled;
98 int cpu; 169 int cpu;
99 int pc; 170 int pc;
100 171
101 if (unlikely(!ftrace_function_enabled)) 172 if (unlikely(!tr->function_enabled))
102 return; 173 return;
103 174
104 /* 175 /*
@@ -128,7 +199,6 @@ function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
128 local_irq_restore(flags); 199 local_irq_restore(flags);
129} 200}
130 201
131
132static struct ftrace_ops trace_ops __read_mostly = 202static struct ftrace_ops trace_ops __read_mostly =
133{ 203{
134 .func = function_trace_call, 204 .func = function_trace_call,
@@ -153,29 +223,21 @@ static struct tracer_flags func_flags = {
153 .opts = func_opts 223 .opts = func_opts
154}; 224};
155 225
156static void tracing_start_function_trace(void) 226static void tracing_start_function_trace(struct trace_array *tr)
157{ 227{
158 ftrace_function_enabled = 0; 228 tr->function_enabled = 0;
159 229 register_ftrace_function(tr->ops);
160 if (func_flags.val & TRACE_FUNC_OPT_STACK) 230 tr->function_enabled = 1;
161 register_ftrace_function(&trace_stack_ops);
162 else
163 register_ftrace_function(&trace_ops);
164
165 ftrace_function_enabled = 1;
166} 231}
167 232
168static void tracing_stop_function_trace(void) 233static void tracing_stop_function_trace(struct trace_array *tr)
169{ 234{
170 ftrace_function_enabled = 0; 235 tr->function_enabled = 0;
171 236 unregister_ftrace_function(tr->ops);
172 if (func_flags.val & TRACE_FUNC_OPT_STACK)
173 unregister_ftrace_function(&trace_stack_ops);
174 else
175 unregister_ftrace_function(&trace_ops);
176} 237}
177 238
178static int func_set_flag(u32 old_flags, u32 bit, int set) 239static int
240func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
179{ 241{
180 switch (bit) { 242 switch (bit) {
181 case TRACE_FUNC_OPT_STACK: 243 case TRACE_FUNC_OPT_STACK:
@@ -183,12 +245,14 @@ static int func_set_flag(u32 old_flags, u32 bit, int set)
183 if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK)) 245 if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK))
184 break; 246 break;
185 247
248 unregister_ftrace_function(tr->ops);
249
186 if (set) { 250 if (set) {
187 unregister_ftrace_function(&trace_ops); 251 tr->ops = &trace_stack_ops;
188 register_ftrace_function(&trace_stack_ops); 252 register_ftrace_function(tr->ops);
189 } else { 253 } else {
190 unregister_ftrace_function(&trace_stack_ops); 254 tr->ops = &trace_ops;
191 register_ftrace_function(&trace_ops); 255 register_ftrace_function(tr->ops);
192 } 256 }
193 257
194 break; 258 break;
@@ -208,6 +272,7 @@ static struct tracer function_trace __tracer_data =
208 .wait_pipe = poll_wait_pipe, 272 .wait_pipe = poll_wait_pipe,
209 .flags = &func_flags, 273 .flags = &func_flags,
210 .set_flag = func_set_flag, 274 .set_flag = func_set_flag,
275 .allow_instances = true,
211#ifdef CONFIG_FTRACE_SELFTEST 276#ifdef CONFIG_FTRACE_SELFTEST
212 .selftest = trace_selftest_startup_function, 277 .selftest = trace_selftest_startup_function,
213#endif 278#endif