diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace.h | 3 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 48 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 10 | ||||
-rw-r--r-- | kernel/trace/trace_export.c | 14 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 8 | ||||
-rw-r--r-- | kernel/trace/trace_syscalls.c | 31 |
6 files changed, 83 insertions, 31 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 911e9864e94a..c88c563a59a5 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -794,6 +794,9 @@ extern void print_subsystem_event_filter(struct event_subsystem *system, | |||
794 | struct trace_seq *s); | 794 | struct trace_seq *s); |
795 | extern int filter_assign_type(const char *type); | 795 | extern int filter_assign_type(const char *type); |
796 | 796 | ||
797 | struct list_head * | ||
798 | trace_get_fields(struct ftrace_event_call *event_call); | ||
799 | |||
797 | static inline int | 800 | static inline int |
798 | filter_check_discard(struct ftrace_event_call *call, void *rec, | 801 | filter_check_discard(struct ftrace_event_call *call, void *rec, |
799 | struct ring_buffer *buffer, | 802 | struct ring_buffer *buffer, |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 19d1eb0a7188..acc0f55742c3 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -29,11 +29,23 @@ DEFINE_MUTEX(event_mutex); | |||
29 | 29 | ||
30 | LIST_HEAD(ftrace_events); | 30 | LIST_HEAD(ftrace_events); |
31 | 31 | ||
32 | struct list_head * | ||
33 | trace_get_fields(struct ftrace_event_call *event_call) | ||
34 | { | ||
35 | if (!event_call->class->get_fields) | ||
36 | return &event_call->class->fields; | ||
37 | return event_call->class->get_fields(event_call); | ||
38 | } | ||
39 | |||
32 | int trace_define_field(struct ftrace_event_call *call, const char *type, | 40 | int trace_define_field(struct ftrace_event_call *call, const char *type, |
33 | const char *name, int offset, int size, int is_signed, | 41 | const char *name, int offset, int size, int is_signed, |
34 | int filter_type) | 42 | int filter_type) |
35 | { | 43 | { |
36 | struct ftrace_event_field *field; | 44 | struct ftrace_event_field *field; |
45 | struct list_head *head; | ||
46 | |||
47 | if (WARN_ON(!call->class)) | ||
48 | return 0; | ||
37 | 49 | ||
38 | field = kzalloc(sizeof(*field), GFP_KERNEL); | 50 | field = kzalloc(sizeof(*field), GFP_KERNEL); |
39 | if (!field) | 51 | if (!field) |
@@ -56,7 +68,8 @@ int trace_define_field(struct ftrace_event_call *call, const char *type, | |||
56 | field->size = size; | 68 | field->size = size; |
57 | field->is_signed = is_signed; | 69 | field->is_signed = is_signed; |
58 | 70 | ||
59 | list_add(&field->link, &call->fields); | 71 | head = trace_get_fields(call); |
72 | list_add(&field->link, head); | ||
60 | 73 | ||
61 | return 0; | 74 | return 0; |
62 | 75 | ||
@@ -94,8 +107,10 @@ static int trace_define_common_fields(struct ftrace_event_call *call) | |||
94 | void trace_destroy_fields(struct ftrace_event_call *call) | 107 | void trace_destroy_fields(struct ftrace_event_call *call) |
95 | { | 108 | { |
96 | struct ftrace_event_field *field, *next; | 109 | struct ftrace_event_field *field, *next; |
110 | struct list_head *head; | ||
97 | 111 | ||
98 | list_for_each_entry_safe(field, next, &call->fields, link) { | 112 | head = trace_get_fields(call); |
113 | list_for_each_entry_safe(field, next, head, link) { | ||
99 | list_del(&field->link); | 114 | list_del(&field->link); |
100 | kfree(field->type); | 115 | kfree(field->type); |
101 | kfree(field->name); | 116 | kfree(field->name); |
@@ -111,7 +126,6 @@ int trace_event_raw_init(struct ftrace_event_call *call) | |||
111 | if (!id) | 126 | if (!id) |
112 | return -ENODEV; | 127 | return -ENODEV; |
113 | call->id = id; | 128 | call->id = id; |
114 | INIT_LIST_HEAD(&call->fields); | ||
115 | 129 | ||
116 | return 0; | 130 | return 0; |
117 | } | 131 | } |
@@ -537,6 +551,7 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
537 | { | 551 | { |
538 | struct ftrace_event_call *call = filp->private_data; | 552 | struct ftrace_event_call *call = filp->private_data; |
539 | struct ftrace_event_field *field; | 553 | struct ftrace_event_field *field; |
554 | struct list_head *head; | ||
540 | struct trace_seq *s; | 555 | struct trace_seq *s; |
541 | int common_field_count = 5; | 556 | int common_field_count = 5; |
542 | char *buf; | 557 | char *buf; |
@@ -555,7 +570,8 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
555 | trace_seq_printf(s, "ID: %d\n", call->id); | 570 | trace_seq_printf(s, "ID: %d\n", call->id); |
556 | trace_seq_printf(s, "format:\n"); | 571 | trace_seq_printf(s, "format:\n"); |
557 | 572 | ||
558 | list_for_each_entry_reverse(field, &call->fields, link) { | 573 | head = trace_get_fields(call); |
574 | list_for_each_entry_reverse(field, head, link) { | ||
559 | /* | 575 | /* |
560 | * Smartly shows the array type(except dynamic array). | 576 | * Smartly shows the array type(except dynamic array). |
561 | * Normal: | 577 | * Normal: |
@@ -931,6 +947,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
931 | const struct file_operations *filter, | 947 | const struct file_operations *filter, |
932 | const struct file_operations *format) | 948 | const struct file_operations *format) |
933 | { | 949 | { |
950 | struct list_head *head; | ||
934 | int ret; | 951 | int ret; |
935 | 952 | ||
936 | /* | 953 | /* |
@@ -957,14 +974,21 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
957 | id); | 974 | id); |
958 | #endif | 975 | #endif |
959 | 976 | ||
960 | if (call->define_fields) { | 977 | if (call->class->define_fields) { |
961 | ret = trace_define_common_fields(call); | 978 | /* |
962 | if (!ret) | 979 | * Other events may have the same class. Only update |
963 | ret = call->define_fields(call); | 980 | * the fields if they are not already defined. |
964 | if (ret < 0) { | 981 | */ |
965 | pr_warning("Could not initialize trace point" | 982 | head = trace_get_fields(call); |
966 | " events/%s\n", call->name); | 983 | if (list_empty(head)) { |
967 | return ret; | 984 | ret = trace_define_common_fields(call); |
985 | if (!ret) | ||
986 | ret = call->class->define_fields(call); | ||
987 | if (ret < 0) { | ||
988 | pr_warning("Could not initialize trace point" | ||
989 | " events/%s\n", call->name); | ||
990 | return ret; | ||
991 | } | ||
968 | } | 992 | } |
969 | trace_create_file("filter", 0644, call->dir, call, | 993 | trace_create_file("filter", 0644, call->dir, call, |
970 | filter); | 994 | filter); |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index ca329603d0bf..961f99b74bdd 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -500,8 +500,10 @@ static struct ftrace_event_field * | |||
500 | find_event_field(struct ftrace_event_call *call, char *name) | 500 | find_event_field(struct ftrace_event_call *call, char *name) |
501 | { | 501 | { |
502 | struct ftrace_event_field *field; | 502 | struct ftrace_event_field *field; |
503 | struct list_head *head; | ||
503 | 504 | ||
504 | list_for_each_entry(field, &call->fields, link) { | 505 | head = trace_get_fields(call); |
506 | list_for_each_entry(field, head, link) { | ||
505 | if (!strcmp(field->name, name)) | 507 | if (!strcmp(field->name, name)) |
506 | return field; | 508 | return field; |
507 | } | 509 | } |
@@ -625,7 +627,7 @@ static int init_subsystem_preds(struct event_subsystem *system) | |||
625 | int err; | 627 | int err; |
626 | 628 | ||
627 | list_for_each_entry(call, &ftrace_events, list) { | 629 | list_for_each_entry(call, &ftrace_events, list) { |
628 | if (!call->define_fields) | 630 | if (!call->class || !call->class->define_fields) |
629 | continue; | 631 | continue; |
630 | 632 | ||
631 | if (strcmp(call->class->system, system->name) != 0) | 633 | if (strcmp(call->class->system, system->name) != 0) |
@@ -644,7 +646,7 @@ static void filter_free_subsystem_preds(struct event_subsystem *system) | |||
644 | struct ftrace_event_call *call; | 646 | struct ftrace_event_call *call; |
645 | 647 | ||
646 | list_for_each_entry(call, &ftrace_events, list) { | 648 | list_for_each_entry(call, &ftrace_events, list) { |
647 | if (!call->define_fields) | 649 | if (!call->class || !call->class->define_fields) |
648 | continue; | 650 | continue; |
649 | 651 | ||
650 | if (strcmp(call->class->system, system->name) != 0) | 652 | if (strcmp(call->class->system, system->name) != 0) |
@@ -1249,7 +1251,7 @@ static int replace_system_preds(struct event_subsystem *system, | |||
1249 | list_for_each_entry(call, &ftrace_events, list) { | 1251 | list_for_each_entry(call, &ftrace_events, list) { |
1250 | struct event_filter *filter = call->filter; | 1252 | struct event_filter *filter = call->filter; |
1251 | 1253 | ||
1252 | if (!call->define_fields) | 1254 | if (!call->class || !call->class->define_fields) |
1253 | continue; | 1255 | continue; |
1254 | 1256 | ||
1255 | if (strcmp(call->class->system, system->name) != 0) | 1257 | if (strcmp(call->class->system, system->name) != 0) |
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index 7f16e2163817..e700a0c1803f 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c | |||
@@ -18,10 +18,6 @@ | |||
18 | #undef TRACE_SYSTEM | 18 | #undef TRACE_SYSTEM |
19 | #define TRACE_SYSTEM ftrace | 19 | #define TRACE_SYSTEM ftrace |
20 | 20 | ||
21 | struct ftrace_event_class event_class_ftrace = { | ||
22 | .system = __stringify(TRACE_SYSTEM), | ||
23 | }; | ||
24 | |||
25 | /* not needed for this file */ | 21 | /* not needed for this file */ |
26 | #undef __field_struct | 22 | #undef __field_struct |
27 | #define __field_struct(type, item) | 23 | #define __field_struct(type, item) |
@@ -131,7 +127,7 @@ ftrace_define_fields_##name(struct ftrace_event_call *event_call) \ | |||
131 | 127 | ||
132 | static int ftrace_raw_init_event(struct ftrace_event_call *call) | 128 | static int ftrace_raw_init_event(struct ftrace_event_call *call) |
133 | { | 129 | { |
134 | INIT_LIST_HEAD(&call->fields); | 130 | INIT_LIST_HEAD(&call->class->fields); |
135 | return 0; | 131 | return 0; |
136 | } | 132 | } |
137 | 133 | ||
@@ -159,15 +155,19 @@ static int ftrace_raw_init_event(struct ftrace_event_call *call) | |||
159 | #undef FTRACE_ENTRY | 155 | #undef FTRACE_ENTRY |
160 | #define FTRACE_ENTRY(call, struct_name, type, tstruct, print) \ | 156 | #define FTRACE_ENTRY(call, struct_name, type, tstruct, print) \ |
161 | \ | 157 | \ |
158 | struct ftrace_event_class event_class_ftrace_##call = { \ | ||
159 | .system = __stringify(TRACE_SYSTEM), \ | ||
160 | .define_fields = ftrace_define_fields_##call, \ | ||
161 | }; \ | ||
162 | \ | ||
162 | struct ftrace_event_call __used \ | 163 | struct ftrace_event_call __used \ |
163 | __attribute__((__aligned__(4))) \ | 164 | __attribute__((__aligned__(4))) \ |
164 | __attribute__((section("_ftrace_events"))) event_##call = { \ | 165 | __attribute__((section("_ftrace_events"))) event_##call = { \ |
165 | .name = #call, \ | 166 | .name = #call, \ |
166 | .id = type, \ | 167 | .id = type, \ |
167 | .class = &event_class_ftrace, \ | 168 | .class = &event_class_ftrace_##call, \ |
168 | .raw_init = ftrace_raw_init_event, \ | 169 | .raw_init = ftrace_raw_init_event, \ |
169 | .print_fmt = print, \ | 170 | .print_fmt = print, \ |
170 | .define_fields = ftrace_define_fields_##call, \ | ||
171 | }; \ | 171 | }; \ |
172 | 172 | ||
173 | #include "trace_entries.h" | 173 | #include "trace_entries.h" |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index f8af21a53f0c..b14bf745356f 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -1112,8 +1112,6 @@ static void probe_event_disable(struct ftrace_event_call *call) | |||
1112 | 1112 | ||
1113 | static int probe_event_raw_init(struct ftrace_event_call *event_call) | 1113 | static int probe_event_raw_init(struct ftrace_event_call *event_call) |
1114 | { | 1114 | { |
1115 | INIT_LIST_HEAD(&event_call->fields); | ||
1116 | |||
1117 | return 0; | 1115 | return 0; |
1118 | } | 1116 | } |
1119 | 1117 | ||
@@ -1362,11 +1360,13 @@ static int register_probe_event(struct trace_probe *tp) | |||
1362 | if (probe_is_return(tp)) { | 1360 | if (probe_is_return(tp)) { |
1363 | tp->event.trace = print_kretprobe_event; | 1361 | tp->event.trace = print_kretprobe_event; |
1364 | call->raw_init = probe_event_raw_init; | 1362 | call->raw_init = probe_event_raw_init; |
1365 | call->define_fields = kretprobe_event_define_fields; | 1363 | INIT_LIST_HEAD(&call->class->fields); |
1364 | call->class->define_fields = kretprobe_event_define_fields; | ||
1366 | } else { | 1365 | } else { |
1367 | tp->event.trace = print_kprobe_event; | 1366 | tp->event.trace = print_kprobe_event; |
1368 | call->raw_init = probe_event_raw_init; | 1367 | call->raw_init = probe_event_raw_init; |
1369 | call->define_fields = kprobe_event_define_fields; | 1368 | INIT_LIST_HEAD(&call->class->fields); |
1369 | call->class->define_fields = kprobe_event_define_fields; | ||
1370 | } | 1370 | } |
1371 | if (set_print_fmt(tp) < 0) | 1371 | if (set_print_fmt(tp) < 0) |
1372 | return -ENOMEM; | 1372 | return -ENOMEM; |
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index a21d366cae46..cceccf0d2e91 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -20,14 +20,37 @@ static int syscall_enter_register(struct ftrace_event_call *event, | |||
20 | static int syscall_exit_register(struct ftrace_event_call *event, | 20 | static int syscall_exit_register(struct ftrace_event_call *event, |
21 | enum trace_reg type); | 21 | enum trace_reg type); |
22 | 22 | ||
23 | static int syscall_enter_define_fields(struct ftrace_event_call *call); | ||
24 | static int syscall_exit_define_fields(struct ftrace_event_call *call); | ||
25 | |||
26 | static struct list_head * | ||
27 | syscall_get_enter_fields(struct ftrace_event_call *call) | ||
28 | { | ||
29 | struct syscall_metadata *entry = call->data; | ||
30 | |||
31 | return &entry->enter_fields; | ||
32 | } | ||
33 | |||
34 | static struct list_head * | ||
35 | syscall_get_exit_fields(struct ftrace_event_call *call) | ||
36 | { | ||
37 | struct syscall_metadata *entry = call->data; | ||
38 | |||
39 | return &entry->exit_fields; | ||
40 | } | ||
41 | |||
23 | struct ftrace_event_class event_class_syscall_enter = { | 42 | struct ftrace_event_class event_class_syscall_enter = { |
24 | .system = "syscalls", | 43 | .system = "syscalls", |
25 | .reg = syscall_enter_register | 44 | .reg = syscall_enter_register, |
45 | .define_fields = syscall_enter_define_fields, | ||
46 | .get_fields = syscall_get_enter_fields, | ||
26 | }; | 47 | }; |
27 | 48 | ||
28 | struct ftrace_event_class event_class_syscall_exit = { | 49 | struct ftrace_event_class event_class_syscall_exit = { |
29 | .system = "syscalls", | 50 | .system = "syscalls", |
30 | .reg = syscall_exit_register | 51 | .reg = syscall_exit_register, |
52 | .define_fields = syscall_exit_define_fields, | ||
53 | .get_fields = syscall_get_exit_fields, | ||
31 | }; | 54 | }; |
32 | 55 | ||
33 | extern unsigned long __start_syscalls_metadata[]; | 56 | extern unsigned long __start_syscalls_metadata[]; |
@@ -220,7 +243,7 @@ static void free_syscall_print_fmt(struct ftrace_event_call *call) | |||
220 | kfree(call->print_fmt); | 243 | kfree(call->print_fmt); |
221 | } | 244 | } |
222 | 245 | ||
223 | int syscall_enter_define_fields(struct ftrace_event_call *call) | 246 | static int syscall_enter_define_fields(struct ftrace_event_call *call) |
224 | { | 247 | { |
225 | struct syscall_trace_enter trace; | 248 | struct syscall_trace_enter trace; |
226 | struct syscall_metadata *meta = call->data; | 249 | struct syscall_metadata *meta = call->data; |
@@ -243,7 +266,7 @@ int syscall_enter_define_fields(struct ftrace_event_call *call) | |||
243 | return ret; | 266 | return ret; |
244 | } | 267 | } |
245 | 268 | ||
246 | int syscall_exit_define_fields(struct ftrace_event_call *call) | 269 | static int syscall_exit_define_fields(struct ftrace_event_call *call) |
247 | { | 270 | { |
248 | struct syscall_trace_exit trace; | 271 | struct syscall_trace_exit trace; |
249 | int ret; | 272 | int ret; |