| From b6868908c58a1425e3ed08fb8fd2e23a284feb2f Mon Sep 17 00:00:00 2001 |
| From: "Steven Rostedt (VMware)" <rostedt@goodmis.org> |
| Date: Fri, 24 Jan 2020 17:47:49 -0500 |
| Subject: [PATCH] tracing: Fix very unlikely race of registering two stat |
| tracers |
| |
| commit dfb6cd1e654315168e36d947471bd2a0ccd834ae upstream. |
| |
| Looking through old emails in my INBOX, I came across a patch from Luis |
| Henriques that attempted to fix a race of two stat tracers registering the |
| same stat trace (extremely unlikely, as this is done in the kernel, and |
| probably doesn't even exist). The submitted patch wasn't quite right as it |
| needed to deal with clean up a bit better (if two stat tracers were the |
| same, it would have the same files). |
| |
| But to make the code cleaner, all we needed to do is to keep the |
| all_stat_sessions_mutex held for most of the registering function. |
| |
| Link: http://lkml.kernel.org/r/1410299375-20068-1-git-send-email-luis.henriques@canonical.com |
| |
| Fixes: 002bb86d8d42f ("tracing/ftrace: separate events tracing and stats tracing engine") |
| Reported-by: Luis Henriques <luis.henriques@canonical.com> |
| Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c |
| index bf68af63538b..92b76f9e25ed 100644 |
| --- a/kernel/trace/trace_stat.c |
| +++ b/kernel/trace/trace_stat.c |
| @@ -306,7 +306,7 @@ static int init_stat_file(struct stat_session *session) |
| int register_stat_tracer(struct tracer_stat *trace) |
| { |
| struct stat_session *session, *node; |
| - int ret; |
| + int ret = -EINVAL; |
| |
| if (!trace) |
| return -EINVAL; |
| @@ -317,17 +317,15 @@ int register_stat_tracer(struct tracer_stat *trace) |
| /* Already registered? */ |
| mutex_lock(&all_stat_sessions_mutex); |
| list_for_each_entry(node, &all_stat_sessions, session_list) { |
| - if (node->ts == trace) { |
| - mutex_unlock(&all_stat_sessions_mutex); |
| - return -EINVAL; |
| - } |
| + if (node->ts == trace) |
| + goto out; |
| } |
| - mutex_unlock(&all_stat_sessions_mutex); |
| |
| + ret = -ENOMEM; |
| /* Init the session */ |
| session = kzalloc(sizeof(*session), GFP_KERNEL); |
| if (!session) |
| - return -ENOMEM; |
| + goto out; |
| |
| session->ts = trace; |
| INIT_LIST_HEAD(&session->session_list); |
| @@ -336,15 +334,16 @@ int register_stat_tracer(struct tracer_stat *trace) |
| ret = init_stat_file(session); |
| if (ret) { |
| destroy_session(session); |
| - return ret; |
| + goto out; |
| } |
| |
| + ret = 0; |
| /* Register */ |
| - mutex_lock(&all_stat_sessions_mutex); |
| list_add_tail(&session->session_list, &all_stat_sessions); |
| + out: |
| mutex_unlock(&all_stat_sessions_mutex); |
| |
| - return 0; |
| + return ret; |
| } |
| |
| void unregister_stat_tracer(struct tracer_stat *trace) |
| -- |
| 2.7.4 |
| |