diff options
| -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()); |
