diff options
author | Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> | 2010-01-27 20:32:29 -0500 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2010-01-28 20:02:57 -0500 |
commit | 430ad5a600a83956749307b13257c464c3826b55 (patch) | |
tree | 9cd3dd3f54e29397ff303478de9fe6902f675b9b | |
parent | 339ce1a4dc2ca26444c4f65c31b71a5056f3bb0b (diff) |
perf: Factorize trace events raw sample buffer operations
Introduce ftrace_perf_buf_prepare() and ftrace_perf_buf_submit() to
gather the common code that operates on raw events sampling buffer.
This cleans up redundant code between regular trace events, syscall
events and kprobe events.
Changelog v1->v2:
- Rename function name as per Masami and Frederic's suggestion
- Add __kprobes for ftrace_perf_buf_prepare() and make
ftrace_perf_buf_submit() inline as per Masami's suggestion
- Export ftrace_perf_buf_prepare since modules will use it
Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
Acked-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Jason Baron <jbaron@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
LKML-Reference: <4B60E92D.9000808@cn.fujitsu.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
-rw-r--r-- | include/linux/ftrace_event.h | 18 | ||||
-rw-r--r-- | include/trace/ftrace.h | 48 | ||||
-rw-r--r-- | kernel/trace/trace_event_profile.c | 52 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 86 | ||||
-rw-r--r-- | kernel/trace/trace_syscalls.c | 71 |
5 files changed, 88 insertions, 187 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 0a09e758c7d3..cd95919d9ff3 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/trace_seq.h> | 5 | #include <linux/trace_seq.h> |
6 | #include <linux/percpu.h> | 6 | #include <linux/percpu.h> |
7 | #include <linux/hardirq.h> | 7 | #include <linux/hardirq.h> |
8 | #include <linux/perf_event.h> | ||
8 | 9 | ||
9 | struct trace_array; | 10 | struct trace_array; |
10 | struct tracer; | 11 | struct tracer; |
@@ -138,9 +139,6 @@ struct ftrace_event_call { | |||
138 | 139 | ||
139 | #define FTRACE_MAX_PROFILE_SIZE 2048 | 140 | #define FTRACE_MAX_PROFILE_SIZE 2048 |
140 | 141 | ||
141 | extern char *perf_trace_buf; | ||
142 | extern char *perf_trace_buf_nmi; | ||
143 | |||
144 | #define MAX_FILTER_PRED 32 | 142 | #define MAX_FILTER_PRED 32 |
145 | #define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ | 143 | #define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ |
146 | 144 | ||
@@ -195,6 +193,20 @@ extern void ftrace_profile_disable(int event_id); | |||
195 | extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, | 193 | extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, |
196 | char *filter_str); | 194 | char *filter_str); |
197 | extern void ftrace_profile_free_filter(struct perf_event *event); | 195 | extern void ftrace_profile_free_filter(struct perf_event *event); |
196 | extern void * | ||
197 | ftrace_perf_buf_prepare(int size, unsigned short type, int *rctxp, | ||
198 | unsigned long *irq_flags); | ||
199 | |||
200 | static inline void | ||
201 | ftrace_perf_buf_submit(void *raw_data, int size, int rctx, u64 addr, | ||
202 | u64 count, unsigned long irq_flags) | ||
203 | { | ||
204 | struct trace_entry *entry = raw_data; | ||
205 | |||
206 | perf_tp_event(entry->type, addr, count, raw_data, size); | ||
207 | perf_swevent_put_recursion_context(rctx); | ||
208 | local_irq_restore(irq_flags); | ||
209 | } | ||
198 | #endif | 210 | #endif |
199 | 211 | ||
200 | #endif /* _LINUX_FTRACE_EVENT_H */ | 212 | #endif /* _LINUX_FTRACE_EVENT_H */ |
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 4a46a60c2077..f2c09e4d656c 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -850,22 +850,12 @@ ftrace_profile_templ_##call(struct ftrace_event_call *event_call, \ | |||
850 | proto) \ | 850 | proto) \ |
851 | { \ | 851 | { \ |
852 | struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ | 852 | struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ |
853 | extern int perf_swevent_get_recursion_context(void); \ | ||
854 | extern void perf_swevent_put_recursion_context(int rctx); \ | ||
855 | extern void perf_tp_event(int, u64, u64, void *, int); \ | ||
856 | struct ftrace_raw_##call *entry; \ | 853 | struct ftrace_raw_##call *entry; \ |
857 | u64 __addr = 0, __count = 1; \ | 854 | u64 __addr = 0, __count = 1; \ |
858 | unsigned long irq_flags; \ | 855 | unsigned long irq_flags; \ |
859 | struct trace_entry *ent; \ | ||
860 | int __entry_size; \ | 856 | int __entry_size; \ |
861 | int __data_size; \ | 857 | int __data_size; \ |
862 | char *trace_buf; \ | ||
863 | char *raw_data; \ | ||
864 | int __cpu; \ | ||
865 | int rctx; \ | 858 | int rctx; \ |
866 | int pc; \ | ||
867 | \ | ||
868 | pc = preempt_count(); \ | ||
869 | \ | 859 | \ |
870 | __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ | 860 | __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ |
871 | __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\ | 861 | __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\ |
@@ -875,42 +865,16 @@ ftrace_profile_templ_##call(struct ftrace_event_call *event_call, \ | |||
875 | if (WARN_ONCE(__entry_size > FTRACE_MAX_PROFILE_SIZE, \ | 865 | if (WARN_ONCE(__entry_size > FTRACE_MAX_PROFILE_SIZE, \ |
876 | "profile buffer not large enough")) \ | 866 | "profile buffer not large enough")) \ |
877 | return; \ | 867 | return; \ |
878 | \ | 868 | entry = (struct ftrace_raw_##call *)ftrace_perf_buf_prepare( \ |
879 | local_irq_save(irq_flags); \ | 869 | __entry_size, event_call->id, &rctx, &irq_flags); \ |
880 | \ | 870 | if (!entry) \ |
881 | rctx = perf_swevent_get_recursion_context(); \ | 871 | return; \ |
882 | if (rctx < 0) \ | ||
883 | goto end_recursion; \ | ||
884 | \ | ||
885 | __cpu = smp_processor_id(); \ | ||
886 | \ | ||
887 | if (in_nmi()) \ | ||
888 | trace_buf = rcu_dereference(perf_trace_buf_nmi); \ | ||
889 | else \ | ||
890 | trace_buf = rcu_dereference(perf_trace_buf); \ | ||
891 | \ | ||
892 | if (!trace_buf) \ | ||
893 | goto end; \ | ||
894 | \ | ||
895 | raw_data = per_cpu_ptr(trace_buf, __cpu); \ | ||
896 | \ | ||
897 | *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \ | ||
898 | entry = (struct ftrace_raw_##call *)raw_data; \ | ||
899 | ent = &entry->ent; \ | ||
900 | tracing_generic_entry_update(ent, irq_flags, pc); \ | ||
901 | ent->type = event_call->id; \ | ||
902 | \ | ||
903 | tstruct \ | 872 | tstruct \ |
904 | \ | 873 | \ |
905 | { assign; } \ | 874 | { assign; } \ |
906 | \ | 875 | \ |
907 | perf_tp_event(event_call->id, __addr, __count, entry, \ | 876 | ftrace_perf_buf_submit(entry, __entry_size, rctx, __addr, \ |
908 | __entry_size); \ | 877 | __count, irq_flags); \ |
909 | \ | ||
910 | end: \ | ||
911 | perf_swevent_put_recursion_context(rctx); \ | ||
912 | end_recursion: \ | ||
913 | local_irq_restore(irq_flags); \ | ||
914 | } | 878 | } |
915 | 879 | ||
916 | #undef DEFINE_EVENT | 880 | #undef DEFINE_EVENT |
diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c index 9e25573242cf..f0d693005075 100644 --- a/kernel/trace/trace_event_profile.c +++ b/kernel/trace/trace_event_profile.c | |||
@@ -6,14 +6,12 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/kprobes.h> | ||
9 | #include "trace.h" | 10 | #include "trace.h" |
10 | 11 | ||
11 | 12 | ||
12 | char *perf_trace_buf; | 13 | static char *perf_trace_buf; |
13 | EXPORT_SYMBOL_GPL(perf_trace_buf); | 14 | static char *perf_trace_buf_nmi; |
14 | |||
15 | char *perf_trace_buf_nmi; | ||
16 | EXPORT_SYMBOL_GPL(perf_trace_buf_nmi); | ||
17 | 15 | ||
18 | typedef typeof(char [FTRACE_MAX_PROFILE_SIZE]) perf_trace_t ; | 16 | typedef typeof(char [FTRACE_MAX_PROFILE_SIZE]) perf_trace_t ; |
19 | 17 | ||
@@ -120,3 +118,47 @@ void ftrace_profile_disable(int event_id) | |||
120 | } | 118 | } |
121 | mutex_unlock(&event_mutex); | 119 | mutex_unlock(&event_mutex); |
122 | } | 120 | } |
121 | |||
122 | __kprobes void *ftrace_perf_buf_prepare(int size, unsigned short type, | ||
123 | int *rctxp, unsigned long *irq_flags) | ||
124 | { | ||
125 | struct trace_entry *entry; | ||
126 | char *trace_buf, *raw_data; | ||
127 | int pc, cpu; | ||
128 | |||
129 | pc = preempt_count(); | ||
130 | |||
131 | /* Protect the per cpu buffer, begin the rcu read side */ | ||
132 | local_irq_save(*irq_flags); | ||
133 | |||
134 | *rctxp = perf_swevent_get_recursion_context(); | ||
135 | if (*rctxp < 0) | ||
136 | goto err_recursion; | ||
137 | |||
138 | cpu = smp_processor_id(); | ||
139 | |||
140 | if (in_nmi()) | ||
141 | trace_buf = rcu_dereference(perf_trace_buf_nmi); | ||
142 | else | ||
143 | trace_buf = rcu_dereference(perf_trace_buf); | ||
144 | |||
145 | if (!trace_buf) | ||
146 | goto err; | ||
147 | |||
148 | raw_data = per_cpu_ptr(trace_buf, cpu); | ||
149 | |||
150 | /* zero the dead bytes from align to not leak stack to user */ | ||
151 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | ||
152 | |||
153 | entry = (struct trace_entry *)raw_data; | ||
154 | tracing_generic_entry_update(entry, *irq_flags, pc); | ||
155 | entry->type = type; | ||
156 | |||
157 | return raw_data; | ||
158 | err: | ||
159 | perf_swevent_put_recursion_context(*rctxp); | ||
160 | err_recursion: | ||
161 | local_irq_restore(*irq_flags); | ||
162 | return NULL; | ||
163 | } | ||
164 | EXPORT_SYMBOL_GPL(ftrace_perf_buf_prepare); | ||
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index d6266cad6953..2e28ee36646f 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -1243,14 +1243,10 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, | |||
1243 | struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); | 1243 | struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); |
1244 | struct ftrace_event_call *call = &tp->call; | 1244 | struct ftrace_event_call *call = &tp->call; |
1245 | struct kprobe_trace_entry *entry; | 1245 | struct kprobe_trace_entry *entry; |
1246 | struct trace_entry *ent; | 1246 | int size, __size, i; |
1247 | int size, __size, i, pc, __cpu; | ||
1248 | unsigned long irq_flags; | 1247 | unsigned long irq_flags; |
1249 | char *trace_buf; | ||
1250 | char *raw_data; | ||
1251 | int rctx; | 1248 | int rctx; |
1252 | 1249 | ||
1253 | pc = preempt_count(); | ||
1254 | __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args); | 1250 | __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args); |
1255 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); | 1251 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); |
1256 | size -= sizeof(u32); | 1252 | size -= sizeof(u32); |
@@ -1258,45 +1254,16 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, | |||
1258 | "profile buffer not large enough")) | 1254 | "profile buffer not large enough")) |
1259 | return 0; | 1255 | return 0; |
1260 | 1256 | ||
1261 | /* | 1257 | entry = ftrace_perf_buf_prepare(size, call->id, &rctx, &irq_flags); |
1262 | * Protect the non nmi buffer | 1258 | if (!entry) |
1263 | * This also protects the rcu read side | 1259 | return 0; |
1264 | */ | ||
1265 | local_irq_save(irq_flags); | ||
1266 | |||
1267 | rctx = perf_swevent_get_recursion_context(); | ||
1268 | if (rctx < 0) | ||
1269 | goto end_recursion; | ||
1270 | |||
1271 | __cpu = smp_processor_id(); | ||
1272 | |||
1273 | if (in_nmi()) | ||
1274 | trace_buf = rcu_dereference(perf_trace_buf_nmi); | ||
1275 | else | ||
1276 | trace_buf = rcu_dereference(perf_trace_buf); | ||
1277 | |||
1278 | if (!trace_buf) | ||
1279 | goto end; | ||
1280 | |||
1281 | raw_data = per_cpu_ptr(trace_buf, __cpu); | ||
1282 | |||
1283 | /* Zero dead bytes from alignment to avoid buffer leak to userspace */ | ||
1284 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | ||
1285 | entry = (struct kprobe_trace_entry *)raw_data; | ||
1286 | ent = &entry->ent; | ||
1287 | 1260 | ||
1288 | tracing_generic_entry_update(ent, irq_flags, pc); | ||
1289 | ent->type = call->id; | ||
1290 | entry->nargs = tp->nr_args; | 1261 | entry->nargs = tp->nr_args; |
1291 | entry->ip = (unsigned long)kp->addr; | 1262 | entry->ip = (unsigned long)kp->addr; |
1292 | for (i = 0; i < tp->nr_args; i++) | 1263 | for (i = 0; i < tp->nr_args; i++) |
1293 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); | 1264 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); |
1294 | perf_tp_event(call->id, entry->ip, 1, entry, size); | ||
1295 | 1265 | ||
1296 | end: | 1266 | ftrace_perf_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags); |
1297 | perf_swevent_put_recursion_context(rctx); | ||
1298 | end_recursion: | ||
1299 | local_irq_restore(irq_flags); | ||
1300 | 1267 | ||
1301 | return 0; | 1268 | return 0; |
1302 | } | 1269 | } |
@@ -1308,14 +1275,10 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1308 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); | 1275 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); |
1309 | struct ftrace_event_call *call = &tp->call; | 1276 | struct ftrace_event_call *call = &tp->call; |
1310 | struct kretprobe_trace_entry *entry; | 1277 | struct kretprobe_trace_entry *entry; |
1311 | struct trace_entry *ent; | 1278 | int size, __size, i; |
1312 | int size, __size, i, pc, __cpu; | ||
1313 | unsigned long irq_flags; | 1279 | unsigned long irq_flags; |
1314 | char *trace_buf; | ||
1315 | char *raw_data; | ||
1316 | int rctx; | 1280 | int rctx; |
1317 | 1281 | ||
1318 | pc = preempt_count(); | ||
1319 | __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args); | 1282 | __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args); |
1320 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); | 1283 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); |
1321 | size -= sizeof(u32); | 1284 | size -= sizeof(u32); |
@@ -1323,46 +1286,17 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1323 | "profile buffer not large enough")) | 1286 | "profile buffer not large enough")) |
1324 | return 0; | 1287 | return 0; |
1325 | 1288 | ||
1326 | /* | 1289 | entry = ftrace_perf_buf_prepare(size, call->id, &rctx, &irq_flags); |
1327 | * Protect the non nmi buffer | 1290 | if (!entry) |
1328 | * This also protects the rcu read side | 1291 | return 0; |
1329 | */ | ||
1330 | local_irq_save(irq_flags); | ||
1331 | |||
1332 | rctx = perf_swevent_get_recursion_context(); | ||
1333 | if (rctx < 0) | ||
1334 | goto end_recursion; | ||
1335 | |||
1336 | __cpu = smp_processor_id(); | ||
1337 | |||
1338 | if (in_nmi()) | ||
1339 | trace_buf = rcu_dereference(perf_trace_buf_nmi); | ||
1340 | else | ||
1341 | trace_buf = rcu_dereference(perf_trace_buf); | ||
1342 | |||
1343 | if (!trace_buf) | ||
1344 | goto end; | ||
1345 | |||
1346 | raw_data = per_cpu_ptr(trace_buf, __cpu); | ||
1347 | |||
1348 | /* Zero dead bytes from alignment to avoid buffer leak to userspace */ | ||
1349 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | ||
1350 | entry = (struct kretprobe_trace_entry *)raw_data; | ||
1351 | ent = &entry->ent; | ||
1352 | 1292 | ||
1353 | tracing_generic_entry_update(ent, irq_flags, pc); | ||
1354 | ent->type = call->id; | ||
1355 | entry->nargs = tp->nr_args; | 1293 | entry->nargs = tp->nr_args; |
1356 | entry->func = (unsigned long)tp->rp.kp.addr; | 1294 | entry->func = (unsigned long)tp->rp.kp.addr; |
1357 | entry->ret_ip = (unsigned long)ri->ret_addr; | 1295 | entry->ret_ip = (unsigned long)ri->ret_addr; |
1358 | for (i = 0; i < tp->nr_args; i++) | 1296 | for (i = 0; i < tp->nr_args; i++) |
1359 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); | 1297 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); |
1360 | perf_tp_event(call->id, entry->ret_ip, 1, entry, size); | ||
1361 | 1298 | ||
1362 | end: | 1299 | ftrace_perf_buf_submit(entry, size, rctx, entry->ret_ip, 1, irq_flags); |
1363 | perf_swevent_put_recursion_context(rctx); | ||
1364 | end_recursion: | ||
1365 | local_irq_restore(irq_flags); | ||
1366 | 1300 | ||
1367 | return 0; | 1301 | return 0; |
1368 | } | 1302 | } |
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index f694f66d75b0..4e332b9e449c 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -433,12 +433,9 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) | |||
433 | struct syscall_metadata *sys_data; | 433 | struct syscall_metadata *sys_data; |
434 | struct syscall_trace_enter *rec; | 434 | struct syscall_trace_enter *rec; |
435 | unsigned long flags; | 435 | unsigned long flags; |
436 | char *trace_buf; | ||
437 | char *raw_data; | ||
438 | int syscall_nr; | 436 | int syscall_nr; |
439 | int rctx; | 437 | int rctx; |
440 | int size; | 438 | int size; |
441 | int cpu; | ||
442 | 439 | ||
443 | syscall_nr = syscall_get_nr(current, regs); | 440 | syscall_nr = syscall_get_nr(current, regs); |
444 | if (!test_bit(syscall_nr, enabled_prof_enter_syscalls)) | 441 | if (!test_bit(syscall_nr, enabled_prof_enter_syscalls)) |
@@ -457,37 +454,15 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) | |||
457 | "profile buffer not large enough")) | 454 | "profile buffer not large enough")) |
458 | return; | 455 | return; |
459 | 456 | ||
460 | /* Protect the per cpu buffer, begin the rcu read side */ | 457 | rec = (struct syscall_trace_enter *)ftrace_perf_buf_prepare(size, |
461 | local_irq_save(flags); | 458 | sys_data->enter_event->id, &rctx, &flags); |
462 | 459 | if (!rec) | |
463 | rctx = perf_swevent_get_recursion_context(); | 460 | return; |
464 | if (rctx < 0) | ||
465 | goto end_recursion; | ||
466 | |||
467 | cpu = smp_processor_id(); | ||
468 | |||
469 | trace_buf = rcu_dereference(perf_trace_buf); | ||
470 | |||
471 | if (!trace_buf) | ||
472 | goto end; | ||
473 | |||
474 | raw_data = per_cpu_ptr(trace_buf, cpu); | ||
475 | |||
476 | /* zero the dead bytes from align to not leak stack to user */ | ||
477 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | ||
478 | 461 | ||
479 | rec = (struct syscall_trace_enter *) raw_data; | ||
480 | tracing_generic_entry_update(&rec->ent, 0, 0); | ||
481 | rec->ent.type = sys_data->enter_event->id; | ||
482 | rec->nr = syscall_nr; | 462 | rec->nr = syscall_nr; |
483 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, | 463 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, |
484 | (unsigned long *)&rec->args); | 464 | (unsigned long *)&rec->args); |
485 | perf_tp_event(sys_data->enter_event->id, 0, 1, rec, size); | 465 | ftrace_perf_buf_submit(rec, size, rctx, 0, 1, flags); |
486 | |||
487 | end: | ||
488 | perf_swevent_put_recursion_context(rctx); | ||
489 | end_recursion: | ||
490 | local_irq_restore(flags); | ||
491 | } | 466 | } |
492 | 467 | ||
493 | int prof_sysenter_enable(struct ftrace_event_call *call) | 468 | int prof_sysenter_enable(struct ftrace_event_call *call) |
@@ -531,11 +506,8 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
531 | struct syscall_trace_exit *rec; | 506 | struct syscall_trace_exit *rec; |
532 | unsigned long flags; | 507 | unsigned long flags; |
533 | int syscall_nr; | 508 | int syscall_nr; |
534 | char *trace_buf; | ||
535 | char *raw_data; | ||
536 | int rctx; | 509 | int rctx; |
537 | int size; | 510 | int size; |
538 | int cpu; | ||
539 | 511 | ||
540 | syscall_nr = syscall_get_nr(current, regs); | 512 | syscall_nr = syscall_get_nr(current, regs); |
541 | if (!test_bit(syscall_nr, enabled_prof_exit_syscalls)) | 513 | if (!test_bit(syscall_nr, enabled_prof_exit_syscalls)) |
@@ -557,38 +529,15 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
557 | "exit event has grown above profile buffer size")) | 529 | "exit event has grown above profile buffer size")) |
558 | return; | 530 | return; |
559 | 531 | ||
560 | /* Protect the per cpu buffer, begin the rcu read side */ | 532 | rec = (struct syscall_trace_exit *)ftrace_perf_buf_prepare(size, |
561 | local_irq_save(flags); | 533 | sys_data->exit_event->id, &rctx, &flags); |
562 | 534 | if (!rec) | |
563 | rctx = perf_swevent_get_recursion_context(); | 535 | return; |
564 | if (rctx < 0) | ||
565 | goto end_recursion; | ||
566 | |||
567 | cpu = smp_processor_id(); | ||
568 | |||
569 | trace_buf = rcu_dereference(perf_trace_buf); | ||
570 | |||
571 | if (!trace_buf) | ||
572 | goto end; | ||
573 | |||
574 | raw_data = per_cpu_ptr(trace_buf, cpu); | ||
575 | |||
576 | /* zero the dead bytes from align to not leak stack to user */ | ||
577 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | ||
578 | |||
579 | rec = (struct syscall_trace_exit *)raw_data; | ||
580 | 536 | ||
581 | tracing_generic_entry_update(&rec->ent, 0, 0); | ||
582 | rec->ent.type = sys_data->exit_event->id; | ||
583 | rec->nr = syscall_nr; | 537 | rec->nr = syscall_nr; |
584 | rec->ret = syscall_get_return_value(current, regs); | 538 | rec->ret = syscall_get_return_value(current, regs); |
585 | 539 | ||
586 | perf_tp_event(sys_data->exit_event->id, 0, 1, rec, size); | 540 | ftrace_perf_buf_submit(rec, size, rctx, 0, 1, flags); |
587 | |||
588 | end: | ||
589 | perf_swevent_put_recursion_context(rctx); | ||
590 | end_recursion: | ||
591 | local_irq_restore(flags); | ||
592 | } | 541 | } |
593 | 542 | ||
594 | int prof_sysexit_enable(struct ftrace_event_call *call) | 543 | int prof_sysexit_enable(struct ftrace_event_call *call) |