diff options
-rw-r--r-- | include/linux/ftrace.h | 6 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 72 | ||||
-rw-r--r-- | kernel/trace/trace.c | 3 |
3 files changed, 79 insertions, 2 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 366098d591de..3121b95443d9 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -49,6 +49,7 @@ enum { | |||
49 | FTRACE_FL_ENABLED = (1 << 3), | 49 | FTRACE_FL_ENABLED = (1 << 3), |
50 | FTRACE_FL_NOTRACE = (1 << 4), | 50 | FTRACE_FL_NOTRACE = (1 << 4), |
51 | FTRACE_FL_CONVERTED = (1 << 5), | 51 | FTRACE_FL_CONVERTED = (1 << 5), |
52 | FTRACE_FL_FROZEN = (1 << 6), | ||
52 | }; | 53 | }; |
53 | 54 | ||
54 | struct dyn_ftrace { | 55 | struct dyn_ftrace { |
@@ -73,15 +74,18 @@ extern void ftrace_caller(void); | |||
73 | extern void ftrace_call(void); | 74 | extern void ftrace_call(void); |
74 | extern void mcount_call(void); | 75 | extern void mcount_call(void); |
75 | 76 | ||
77 | extern int skip_trace(unsigned long ip); | ||
78 | |||
76 | void ftrace_disable_daemon(void); | 79 | void ftrace_disable_daemon(void); |
77 | void ftrace_enable_daemon(void); | 80 | void ftrace_enable_daemon(void); |
78 | 81 | ||
79 | #else | 82 | #else |
83 | # define skip_trace(ip) ({ 0; }) | ||
80 | # define ftrace_force_update() ({ 0; }) | 84 | # define ftrace_force_update() ({ 0; }) |
81 | # define ftrace_set_filter(buf, len, reset) do { } while (0) | 85 | # define ftrace_set_filter(buf, len, reset) do { } while (0) |
82 | # define ftrace_disable_daemon() do { } while (0) | 86 | # define ftrace_disable_daemon() do { } while (0) |
83 | # define ftrace_enable_daemon() do { } while (0) | 87 | # define ftrace_enable_daemon() do { } while (0) |
84 | #endif | 88 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
85 | 89 | ||
86 | /* totally disable ftrace - can not re-enable after this */ | 90 | /* totally disable ftrace - can not re-enable after this */ |
87 | void ftrace_kill(void); | 91 | void ftrace_kill(void); |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index f1e9e5c74e64..d1238163155f 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -163,6 +163,8 @@ enum { | |||
163 | }; | 163 | }; |
164 | 164 | ||
165 | static int ftrace_filtered; | 165 | static int ftrace_filtered; |
166 | static int tracing_on; | ||
167 | static int frozen_record_count; | ||
166 | 168 | ||
167 | static struct hlist_head ftrace_hash[FTRACE_HASHSIZE]; | 169 | static struct hlist_head ftrace_hash[FTRACE_HASHSIZE]; |
168 | 170 | ||
@@ -195,6 +197,71 @@ static int ftrace_record_suspend; | |||
195 | 197 | ||
196 | static struct dyn_ftrace *ftrace_free_records; | 198 | static struct dyn_ftrace *ftrace_free_records; |
197 | 199 | ||
200 | |||
201 | #ifdef CONFIG_KPROBES | ||
202 | static inline void freeze_record(struct dyn_ftrace *rec) | ||
203 | { | ||
204 | if (!(rec->flags & FTRACE_FL_FROZEN)) { | ||
205 | rec->flags |= FTRACE_FL_FROZEN; | ||
206 | frozen_record_count++; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | static inline void unfreeze_record(struct dyn_ftrace *rec) | ||
211 | { | ||
212 | if (rec->flags & FTRACE_FL_FROZEN) { | ||
213 | rec->flags &= ~FTRACE_FL_FROZEN; | ||
214 | frozen_record_count--; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | static inline int record_frozen(struct dyn_ftrace *rec) | ||
219 | { | ||
220 | return rec->flags & FTRACE_FL_FROZEN; | ||
221 | } | ||
222 | #else | ||
223 | # define freeze_record(rec) ({ 0; }) | ||
224 | # define unfreeze_record(rec) ({ 0; }) | ||
225 | # define record_frozen(rec) ({ 0; }) | ||
226 | #endif /* CONFIG_KPROBES */ | ||
227 | |||
228 | int skip_trace(unsigned long ip) | ||
229 | { | ||
230 | unsigned long fl; | ||
231 | struct dyn_ftrace *rec; | ||
232 | struct hlist_node *t; | ||
233 | struct hlist_head *head; | ||
234 | |||
235 | if (frozen_record_count == 0) | ||
236 | return 0; | ||
237 | |||
238 | head = &ftrace_hash[hash_long(ip, FTRACE_HASHBITS)]; | ||
239 | hlist_for_each_entry_rcu(rec, t, head, node) { | ||
240 | if (rec->ip == ip) { | ||
241 | if (record_frozen(rec)) { | ||
242 | if (rec->flags & FTRACE_FL_FAILED) | ||
243 | return 1; | ||
244 | |||
245 | if (!(rec->flags & FTRACE_FL_CONVERTED)) | ||
246 | return 1; | ||
247 | |||
248 | if (!tracing_on || !ftrace_enabled) | ||
249 | return 1; | ||
250 | |||
251 | if (ftrace_filtered) { | ||
252 | fl = rec->flags & (FTRACE_FL_FILTER | | ||
253 | FTRACE_FL_NOTRACE); | ||
254 | if (!fl || (fl & FTRACE_FL_NOTRACE)) | ||
255 | return 1; | ||
256 | } | ||
257 | } | ||
258 | break; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
198 | static inline int | 265 | static inline int |
199 | ftrace_ip_in_hash(unsigned long ip, unsigned long key) | 266 | ftrace_ip_in_hash(unsigned long ip, unsigned long key) |
200 | { | 267 | { |
@@ -489,8 +556,11 @@ static int __ftrace_modify_code(void *data) | |||
489 | */ | 556 | */ |
490 | __ftrace_update_code(NULL); | 557 | __ftrace_update_code(NULL); |
491 | ftrace_replace_code(1); | 558 | ftrace_replace_code(1); |
492 | } else if (*command & FTRACE_DISABLE_CALLS) | 559 | tracing_on = 1; |
560 | } else if (*command & FTRACE_DISABLE_CALLS) { | ||
493 | ftrace_replace_code(0); | 561 | ftrace_replace_code(0); |
562 | tracing_on = 0; | ||
563 | } | ||
494 | 564 | ||
495 | if (*command & FTRACE_UPDATE_TRACE_FUNC) | 565 | if (*command & FTRACE_UPDATE_TRACE_FUNC) |
496 | ftrace_update_ftrace_func(ftrace_trace_function); | 566 | ftrace_update_ftrace_func(ftrace_trace_function); |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 6e9dae7eb418..9ade79369bfb 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -988,6 +988,9 @@ function_trace_call(unsigned long ip, unsigned long parent_ip) | |||
988 | if (unlikely(!tracer_enabled)) | 988 | if (unlikely(!tracer_enabled)) |
989 | return; | 989 | return; |
990 | 990 | ||
991 | if (skip_trace(ip)) | ||
992 | return; | ||
993 | |||
991 | local_irq_save(flags); | 994 | local_irq_save(flags); |
992 | cpu = raw_smp_processor_id(); | 995 | cpu = raw_smp_processor_id(); |
993 | data = tr->data[cpu]; | 996 | data = tr->data[cpu]; |