diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 82 |
1 files changed, 66 insertions, 16 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index b5c09242683d..0b99120d395c 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -82,9 +82,9 @@ static struct trace_array *graph_array; | |||
82 | * to fill in space into DURATION column. | 82 | * to fill in space into DURATION column. |
83 | */ | 83 | */ |
84 | enum { | 84 | enum { |
85 | DURATION_FILL_FULL = -1, | 85 | FLAGS_FILL_FULL = 1 << TRACE_GRAPH_PRINT_FILL_SHIFT, |
86 | DURATION_FILL_START = -2, | 86 | FLAGS_FILL_START = 2 << TRACE_GRAPH_PRINT_FILL_SHIFT, |
87 | DURATION_FILL_END = -3, | 87 | FLAGS_FILL_END = 3 << TRACE_GRAPH_PRINT_FILL_SHIFT, |
88 | }; | 88 | }; |
89 | 89 | ||
90 | static enum print_line_t | 90 | static enum print_line_t |
@@ -114,16 +114,37 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, | |||
114 | return -EBUSY; | 114 | return -EBUSY; |
115 | } | 115 | } |
116 | 116 | ||
117 | /* | ||
118 | * The curr_ret_stack is an index to ftrace return stack of | ||
119 | * current task. Its value should be in [0, FTRACE_RETFUNC_ | ||
120 | * DEPTH) when the function graph tracer is used. To support | ||
121 | * filtering out specific functions, it makes the index | ||
122 | * negative by subtracting huge value (FTRACE_NOTRACE_DEPTH) | ||
123 | * so when it sees a negative index the ftrace will ignore | ||
124 | * the record. And the index gets recovered when returning | ||
125 | * from the filtered function by adding the FTRACE_NOTRACE_ | ||
126 | * DEPTH and then it'll continue to record functions normally. | ||
127 | * | ||
128 | * The curr_ret_stack is initialized to -1 and get increased | ||
129 | * in this function. So it can be less than -1 only if it was | ||
130 | * filtered out via ftrace_graph_notrace_addr() which can be | ||
131 | * set from set_graph_notrace file in debugfs by user. | ||
132 | */ | ||
133 | if (current->curr_ret_stack < -1) | ||
134 | return -EBUSY; | ||
135 | |||
117 | calltime = trace_clock_local(); | 136 | calltime = trace_clock_local(); |
118 | 137 | ||
119 | index = ++current->curr_ret_stack; | 138 | index = ++current->curr_ret_stack; |
139 | if (ftrace_graph_notrace_addr(func)) | ||
140 | current->curr_ret_stack -= FTRACE_NOTRACE_DEPTH; | ||
120 | barrier(); | 141 | barrier(); |
121 | current->ret_stack[index].ret = ret; | 142 | current->ret_stack[index].ret = ret; |
122 | current->ret_stack[index].func = func; | 143 | current->ret_stack[index].func = func; |
123 | current->ret_stack[index].calltime = calltime; | 144 | current->ret_stack[index].calltime = calltime; |
124 | current->ret_stack[index].subtime = 0; | 145 | current->ret_stack[index].subtime = 0; |
125 | current->ret_stack[index].fp = frame_pointer; | 146 | current->ret_stack[index].fp = frame_pointer; |
126 | *depth = index; | 147 | *depth = current->curr_ret_stack; |
127 | 148 | ||
128 | return 0; | 149 | return 0; |
129 | } | 150 | } |
@@ -137,7 +158,17 @@ ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret, | |||
137 | 158 | ||
138 | index = current->curr_ret_stack; | 159 | index = current->curr_ret_stack; |
139 | 160 | ||
140 | if (unlikely(index < 0)) { | 161 | /* |
162 | * A negative index here means that it's just returned from a | ||
163 | * notrace'd function. Recover index to get an original | ||
164 | * return address. See ftrace_push_return_trace(). | ||
165 | * | ||
166 | * TODO: Need to check whether the stack gets corrupted. | ||
167 | */ | ||
168 | if (index < 0) | ||
169 | index += FTRACE_NOTRACE_DEPTH; | ||
170 | |||
171 | if (unlikely(index < 0 || index >= FTRACE_RETFUNC_DEPTH)) { | ||
141 | ftrace_graph_stop(); | 172 | ftrace_graph_stop(); |
142 | WARN_ON(1); | 173 | WARN_ON(1); |
143 | /* Might as well panic, otherwise we have no where to go */ | 174 | /* Might as well panic, otherwise we have no where to go */ |
@@ -193,6 +224,15 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer) | |||
193 | trace.rettime = trace_clock_local(); | 224 | trace.rettime = trace_clock_local(); |
194 | barrier(); | 225 | barrier(); |
195 | current->curr_ret_stack--; | 226 | current->curr_ret_stack--; |
227 | /* | ||
228 | * The curr_ret_stack can be less than -1 only if it was | ||
229 | * filtered out and it's about to return from the function. | ||
230 | * Recover the index and continue to trace normal functions. | ||
231 | */ | ||
232 | if (current->curr_ret_stack < -1) { | ||
233 | current->curr_ret_stack += FTRACE_NOTRACE_DEPTH; | ||
234 | return ret; | ||
235 | } | ||
196 | 236 | ||
197 | /* | 237 | /* |
198 | * The trace should run after decrementing the ret counter | 238 | * The trace should run after decrementing the ret counter |
@@ -230,7 +270,7 @@ int __trace_graph_entry(struct trace_array *tr, | |||
230 | return 0; | 270 | return 0; |
231 | entry = ring_buffer_event_data(event); | 271 | entry = ring_buffer_event_data(event); |
232 | entry->graph_ent = *trace; | 272 | entry->graph_ent = *trace; |
233 | if (!filter_current_check_discard(buffer, call, entry, event)) | 273 | if (!call_filter_check_discard(call, entry, buffer, event)) |
234 | __buffer_unlock_commit(buffer, event); | 274 | __buffer_unlock_commit(buffer, event); |
235 | 275 | ||
236 | return 1; | 276 | return 1; |
@@ -259,10 +299,20 @@ int trace_graph_entry(struct ftrace_graph_ent *trace) | |||
259 | 299 | ||
260 | /* trace it when it is-nested-in or is a function enabled. */ | 300 | /* trace it when it is-nested-in or is a function enabled. */ |
261 | if ((!(trace->depth || ftrace_graph_addr(trace->func)) || | 301 | if ((!(trace->depth || ftrace_graph_addr(trace->func)) || |
262 | ftrace_graph_ignore_irqs()) || | 302 | ftrace_graph_ignore_irqs()) || (trace->depth < 0) || |
263 | (max_depth && trace->depth >= max_depth)) | 303 | (max_depth && trace->depth >= max_depth)) |
264 | return 0; | 304 | return 0; |
265 | 305 | ||
306 | /* | ||
307 | * Do not trace a function if it's filtered by set_graph_notrace. | ||
308 | * Make the index of ret stack negative to indicate that it should | ||
309 | * ignore further functions. But it needs its own ret stack entry | ||
310 | * to recover the original index in order to continue tracing after | ||
311 | * returning from the function. | ||
312 | */ | ||
313 | if (ftrace_graph_notrace_addr(trace->func)) | ||
314 | return 1; | ||
315 | |||
266 | local_irq_save(flags); | 316 | local_irq_save(flags); |
267 | cpu = raw_smp_processor_id(); | 317 | cpu = raw_smp_processor_id(); |
268 | data = per_cpu_ptr(tr->trace_buffer.data, cpu); | 318 | data = per_cpu_ptr(tr->trace_buffer.data, cpu); |
@@ -335,7 +385,7 @@ void __trace_graph_return(struct trace_array *tr, | |||
335 | return; | 385 | return; |
336 | entry = ring_buffer_event_data(event); | 386 | entry = ring_buffer_event_data(event); |
337 | entry->ret = *trace; | 387 | entry->ret = *trace; |
338 | if (!filter_current_check_discard(buffer, call, entry, event)) | 388 | if (!call_filter_check_discard(call, entry, buffer, event)) |
339 | __buffer_unlock_commit(buffer, event); | 389 | __buffer_unlock_commit(buffer, event); |
340 | } | 390 | } |
341 | 391 | ||
@@ -652,7 +702,7 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr, | |||
652 | } | 702 | } |
653 | 703 | ||
654 | /* No overhead */ | 704 | /* No overhead */ |
655 | ret = print_graph_duration(DURATION_FILL_START, s, flags); | 705 | ret = print_graph_duration(0, s, flags | FLAGS_FILL_START); |
656 | if (ret != TRACE_TYPE_HANDLED) | 706 | if (ret != TRACE_TYPE_HANDLED) |
657 | return ret; | 707 | return ret; |
658 | 708 | ||
@@ -664,7 +714,7 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr, | |||
664 | if (!ret) | 714 | if (!ret) |
665 | return TRACE_TYPE_PARTIAL_LINE; | 715 | return TRACE_TYPE_PARTIAL_LINE; |
666 | 716 | ||
667 | ret = print_graph_duration(DURATION_FILL_END, s, flags); | 717 | ret = print_graph_duration(0, s, flags | FLAGS_FILL_END); |
668 | if (ret != TRACE_TYPE_HANDLED) | 718 | if (ret != TRACE_TYPE_HANDLED) |
669 | return ret; | 719 | return ret; |
670 | 720 | ||
@@ -729,14 +779,14 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s, | |||
729 | return TRACE_TYPE_HANDLED; | 779 | return TRACE_TYPE_HANDLED; |
730 | 780 | ||
731 | /* No real adata, just filling the column with spaces */ | 781 | /* No real adata, just filling the column with spaces */ |
732 | switch (duration) { | 782 | switch (flags & TRACE_GRAPH_PRINT_FILL_MASK) { |
733 | case DURATION_FILL_FULL: | 783 | case FLAGS_FILL_FULL: |
734 | ret = trace_seq_puts(s, " | "); | 784 | ret = trace_seq_puts(s, " | "); |
735 | return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; | 785 | return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; |
736 | case DURATION_FILL_START: | 786 | case FLAGS_FILL_START: |
737 | ret = trace_seq_puts(s, " "); | 787 | ret = trace_seq_puts(s, " "); |
738 | return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; | 788 | return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; |
739 | case DURATION_FILL_END: | 789 | case FLAGS_FILL_END: |
740 | ret = trace_seq_puts(s, " |"); | 790 | ret = trace_seq_puts(s, " |"); |
741 | return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; | 791 | return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; |
742 | } | 792 | } |
@@ -852,7 +902,7 @@ print_graph_entry_nested(struct trace_iterator *iter, | |||
852 | } | 902 | } |
853 | 903 | ||
854 | /* No time */ | 904 | /* No time */ |
855 | ret = print_graph_duration(DURATION_FILL_FULL, s, flags); | 905 | ret = print_graph_duration(0, s, flags | FLAGS_FILL_FULL); |
856 | if (ret != TRACE_TYPE_HANDLED) | 906 | if (ret != TRACE_TYPE_HANDLED) |
857 | return ret; | 907 | return ret; |
858 | 908 | ||
@@ -1172,7 +1222,7 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, | |||
1172 | return TRACE_TYPE_PARTIAL_LINE; | 1222 | return TRACE_TYPE_PARTIAL_LINE; |
1173 | 1223 | ||
1174 | /* No time */ | 1224 | /* No time */ |
1175 | ret = print_graph_duration(DURATION_FILL_FULL, s, flags); | 1225 | ret = print_graph_duration(0, s, flags | FLAGS_FILL_FULL); |
1176 | if (ret != TRACE_TYPE_HANDLED) | 1226 | if (ret != TRACE_TYPE_HANDLED) |
1177 | return ret; | 1227 | return ret; |
1178 | 1228 | ||