[PATCH 4.9 02/49] fgraph: Initialize tracing_graph_pause at task creation

From: Greg Kroah-Hartman
Date: Mon Feb 22 2021 - 08:37:17 EST


From: Steven Rostedt (VMware) <rostedt@xxxxxxxxxxx>

commit 7e0a9220467dbcfdc5bc62825724f3e52e50ab31 upstream.

On some archs, the idle task can call into cpu_suspend(). The cpu_suspend()
will disable or pause function graph tracing, as there's some paths in
bringing down the CPU that can have issues with its return address being
modified. The task_struct structure has a "tracing_graph_pause" atomic
counter, that when set to something other than zero, the function graph
tracer will not modify the return address.

The problem is that the tracing_graph_pause counter is initialized when the
function graph tracer is enabled. This can corrupt the counter for the idle
task if it is suspended in these architectures.

CPU 1 CPU 2
----- -----
do_idle()
cpu_suspend()
pause_graph_tracing()
task_struct->tracing_graph_pause++ (0 -> 1)

start_graph_tracing()
for_each_online_cpu(cpu) {
ftrace_graph_init_idle_task(cpu)
task-struct->tracing_graph_pause = 0 (1 -> 0)

unpause_graph_tracing()
task_struct->tracing_graph_pause-- (0 -> -1)

The above should have gone from 1 to zero, and enabled function graph
tracing again. But instead, it is set to -1, which keeps it disabled.

There's no reason that the field tracing_graph_pause on the task_struct can
not be initialized at boot up.

Cc: stable@xxxxxxxxxxxxxxx
Fixes: 380c4b1411ccd ("tracing/function-graph-tracer: append the tracing_graph_flag")
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=211339
Reported-by: pierre.gondois@xxxxxxx
Signed-off-by: Steven Rostedt (VMware) <rostedt@xxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
include/linux/ftrace.h | 4 +++-
kernel/trace/ftrace.c | 2 --
2 files changed, 3 insertions(+), 3 deletions(-)

--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -783,7 +783,9 @@ typedef int (*trace_func_graph_ent_t)(st
#ifdef CONFIG_FUNCTION_GRAPH_TRACER

/* for init task */
-#define INIT_FTRACE_GRAPH .ret_stack = NULL,
+#define INIT_FTRACE_GRAPH \
+ .ret_stack = NULL, \
+ .tracing_graph_pause = ATOMIC_INIT(0),

/*
* Stack of return addresses for functions
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5803,7 +5803,6 @@ static int alloc_retstack_tasklist(struc
}

if (t->ret_stack == NULL) {
- atomic_set(&t->tracing_graph_pause, 0);
atomic_set(&t->trace_overrun, 0);
t->curr_ret_stack = -1;
/* Make sure the tasks see the -1 first: */
@@ -6015,7 +6014,6 @@ static DEFINE_PER_CPU(struct ftrace_ret_
static void
graph_init_task(struct task_struct *t, struct ftrace_ret_stack *ret_stack)
{
- atomic_set(&t->tracing_graph_pause, 0);
atomic_set(&t->trace_overrun, 0);
t->ftrace_timestamp = 0;
/* make curr_ret_stack visible before we add the ret_stack */