|
@@ -409,6 +409,35 @@ static void put_system(struct ftrace_subsystem_dir *dir)
|
|
|
mutex_unlock(&event_mutex);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Open and update trace_array ref count.
|
|
|
+ * Must have the current trace_array passed to it.
|
|
|
+ */
|
|
|
+static int tracing_open_generic_file(struct inode *inode, struct file *filp)
|
|
|
+{
|
|
|
+ struct ftrace_event_file *file = inode->i_private;
|
|
|
+ struct trace_array *tr = file->tr;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (trace_array_get(tr) < 0)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ ret = tracing_open_generic(inode, filp);
|
|
|
+ if (ret < 0)
|
|
|
+ trace_array_put(tr);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int tracing_release_generic_file(struct inode *inode, struct file *filp)
|
|
|
+{
|
|
|
+ struct ftrace_event_file *file = inode->i_private;
|
|
|
+ struct trace_array *tr = file->tr;
|
|
|
+
|
|
|
+ trace_array_put(tr);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events.
|
|
|
*/
|
|
@@ -1032,9 +1061,17 @@ static int subsystem_open(struct inode *inode, struct file *filp)
|
|
|
/* Some versions of gcc think dir can be uninitialized here */
|
|
|
WARN_ON(!dir);
|
|
|
|
|
|
+ /* Still need to increment the ref count of the system */
|
|
|
+ if (trace_array_get(tr) < 0) {
|
|
|
+ put_system(dir);
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
ret = tracing_open_generic(inode, filp);
|
|
|
- if (ret < 0)
|
|
|
+ if (ret < 0) {
|
|
|
+ trace_array_put(tr);
|
|
|
put_system(dir);
|
|
|
+ }
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -1045,16 +1082,23 @@ static int system_tr_open(struct inode *inode, struct file *filp)
|
|
|
struct trace_array *tr = inode->i_private;
|
|
|
int ret;
|
|
|
|
|
|
+ if (trace_array_get(tr) < 0)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
/* Make a temporary dir that has no system but points to tr */
|
|
|
dir = kzalloc(sizeof(*dir), GFP_KERNEL);
|
|
|
- if (!dir)
|
|
|
+ if (!dir) {
|
|
|
+ trace_array_put(tr);
|
|
|
return -ENOMEM;
|
|
|
+ }
|
|
|
|
|
|
dir->tr = tr;
|
|
|
|
|
|
ret = tracing_open_generic(inode, filp);
|
|
|
- if (ret < 0)
|
|
|
+ if (ret < 0) {
|
|
|
+ trace_array_put(tr);
|
|
|
kfree(dir);
|
|
|
+ }
|
|
|
|
|
|
filp->private_data = dir;
|
|
|
|
|
@@ -1065,6 +1109,8 @@ static int subsystem_release(struct inode *inode, struct file *file)
|
|
|
{
|
|
|
struct ftrace_subsystem_dir *dir = file->private_data;
|
|
|
|
|
|
+ trace_array_put(dir->tr);
|
|
|
+
|
|
|
/*
|
|
|
* If dir->subsystem is NULL, then this is a temporary
|
|
|
* descriptor that was made for a trace_array to enable
|
|
@@ -1192,9 +1238,10 @@ static const struct file_operations ftrace_set_event_fops = {
|
|
|
};
|
|
|
|
|
|
static const struct file_operations ftrace_enable_fops = {
|
|
|
- .open = tracing_open_generic,
|
|
|
+ .open = tracing_open_generic_file,
|
|
|
.read = event_enable_read,
|
|
|
.write = event_enable_write,
|
|
|
+ .release = tracing_release_generic_file,
|
|
|
.llseek = default_llseek,
|
|
|
};
|
|
|
|