diff options
author | Abhishek Sagar <sagar.abhishek@gmail.com> | 2008-06-21 14:20:29 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-06-23 16:10:59 -0400 |
commit | f22f9a89ce6857d377bf22dba4c1a8cd256c5136 (patch) | |
tree | 34899ea2a9dc603014052742f774e8aeb51d9591 /kernel/trace/ftrace.c | |
parent | ecea656d1d5e912d2f3d332657ea4a6d8380f891 (diff) |
ftrace: avoid modifying kprobe'd records
Avoid modifying the mcount call-site if there is a kprobe installed on it.
These records are not marked as failed however. This allowed the filter
rules on them to remain up-to-date. Whenever the kprobe on the corresponding
record is removed, the record gets updated as normal.
Signed-off-by: Abhishek Sagar <sagar.abhishek@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index d1238163155f..85e841335417 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/hardirq.h> | 21 | #include <linux/hardirq.h> |
22 | #include <linux/kthread.h> | 22 | #include <linux/kthread.h> |
23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
24 | #include <linux/kprobes.h> | ||
24 | #include <linux/ftrace.h> | 25 | #include <linux/ftrace.h> |
25 | #include <linux/sysctl.h> | 26 | #include <linux/sysctl.h> |
26 | #include <linux/ctype.h> | 27 | #include <linux/ctype.h> |
@@ -500,6 +501,10 @@ static void ftrace_replace_code(int enable) | |||
500 | if (rec->flags & FTRACE_FL_FAILED) | 501 | if (rec->flags & FTRACE_FL_FAILED) |
501 | continue; | 502 | continue; |
502 | 503 | ||
504 | /* ignore updates to this record's mcount site */ | ||
505 | if (get_kprobe((void *)rec->ip)) | ||
506 | continue; | ||
507 | |||
503 | failed = __ftrace_replace_code(rec, old, new, enable); | 508 | failed = __ftrace_replace_code(rec, old, new, enable); |
504 | if (failed && (rec->flags & FTRACE_FL_CONVERTED)) { | 509 | if (failed && (rec->flags & FTRACE_FL_CONVERTED)) { |
505 | rec->flags |= FTRACE_FL_FAILED; | 510 | rec->flags |= FTRACE_FL_FAILED; |
@@ -692,11 +697,11 @@ unsigned long ftrace_update_tot_cnt; | |||
692 | 697 | ||
693 | static int __ftrace_update_code(void *ignore) | 698 | static int __ftrace_update_code(void *ignore) |
694 | { | 699 | { |
700 | int i, save_ftrace_enabled; | ||
701 | cycle_t start, stop; | ||
695 | struct dyn_ftrace *p; | 702 | struct dyn_ftrace *p; |
696 | struct hlist_node *t, *n; | 703 | struct hlist_node *t, *n; |
697 | int save_ftrace_enabled; | 704 | struct hlist_head *head, temp_list; |
698 | cycle_t start, stop; | ||
699 | int i; | ||
700 | 705 | ||
701 | /* Don't be recording funcs now */ | 706 | /* Don't be recording funcs now */ |
702 | ftrace_record_suspend++; | 707 | ftrace_record_suspend++; |
@@ -708,8 +713,11 @@ static int __ftrace_update_code(void *ignore) | |||
708 | 713 | ||
709 | /* No locks needed, the machine is stopped! */ | 714 | /* No locks needed, the machine is stopped! */ |
710 | for (i = 0; i < FTRACE_HASHSIZE; i++) { | 715 | for (i = 0; i < FTRACE_HASHSIZE; i++) { |
716 | INIT_HLIST_HEAD(&temp_list); | ||
717 | head = &ftrace_hash[i]; | ||
718 | |||
711 | /* all CPUS are stopped, we are safe to modify code */ | 719 | /* all CPUS are stopped, we are safe to modify code */ |
712 | hlist_for_each_entry_safe(p, t, n, &ftrace_hash[i], node) { | 720 | hlist_for_each_entry_safe(p, t, n, head, node) { |
713 | /* Skip over failed records which have not been | 721 | /* Skip over failed records which have not been |
714 | * freed. */ | 722 | * freed. */ |
715 | if (p->flags & FTRACE_FL_FAILED) | 723 | if (p->flags & FTRACE_FL_FAILED) |
@@ -723,6 +731,19 @@ static int __ftrace_update_code(void *ignore) | |||
723 | if (p->flags & (FTRACE_FL_CONVERTED)) | 731 | if (p->flags & (FTRACE_FL_CONVERTED)) |
724 | break; | 732 | break; |
725 | 733 | ||
734 | /* Ignore updates to this record's mcount site. | ||
735 | * Reintroduce this record at the head of this | ||
736 | * bucket to attempt to "convert" it again if | ||
737 | * the kprobe on it is unregistered before the | ||
738 | * next run. */ | ||
739 | if (get_kprobe((void *)p->ip)) { | ||
740 | ftrace_del_hash(p); | ||
741 | INIT_HLIST_NODE(&p->node); | ||
742 | hlist_add_head(&p->node, &temp_list); | ||
743 | continue; | ||
744 | } | ||
745 | |||
746 | /* convert record (i.e, patch mcount-call with NOP) */ | ||
726 | if (ftrace_code_disable(p)) { | 747 | if (ftrace_code_disable(p)) { |
727 | p->flags |= FTRACE_FL_CONVERTED; | 748 | p->flags |= FTRACE_FL_CONVERTED; |
728 | ftrace_update_cnt++; | 749 | ftrace_update_cnt++; |
@@ -734,6 +755,12 @@ static int __ftrace_update_code(void *ignore) | |||
734 | } | 755 | } |
735 | } | 756 | } |
736 | } | 757 | } |
758 | |||
759 | hlist_for_each_entry_safe(p, t, n, &temp_list, node) { | ||
760 | hlist_del(&p->node); | ||
761 | INIT_HLIST_NODE(&p->node); | ||
762 | hlist_add_head(&p->node, head); | ||
763 | } | ||
737 | } | 764 | } |
738 | 765 | ||
739 | stop = ftrace_now(raw_smp_processor_id()); | 766 | stop = ftrace_now(raw_smp_processor_id()); |