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]; |
