From: Greg Kroah-Hartman Date: Thu, 22 Aug 2013 23:17:03 +0000 (-0700) Subject: 3.10-stable patches X-Git-Tag: v3.0.94~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0d9ebbff80a796bc87bdb739862847034f064a04;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: tracing-change-remove_event_file_dir-to-clear-d_subdirs-i_private.patch --- diff --git a/queue-3.10/series b/queue-3.10/series index 565ecada592..3778680c733 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -28,3 +28,4 @@ tracing-change-event_enable-disable_read-to-verify-i_private-null.patch tracing-change-event_filter_read-write-to-verify-i_private-null.patch tracing-change-f_start-to-take-event_mutex-and-verify-i_private-null.patch tracing-introduce-remove_event_file_dir.patch +tracing-change-remove_event_file_dir-to-clear-d_subdirs-i_private.patch diff --git a/queue-3.10/tracing-change-remove_event_file_dir-to-clear-d_subdirs-i_private.patch b/queue-3.10/tracing-change-remove_event_file_dir-to-clear-d_subdirs-i_private.patch new file mode 100644 index 00000000000..1122cab1995 --- /dev/null +++ b/queue-3.10/tracing-change-remove_event_file_dir-to-clear-d_subdirs-i_private.patch @@ -0,0 +1,111 @@ +From bf682c3159c4d298d1126a56793ed3f5e80395f7 Mon Sep 17 00:00:00 2001 +From: Oleg Nesterov +Date: Sun, 28 Jul 2013 20:35:27 +0200 +Subject: tracing: Change remove_event_file_dir() to clear "d_subdirs"->i_private + +From: Oleg Nesterov + +commit bf682c3159c4d298d1126a56793ed3f5e80395f7 upstream. + +Change remove_event_file_dir() to clear ->i_private for every +file we are going to remove. + +We need to check file->dir != NULL because event_create_dir() +can fail. debugfs_remove_recursive(NULL) is fine but the patch +moves it under the same check anyway for readability. + +spin_lock(d_lock) and "d_inode != NULL" check are not needed +afaics, but I do not understand this code enough. + +tracing_open_generic_file() and tracing_release_generic_file() +can go away, ftrace_enable_fops and ftrace_event_filter_fops() +use tracing_open_generic() but only to check tracing_disabled. + +This fixes all races with event_remove() or instance_delete(). +f_op->read/write/whatever can never use the freed file/call, +all event/* files were changed to check and use ->i_private +under event_mutex. + +Note: this doesn't not fix other problems, event_remove() can +destroy the active ftrace_event_call, we need more changes but +those changes are completely orthogonal. + +Link: http://lkml.kernel.org/r/20130728183527.GB16723@redhat.com + +Reviewed-by: Masami Hiramatsu +Signed-off-by: Oleg Nesterov +Signed-off-by: Steven Rostedt +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/trace/trace_events.c | 47 ++++++++++++++------------------------------ + 1 file changed, 15 insertions(+), 32 deletions(-) + +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -426,39 +426,23 @@ static void *event_file_data(struct file + + static void remove_event_file_dir(struct ftrace_event_file *file) + { +- list_del(&file->list); +- debugfs_remove_recursive(file->dir); +- remove_subsystem(file->system); +- kmem_cache_free(file_cachep, file); +-} ++ struct dentry *dir = file->dir; ++ struct dentry *child; + +-/* +- * 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; ++ if (dir) { ++ spin_lock(&dir->d_lock); /* probably unneeded */ ++ list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) { ++ if (child->d_inode) /* probably unneeded */ ++ child->d_inode->i_private = NULL; ++ } ++ spin_unlock(&dir->d_lock); + +- trace_array_put(tr); ++ debugfs_remove_recursive(dir); ++ } + +- return 0; ++ list_del(&file->list); ++ remove_subsystem(file->system); ++ kmem_cache_free(file_cachep, file); + } + + /* +@@ -1303,10 +1287,9 @@ static const struct file_operations ftra + }; + + static const struct file_operations ftrace_enable_fops = { +- .open = tracing_open_generic_file, ++ .open = tracing_open_generic, + .read = event_enable_read, + .write = event_enable_write, +- .release = tracing_release_generic_file, + .llseek = default_llseek, + }; +