diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 462d2a70a835133de4f5b9b72c8b04ce87625eea..39c37b7d2d126f074c953b755bf7e82567cd509a 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4508,14 +4508,21 @@ int tracing_open_generic_tr(struct inode *inode, struct file *filp) */ int tracing_open_file_tr(struct inode *inode, struct file *filp) { - struct trace_event_file *file = inode->i_private; + struct trace_event_file *file; int ret; + mutex_lock(&event_mutex); + file = inode->i_private; + if (!file) { + mutex_unlock(&event_mutex); + return -ENODEV; + } + ret = tracing_check_open_get_tr(file->tr); - if (ret) + if (ret) { + mutex_unlock(&event_mutex); return ret; - - mutex_lock(&event_mutex); + } /* Fail if the file is marked for removal */ if (file->flags & EVENT_FILE_FL_FREED) { @@ -4529,14 +4536,14 @@ int tracing_open_file_tr(struct inode *inode, struct file *filp) if (ret) return ret; - filp->private_data = inode->i_private; + filp->private_data = file; return 0; } int tracing_release_file_tr(struct inode *inode, struct file *filp) { - struct trace_event_file *file = inode->i_private; + struct trace_event_file *file = filp->private_data; trace_array_put(file->tr); event_file_put(file); diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index c9ee8b730e43175bf85b193f7e7acbd70c3bceae..32b5d043203afe91fe977d8fd50d5d0064792057 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -764,9 +764,41 @@ void event_file_put(struct trace_event_file *file) } } +static bool file_op_depends_on_i_priv(const struct dentry *dentry) +{ + const struct file_operations *fop = NULL; + + if (!d_really_is_positive(dentry) || !d_inode(dentry)->i_fop) + return false; + + fop = d_inode(dentry)->i_fop; + if (fop->open == tracing_open_file_tr) + return true; +#ifdef CONFIG_HIST_TRIGGERS + if (fop == &event_hist_fops) + return true; +#endif +#ifdef CONFIG_HIST_TRIGGERS_DEBUG + if (fop == &event_hist_debug_fops) + return true; +#endif + + return false; +} + static void remove_event_file_dir(struct trace_event_file *file) { struct dentry *dir = file->dir; + struct dentry *child; + + if (dir) { + spin_lock(&dir->d_lock); /* probably unneeded */ + list_for_each_entry(child, &dir->d_subdirs, d_child) { + if (file_op_depends_on_i_priv(child)) + d_inode(child)->i_private = NULL; + } + spin_unlock(&dir->d_lock); + } tracefs_remove(dir); diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 920588dfdeb46994b0fa3c65dfe33b4797a725ed..532e4dbc98e684a6294cd97dad25ad831167b6be 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -4794,15 +4794,21 @@ static void hist_trigger_show(struct seq_file *m, n_entries, (u64)atomic64_read(&hist_data->map->drops)); } +struct hist_file_data { + struct file *file; + struct trace_event_file *event_file; +}; + static int hist_show(struct seq_file *m, void *v) { + struct hist_file_data *hist_file = m->private; struct event_trigger_data *data; struct trace_event_file *event_file; int n = 0, ret = 0; mutex_lock(&event_mutex); - event_file = event_file_data(m->private); + event_file = event_file_data(hist_file->file); if (unlikely(!event_file)) { ret = -ENODEV; goto out_unlock; @@ -4819,24 +4825,50 @@ static int hist_show(struct seq_file *m, void *v) return ret; } +static int tracing_release_hist_file_tr(struct inode *inode, struct file *file) +{ + struct seq_file *m = file->private_data; + struct hist_file_data *hist_file = m->private; + struct trace_event_file *event_file = hist_file->event_file; + + trace_array_put(event_file->tr); + event_file_put(event_file); + kfree(hist_file); + + return single_release(inode, file); +} + static int event_hist_open(struct inode *inode, struct file *file) { + struct hist_file_data *hist_file; int ret; + hist_file = kzalloc(sizeof(*hist_file), GFP_KERNEL); + if (!hist_file) + return -ENOMEM; + ret = tracing_open_file_tr(inode, file); - if (ret) + if (ret) { + kfree(hist_file); return ret; + } + + hist_file->file = file; + hist_file->event_file = file->private_data; /* Clear private_data to avoid warning in single_open() */ file->private_data = NULL; - return single_open(file, hist_show, file); + ret = single_open(file, hist_show, hist_file); + if (ret) + kfree(hist_file); + return ret; } const struct file_operations event_hist_fops = { .open = event_hist_open, .read = seq_read, .llseek = seq_lseek, - .release = tracing_single_release_file_tr, + .release = tracing_release_hist_file_tr, }; #ifdef CONFIG_HIST_TRIGGERS_DEBUG @@ -5070,13 +5102,14 @@ static void hist_trigger_debug_show(struct seq_file *m, static int hist_debug_show(struct seq_file *m, void *v) { + struct hist_file_data *hist_file = m->private; struct event_trigger_data *data; struct trace_event_file *event_file; int n = 0, ret = 0; mutex_lock(&event_mutex); - event_file = event_file_data(m->private); + event_file = event_file_data(hist_file->file); if (unlikely(!event_file)) { ret = -ENODEV; goto out_unlock; @@ -5095,22 +5128,35 @@ static int hist_debug_show(struct seq_file *m, void *v) static int event_hist_debug_open(struct inode *inode, struct file *file) { + struct hist_file_data *hist_file; int ret; + hist_file = kzalloc(sizeof(*hist_file), GFP_KERNEL); + if (!hist_file) + return -ENOMEM; + ret = tracing_open_file_tr(inode, file); - if (ret) + if (ret) { + kfree(hist_file); return ret; + } + + hist_file->file = file; + hist_file->event_file = file->private_data; /* Clear private_data to avoid warning in single_open() */ file->private_data = NULL; - return single_open(file, hist_debug_show, file); + ret = single_open(file, hist_debug_show, hist_file); + if (ret) + kfree(hist_file); + return ret; } const struct file_operations event_hist_debug_fops = { .open = event_hist_debug_open, .read = seq_read, .llseek = seq_lseek, - .release = tracing_single_release_file_tr, + .release = tracing_release_hist_file_tr, }; #endif