diff options
-rw-r--r-- | kernel/trace/trace.c | 110 | ||||
-rw-r--r-- | kernel/trace/trace.h | 1 | ||||
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 122 | ||||
-rw-r--r-- | kernel/trace/trace_selftest.c | 1 |
4 files changed, 121 insertions, 113 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 1b73acb40e56..0cfd1a62def1 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -942,54 +942,6 @@ trace_function(struct trace_array *tr, | |||
942 | ring_buffer_unlock_commit(tr->buffer, event); | 942 | ring_buffer_unlock_commit(tr->buffer, event); |
943 | } | 943 | } |
944 | 944 | ||
945 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
946 | static int __trace_graph_entry(struct trace_array *tr, | ||
947 | struct ftrace_graph_ent *trace, | ||
948 | unsigned long flags, | ||
949 | int pc) | ||
950 | { | ||
951 | struct ftrace_event_call *call = &event_funcgraph_entry; | ||
952 | struct ring_buffer_event *event; | ||
953 | struct ftrace_graph_ent_entry *entry; | ||
954 | |||
955 | if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled)))) | ||
956 | return 0; | ||
957 | |||
958 | event = trace_buffer_lock_reserve(&global_trace, TRACE_GRAPH_ENT, | ||
959 | sizeof(*entry), flags, pc); | ||
960 | if (!event) | ||
961 | return 0; | ||
962 | entry = ring_buffer_event_data(event); | ||
963 | entry->graph_ent = *trace; | ||
964 | if (!filter_current_check_discard(call, entry, event)) | ||
965 | ring_buffer_unlock_commit(global_trace.buffer, event); | ||
966 | |||
967 | return 1; | ||
968 | } | ||
969 | |||
970 | static void __trace_graph_return(struct trace_array *tr, | ||
971 | struct ftrace_graph_ret *trace, | ||
972 | unsigned long flags, | ||
973 | int pc) | ||
974 | { | ||
975 | struct ftrace_event_call *call = &event_funcgraph_exit; | ||
976 | struct ring_buffer_event *event; | ||
977 | struct ftrace_graph_ret_entry *entry; | ||
978 | |||
979 | if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled)))) | ||
980 | return; | ||
981 | |||
982 | event = trace_buffer_lock_reserve(&global_trace, TRACE_GRAPH_RET, | ||
983 | sizeof(*entry), flags, pc); | ||
984 | if (!event) | ||
985 | return; | ||
986 | entry = ring_buffer_event_data(event); | ||
987 | entry->ret = *trace; | ||
988 | if (!filter_current_check_discard(call, entry, event)) | ||
989 | ring_buffer_unlock_commit(global_trace.buffer, event); | ||
990 | } | ||
991 | #endif | ||
992 | |||
993 | void | 945 | void |
994 | ftrace(struct trace_array *tr, struct trace_array_cpu *data, | 946 | ftrace(struct trace_array *tr, struct trace_array_cpu *data, |
995 | unsigned long ip, unsigned long parent_ip, unsigned long flags, | 947 | unsigned long ip, unsigned long parent_ip, unsigned long flags, |
@@ -1129,68 +1081,6 @@ ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) | |||
1129 | local_irq_restore(flags); | 1081 | local_irq_restore(flags); |
1130 | } | 1082 | } |
1131 | 1083 | ||
1132 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
1133 | int trace_graph_entry(struct ftrace_graph_ent *trace) | ||
1134 | { | ||
1135 | struct trace_array *tr = &global_trace; | ||
1136 | struct trace_array_cpu *data; | ||
1137 | unsigned long flags; | ||
1138 | long disabled; | ||
1139 | int ret; | ||
1140 | int cpu; | ||
1141 | int pc; | ||
1142 | |||
1143 | if (!ftrace_trace_task(current)) | ||
1144 | return 0; | ||
1145 | |||
1146 | if (!ftrace_graph_addr(trace->func)) | ||
1147 | return 0; | ||
1148 | |||
1149 | local_irq_save(flags); | ||
1150 | cpu = raw_smp_processor_id(); | ||
1151 | data = tr->data[cpu]; | ||
1152 | disabled = atomic_inc_return(&data->disabled); | ||
1153 | if (likely(disabled == 1)) { | ||
1154 | pc = preempt_count(); | ||
1155 | ret = __trace_graph_entry(tr, trace, flags, pc); | ||
1156 | } else { | ||
1157 | ret = 0; | ||
1158 | } | ||
1159 | /* Only do the atomic if it is not already set */ | ||
1160 | if (!test_tsk_trace_graph(current)) | ||
1161 | set_tsk_trace_graph(current); | ||
1162 | |||
1163 | atomic_dec(&data->disabled); | ||
1164 | local_irq_restore(flags); | ||
1165 | |||
1166 | return ret; | ||
1167 | } | ||
1168 | |||
1169 | void trace_graph_return(struct ftrace_graph_ret *trace) | ||
1170 | { | ||
1171 | struct trace_array *tr = &global_trace; | ||
1172 | struct trace_array_cpu *data; | ||
1173 | unsigned long flags; | ||
1174 | long disabled; | ||
1175 | int cpu; | ||
1176 | int pc; | ||
1177 | |||
1178 | local_irq_save(flags); | ||
1179 | cpu = raw_smp_processor_id(); | ||
1180 | data = tr->data[cpu]; | ||
1181 | disabled = atomic_inc_return(&data->disabled); | ||
1182 | if (likely(disabled == 1)) { | ||
1183 | pc = preempt_count(); | ||
1184 | __trace_graph_return(tr, trace, flags, pc); | ||
1185 | } | ||
1186 | if (!trace->depth) | ||
1187 | clear_tsk_trace_graph(current); | ||
1188 | atomic_dec(&data->disabled); | ||
1189 | local_irq_restore(flags); | ||
1190 | } | ||
1191 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
1192 | |||
1193 | |||
1194 | /** | 1084 | /** |
1195 | * trace_vbprintk - write binary msg to tracing buffer | 1085 | * trace_vbprintk - write binary msg to tracing buffer |
1196 | * | 1086 | * |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 116524d62366..9301f1263c5c 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -471,6 +471,7 @@ void trace_function(struct trace_array *tr, | |||
471 | 471 | ||
472 | void trace_graph_return(struct ftrace_graph_ret *trace); | 472 | void trace_graph_return(struct ftrace_graph_ret *trace); |
473 | int trace_graph_entry(struct ftrace_graph_ent *trace); | 473 | int trace_graph_entry(struct ftrace_graph_ent *trace); |
474 | void set_graph_array(struct trace_array *tr); | ||
474 | 475 | ||
475 | void tracing_start_cmdline_record(void); | 476 | void tracing_start_cmdline_record(void); |
476 | void tracing_stop_cmdline_record(void); | 477 | void tracing_stop_cmdline_record(void); |
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index e30472da15d5..f97244a41a4f 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -52,7 +52,7 @@ static struct tracer_flags tracer_flags = { | |||
52 | .opts = trace_opts | 52 | .opts = trace_opts |
53 | }; | 53 | }; |
54 | 54 | ||
55 | /* pid on the last trace processed */ | 55 | static struct trace_array *graph_array; |
56 | 56 | ||
57 | 57 | ||
58 | /* Add a function return address to the trace stack on thread info.*/ | 58 | /* Add a function return address to the trace stack on thread info.*/ |
@@ -166,10 +166,121 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer) | |||
166 | return ret; | 166 | return ret; |
167 | } | 167 | } |
168 | 168 | ||
169 | static int __trace_graph_entry(struct trace_array *tr, | ||
170 | struct ftrace_graph_ent *trace, | ||
171 | unsigned long flags, | ||
172 | int pc) | ||
173 | { | ||
174 | struct ftrace_event_call *call = &event_funcgraph_entry; | ||
175 | struct ring_buffer_event *event; | ||
176 | struct ftrace_graph_ent_entry *entry; | ||
177 | |||
178 | if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled)))) | ||
179 | return 0; | ||
180 | |||
181 | event = trace_buffer_lock_reserve(tr, TRACE_GRAPH_ENT, | ||
182 | sizeof(*entry), flags, pc); | ||
183 | if (!event) | ||
184 | return 0; | ||
185 | entry = ring_buffer_event_data(event); | ||
186 | entry->graph_ent = *trace; | ||
187 | if (!filter_current_check_discard(call, entry, event)) | ||
188 | ring_buffer_unlock_commit(tr->buffer, event); | ||
189 | |||
190 | return 1; | ||
191 | } | ||
192 | |||
193 | int trace_graph_entry(struct ftrace_graph_ent *trace) | ||
194 | { | ||
195 | struct trace_array *tr = graph_array; | ||
196 | struct trace_array_cpu *data; | ||
197 | unsigned long flags; | ||
198 | long disabled; | ||
199 | int ret; | ||
200 | int cpu; | ||
201 | int pc; | ||
202 | |||
203 | if (unlikely(!tr)) | ||
204 | return 0; | ||
205 | |||
206 | if (!ftrace_trace_task(current)) | ||
207 | return 0; | ||
208 | |||
209 | if (!ftrace_graph_addr(trace->func)) | ||
210 | return 0; | ||
211 | |||
212 | local_irq_save(flags); | ||
213 | cpu = raw_smp_processor_id(); | ||
214 | data = tr->data[cpu]; | ||
215 | disabled = atomic_inc_return(&data->disabled); | ||
216 | if (likely(disabled == 1)) { | ||
217 | pc = preempt_count(); | ||
218 | ret = __trace_graph_entry(tr, trace, flags, pc); | ||
219 | } else { | ||
220 | ret = 0; | ||
221 | } | ||
222 | /* Only do the atomic if it is not already set */ | ||
223 | if (!test_tsk_trace_graph(current)) | ||
224 | set_tsk_trace_graph(current); | ||
225 | |||
226 | atomic_dec(&data->disabled); | ||
227 | local_irq_restore(flags); | ||
228 | |||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | static void __trace_graph_return(struct trace_array *tr, | ||
233 | struct ftrace_graph_ret *trace, | ||
234 | unsigned long flags, | ||
235 | int pc) | ||
236 | { | ||
237 | struct ftrace_event_call *call = &event_funcgraph_exit; | ||
238 | struct ring_buffer_event *event; | ||
239 | struct ftrace_graph_ret_entry *entry; | ||
240 | |||
241 | if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled)))) | ||
242 | return; | ||
243 | |||
244 | event = trace_buffer_lock_reserve(tr, TRACE_GRAPH_RET, | ||
245 | sizeof(*entry), flags, pc); | ||
246 | if (!event) | ||
247 | return; | ||
248 | entry = ring_buffer_event_data(event); | ||
249 | entry->ret = *trace; | ||
250 | if (!filter_current_check_discard(call, entry, event)) | ||
251 | ring_buffer_unlock_commit(tr->buffer, event); | ||
252 | } | ||
253 | |||
254 | void trace_graph_return(struct ftrace_graph_ret *trace) | ||
255 | { | ||
256 | struct trace_array *tr = graph_array; | ||
257 | struct trace_array_cpu *data; | ||
258 | unsigned long flags; | ||
259 | long disabled; | ||
260 | int cpu; | ||
261 | int pc; | ||
262 | |||
263 | local_irq_save(flags); | ||
264 | cpu = raw_smp_processor_id(); | ||
265 | data = tr->data[cpu]; | ||
266 | disabled = atomic_inc_return(&data->disabled); | ||
267 | if (likely(disabled == 1)) { | ||
268 | pc = preempt_count(); | ||
269 | __trace_graph_return(tr, trace, flags, pc); | ||
270 | } | ||
271 | if (!trace->depth) | ||
272 | clear_tsk_trace_graph(current); | ||
273 | atomic_dec(&data->disabled); | ||
274 | local_irq_restore(flags); | ||
275 | } | ||
276 | |||
169 | static int graph_trace_init(struct trace_array *tr) | 277 | static int graph_trace_init(struct trace_array *tr) |
170 | { | 278 | { |
171 | int ret = register_ftrace_graph(&trace_graph_return, | 279 | int ret; |
172 | &trace_graph_entry); | 280 | |
281 | graph_array = tr; | ||
282 | ret = register_ftrace_graph(&trace_graph_return, | ||
283 | &trace_graph_entry); | ||
173 | if (ret) | 284 | if (ret) |
174 | return ret; | 285 | return ret; |
175 | tracing_start_cmdline_record(); | 286 | tracing_start_cmdline_record(); |
@@ -177,6 +288,11 @@ static int graph_trace_init(struct trace_array *tr) | |||
177 | return 0; | 288 | return 0; |
178 | } | 289 | } |
179 | 290 | ||
291 | void set_graph_array(struct trace_array *tr) | ||
292 | { | ||
293 | graph_array = tr; | ||
294 | } | ||
295 | |||
180 | static void graph_trace_reset(struct trace_array *tr) | 296 | static void graph_trace_reset(struct trace_array *tr) |
181 | { | 297 | { |
182 | tracing_stop_cmdline_record(); | 298 | tracing_stop_cmdline_record(); |
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 00dd6485bdd7..d2cdbabb4ead 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c | |||
@@ -288,6 +288,7 @@ trace_selftest_startup_function_graph(struct tracer *trace, | |||
288 | * to detect and recover from possible hangs | 288 | * to detect and recover from possible hangs |
289 | */ | 289 | */ |
290 | tracing_reset_online_cpus(tr); | 290 | tracing_reset_online_cpus(tr); |
291 | set_graph_array(tr); | ||
291 | ret = register_ftrace_graph(&trace_graph_return, | 292 | ret = register_ftrace_graph(&trace_graph_return, |
292 | &trace_graph_entry_watchdog); | 293 | &trace_graph_entry_watchdog); |
293 | if (ret) { | 294 | if (ret) { |