diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2008-05-12 15:20:48 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2008-05-23 14:54:16 -0400 |
| commit | 4eebcc81a33fbc45e28542b50197ed7b3c486d90 (patch) | |
| tree | 13bbad50aa8d4dc36d630ef08886876f4dc0b6eb /kernel/trace | |
| parent | 37ad508419f0fdfda7b378756eb1f35cfd26d96d (diff) | |
ftrace: disable tracing on failure
Since ftrace touches practically every function. If we detect any
anomaly, we want to fully disable ftrace. This patch adds code
to try shutdown ftrace as much as possible without doing any more
harm is something is detected not quite correct.
This only kills ftrace, this patch does have checks for other parts of
the tracer (irqsoff, wakeup, etc.).
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/ftrace.c | 112 | ||||
| -rw-r--r-- | kernel/trace/trace_selftest.c | 4 |
2 files changed, 107 insertions, 9 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 8e02aa690b2b..ff42345dd78e 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -29,9 +29,16 @@ | |||
| 29 | 29 | ||
| 30 | #include "trace.h" | 30 | #include "trace.h" |
| 31 | 31 | ||
| 32 | int ftrace_enabled; | 32 | /* ftrace_enabled is a method to turn ftrace on or off */ |
| 33 | int ftrace_enabled __read_mostly; | ||
| 33 | static int last_ftrace_enabled; | 34 | static int last_ftrace_enabled; |
| 34 | 35 | ||
| 36 | /* | ||
| 37 | * ftrace_disabled is set when an anomaly is discovered. | ||
| 38 | * ftrace_disabled is much stronger than ftrace_enabled. | ||
| 39 | */ | ||
| 40 | static int ftrace_disabled __read_mostly; | ||
| 41 | |||
| 35 | static DEFINE_SPINLOCK(ftrace_lock); | 42 | static DEFINE_SPINLOCK(ftrace_lock); |
| 36 | static DEFINE_MUTEX(ftrace_sysctl_lock); | 43 | static DEFINE_MUTEX(ftrace_sysctl_lock); |
| 37 | 44 | ||
| @@ -230,10 +237,11 @@ static notrace struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) | |||
| 230 | if (ftrace_free_records) { | 237 | if (ftrace_free_records) { |
| 231 | rec = ftrace_free_records; | 238 | rec = ftrace_free_records; |
| 232 | 239 | ||
| 233 | /* todo, disable tracing altogether on this warning */ | ||
| 234 | if (unlikely(!(rec->flags & FTRACE_FL_FREE))) { | 240 | if (unlikely(!(rec->flags & FTRACE_FL_FREE))) { |
| 235 | WARN_ON_ONCE(1); | 241 | WARN_ON_ONCE(1); |
| 236 | ftrace_free_records = NULL; | 242 | ftrace_free_records = NULL; |
| 243 | ftrace_disabled = 1; | ||
| 244 | ftrace_enabled = 0; | ||
| 237 | return NULL; | 245 | return NULL; |
| 238 | } | 246 | } |
| 239 | 247 | ||
| @@ -260,7 +268,7 @@ ftrace_record_ip(unsigned long ip) | |||
| 260 | int resched; | 268 | int resched; |
| 261 | int atomic; | 269 | int atomic; |
| 262 | 270 | ||
| 263 | if (!ftrace_enabled) | 271 | if (!ftrace_enabled || ftrace_disabled) |
| 264 | return; | 272 | return; |
| 265 | 273 | ||
| 266 | resched = need_resched(); | 274 | resched = need_resched(); |
| @@ -485,6 +493,9 @@ static void notrace ftrace_startup(void) | |||
| 485 | { | 493 | { |
| 486 | int command = 0; | 494 | int command = 0; |
| 487 | 495 | ||
| 496 | if (unlikely(ftrace_disabled)) | ||
| 497 | return; | ||
| 498 | |||
| 488 | mutex_lock(&ftraced_lock); | 499 | mutex_lock(&ftraced_lock); |
| 489 | ftraced_suspend++; | 500 | ftraced_suspend++; |
| 490 | if (ftraced_suspend == 1) | 501 | if (ftraced_suspend == 1) |
| @@ -507,6 +518,9 @@ static void notrace ftrace_shutdown(void) | |||
| 507 | { | 518 | { |
| 508 | int command = 0; | 519 | int command = 0; |
| 509 | 520 | ||
| 521 | if (unlikely(ftrace_disabled)) | ||
| 522 | return; | ||
| 523 | |||
| 510 | mutex_lock(&ftraced_lock); | 524 | mutex_lock(&ftraced_lock); |
| 511 | ftraced_suspend--; | 525 | ftraced_suspend--; |
| 512 | if (!ftraced_suspend) | 526 | if (!ftraced_suspend) |
| @@ -529,6 +543,9 @@ static void notrace ftrace_startup_sysctl(void) | |||
| 529 | { | 543 | { |
| 530 | int command = FTRACE_ENABLE_MCOUNT; | 544 | int command = FTRACE_ENABLE_MCOUNT; |
| 531 | 545 | ||
| 546 | if (unlikely(ftrace_disabled)) | ||
| 547 | return; | ||
| 548 | |||
| 532 | mutex_lock(&ftraced_lock); | 549 | mutex_lock(&ftraced_lock); |
| 533 | /* Force update next time */ | 550 | /* Force update next time */ |
| 534 | saved_ftrace_func = NULL; | 551 | saved_ftrace_func = NULL; |
| @@ -544,6 +561,9 @@ static void notrace ftrace_shutdown_sysctl(void) | |||
| 544 | { | 561 | { |
| 545 | int command = FTRACE_DISABLE_MCOUNT; | 562 | int command = FTRACE_DISABLE_MCOUNT; |
| 546 | 563 | ||
| 564 | if (unlikely(ftrace_disabled)) | ||
| 565 | return; | ||
| 566 | |||
| 547 | mutex_lock(&ftraced_lock); | 567 | mutex_lock(&ftraced_lock); |
| 548 | /* ftraced_suspend is true if ftrace is running */ | 568 | /* ftraced_suspend is true if ftrace is running */ |
| 549 | if (ftraced_suspend) | 569 | if (ftraced_suspend) |
| @@ -600,6 +620,9 @@ static int notrace __ftrace_update_code(void *ignore) | |||
| 600 | 620 | ||
| 601 | static void notrace ftrace_update_code(void) | 621 | static void notrace ftrace_update_code(void) |
| 602 | { | 622 | { |
| 623 | if (unlikely(ftrace_disabled)) | ||
| 624 | return; | ||
| 625 | |||
| 603 | stop_machine_run(__ftrace_update_code, NULL, NR_CPUS); | 626 | stop_machine_run(__ftrace_update_code, NULL, NR_CPUS); |
| 604 | } | 627 | } |
| 605 | 628 | ||
| @@ -614,6 +637,9 @@ static int notrace ftraced(void *ignore) | |||
| 614 | /* check once a second */ | 637 | /* check once a second */ |
| 615 | schedule_timeout(HZ); | 638 | schedule_timeout(HZ); |
| 616 | 639 | ||
| 640 | if (unlikely(ftrace_disabled)) | ||
| 641 | continue; | ||
| 642 | |||
| 617 | mutex_lock(&ftrace_sysctl_lock); | 643 | mutex_lock(&ftrace_sysctl_lock); |
| 618 | mutex_lock(&ftraced_lock); | 644 | mutex_lock(&ftraced_lock); |
| 619 | if (ftrace_enabled && ftraced_trigger && !ftraced_suspend) { | 645 | if (ftrace_enabled && ftraced_trigger && !ftraced_suspend) { |
| @@ -628,6 +654,7 @@ static int notrace ftraced(void *ignore) | |||
| 628 | ftrace_update_cnt != 1 ? "s" : "", | 654 | ftrace_update_cnt != 1 ? "s" : "", |
| 629 | ftrace_update_tot_cnt, | 655 | ftrace_update_tot_cnt, |
| 630 | usecs, usecs != 1 ? "s" : ""); | 656 | usecs, usecs != 1 ? "s" : ""); |
| 657 | ftrace_disabled = 1; | ||
| 631 | WARN_ON_ONCE(1); | 658 | WARN_ON_ONCE(1); |
| 632 | } | 659 | } |
| 633 | ftraced_trigger = 0; | 660 | ftraced_trigger = 0; |
| @@ -785,6 +812,9 @@ ftrace_avail_open(struct inode *inode, struct file *file) | |||
| 785 | struct ftrace_iterator *iter; | 812 | struct ftrace_iterator *iter; |
| 786 | int ret; | 813 | int ret; |
| 787 | 814 | ||
| 815 | if (unlikely(ftrace_disabled)) | ||
| 816 | return -ENODEV; | ||
| 817 | |||
| 788 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); | 818 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); |
| 789 | if (!iter) | 819 | if (!iter) |
| 790 | return -ENOMEM; | 820 | return -ENOMEM; |
| @@ -843,6 +873,9 @@ ftrace_filter_open(struct inode *inode, struct file *file) | |||
| 843 | struct ftrace_iterator *iter; | 873 | struct ftrace_iterator *iter; |
| 844 | int ret = 0; | 874 | int ret = 0; |
| 845 | 875 | ||
| 876 | if (unlikely(ftrace_disabled)) | ||
| 877 | return -ENODEV; | ||
| 878 | |||
| 846 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); | 879 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); |
| 847 | if (!iter) | 880 | if (!iter) |
| 848 | return -ENOMEM; | 881 | return -ENOMEM; |
| @@ -1063,6 +1096,9 @@ ftrace_filter_write(struct file *file, const char __user *ubuf, | |||
| 1063 | */ | 1096 | */ |
| 1064 | notrace void ftrace_set_filter(unsigned char *buf, int len, int reset) | 1097 | notrace void ftrace_set_filter(unsigned char *buf, int len, int reset) |
| 1065 | { | 1098 | { |
| 1099 | if (unlikely(ftrace_disabled)) | ||
| 1100 | return; | ||
| 1101 | |||
| 1066 | mutex_lock(&ftrace_filter_lock); | 1102 | mutex_lock(&ftrace_filter_lock); |
| 1067 | if (reset) | 1103 | if (reset) |
| 1068 | ftrace_filter_reset(); | 1104 | ftrace_filter_reset(); |
| @@ -1133,7 +1169,7 @@ int ftrace_force_update(void) | |||
| 1133 | DECLARE_WAITQUEUE(wait, current); | 1169 | DECLARE_WAITQUEUE(wait, current); |
| 1134 | int ret = 0; | 1170 | int ret = 0; |
| 1135 | 1171 | ||
| 1136 | if (!ftraced_task) | 1172 | if (unlikely(ftrace_disabled)) |
| 1137 | return -ENODEV; | 1173 | return -ENODEV; |
| 1138 | 1174 | ||
| 1139 | mutex_lock(&ftraced_lock); | 1175 | mutex_lock(&ftraced_lock); |
| @@ -1142,6 +1178,11 @@ int ftrace_force_update(void) | |||
| 1142 | set_current_state(TASK_INTERRUPTIBLE); | 1178 | set_current_state(TASK_INTERRUPTIBLE); |
| 1143 | add_wait_queue(&ftraced_waiters, &wait); | 1179 | add_wait_queue(&ftraced_waiters, &wait); |
| 1144 | 1180 | ||
| 1181 | if (unlikely(!ftraced_task)) { | ||
| 1182 | ret = -ENODEV; | ||
| 1183 | goto out; | ||
| 1184 | } | ||
| 1185 | |||
| 1145 | do { | 1186 | do { |
| 1146 | |||
