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; |
