diff options
| -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) |
