diff options
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/trace.h | 1 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 86 | ||||
| -rw-r--r-- | kernel/trace/trace_events_filter.c | 6 |
3 files changed, 82 insertions, 11 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 229f8591f61d..f8074072d111 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -677,6 +677,7 @@ struct event_subsystem { | |||
| 677 | struct dentry *entry; | 677 | struct dentry *entry; |
| 678 | struct event_filter *filter; | 678 | struct event_filter *filter; |
| 679 | int nr_events; | 679 | int nr_events; |
| 680 | int ref_count; | ||
| 680 | }; | 681 | }; |
| 681 | 682 | ||
| 682 | #define FILTER_PRED_INVALID ((unsigned short)-1) | 683 | #define FILTER_PRED_INVALID ((unsigned short)-1) |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 686ec399f2a8..ffc5b2884af1 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -244,6 +244,35 @@ static void ftrace_clear_events(void) | |||
| 244 | mutex_unlock(&event_mutex); | 244 | mutex_unlock(&event_mutex); |
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | static void __put_system(struct event_subsystem *system) | ||
| 248 | { | ||
| 249 | struct event_filter *filter = system->filter; | ||
| 250 | |||
| 251 | WARN_ON_ONCE(system->ref_count == 0); | ||
| 252 | if (--system->ref_count) | ||
| 253 | return; | ||
| 254 | |||
| 255 | if (filter) { | ||
| 256 | kfree(filter->filter_string); | ||
| 257 | kfree(filter); | ||
| 258 | } | ||
| 259 | kfree(system->name); | ||
| 260 | kfree(system); | ||
| 261 | } | ||
| 262 | |||
| 263 | static void __get_system(struct event_subsystem *system) | ||
| 264 | { | ||
| 265 | WARN_ON_ONCE(system->ref_count == 0); | ||
| 266 | system->ref_count++; | ||
| 267 | } | ||
| 268 | |||
| 269 | static void put_system(struct event_subsystem *system) | ||
| 270 | { | ||
| 271 | mutex_lock(&event_mutex); | ||
| 272 | __put_system(system); | ||
| 273 | mutex_unlock(&event_mutex); | ||
| 274 | } | ||
| 275 | |||
| 247 | /* | 276 | /* |
| 248 | * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events. | 277 | * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events. |
| 249 | */ | 278 | */ |
| @@ -826,6 +855,47 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
| 826 | return cnt; | 855 | return cnt; |
| 827 | } | 856 | } |
| 828 | 857 | ||
| 858 | static LIST_HEAD(event_subsystems); | ||
| 859 | |||
| 860 | static int subsystem_open(struct inode *inode, struct file *filp) | ||
| 861 | { | ||
| 862 | struct event_subsystem *system = NULL; | ||
| 863 | int ret; | ||
| 864 | |||
| 865 | /* Make sure the system still exists */ | ||
| 866 | mutex_lock(&event_mutex); | ||
| 867 | list_for_each_entry(system, &event_subsystems, list) { | ||
| 868 | if (system == inode->i_private) { | ||
| 869 | /* Don't open systems with no events */ | ||
| 870 | if (!system->nr_events) { | ||
| 871 | system = NULL; | ||
| 872 | break; | ||
| 873 | } | ||
| 874 | __get_system(system); | ||
| 875 | break; | ||
| 876 | } | ||
| 877 | } | ||
| 878 | mutex_unlock(&event_mutex); | ||
| 879 | |||
| 880 | if (system != inode->i_private) | ||
| 881 | return -ENODEV; | ||
| 882 | |||
| 883 | ret = tracing_open_generic(inode, filp); | ||
| 884 | if (ret < 0) | ||
| 885 | put_system(system); | ||
| 886 | |||
| 887 | return ret; | ||
| 888 | } | ||
| 889 | |||
| 890 | static int subsystem_release(struct inode *inode, struct file *file) | ||
| 891 | { | ||
| 892 | struct event_subsystem *system = inode->i_private; | ||
| 893 | |||
| 894 | put_system(system); | ||
| 895 | |||
| 896 | return 0; | ||
| 897 | } | ||
| 898 | |||
| 829 | static ssize_t | 899 | static ssize_t |
| 830 | subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt, | 900 | subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt, |
| 831 | loff_t *ppos) | 901 | loff_t *ppos) |
| @@ -963,10 +1033,11 @@ static const struct file_operations ftrace_event_filter_fops = { | |||
| 963 | }; | 1033 | }; |
| 964 | 1034 | ||
| 965 | static const struct file_operations ftrace_subsystem_filter_fops = { | 1035 | static const struct file_operations ftrace_subsystem_filter_fops = { |
| 966 | .open = tracing_open_generic, | 1036 | .open = subsystem_open, |
| 967 | .read = subsystem_filter_read, | 1037 | .read = subsystem_filter_read, |
| 968 | .write = subsystem_filter_write, | 1038 | .write = subsystem_filter_write, |
| 969 | .llseek = default_llseek, | 1039 | .llseek = default_llseek, |
| 1040 | .release = subsystem_release, | ||
| 970 | }; | 1041 | }; |
| 971 | 1042 | ||
| 972 | static const struct file_operations ftrace_system_enable_fops = { | 1043 | static const struct file_operations ftrace_system_enable_fops = { |
| @@ -1002,8 +1073,6 @@ static struct dentry *event_trace_events_dir(void) | |||
| 1002 | return d_events; | 1073 | return d_events; |
| 1003 | } | 1074 | } |
| 1004 | 1075 | ||
| 1005 | static LIST_HEAD(event_subsystems); | ||
| 1006 | |||
| 1007 | static struct dentry * | 1076 | static struct dentry * |
| 1008 | event_subsystem_dir(const char *name, struct dentry *d_events) | 1077 | event_subsystem_dir(const char *name, struct dentry *d_events) |
| 1009 | { | 1078 | { |
| @@ -1013,6 +1082,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events) | |||
| 1013 | /* First see if we did not already create this dir */ | 1082 | /* First see if we did not already create this dir */ |
| 1014 | list_for_each_entry(system, &event_subsystems, list) { | 1083 | list_for_each_entry(system, &event_subsystems, list) { |
| 1015 | if (strcmp(system->name, name) == 0) { | 1084 | if (strcmp(system->name, name) == 0) { |
| 1085 | __get_system(system); | ||
| 1016 | system->nr_events++; | 1086 | system->nr_events++; |
| 1017 | return system->entry; | 1087 | return system->entry; |
| 1018 | } | 1088 | } |
| @@ -1035,6 +1105,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events) | |||
| 1035 | } | 1105 | } |
| 1036 | 1106 | ||
| 1037 | system->nr_events = 1; | 1107 | system->nr_events = 1; |
| 1108 | system->ref_count = 1; | ||
| 1038 | system->name = kstrdup(name, GFP_KERNEL); | 1109 | system->name = kstrdup(name, GFP_KERNEL); |
| 1039 | if (!system->name) { | 1110 | if (!system->name) { |
| 1040 | debugfs_remove(system->entry); | 1111 | debugfs_remove(system->entry); |
| @@ -1184,16 +1255,9 @@ static void remove_subsystem_dir(const char *name) | |||
| 1184 | list_for_each_entry(system, &event_subsystems, list) { | 1255 | list_for_each_entry(system, &event_subsystems, list) { |
| 1185 | if (strcmp(system->name, name) == 0) { | 1256 | if (strcmp(system->name, name) == 0) { |
| 1186 | if (!--system->nr_events) { | 1257 | if (!--system->nr_events) { |
| 1187 | struct event_filter *filter = system->filter; | ||
| 1188 | |||
| 1189 | debugfs_remove_recursive(system->entry); | 1258 | debugfs_remove_recursive(system->entry); |
| 1190 | list_del(&system->list); | 1259 | list_del(&system->list); |
| 1191 | if (filter) { | 1260 | __put_system(system); |
| 1192 | kfree(filter->filter_string); | ||
| 1193 | kfree(filter); | ||
| 1194 | } | ||
| 1195 | kfree(system->name); | ||
| 1196 | kfree(system); | ||
| 1197 | } | 1261 | } |
| 1198 | break; | 1262 | break; |
| 1199 | } | 1263 | } |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 8008ddcfbf20..256764ecccd6 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
| @@ -1886,6 +1886,12 @@ int apply_subsystem_event_filter(struct event_subsystem *system, | |||
| 1886 | 1886 | ||
| 1887 | mutex_lock(&event_mutex); | 1887 | mutex_lock(&event_mutex); |
| 1888 | 1888 | ||
| 1889 | /* Make sure the system still has events */ | ||
| 1890 | if (!system->nr_events) { | ||
| 1891 | err = -ENODEV; | ||
| 1892 | goto out_unlock; | ||
| 1893 | } | ||
| 1894 | |||
| 1889 | if (!strcmp(strstrip(filter_string), "0")) { | 1895 | if (!strcmp(strstrip(filter_string), "0")) { |
| 1890 | filter_free_subsystem_preds(system); | 1896 | filter_free_subsystem_preds(system); |
| 1891 | remove_filter_string(system->filter); | 1897 | remove_filter_string(system->filter); |
