]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-4.14/tracing-fgraph-fix-set_graph_function-from-showing-i.patch
autosel fixes for 4.14
[thirdparty/kernel/stable-queue.git] / queue-4.14 / tracing-fgraph-fix-set_graph_function-from-showing-i.patch
1 From b4edd765b94daf478cdc5d964a81d826af395af3 Mon Sep 17 00:00:00 2001
2 From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
3 Date: Thu, 29 Nov 2018 08:50:27 -0500
4 Subject: tracing/fgraph: Fix set_graph_function from showing interrupts
5
6 [ Upstream commit 5cf99a0f3161bc3ae2391269d134d6bf7e26f00e ]
7
8 The tracefs file set_graph_function is used to only function graph functions
9 that are listed in that file (or all functions if the file is empty). The
10 way this is implemented is that the function graph tracer looks at every
11 function, and if the current depth is zero and the function matches
12 something in the file then it will trace that function. When other functions
13 are called, the depth will be greater than zero (because the original
14 function will be at depth zero), and all functions will be traced where the
15 depth is greater than zero.
16
17 The issue is that when a function is first entered, and the handler that
18 checks this logic is called, the depth is set to zero. If an interrupt comes
19 in and a function in the interrupt handler is traced, its depth will be
20 greater than zero and it will automatically be traced, even if the original
21 function was not. But because the logic only looks at depth it may trace
22 interrupts when it should not be.
23
24 The recent design change of the function graph tracer to fix other bugs
25 caused the depth to be zero while the function graph callback handler is
26 being called for a longer time, widening the race of this happening. This
27 bug was actually there for a longer time, but because the race window was so
28 small it seldom happened. The Fixes tag below is for the commit that widen
29 the race window, because that commit belongs to a series that will also help
30 fix the original bug.
31
32 Cc: stable@kernel.org
33 Fixes: 39eb456dacb5 ("function_graph: Use new curr_ret_depth to manage depth instead of curr_ret_stack")
34 Reported-by: Joe Lawrence <joe.lawrence@redhat.com>
35 Tested-by: Joe Lawrence <joe.lawrence@redhat.com>
36 Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
37 Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
38 ---
39 kernel/trace/trace.h | 57 ++++++++++++++++++++++++++--
40 kernel/trace/trace_functions_graph.c | 4 ++
41 kernel/trace/trace_irqsoff.c | 2 +
42 kernel/trace/trace_sched_wakeup.c | 2 +
43 4 files changed, 62 insertions(+), 3 deletions(-)
44
45 diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
46 index 851cd16050857..a51e32de7c5f7 100644
47 --- a/kernel/trace/trace.h
48 +++ b/kernel/trace/trace.h
49 @@ -504,12 +504,44 @@ enum {
50 * can only be modified by current, we can reuse trace_recursion.
51 */
52 TRACE_IRQ_BIT,
53 +
54 + /* Set if the function is in the set_graph_function file */
55 + TRACE_GRAPH_BIT,
56 +
57 + /*
58 + * In the very unlikely case that an interrupt came in
59 + * at a start of graph tracing, and we want to trace
60 + * the function in that interrupt, the depth can be greater
61 + * than zero, because of the preempted start of a previous
62 + * trace. In an even more unlikely case, depth could be 2
63 + * if a softirq interrupted the start of graph tracing,
64 + * followed by an interrupt preempting a start of graph
65 + * tracing in the softirq, and depth can even be 3
66 + * if an NMI came in at the start of an interrupt function
67 + * that preempted a softirq start of a function that
68 + * preempted normal context!!!! Luckily, it can't be
69 + * greater than 3, so the next two bits are a mask
70 + * of what the depth is when we set TRACE_GRAPH_BIT
71 + */
72 +
73 + TRACE_GRAPH_DEPTH_START_BIT,
74 + TRACE_GRAPH_DEPTH_END_BIT,
75 };
76
77 #define trace_recursion_set(bit) do { (current)->trace_recursion |= (1<<(bit)); } while (0)
78 #define trace_recursion_clear(bit) do { (current)->trace_recursion &= ~(1<<(bit)); } while (0)
79 #define trace_recursion_test(bit) ((current)->trace_recursion & (1<<(bit)))
80
81 +#define trace_recursion_depth() \
82 + (((current)->trace_recursion >> TRACE_GRAPH_DEPTH_START_BIT) & 3)
83 +#define trace_recursion_set_depth(depth) \
84 + do { \
85 + current->trace_recursion &= \
86 + ~(3 << TRACE_GRAPH_DEPTH_START_BIT); \
87 + current->trace_recursion |= \
88 + ((depth) & 3) << TRACE_GRAPH_DEPTH_START_BIT; \
89 + } while (0)
90 +
91 #define TRACE_CONTEXT_BITS 4
92
93 #define TRACE_FTRACE_START TRACE_FTRACE_BIT
94 @@ -839,8 +871,9 @@ extern void __trace_graph_return(struct trace_array *tr,
95 extern struct ftrace_hash *ftrace_graph_hash;
96 extern struct ftrace_hash *ftrace_graph_notrace_hash;
97
98 -static inline int ftrace_graph_addr(unsigned long addr)
99 +static inline int ftrace_graph_addr(struct ftrace_graph_ent *trace)
100 {
101 + unsigned long addr = trace->func;
102 int ret = 0;
103
104 preempt_disable_notrace();
105 @@ -851,6 +884,14 @@ static inline int ftrace_graph_addr(unsigned long addr)
106 }
107
108 if (ftrace_lookup_ip(ftrace_graph_hash, addr)) {
109 +
110 + /*
111 + * This needs to be cleared on the return functions
112 + * when the depth is zero.
113 + */
114 + trace_recursion_set(TRACE_GRAPH_BIT);
115 + trace_recursion_set_depth(trace->depth);
116 +
117 /*
118 * If no irqs are to be traced, but a set_graph_function
119 * is set, and called by an interrupt handler, we still
120 @@ -868,6 +909,13 @@ static inline int ftrace_graph_addr(unsigned long addr)
121 return ret;
122 }
123
124 +static inline void ftrace_graph_addr_finish(struct ftrace_graph_ret *trace)
125 +{
126 + if (trace_recursion_test(TRACE_GRAPH_BIT) &&
127 + trace->depth == trace_recursion_depth())
128 + trace_recursion_clear(TRACE_GRAPH_BIT);
129 +}
130 +
131 static inline int ftrace_graph_notrace_addr(unsigned long addr)
132 {
133 int ret = 0;
134 @@ -881,7 +929,7 @@ static inline int ftrace_graph_notrace_addr(unsigned long addr)
135 return ret;
136 }
137 #else
138 -static inline int ftrace_graph_addr(unsigned long addr)
139 +static inline int ftrace_graph_addr(struct ftrace_graph_ent *trace)
140 {
141 return 1;
142 }
143 @@ -890,6 +938,8 @@ static inline int ftrace_graph_notrace_addr(unsigned long addr)
144 {
145 return 0;
146 }
147 +static inline void ftrace_graph_addr_finish(struct ftrace_graph_ret *trace)
148 +{ }
149 #endif /* CONFIG_DYNAMIC_FTRACE */
150
151 extern unsigned int fgraph_max_depth;
152 @@ -897,7 +947,8 @@ extern unsigned int fgraph_max_depth;
153 static inline bool ftrace_graph_ignore_func(struct ftrace_graph_ent *trace)
154 {
155 /* trace it when it is-nested-in or is a function enabled. */
156 - return !(trace->depth || ftrace_graph_addr(trace->func)) ||
157 + return !(trace_recursion_test(TRACE_GRAPH_BIT) ||
158 + ftrace_graph_addr(trace)) ||
159 (trace->depth < 0) ||
160 (fgraph_max_depth && trace->depth >= fgraph_max_depth);
161 }
162 diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
163 index 169b3c44ee97f..72d0d477f5c16 100644
164 --- a/kernel/trace/trace_functions_graph.c
165 +++ b/kernel/trace/trace_functions_graph.c
166 @@ -482,6 +482,8 @@ void trace_graph_return(struct ftrace_graph_ret *trace)
167 int cpu;
168 int pc;
169
170 + ftrace_graph_addr_finish(trace);
171 +
172 local_irq_save(flags);
173 cpu = raw_smp_processor_id();
174 data = per_cpu_ptr(tr->trace_buffer.data, cpu);
175 @@ -505,6 +507,8 @@ void set_graph_array(struct trace_array *tr)
176
177 static void trace_graph_thresh_return(struct ftrace_graph_ret *trace)
178 {
179 + ftrace_graph_addr_finish(trace);
180 +
181 if (tracing_thresh &&
182 (trace->rettime - trace->calltime < tracing_thresh))
183 return;
184 diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
185 index 7758bc0617cb1..2d9e12380dc3b 100644
186 --- a/kernel/trace/trace_irqsoff.c
187 +++ b/kernel/trace/trace_irqsoff.c
188 @@ -204,6 +204,8 @@ static void irqsoff_graph_return(struct ftrace_graph_ret *trace)
189 unsigned long flags;
190 int pc;
191
192 + ftrace_graph_addr_finish(trace);
193 +
194 if (!func_prolog_dec(tr, &data, &flags))
195 return;
196
197 diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
198 index 7d461dcd48318..0fa9dadf3f4f2 100644
199 --- a/kernel/trace/trace_sched_wakeup.c
200 +++ b/kernel/trace/trace_sched_wakeup.c
201 @@ -270,6 +270,8 @@ static void wakeup_graph_return(struct ftrace_graph_ret *trace)
202 unsigned long flags;
203 int pc;
204
205 + ftrace_graph_addr_finish(trace);
206 +
207 if (!func_prolog_preempt_disable(tr, &data, &pc))
208 return;
209
210 --
211 2.20.1
212