| @@ -244,6 +244,35 @@ static void ftrace_clear_events(void) · 243 unmodified lines |
| 244 | 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 | 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, · 576 unmodified lines |
| 826 | 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 | 899 | static ssize_t |
| 830 | 900 | subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt, |
| 831 | 901 | loff_t *ppos) |
| @@ -963,10 +1033,11 @@ static const struct file_operations ftrace_event_filter_fops = { · 131 unmodified lines |
| 963 | 1033 | }; |
| 964 | 1034 | |
| 965 | 1035 | static const struct file_operations ftrace_subsystem_filter_fops = { |
| 966 | | − .open = tracing_open_generic, |
| 1036 | + .open = subsystem_open, |
| 967 | 1037 | .read = subsystem_filter_read, |
| 968 | 1038 | .write = subsystem_filter_write, |
| 969 | 1039 | .llseek = default_llseek, |
| 1040 | + .release = subsystem_release, |
| 970 | 1041 | }; |
| 971 | 1042 | |
| 972 | 1043 | static const struct file_operations ftrace_system_enable_fops = { |
| @@ -1002,8 +1073,6 @@ static struct dentry *event_trace_events_dir(void) · 29 unmodified lines |
| 1002 | 1073 | return d_events; |
| 1003 | 1074 | } |
| 1004 | 1075 | |
| 1005 | | −static LIST_HEAD(event_subsystems); |
| 1006 | | − |
| 1007 | 1076 | static struct dentry * |
| 1008 | 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) · 3 unmodified lines |
| 1013 | 1082 | /* First see if we did not already create this dir */ |
| 1014 | 1083 | list_for_each_entry(system, &event_subsystems, list) { |
| 1015 | 1084 | if (strcmp(system->name, name) == 0) { |
| 1085 | + __get_system(system); |
| 1016 | 1086 | system->nr_events++; |
| 1017 | 1087 | return system->entry; |
| 1018 | 1088 | } |
| @@ -1035,6 +1105,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events) · 16 unmodified lines |
| 1035 | 1105 | } |
| 1036 | 1106 | |
| 1037 | 1107 | system->nr_events = 1; |
| 1108 | + system->ref_count = 1; |
| 1038 | 1109 | system->name = kstrdup(name, GFP_KERNEL); |
| 1039 | 1110 | if (!system->name) { |
| 1040 | 1111 | debugfs_remove(system->entry); |
| @@ -1184,16 +1255,9 @@ static void remove_subsystem_dir(const char *name) · 143 unmodified lines |
| 1184 | 1255 | list_for_each_entry(system, &event_subsystems, list) { |
| 1185 | 1256 | if (strcmp(system->name, name) == 0) { |
| 1186 | 1257 | if (!--system->nr_events) { |
| 1187 | | − struct event_filter *filter = system->filter; |
| 1188 | | − |
| 1189 | 1258 | debugfs_remove_recursive(system->entry); |
| 1190 | 1259 | list_del(&system->list); |
| 1191 | | − if (filter) { |
| 1192 | | − kfree(filter->filter_string); |
| 1193 | | − kfree(filter); |
| 1194 | | − } |
| 1195 | | − kfree(system->name); |
| 1196 | | − kfree(system); |
| 1260 | + __put_system(system); |
| 1197 | 1261 | } |
| 1198 | 1262 | break; |
| 1199 | 1263 | } |