diff options
Diffstat (limited to 'kernel/trace/trace_events.c')
| -rw-r--r-- | kernel/trace/trace_events.c | 191 |
1 files changed, 124 insertions, 67 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index d128f65778e6..1d18315dc836 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -93,9 +93,7 @@ int trace_define_common_fields(struct ftrace_event_call *call) | |||
| 93 | } | 93 | } |
| 94 | EXPORT_SYMBOL_GPL(trace_define_common_fields); | 94 | EXPORT_SYMBOL_GPL(trace_define_common_fields); |
| 95 | 95 | ||
| 96 | #ifdef CONFIG_MODULES | 96 | void trace_destroy_fields(struct ftrace_event_call *call) |
| 97 | |||
| 98 | static void trace_destroy_fields(struct ftrace_event_call *call) | ||
| 99 | { | 97 | { |
| 100 | struct ftrace_event_field *field, *next; | 98 | struct ftrace_event_field *field, *next; |
| 101 | 99 | ||
| @@ -107,8 +105,6 @@ static void trace_destroy_fields(struct ftrace_event_call *call) | |||
| 107 | } | 105 | } |
| 108 | } | 106 | } |
| 109 | 107 | ||
| 110 | #endif /* CONFIG_MODULES */ | ||
| 111 | |||
| 112 | static void ftrace_event_enable_disable(struct ftrace_event_call *call, | 108 | static void ftrace_event_enable_disable(struct ftrace_event_call *call, |
| 113 | int enable) | 109 | int enable) |
| 114 | { | 110 | { |
| @@ -117,14 +113,14 @@ static void ftrace_event_enable_disable(struct ftrace_event_call *call, | |||
| 117 | if (call->enabled) { | 113 | if (call->enabled) { |
| 118 | call->enabled = 0; | 114 | call->enabled = 0; |
| 119 | tracing_stop_cmdline_record(); | 115 | tracing_stop_cmdline_record(); |
| 120 | call->unregfunc(call->data); | 116 | call->unregfunc(call); |
| 121 | } | 117 | } |
| 122 | break; | 118 | break; |
| 123 | case 1: | 119 | case 1: |
| 124 | if (!call->enabled) { | 120 | if (!call->enabled) { |
| 125 | call->enabled = 1; | 121 | call->enabled = 1; |
| 126 | tracing_start_cmdline_record(); | 122 | tracing_start_cmdline_record(); |
| 127 | call->regfunc(call->data); | 123 | call->regfunc(call); |
| 128 | } | 124 | } |
| 129 | break; | 125 | break; |
| 130 | } | 126 | } |
| @@ -507,7 +503,7 @@ extern char *__bad_type_size(void); | |||
| 507 | #define FIELD(type, name) \ | 503 | #define FIELD(type, name) \ |
| 508 | sizeof(type) != sizeof(field.name) ? __bad_type_size() : \ | 504 | sizeof(type) != sizeof(field.name) ? __bad_type_size() : \ |
| 509 | #type, "common_" #name, offsetof(typeof(field), name), \ | 505 | #type, "common_" #name, offsetof(typeof(field), name), \ |
| 510 | sizeof(field.name) | 506 | sizeof(field.name), is_signed_type(type) |
| 511 | 507 | ||
| 512 | static int trace_write_header(struct trace_seq *s) | 508 | static int trace_write_header(struct trace_seq *s) |
| 513 | { | 509 | { |
| @@ -515,17 +511,17 @@ static int trace_write_header(struct trace_seq *s) | |||
| 515 | 511 | ||
| 516 | /* struct trace_entry */ | 512 | /* struct trace_entry */ |
| 517 | return trace_seq_printf(s, | 513 | return trace_seq_printf(s, |
| 518 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 514 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
| 519 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 515 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
| 520 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 516 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
| 521 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 517 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
| 522 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 518 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
| 523 | "\n", | 519 | "\n", |
| 524 | FIELD(unsigned short, type), | 520 | FIELD(unsigned short, type), |
| 525 | FIELD(unsigned char, flags), | 521 | FIELD(unsigned char, flags), |
| 526 | FIELD(unsigned char, preempt_count), | 522 | FIELD(unsigned char, preempt_count), |
| 527 | FIELD(int, pid), | 523 | FIELD(int, pid), |
| 528 | FIELD(int, lock_depth)); | 524 | FIELD(int, lock_depth)); |
| 529 | } | 525 | } |
| 530 | 526 | ||
| 531 | static ssize_t | 527 | static ssize_t |
| @@ -878,9 +874,9 @@ event_subsystem_dir(const char *name, struct dentry *d_events) | |||
| 878 | "'%s/filter' entry\n", name); | 874 | "'%s/filter' entry\n", name); |
| 879 | } | 875 | } |
| 880 | 876 | ||
| 881 | entry = trace_create_file("enable", 0644, system->entry, | 877 | trace_create_file("enable", 0644, system->entry, |
| 882 | (void *)system->name, | 878 | (void *)system->name, |
| 883 | &ftrace_system_enable_fops); | 879 | &ftrace_system_enable_fops); |
| 884 | 880 | ||
| 885 | return system->entry; | 881 | return system->entry; |
| 886 | } | 882 | } |
| @@ -892,7 +888,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 892 | const struct file_operations *filter, | 888 | const struct file_operations *filter, |
| 893 | const struct file_operations *format) | 889 | const struct file_operations *format) |
| 894 | { | 890 | { |
| 895 | struct dentry *entry; | ||
| 896 | int ret; | 891 | int ret; |
| 897 | 892 | ||
| 898 | /* | 893 | /* |
| @@ -910,12 +905,12 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 910 | } | 905 | } |
| 911 | 906 | ||
| 912 | if (call->regfunc) | 907 | if (call->regfunc) |
| 913 | entry = trace_create_file("enable", 0644, call->dir, call, | 908 | trace_create_file("enable", 0644, call->dir, call, |
| 914 | enable); | 909 | enable); |
| 915 | 910 | ||
| 916 | if (call->id && call->profile_enable) | 911 | if (call->id && call->profile_enable) |
| 917 | entry = trace_create_file("id", 0444, call->dir, call, | 912 | trace_create_file("id", 0444, call->dir, call, |
| 918 | id); | 913 | id); |
| 919 | 914 | ||
| 920 | if (call->define_fields) { | 915 | if (call->define_fields) { |
| 921 | ret = call->define_fields(call); | 916 | ret = call->define_fields(call); |
| @@ -924,41 +919,60 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 924 | " events/%s\n", call->name); | 919 | " events/%s\n", call->name); |
| 925 | return ret; | 920 | return ret; |
| 926 | } | 921 | } |
| 927 | entry = trace_create_file("filter", 0644, call->dir, call, | 922 | trace_create_file("filter", 0644, call->dir, call, |
| 928 | filter); | 923 | filter); |
| 929 | } | 924 | } |
| 930 | 925 | ||
| 931 | /* A trace may not want to export its format */ | 926 | /* A trace may not want to export its format */ |
| 932 | if (!call->show_format) | 927 | if (!call->show_format) |
| 933 | return 0; | 928 | return 0; |
| 934 | 929 | ||
| 935 | entry = trace_create_file("format", 0444, call->dir, call, | 930 | trace_create_file("format", 0444, call->dir, call, |
| 936 | format); | 931 | format); |
| 937 | 932 | ||
| 938 | return 0; | 933 | return 0; |
| 939 | } | 934 | } |
| 940 | 935 | ||
| 941 | #define for_each_event(event, start, end) \ | 936 | static int __trace_add_event_call(struct ftrace_event_call *call) |
| 942 | for (event = start; \ | 937 | { |
| 943 | (unsigned long)event < (unsigned long)end; \ | 938 | struct dentry *d_events; |
| 944 | event++) | 939 | int ret; |
| 945 | 940 | ||
| 946 | #ifdef CONFIG_MODULES | 941 | if (!call->name) |
| 942 | return -EINVAL; | ||
| 947 | 943 | ||
| 948 | static LIST_HEAD(ftrace_module_file_list); | 944 | if (call->raw_init) { |
| 945 | ret = call->raw_init(call); | ||
| 946 | if (ret < 0) { | ||
| 947 | if (ret != -ENOSYS) | ||
| 948 | pr_warning("Could not initialize trace " | ||
| 949 | "events/%s\n", call->name); | ||
| 950 | return ret; | ||
| 951 | } | ||
| 952 | } | ||
| 949 | 953 | ||
| 950 | /* | 954 | d_events = event_trace_events_dir(); |
| 951 | * Modules must own their file_operations to keep up with | 955 | if (!d_events) |
| 952 | * reference counting. | 956 | return -ENOENT; |
| 953 | */ | 957 | |
| 954 | struct ftrace_module_file_ops { | 958 | ret = event_create_dir(call, d_events, &ftrace_event_id_fops, |
| 955 | struct list_head list; | 959 | &ftrace_enable_fops, &ftrace_event_filter_fops, |
| 956 | struct module *mod; | 960 | &ftrace_event_format_fops); |
| 957 | struct file_operations id; | 961 | if (!ret) |
| 958 | struct file_operations enable; | 962 | list_add(&call->list, &ftrace_events); |
| 959 | struct file_operations format; | 963 | |
| 960 | struct file_operations filter; | 964 | return ret; |
| 961 | }; | 965 | } |
| 966 | |||
| 967 | /* Add an additional event_call dynamically */ | ||
| 968 | int trace_add_event_call(struct ftrace_event_call *call) | ||
| 969 | { | ||
| 970 | int ret; | ||
| 971 | mutex_lock(&event_mutex); | ||
| 972 | ret = __trace_add_event_call(call); | ||
| 973 | mutex_unlock(&event_mutex); | ||
| 974 | return ret; | ||
| 975 | } | ||
| 962 | 976 | ||
| 963 | static void remove_subsystem_dir(const char *name) | 977 | static void remove_subsystem_dir(const char *name) |
| 964 | { | 978 | { |
| @@ -986,6 +1000,53 @@ static void remove_subsystem_dir(const char *name) | |||
| 986 | } | 1000 | } |
| 987 | } | 1001 | } |
| 988 | 1002 | ||
| 1003 | /* | ||
| 1004 | * Must be called under locking both of event_mutex and trace_event_mutex. | ||
| 1005 | */ | ||
| 1006 | static void __trace_remove_event_call(struct ftrace_event_call *call) | ||
| 1007 | { | ||
| 1008 | ftrace_event_enable_disable(call, 0); | ||
| 1009 | if (call->event) | ||
| 1010 | __unregister_ftrace_event(call->event); | ||
| 1011 | debugfs_remove_recursive(call->dir); | ||
| 1012 | list_del(&call->list); | ||
| 1013 | trace_destroy_fields(call); | ||
| 1014 | destroy_preds(call); | ||
| 1015 | remove_subsystem_dir(call->system); | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | /* Remove an event_call */ | ||
| 1019 | void trace_remove_event_call(struct ftrace_event_call *call) | ||
| 1020 | { | ||
| 1021 | mutex_lock(&event_mutex); | ||
| 1022 | down_write(&trace_event_mutex); | ||
| 1023 | __trace_remove_event_call(call); | ||
| 1024 | up_write(&trace_event_mutex); | ||
| 1025 | mutex_unlock(&event_mutex); | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | #define for_each_event(event, start, end) \ | ||
| 1029 | for (event = start; \ | ||
| 1030 | (unsigned long)event < (unsigned long)end; \ | ||
| 1031 | event++) | ||
| 1032 | |||
| 1033 | #ifdef CONFIG_MODULES | ||
| 1034 | |||
| 1035 | static LIST_HEAD(ftrace_module_file_list); | ||
| 1036 | |||
| 1037 | /* | ||
| 1038 | * Modules must own their file_operations to keep up with | ||
| 1039 | * reference counting. | ||
| 1040 | */ | ||
| 1041 | struct ftrace_module_file_ops { | ||
| 1042 | struct list_head list; | ||
| 1043 | struct module *mod; | ||
| 1044 | struct file_operations id; | ||
| 1045 | struct file_operations enable; | ||
| 1046 | struct file_operations format; | ||
| 1047 | struct file_operations filter; | ||
| 1048 | }; | ||
| 1049 | |||
| 989 | static struct ftrace_module_file_ops * | 1050 | static struct ftrace_module_file_ops * |
| 990 | trace_create_file_ops(struct module *mod) | 1051 | trace_create_file_ops(struct module *mod) |
| 991 | { | 1052 | { |
| @@ -1043,7 +1104,7 @@ static void trace_module_add_events(struct module *mod) | |||
| 1043 | if (!call->name) | 1104 | if (!call->name) |
| 1044 | continue; | 1105 | continue; |
| 1045 | if (call->raw_init) { | 1106 | if (call->raw_init) { |
| 1046 | ret = call->raw_init(); | 1107 | ret = call->raw_init(call); |
| 1047 | if (ret < 0) { | 1108 | if (ret < 0) { |
| 1048 | if (ret != -ENOSYS) | 1109 | if (ret != -ENOSYS) |
| 1049 | pr_warning("Could not initialize trace " | 1110 | pr_warning("Could not initialize trace " |
| @@ -1061,10 +1122,11 @@ static void trace_module_add_events(struct module *mod) | |||
| 1061 | return; | 1122 | return; |
| 1062 | } | 1123 | } |
| 1063 | call->mod = mod; | 1124 | call->mod = mod; |
| 1064 | list_add(&call->list, &ftrace_events); | 1125 | ret = event_create_dir(call, d_events, |
| 1065 | event_create_dir(call, d_events, | 1126 | &file_ops->id, &file_ops->enable, |
| 1066 | &file_ops->id, &file_ops->enable, | 1127 | &file_ops->filter, &file_ops->format); |
| 1067 | &file_ops->filter, &file_ops->format); | 1128 | if (!ret) |
| 1129 | list_add(&call->list, &ftrace_events); | ||
| 1068 | } | 1130 | } |
| 1069 | } | 1131 | } |
| 1070 | 1132 | ||
| @@ -1078,14 +1140,7 @@ static void trace_module_remove_events(struct module *mod) | |||
| 1078 | list_for_each_entry_safe(call, p, &ftrace_events, list) { | 1140 | list_for_each_entry_safe(call, p, &ftrace_events, list) { |
| 1079 | if (call->mod == mod) { | 1141 | if (call->mod == mod) { |
| 1080 | found = true; | 1142 | found = true; |
| 1081 | ftrace_event_enable_disable(call, 0); | 1143 | __trace_remove_event_call(call); |
| 1082 | if (call->event) | ||
| 1083 | __unregister_ftrace_event(call->event); | ||
| 1084 | debugfs_remove_recursive(call->dir); | ||
| 1085 | list_del(&call->list); | ||
| 1086 | trace_destroy_fields(call); | ||
| 1087 | destroy_preds(call); | ||
| 1088 | remove_subsystem_dir(call->system); | ||
| 1089 | } | 1144 | } |
| 1090 | } | 1145 | } |
| 1091 | 1146 | ||
| @@ -1203,7 +1258,7 @@ static __init int event_trace_init(void) | |||
| 1203 | if (!call->name) | 1258 | if (!call->name) |
| 1204 | continue; | 1259 | continue; |
| 1205 | if (call->raw_init) { | 1260 | if (call->raw_init) { |
| 1206 | ret = call->raw_init(); | 1261 | ret = call->raw_init(call); |
| 1207 | if (ret < 0) { | 1262 | if (ret < 0) { |
| 1208 | if (ret != -ENOSYS) | 1263 | if (ret != -ENOSYS) |
| 1209 | pr_warning("Could not initialize trace " | 1264 | pr_warning("Could not initialize trace " |
| @@ -1211,10 +1266,12 @@ static __init int event_trace_init(void) | |||
| 1211 | continue; | 1266 | continue; |
| 1212 | } | 1267 | } |
| 1213 | } | 1268 | } |
| 1214 | list_add(&call->list, &ftrace_events); | 1269 | ret = event_create_dir(call, d_events, &ftrace_event_id_fops, |
| 1215 | event_create_dir(call, d_events, &ftrace_event_id_fops, | 1270 | &ftrace_enable_fops, |
| 1216 | &ftrace_enable_fops, &ftrace_event_filter_fops, | 1271 | &ftrace_event_filter_fops, |
| 1217 | &ftrace_event_format_fops); | 1272 | &ftrace_event_format_fops); |
| 1273 | if (!ret) | ||
| 1274 | list_add(&call->list, &ftrace_events); | ||
| 1218 | } | 1275 | } |
| 1219 | 1276 | ||
| 1220 | while (true) { | 1277 | while (true) { |
