aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ftrace.h6
-rw-r--r--kernel/trace/ftrace.c72
-rw-r--r--kernel/trace/trace.c3
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
54struct dyn_ftrace { 55struct dyn_ftrace {
@@ -73,15 +74,18 @@ extern void ftrace_caller(void);
73extern void ftrace_call(void); 74extern void ftrace_call(void);
74extern void mcount_call(void); 75extern void mcount_call(void);
75 76
77extern int skip_trace(unsigned long ip);
78
76void ftrace_disable_daemon(void); 79void ftrace_disable_daemon(void);
77void ftrace_enable_daemon(void); 80void 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 */
87void ftrace_kill(void); 91void 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
165static int ftrace_filtered; 165static int ftrace_filtered;
166static int tracing_on;
167static int frozen_record_count;
166 168
167static struct hlist_head ftrace_hash[FTRACE_HASHSIZE]; 169static struct hlist_head ftrace_hash[FTRACE_HASHSIZE];
168 170
@@ -195,6 +197,71 @@ static int ftrace_record_suspend;
195 197
196static struct dyn_ftrace *ftrace_free_records; 198static struct dyn_ftrace *ftrace_free_records;
197 199
200
201#ifdef CONFIG_KPROBES
202static 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
210static 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
218static 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
228int 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
198static inline int 265static inline int
199ftrace_ip_in_hash(unsigned long ip, unsigned long key) 266ftrace_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];