diff options
-rw-r--r-- | kernel/trace/trace.h | 3 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 55 |
2 files changed, 54 insertions, 4 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 2c3cba59552d..c7fbf93f1b7c 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -226,6 +226,9 @@ extern struct list_head ftrace_trace_arrays; | |||
226 | 226 | ||
227 | extern struct mutex trace_types_lock; | 227 | extern struct mutex trace_types_lock; |
228 | 228 | ||
229 | extern int trace_array_get(struct trace_array *tr); | ||
230 | extern void trace_array_put(struct trace_array *tr); | ||
231 | |||
229 | /* | 232 | /* |
230 | * The global tracer (top) should be the first trace array added, | 233 | * The global tracer (top) should be the first trace array added, |
231 | * but we check the flag anyway. | 234 | * but we check the flag anyway. |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 35c6f23c71b2..920e08fb53b3 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -410,6 +410,35 @@ static void put_system(struct ftrace_subsystem_dir *dir) | |||
410 | } | 410 | } |
411 | 411 | ||
412 | /* | 412 | /* |
413 | * Open and update trace_array ref count. | ||
414 | * Must have the current trace_array passed to it. | ||
415 | */ | ||
416 | static int tracing_open_generic_file(struct inode *inode, struct file *filp) | ||
417 | { | ||
418 | struct ftrace_event_file *file = inode->i_private; | ||
419 | struct trace_array *tr = file->tr; | ||
420 | int ret; | ||
421 | |||
422 | if (trace_array_get(tr) < 0) | ||
423 | return -ENODEV; | ||
424 | |||
425 | ret = tracing_open_generic(inode, filp); | ||
426 | if (ret < 0) | ||
427 | trace_array_put(tr); | ||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | static int tracing_release_generic_file(struct inode *inode, struct file *filp) | ||
432 | { | ||
433 | struct ftrace_event_file *file = inode->i_private; | ||
434 | struct trace_array *tr = file->tr; | ||
435 | |||
436 | trace_array_put(tr); | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | /* | ||
413 | * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events. | 442 | * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events. |
414 | */ | 443 | */ |
415 | static int __ftrace_set_clr_event(struct trace_array *tr, const char *match, | 444 | static int __ftrace_set_clr_event(struct trace_array *tr, const char *match, |
@@ -1032,9 +1061,17 @@ static int subsystem_open(struct inode *inode, struct file *filp) | |||
1032 | /* Some versions of gcc think dir can be uninitialized here */ | 1061 | /* Some versions of gcc think dir can be uninitialized here */ |
1033 | WARN_ON(!dir); | 1062 | WARN_ON(!dir); |
1034 | 1063 | ||
1064 | /* Still need to increment the ref count of the system */ | ||
1065 | if (trace_array_get(tr) < 0) { | ||
1066 | put_system(dir); | ||
1067 | return -ENODEV; | ||
1068 | } | ||
1069 | |||
1035 | ret = tracing_open_generic(inode, filp); | 1070 | ret = tracing_open_generic(inode, filp); |
1036 | if (ret < 0) | 1071 | if (ret < 0) { |
1072 | trace_array_put(tr); | ||
1037 | put_system(dir); | 1073 | put_system(dir); |
1074 | } | ||
1038 | 1075 | ||
1039 | return ret; | 1076 | return ret; |
1040 | } | 1077 | } |
@@ -1045,16 +1082,23 @@ static int system_tr_open(struct inode *inode, struct file *filp) | |||
1045 | struct trace_array *tr = inode->i_private; | 1082 | struct trace_array *tr = inode->i_private; |
1046 | int ret; | 1083 | int ret; |
1047 | 1084 | ||
1085 | if (trace_array_get(tr) < 0) | ||
1086 | return -ENODEV; | ||
1087 | |||
1048 | /* Make a temporary dir that has no system but points to tr */ | 1088 | /* Make a temporary dir that has no system but points to tr */ |
1049 | dir = kzalloc(sizeof(*dir), GFP_KERNEL); | 1089 | dir = kzalloc(sizeof(*dir), GFP_KERNEL); |
1050 | if (!dir) | 1090 | if (!dir) { |
1091 | trace_array_put(tr); | ||
1051 | return -ENOMEM; | 1092 | return -ENOMEM; |
1093 | } | ||
1052 | 1094 | ||
1053 | dir->tr = tr; | 1095 | dir->tr = tr; |
1054 | 1096 | ||
1055 | ret = tracing_open_generic(inode, filp); | 1097 | ret = tracing_open_generic(inode, filp); |
1056 | if (ret < 0) | 1098 | if (ret < 0) { |
1099 | trace_array_put(tr); | ||
1057 | kfree(dir); | 1100 | kfree(dir); |
1101 | } | ||
1058 | 1102 | ||
1059 | filp->private_data = dir; | 1103 | filp->private_data = dir; |
1060 | 1104 | ||
@@ -1065,6 +1109,8 @@ static int subsystem_release(struct inode *inode, struct file *file) | |||
1065 | { | 1109 | { |
1066 | struct ftrace_subsystem_dir *dir = file->private_data; | 1110 | struct ftrace_subsystem_dir *dir = file->private_data; |
1067 | 1111 | ||
1112 | trace_array_put(dir->tr); | ||
1113 | |||
1068 | /* | 1114 | /* |
1069 | * If dir->subsystem is NULL, then this is a temporary | 1115 | * If dir->subsystem is NULL, then this is a temporary |
1070 | * descriptor that was made for a trace_array to enable | 1116 | * descriptor that was made for a trace_array to enable |
@@ -1192,9 +1238,10 @@ static const struct file_operations ftrace_set_event_fops = { | |||
1192 | }; | 1238 | }; |
1193 | 1239 | ||
1194 | static const struct file_operations ftrace_enable_fops = { | 1240 | static const struct file_operations ftrace_enable_fops = { |
1195 | .open = tracing_open_generic, | 1241 | .open = tracing_open_generic_file, |
1196 | .read = event_enable_read, | 1242 | .read = event_enable_read, |
1197 | .write = event_enable_write, | 1243 | .write = event_enable_write, |
1244 | .release = tracing_release_generic_file, | ||
1198 | .llseek = default_llseek, | 1245 | .llseek = default_llseek, |
1199 | }; | 1246 | }; |
1200 | 1247 | ||