aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/perf_counter.h2
-rw-r--r--include/linux/syscalls.h52
-rw-r--r--include/trace/syscall.h7
-rw-r--r--kernel/trace/trace_syscalls.c121
4 files changed, 181 insertions, 1 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index a9d823a93fe8..8e6460fb4c02 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -734,6 +734,8 @@ extern int sysctl_perf_counter_mlock;
734extern int sysctl_perf_counter_sample_rate; 734extern int sysctl_perf_counter_sample_rate;
735 735
736extern void perf_counter_init(void); 736extern void perf_counter_init(void);
737extern void perf_tpcounter_event(int event_id, u64 addr, u64 count,
738 void *record, int entry_size);
737 739
738#ifndef perf_misc_flags 740#ifndef perf_misc_flags
739#define perf_misc_flags(regs) (user_mode(regs) ? PERF_EVENT_MISC_USER : \ 741#define perf_misc_flags(regs) (user_mode(regs) ? PERF_EVENT_MISC_USER : \
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index ce4b01c658eb..5541e75e140a 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -98,6 +98,53 @@ struct perf_counter_attr;
98#define __SC_TEST5(t5, a5, ...) __SC_TEST(t5); __SC_TEST4(__VA_ARGS__) 98#define __SC_TEST5(t5, a5, ...) __SC_TEST(t5); __SC_TEST4(__VA_ARGS__)
99#define __SC_TEST6(t6, a6, ...) __SC_TEST(t6); __SC_TEST5(__VA_ARGS__) 99#define __SC_TEST6(t6, a6, ...) __SC_TEST(t6); __SC_TEST5(__VA_ARGS__)
100 100
101#ifdef CONFIG_EVENT_PROFILE
102#define TRACE_SYS_ENTER_PROFILE(sname) \
103static int prof_sysenter_enable_##sname(struct ftrace_event_call *event_call) \
104{ \
105 int ret = 0; \
106 if (!atomic_inc_return(&event_enter_##sname.profile_count)) \
107 ret = reg_prof_syscall_enter("sys"#sname); \
108 return ret; \
109} \
110 \
111static void prof_sysenter_disable_##sname(struct ftrace_event_call *event_call)\
112{ \
113 if (atomic_add_negative(-1, &event_enter_##sname.profile_count)) \
114 unreg_prof_syscall_enter("sys"#sname); \
115}
116
117#define TRACE_SYS_EXIT_PROFILE(sname) \
118static int prof_sysexit_enable_##sname(struct ftrace_event_call *event_call) \
119{ \
120 int ret = 0; \
121 if (!atomic_inc_return(&event_exit_##sname.profile_count)) \
122 ret = reg_prof_syscall_exit("sys"#sname); \
123 return ret; \
124} \
125 \
126static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \
127{ \
128 if (atomic_add_negative(-1, &event_exit_##sname.profile_count)) \
129 unreg_prof_syscall_exit("sys"#sname); \
130}
131
132#define TRACE_SYS_ENTER_PROFILE_INIT(sname) \
133 .profile_count = ATOMIC_INIT(-1), \
134 .profile_enable = prof_sysenter_enable_##sname, \
135 .profile_disable = prof_sysenter_disable_##sname,
136
137#define TRACE_SYS_EXIT_PROFILE_INIT(sname) \
138 .profile_count = ATOMIC_INIT(-1), \
139 .profile_enable = prof_sysexit_enable_##sname, \
140 .profile_disable = prof_sysexit_disable_##sname,
141#else
142#define TRACE_SYS_ENTER_PROFILE(sname)
143#define TRACE_SYS_ENTER_PROFILE_INIT(sname)
144#define TRACE_SYS_EXIT_PROFILE(sname)
145#define TRACE_SYS_EXIT_PROFILE_INIT(sname)
146#endif
147
101#ifdef CONFIG_FTRACE_SYSCALLS 148#ifdef CONFIG_FTRACE_SYSCALLS
102#define __SC_STR_ADECL1(t, a) #a 149#define __SC_STR_ADECL1(t, a) #a
103#define __SC_STR_ADECL2(t, a, ...) #a, __SC_STR_ADECL1(__VA_ARGS__) 150#define __SC_STR_ADECL2(t, a, ...) #a, __SC_STR_ADECL1(__VA_ARGS__)
@@ -113,7 +160,6 @@ struct perf_counter_attr;
113#define __SC_STR_TDECL5(t, a, ...) #t, __SC_STR_TDECL4(__VA_ARGS__) 160#define __SC_STR_TDECL5(t, a, ...) #t, __SC_STR_TDECL4(__VA_ARGS__)
114#define __SC_STR_TDECL6(t, a, ...) #t, __SC_STR_TDECL5(__VA_ARGS__) 161#define __SC_STR_TDECL6(t, a, ...) #t, __SC_STR_TDECL5(__VA_ARGS__)
115 162
116
117#define SYSCALL_TRACE_ENTER_EVENT(sname) \ 163#define SYSCALL_TRACE_ENTER_EVENT(sname) \
118 static struct ftrace_event_call event_enter_##sname; \ 164 static struct ftrace_event_call event_enter_##sname; \
119 struct trace_event enter_syscall_print_##sname = { \ 165 struct trace_event enter_syscall_print_##sname = { \
@@ -134,6 +180,7 @@ struct perf_counter_attr;
134 init_preds(&event_enter_##sname); \ 180 init_preds(&event_enter_##sname); \
135 return 0; \ 181 return 0; \
136 } \ 182 } \
183 TRACE_SYS_ENTER_PROFILE(sname); \
137 static struct ftrace_event_call __used \ 184 static struct ftrace_event_call __used \
138 __attribute__((__aligned__(4))) \ 185 __attribute__((__aligned__(4))) \
139 __attribute__((section("_ftrace_events"))) \ 186 __attribute__((section("_ftrace_events"))) \
@@ -145,6 +192,7 @@ struct perf_counter_attr;
145 .regfunc = reg_event_syscall_enter, \ 192 .regfunc = reg_event_syscall_enter, \
146 .unregfunc = unreg_event_syscall_enter, \ 193 .unregfunc = unreg_event_syscall_enter, \
147 .data = "sys"#sname, \ 194 .data = "sys"#sname, \
195 TRACE_SYS_ENTER_PROFILE_INIT(sname) \
148 } 196 }
149 197
150#define SYSCALL_TRACE_EXIT_EVENT(sname) \ 198#define SYSCALL_TRACE_EXIT_EVENT(sname) \
@@ -167,6 +215,7 @@ struct perf_counter_attr;
167 init_preds(&event_exit_##sname); \ 215 init_preds(&event_exit_##sname); \
168 return 0; \ 216 return 0; \
169 } \ 217 } \
218 TRACE_SYS_EXIT_PROFILE(sname); \
170 static struct ftrace_event_call __used \ 219 static struct ftrace_event_call __used \
171 __attribute__((__aligned__(4))) \ 220 __attribute__((__aligned__(4))) \
172 __attribute__((section("_ftrace_events"))) \ 221 __attribute__((section("_ftrace_events"))) \
@@ -178,6 +227,7 @@ struct perf_counter_attr;
178 .regfunc = reg_event_syscall_exit, \ 227 .regfunc = reg_event_syscall_exit, \
179 .unregfunc = unreg_event_syscall_exit, \ 228 .unregfunc = unreg_event_syscall_exit, \
180 .data = "sys"#sname, \ 229 .data = "sys"#sname, \
230 TRACE_SYS_EXIT_PROFILE_INIT(sname) \
181 } 231 }
182 232
183#define SYSCALL_METADATA(sname, nb) \ 233#define SYSCALL_METADATA(sname, nb) \
diff --git a/include/trace/syscall.h b/include/trace/syscall.h
index df628404241a..3ab6dd18fa3a 100644
--- a/include/trace/syscall.h
+++ b/include/trace/syscall.h
@@ -58,5 +58,12 @@ extern void unreg_event_syscall_exit(void *ptr);
58enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags); 58enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags);
59enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags); 59enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags);
60#endif 60#endif
61#ifdef CONFIG_EVENT_PROFILE
62int reg_prof_syscall_enter(char *name);
63void unreg_prof_syscall_enter(char *name);
64int reg_prof_syscall_exit(char *name);
65void unreg_prof_syscall_exit(char *name);
66
67#endif
61 68
62#endif /* _TRACE_SYSCALL_H */ 69#endif /* _TRACE_SYSCALL_H */
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index e58a9c11ba85..f4eaec3d559a 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -1,6 +1,7 @@
1#include <trace/syscall.h> 1#include <trace/syscall.h>
2#include <linux/kernel.h> 2#include <linux/kernel.h>
3#include <linux/ftrace.h> 3#include <linux/ftrace.h>
4#include <linux/perf_counter.h>
4#include <asm/syscall.h> 5#include <asm/syscall.h>
5 6
6#include "trace_output.h" 7#include "trace_output.h"
@@ -252,3 +253,123 @@ struct trace_event event_syscall_enter = {
252struct trace_event event_syscall_exit = { 253struct trace_event event_syscall_exit = {
253 .trace = print_syscall_exit, 254 .trace = print_syscall_exit,
254}; 255};
256
257#ifdef CONFIG_EVENT_PROFILE
258static DECLARE_BITMAP(enabled_prof_enter_syscalls, FTRACE_SYSCALL_MAX);
259static DECLARE_BITMAP(enabled_prof_exit_syscalls, FTRACE_SYSCALL_MAX);
260static int sys_prof_refcount_enter;
261static int sys_prof_refcount_exit;
262
263static void prof_syscall_enter(struct pt_regs *regs, long id)
264{
265 struct syscall_metadata *sys_data;
266 int syscall_nr;
267
268 syscall_nr = syscall_get_nr(current, regs);
269 if (!test_bit(syscall_nr, enabled_prof_enter_syscalls))
270 return;
271
272 sys_data = syscall_nr_to_meta(syscall_nr);
273 if (!sys_data)
274 return;
275
276 perf_tpcounter_event(sys_data->enter_id, 0, 1, NULL, 0);
277}
278
279int reg_prof_syscall_enter(char *name)
280{
281 int ret = 0;
282 int num;
283
284 num = syscall_name_to_nr(name);
285 if (num < 0 || num >= FTRACE_SYSCALL_MAX)
286 return -ENOSYS;
287
288 mutex_lock(&syscall_trace_lock);
289 if (!sys_prof_refcount_enter)
290 ret = register_trace_syscall_enter(prof_syscall_enter);
291 if (ret) {
292 pr_info("event trace: Could not activate"
293 "syscall entry trace point");
294 } else {
295 set_bit(num, enabled_prof_enter_syscalls);
296 sys_prof_refcount_enter++;
297 }
298 mutex_unlock(&syscall_trace_lock);
299 return ret;
300}
301
302void unreg_prof_syscall_enter(char *name)
303{
304 int num;
305
306 num = syscall_name_to_nr(name);
307 if (num < 0 || num >= FTRACE_SYSCALL_MAX)
308 return;
309
310 mutex_lock(&syscall_trace_lock);
311 sys_prof_refcount_enter--;
312 clear_bit(num, enabled_prof_enter_syscalls);
313 if (!sys_prof_refcount_enter)
314 unregister_trace_syscall_enter(prof_syscall_enter);
315 mutex_unlock(&syscall_trace_lock);
316}
317
318static void prof_syscall_exit(struct pt_regs *regs, long ret)
319{
320 struct syscall_metadata *sys_data;
321 int syscall_nr;
322
323 syscall_nr = syscall_get_nr(current, regs);
324 if (!test_bit(syscall_nr, enabled_prof_exit_syscalls))
325 return;
326
327 sys_data = syscall_nr_to_meta(syscall_nr);
328 if (!sys_data)
329 return;
330
331 perf_tpcounter_event(sys_data->exit_id, 0, 1, NULL, 0);
332}
333
334int reg_prof_syscall_exit(char *name)
335{
336 int ret = 0;
337 int num;
338
339 num = syscall_name_to_nr(name);
340 if (num < 0 || num >= FTRACE_SYSCALL_MAX)
341 return -ENOSYS;
342
343 mutex_lock(&syscall_trace_lock);
344 if (!sys_prof_refcount_exit)
345 ret = register_trace_syscall_exit(prof_syscall_exit);
346 if (ret) {
347 pr_info("event trace: Could not activate"
348 "syscall entry trace point");
349 } else {
350 set_bit(num, enabled_prof_exit_syscalls);
351 sys_prof_refcount_exit++;
352 }
353 mutex_unlock(&syscall_trace_lock);
354 return ret;
355}
356
357void unreg_prof_syscall_exit(char *name)
358{
359 int num;
360
361 num = syscall_name_to_nr(name);
362 if (num < 0 || num >= FTRACE_SYSCALL_MAX)
363 return;
364
365 mutex_lock(&syscall_trace_lock);
366 sys_prof_refcount_exit--;
367 clear_bit(num, enabled_prof_exit_syscalls);
368 if (!sys_prof_refcount_exit)
369 unregister_trace_syscall_exit(prof_syscall_exit);
370 mutex_unlock(&syscall_trace_lock);
371}
372
373#endif
374
375