diff options
Diffstat (limited to 'kernel/trace/trace_events.c')
| -rw-r--r-- | kernel/trace/trace_events.c | 228 |
1 files changed, 155 insertions, 73 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index d128f65778e6..189b09baf4fb 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -78,7 +78,7 @@ EXPORT_SYMBOL_GPL(trace_define_field); | |||
| 78 | if (ret) \ | 78 | if (ret) \ |
| 79 | return ret; | 79 | return ret; |
| 80 | 80 | ||
| 81 | int trace_define_common_fields(struct ftrace_event_call *call) | 81 | static int trace_define_common_fields(struct ftrace_event_call *call) |
| 82 | { | 82 | { |
| 83 | int ret; | 83 | int ret; |
| 84 | struct trace_entry ent; | 84 | struct trace_entry ent; |
| @@ -91,11 +91,8 @@ int trace_define_common_fields(struct ftrace_event_call *call) | |||
| 91 | 91 | ||
| 92 | return ret; | 92 | return ret; |
| 93 | } | 93 | } |
| 94 | EXPORT_SYMBOL_GPL(trace_define_common_fields); | ||
| 95 | 94 | ||
| 96 | #ifdef CONFIG_MODULES | 95 | void trace_destroy_fields(struct ftrace_event_call *call) |
| 97 | |||
| 98 | static void trace_destroy_fields(struct ftrace_event_call *call) | ||
| 99 | { | 96 | { |
| 100 | struct ftrace_event_field *field, *next; | 97 | struct ftrace_event_field *field, *next; |
| 101 | 98 | ||
| @@ -107,27 +104,49 @@ static void trace_destroy_fields(struct ftrace_event_call *call) | |||
| 107 | } | 104 | } |
| 108 | } | 105 | } |
| 109 | 106 | ||
| 110 | #endif /* CONFIG_MODULES */ | 107 | int trace_event_raw_init(struct ftrace_event_call *call) |
| 108 | { | ||
| 109 | int id; | ||
| 110 | |||
| 111 | id = register_ftrace_event(call->event); | ||
| 112 | if (!id) | ||
| 113 | return -ENODEV; | ||
| 114 | call->id = id; | ||
| 115 | INIT_LIST_HEAD(&call->fields); | ||
| 116 | |||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | EXPORT_SYMBOL_GPL(trace_event_raw_init); | ||
| 111 | 120 | ||
| 112 | static void ftrace_event_enable_disable(struct ftrace_event_call *call, | 121 | static int ftrace_event_enable_disable(struct ftrace_event_call *call, |
| 113 | int enable) | 122 | int enable) |
| 114 | { | 123 | { |
| 124 | int ret = 0; | ||
| 125 | |||
| 115 | switch (enable) { | 126 | switch (enable) { |
| 116 | case 0: | 127 | case 0: |
| 117 | if (call->enabled) { | 128 | if (call->enabled) { |
| 118 | call->enabled = 0; | 129 | call->enabled = 0; |
| 119 | tracing_stop_cmdline_record(); | 130 | tracing_stop_cmdline_record(); |
| 120 | call->unregfunc(call->data); | 131 | call->unregfunc(call); |
| 121 | } | 132 | } |
| 122 | break; | 133 | break; |
| 123 | case 1: | 134 | case 1: |
| 124 | if (!call->enabled) { | 135 | if (!call->enabled) { |
| 125 | call->enabled = 1; | ||
| 126 | tracing_start_cmdline_record(); | 136 | tracing_start_cmdline_record(); |
| 127 | call->regfunc(call->data); | 137 | ret = call->regfunc(call); |
| 138 | if (ret) { | ||
| 139 | tracing_stop_cmdline_record(); | ||
| 140 | pr_info("event trace: Could not enable event " | ||
| 141 | "%s\n", call->name); | ||
| 142 | break; | ||
| 143 | } | ||
| 144 | call->enabled = 1; | ||
| 128 | } | 145 | } |
| 129 | break; | 146 | break; |
| 130 | } | 147 | } |
| 148 | |||
| 149 | return ret; | ||
| 131 | } | 150 | } |
| 132 | 151 | ||
| 133 | static void ftrace_clear_events(void) | 152 | static void ftrace_clear_events(void) |
| @@ -406,7 +425,7 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
| 406 | case 0: | 425 | case 0: |
| 407 | case 1: | 426 | case 1: |
| 408 | mutex_lock(&event_mutex); | 427 | mutex_lock(&event_mutex); |
| 409 | ftrace_event_enable_disable(call, val); | 428 | ret = ftrace_event_enable_disable(call, val); |
| 410 | mutex_unlock(&event_mutex); | 429 | mutex_unlock(&event_mutex); |
| 411 | break; | 430 | break; |
| 412 | 431 | ||
| @@ -416,7 +435,7 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
| 416 | 435 | ||
| 417 | *ppos += cnt; | 436 | *ppos += cnt; |
| 418 | 437 | ||
| 419 | return cnt; | 438 | return ret ? ret : cnt; |
| 420 | } | 439 | } |
| 421 | 440 | ||
| 422 | static ssize_t | 441 | static ssize_t |
| @@ -507,7 +526,7 @@ extern char *__bad_type_size(void); | |||
| 507 | #define FIELD(type, name) \ | 526 | #define FIELD(type, name) \ |
| 508 | sizeof(type) != sizeof(field.name) ? __bad_type_size() : \ | 527 | sizeof(type) != sizeof(field.name) ? __bad_type_size() : \ |
| 509 | #type, "common_" #name, offsetof(typeof(field), name), \ | 528 | #type, "common_" #name, offsetof(typeof(field), name), \ |
| 510 | sizeof(field.name) | 529 | sizeof(field.name), is_signed_type(type) |
| 511 | 530 | ||
| 512 | static int trace_write_header(struct trace_seq *s) | 531 | static int trace_write_header(struct trace_seq *s) |
| 513 | { | 532 | { |
| @@ -515,17 +534,17 @@ static int trace_write_header(struct trace_seq *s) | |||
| 515 | 534 | ||
| 516 | /* struct trace_entry */ | 535 | /* struct trace_entry */ |
| 517 | return trace_seq_printf(s, | 536 | return trace_seq_printf(s, |
| 518 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 537 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
| 519 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 538 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
| 520 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 539 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
| 521 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 540 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
| 522 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 541 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
| 523 | "\n", | 542 | "\n", |
| 524 | FIELD(unsigned short, type), | 543 | FIELD(unsigned short, type), |
| 525 | FIELD(unsigned char, flags), | 544 | FIELD(unsigned char, flags), |
| 526 | FIELD(unsigned char, preempt_count), | 545 | FIELD(unsigned char, preempt_count), |
| 527 | FIELD(int, pid), | 546 | FIELD(int, pid), |
| 528 | FIELD(int, lock_depth)); | 547 | FIELD(int, lock_depth)); |
| 529 | } | 548 | } |
| 530 | 549 | ||
| 531 | static ssize_t | 550 | static ssize_t |
| @@ -878,9 +897,9 @@ event_subsystem_dir(const char *name, struct dentry *d_events) | |||
| 878 | "'%s/filter' entry\n", name); | 897 | "'%s/filter' entry\n", name); |
| 879 | } | 898 | } |
| 880 | 899 | ||
| 881 | entry = trace_create_file("enable", 0644, system->entry, | 900 | trace_create_file("enable", 0644, system->entry, |
| 882 | (void *)system->name, | 901 | (void *)system->name, |
| 883 | &ftrace_system_enable_fops); | 902 | &ftrace_system_enable_fops); |
| 884 | 903 | ||
| 885 | return system->entry; | 904 | return system->entry; |
| 886 | } | 905 | } |
| @@ -892,7 +911,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 892 | const struct file_operations *filter, | 911 | const struct file_operations *filter, |
| 893 | const struct file_operations *format) | 912 | const struct file_operations *format) |
| 894 | { | 913 | { |
| 895 | struct dentry *entry; | ||
| 896 | int ret; | 914 | int ret; |
| 897 | 915 | ||
| 898 | /* | 916 | /* |
| @@ -910,55 +928,76 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 910 | } | 928 | } |
| 911 | 929 | ||
| 912 | if (call->regfunc) | 930 | if (call->regfunc) |
| 913 | entry = trace_create_file("enable", 0644, call->dir, call, | 931 | trace_create_file("enable", 0644, call->dir, call, |
| 914 | enable); | 932 | enable); |
| 915 | 933 | ||
| 916 | if (call->id && call->profile_enable) | 934 | if (call->id && call->profile_enable) |
| 917 | entry = trace_create_file("id", 0444, call->dir, call, | 935 | trace_create_file("id", 0444, call->dir, call, |
| 918 | id); | 936 | id); |
| 919 | 937 | ||
| 920 | if (call->define_fields) { | 938 | if (call->define_fields) { |
| 921 | ret = call->define_fields(call); | 939 | ret = trace_define_common_fields(call); |
| 940 | if (!ret) | ||
| 941 | ret = call->define_fields(call); | ||
| 922 | if (ret < 0) { | 942 | if (ret < 0) { |
| 923 | pr_warning("Could not initialize trace point" | 943 | pr_warning("Could not initialize trace point" |
| 924 | " events/%s\n", call->name); | 944 | " events/%s\n", call->name); |
| 925 | return ret; | 945 | return ret; |
| 926 | } | 946 | } |
| 927 | entry = trace_create_file("filter", 0644, call->dir, call, | 947 | trace_create_file("filter", 0644, call->dir, call, |
| 928 | filter); | 948 | filter); |
| 929 | } | 949 | } |
| 930 | 950 | ||
| 931 | /* A trace may not want to export its format */ | 951 | /* A trace may not want to export its format */ |
| 932 | if (!call->show_format) | 952 | if (!call->show_format) |
| 933 | return 0; | 953 | return 0; |
| 934 | 954 | ||
| 935 | entry = trace_create_file("format", 0444, call->dir, call, | 955 | trace_create_file("format", 0444, call->dir, call, |
| 936 | format); | 956 | format); |
| 937 | 957 | ||
| 938 | return 0; | 958 | return 0; |
| 939 | } | 959 | } |
| 940 | 960 | ||
| 941 | #define for_each_event(event, start, end) \ | 961 | static int __trace_add_event_call(struct ftrace_event_call *call) |
| 942 | for (event = start; \ | 962 | { |
| 943 | (unsigned long)event < (unsigned long)end; \ | 963 | struct dentry *d_events; |
| 944 | event++) | 964 | int ret; |
| 945 | 965 | ||
| 946 | #ifdef CONFIG_MODULES | 966 | if (!call->name) |
| 967 | return -EINVAL; | ||
| 947 | 968 | ||
| 948 | static LIST_HEAD(ftrace_module_file_list); | 969 | if (call->raw_init) { |
| 970 | ret = call->raw_init(call); | ||
| 971 | if (ret < 0) { | ||
| 972 | if (ret != -ENOSYS) | ||
| 973 | pr_warning("Could not initialize trace " | ||
| 974 | "events/%s\n", call->name); | ||
| 975 | return ret; | ||
| 976 | } | ||
| 977 | } | ||
| 949 | 978 | ||
| 950 | /* | 979 | d_events = event_trace_events_dir(); |
| 951 | * Modules must own their file_operations to keep up with | 980 | if (!d_events) |
| 952 | * reference counting. | 981 | return -ENOENT; |
| 953 | */ | 982 | |
| 954 | struct ftrace_module_file_ops { | 983 | ret = event_create_dir(call, d_events, &ftrace_event_id_fops, |
| 955 | struct list_head list; | 984 | &ftrace_enable_fops, &ftrace_event_filter_fops, |
| 956 | struct module *mod; | 985 | &ftrace_event_format_fops); |
| 957 | struct file_operations id; | 986 | if (!ret) |
| 958 | struct file_operations enable; | 987 | list_add(&call->list, &ftrace_events); |
| 959 | struct file_operations format; | 988 | |
| 960 | struct file_operations filter; | 989 | return ret; |
| 961 | }; | 990 | } |
| 991 | |||
| 992 | /* Add an additional event_call dynamically */ | ||
| 993 | int trace_add_event_call(struct ftrace_event_call *call) | ||
| 994 | { | ||
| 995 | int ret; | ||
| 996 | mutex_lock(&event_mutex); | ||
| 997 | ret = __trace_add_event_call(call); | ||
| 998 | mutex_unlock(&event_mutex); | ||
| 999 | return ret; | ||
| 1000 | } | ||
| 962 | 1001 | ||
| 963 | static void remove_subsystem_dir(const char *name) | 1002 | static void remove_subsystem_dir(const char *name) |
| 964 | { | 1003 | { |
| @@ -986,6 +1025,53 @@ static void remove_subsystem_dir(const char *name) | |||
| 986 | } | 1025 | } |
| 987 | } | 1026 | } |
| 988 | 1027 | ||
| 1028 | /* | ||
| 1029 | * Must be called under locking both of event_mutex and trace_event_mutex. | ||
| 1030 | */ | ||
| 1031 | static void __trace_remove_event_call(struct ftrace_event_call *call) | ||
| 1032 | { | ||
| 1033 | ftrace_event_enable_disable(call, 0); | ||
| 1034 | if (call->event) | ||
| 1035 | __unregister_ftrace_event(call->event); | ||
| 1036 | debugfs_remove_recursive(call->dir); | ||
| 1037 | list_del(&call->list); | ||
| 1038 | trace_destroy_fields(call); | ||
| 1039 | destroy_preds(call); | ||
| 1040 | remove_subsystem_dir(call->system); | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | /* Remove an event_call */ | ||
| 1044 | void trace_remove_event_call(struct ftrace_event_call *call) | ||
| 1045 | { | ||
| 1046 | mutex_lock(&event_mutex); | ||
| 1047 | down_write(&trace_event_mutex); | ||
| 1048 | __trace_remove_event_call(call); | ||
| 1049 | up_write(&trace_event_mutex); | ||
| 1050 | mutex_unlock(&event_mutex); | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | #define for_each_event(event, start, end) \ | ||
| 1054 | for (event = start; \ | ||
| 1055 | (unsigned long)event < (unsigned long)end; \ | ||
| 1056 | event++) | ||
| 1057 | |||
| 1058 | #ifdef CONFIG_MODULES | ||
| 1059 | |||
| 1060 | static LIST_HEAD(ftrace_module_file_list); | ||
| 1061 | |||
| 1062 | /* | ||
| 1063 | * Modules must own their file_operations to keep up with | ||
| 1064 | * reference counting. | ||
| 1065 | */ | ||
| 1066 | struct ftrace_module_file_ops { | ||
| 1067 | struct list_head list; | ||
| 1068 | struct module *mod; | ||
| 1069 | struct file_operations id; | ||
| 1070 | struct file_operations enable; | ||
| 1071 | struct file_operations format; | ||
| 1072 | struct file_operations filter; | ||
| 1073 | }; | ||
| 1074 | |||
| 989 | static struct ftrace_module_file_ops * | 1075 | static struct ftrace_module_file_ops * |
| 990 | trace_create_file_ops(struct module *mod) | 1076 | trace_create_file_ops(struct module *mod) |
| 991 | { | 1077 | { |
| @@ -1043,7 +1129,7 @@ static void trace_module_add_events(struct module *mod) | |||
| 1043 | if (!call->name) | 1129 | if (!call->name) |
| 1044 | continue; | 1130 | continue; |
| 1045 | if (call->raw_init) { | 1131 | if (call->raw_init) { |
| 1046 | ret = call->raw_init(); | 1132 | ret = call->raw_init(call); |
| 1047 | if (ret < 0) { | 1133 | if (ret < 0) { |
| 1048 | if (ret != -ENOSYS) | 1134 | if (ret != -ENOSYS) |
| 1049 | pr_warning("Could not initialize trace " | 1135 | pr_warning("Could not initialize trace " |
| @@ -1061,10 +1147,11 @@ static void trace_module_add_events(struct module *mod) | |||
| 1061 | return; | 1147 | return; |
| 1062 | } | 1148 | } |
| 1063 | call->mod = mod; | 1149 | call->mod = mod; |
| 1064 | list_add(&call->list, &ftrace_events); | 1150 | ret = event_create_dir(call, d_events, |
| 1065 | event_create_dir(call, d_events, | 1151 | &file_ops->id, &file_ops->enable, |
| 1066 | &file_ops->id, &file_ops->enable, | 1152 | &file_ops->filter, &file_ops->format); |
| 1067 | &file_ops->filter, &file_ops->format); | 1153 | if (!ret) |
| 1154 | list_add(&call->list, &ftrace_events); | ||
| 1068 | } | 1155 | } |
| 1069 | } | 1156 | } |
| 1070 | 1157 | ||
| @@ -1078,14 +1165,7 @@ static void trace_module_remove_events(struct module *mod) | |||
| 1078 | list_for_each_entry_safe(call, p, &ftrace_events, list) { | 1165 | list_for_each_entry_safe(call, p, &ftrace_events, list) { |
| 1079 | if (call->mod == mod) { | 1166 | if (call->mod == mod) { |
| 1080 | found = true; | 1167 | found = true; |
| 1081 | ftrace_event_enable_disable(call, 0); | 1168 | __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 | } | 1169 | } |
| 1090 | } | 1170 | } |
| 1091 | 1171 | ||
| @@ -1203,7 +1283,7 @@ static __init int event_trace_init(void) | |||
| 1203 | if (!call->name) | 1283 | if (!call->name) |
| 1204 | continue; | 1284 | continue; |
| 1205 | if (call->raw_init) { | 1285 | if (call->raw_init) { |
| 1206 | ret = call->raw_init(); | 1286 | ret = call->raw_init(call); |
| 1207 | if (ret < 0) { | 1287 | if (ret < 0) { |
| 1208 | if (ret != -ENOSYS) | 1288 | if (ret != -ENOSYS) |
| 1209 | pr_warning("Could not initialize trace " | 1289 | pr_warning("Could not initialize trace " |
| @@ -1211,10 +1291,12 @@ static __init int event_trace_init(void) | |||
| 1211 | continue; | 1291 | continue; |
| 1212 | } | 1292 | } |
| 1213 | } | 1293 | } |
| 1214 | list_add(&call->list, &ftrace_events); | 1294 | ret = event_create_dir(call, d_events, &ftrace_event_id_fops, |
| 1215 | event_create_dir(call, d_events, &ftrace_event_id_fops, | 1295 | &ftrace_enable_fops, |
| 1216 | &ftrace_enable_fops, &ftrace_event_filter_fops, | 1296 | &ftrace_event_filter_fops, |
| 1217 | &ftrace_event_format_fops); | 1297 | &ftrace_event_format_fops); |
| 1298 | if (!ret) | ||
| 1299 | list_add(&call->list, &ftrace_events); | ||
| 1218 | } | 1300 | } |
| 1219 | 1301 | ||
| 1220 | while (true) { | 1302 | while (true) { |
