diff options
Diffstat (limited to 'kernel/trace/trace_event_profile.c')
| -rw-r--r-- | kernel/trace/trace_event_profile.c | 52 |
1 files changed, 47 insertions, 5 deletions
diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c index 9e25573242c..f0d69300507 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); | ||
