diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 275 |
1 files changed, 210 insertions, 65 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index f6e3af31b403..4dda4f60a2a9 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -81,7 +81,7 @@ void clear_ftrace_function(void) | |||
81 | 81 | ||
82 | static int __register_ftrace_function(struct ftrace_ops *ops) | 82 | static int __register_ftrace_function(struct ftrace_ops *ops) |
83 | { | 83 | { |
84 | /* Should never be called by interrupts */ | 84 | /* should not be called from interrupt context */ |
85 | spin_lock(&ftrace_lock); | 85 | spin_lock(&ftrace_lock); |
86 | 86 | ||
87 | ops->next = ftrace_list; | 87 | ops->next = ftrace_list; |
@@ -115,6 +115,7 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) | |||
115 | struct ftrace_ops **p; | 115 | struct ftrace_ops **p; |
116 | int ret = 0; | 116 | int ret = 0; |
117 | 117 | ||
118 | /* should not be called from interrupt context */ | ||
118 | spin_lock(&ftrace_lock); | 119 | spin_lock(&ftrace_lock); |
119 | 120 | ||
120 | /* | 121 | /* |
@@ -153,6 +154,30 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) | |||
153 | 154 | ||
154 | #ifdef CONFIG_DYNAMIC_FTRACE | 155 | #ifdef CONFIG_DYNAMIC_FTRACE |
155 | 156 | ||
157 | #ifndef CONFIG_FTRACE_MCOUNT_RECORD | ||
158 | /* | ||
159 | * The hash lock is only needed when the recording of the mcount | ||
160 | * callers are dynamic. That is, by the caller themselves and | ||
161 | * not recorded via the compilation. | ||
162 | */ | ||
163 | static DEFINE_SPINLOCK(ftrace_hash_lock); | ||
164 | #define ftrace_hash_lock(flags) spin_lock_irqsave(&ftrace_hash_lock, flags) | ||
165 | #define ftrace_hash_unlock(flags) \ | ||
166 | spin_unlock_irqrestore(&ftrace_hash_lock, flags) | ||
167 | #else | ||
168 | /* This is protected via the ftrace_lock with MCOUNT_RECORD. */ | ||
169 | #define ftrace_hash_lock(flags) do { (void)(flags); } while (0) | ||
170 | #define ftrace_hash_unlock(flags) do { } while(0) | ||
171 | #endif | ||
172 | |||
173 | /* | ||
174 | * Since MCOUNT_ADDR may point to mcount itself, we do not want | ||
175 | * to get it confused by reading a reference in the code as we | ||
176 | * are parsing on objcopy output of text. Use a variable for | ||
177 | * it instead. | ||
178 | */ | ||
179 | static unsigned long mcount_addr = MCOUNT_ADDR; | ||
180 | |||
156 | static struct task_struct *ftraced_task; | 181 | static struct task_struct *ftraced_task; |
157 | 182 | ||
158 | enum { | 183 | enum { |
@@ -171,7 +196,6 @@ static struct hlist_head ftrace_hash[FTRACE_HASHSIZE]; | |||
171 | 196 | ||
172 | static DEFINE_PER_CPU(int, ftrace_shutdown_disable_cpu); | 197 | static DEFINE_PER_CPU(int, ftrace_shutdown_disable_cpu); |
173 | 198 | ||
174 | static DEFINE_SPINLOCK(ftrace_shutdown_lock); | ||
175 | static DEFINE_MUTEX(ftraced_lock); | 199 | static DEFINE_MUTEX(ftraced_lock); |
176 | static DEFINE_MUTEX(ftrace_regex_lock); | 200 | static DEFINE_MUTEX(ftrace_regex_lock); |
177 | 201 | ||
@@ -294,13 +318,37 @@ static inline void ftrace_del_hash(struct dyn_ftrace *node) | |||
294 | 318 | ||
295 | static void ftrace_free_rec(struct dyn_ftrace *rec) | 319 | static void ftrace_free_rec(struct dyn_ftrace *rec) |
296 | { | 320 | { |
297 | /* no locking, only called from kstop_machine */ | ||
298 | |||
299 | rec->ip = (unsigned long)ftrace_free_records; | 321 | rec->ip = (unsigned long)ftrace_free_records; |
300 | ftrace_free_records = rec; | 322 | ftrace_free_records = rec; |
301 | rec->flags |= FTRACE_FL_FREE; | 323 | rec->flags |= FTRACE_FL_FREE; |
302 | } | 324 | } |
303 | 325 | ||
326 | void ftrace_release(void *start, unsigned long size) | ||
327 | { | ||
328 | struct dyn_ftrace *rec; | ||
329 | struct ftrace_page *pg; | ||
330 | unsigned long s = (unsigned long)start; | ||
331 | unsigned long e = s + size; | ||
332 | int i; | ||
333 | |||
334 | if (ftrace_disabled || !start) | ||
335 | return; | ||
336 | |||
337 | /* should not be called from interrupt context */ | ||
338 | spin_lock(&ftrace_lock); | ||
339 | |||
340 | for (pg = ftrace_pages_start; pg; pg = pg->next) { | ||
341 | for (i = 0; i < pg->index; i++) { | ||
342 | rec = &pg->records[i]; | ||
343 | |||
344 | if ((rec->ip >= s) && (rec->ip < e)) | ||
345 | ftrace_free_rec(rec); | ||
346 | } | ||
347 | } | ||
348 | spin_unlock(&ftrace_lock); | ||
349 | |||
350 | } | ||
351 | |||
304 | static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) | 352 | static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) |
305 | { | 353 | { |
306 | struct dyn_ftrace *rec; | 354 | struct dyn_ftrace *rec; |
@@ -338,7 +386,6 @@ ftrace_record_ip(unsigned long ip) | |||
338 | unsigned long flags; | 386 | unsigned long flags; |
339 | unsigned long key; | 387 | unsigned long key; |
340 | int resched; | 388 | int resched; |
341 | int atomic; | ||
342 | int cpu; | 389 | int cpu; |
343 | 390 | ||
344 | if (!ftrace_enabled || ftrace_disabled) | 391 | if (!ftrace_enabled || ftrace_disabled) |
@@ -368,9 +415,7 @@ ftrace_record_ip(unsigned long ip) | |||
368 | if (ftrace_ip_in_hash(ip, key)) | 415 | if (ftrace_ip_in_hash(ip, key)) |
369 | goto out; | 416 | goto out; |
370 | 417 | ||
371 | atomic = irqs_disabled(); | 418 | ftrace_hash_lock(flags); |
372 | |||
373 | spin_lock_irqsave(&ftrace_shutdown_lock, flags); | ||
374 | 419 | ||
375 | /* This ip may have hit the hash before the lock */ | 420 | /* This ip may have hit the hash before the lock */ |
376 | if (ftrace_ip_in_hash(ip, key)) | 421 | if (ftrace_ip_in_hash(ip, key)) |
@@ -387,7 +432,7 @@ ftrace_record_ip(unsigned long ip) | |||
387 | ftraced_trigger = 1; | 432 | ftraced_trigger = 1; |
388 | 433 | ||
389 | out_unlock: | 434 | out_unlock: |
390 | spin_unlock_irqrestore(&ftrace_shutdown_lock, flags); | 435 | ftrace_hash_unlock(flags); |
391 | out: | 436 | out: |
392 | per_cpu(ftrace_shutdown_disable_cpu, cpu)--; | 437 | per_cpu(ftrace_shutdown_disable_cpu, cpu)--; |
393 | 438 | ||
@@ -531,6 +576,16 @@ static void ftrace_shutdown_replenish(void) | |||
531 | ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL); | 576 | ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL); |
532 | } | 577 | } |
533 | 578 | ||
579 | static void print_ip_ins(const char *fmt, unsigned char *p) | ||
580 | { | ||
581 | int i; | ||
582 | |||
583 | printk(KERN_CONT "%s", fmt); | ||
584 | |||
585 | for (i = 0; i < MCOUNT_INSN_SIZE; i++) | ||
586 | printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]); | ||
587 | } | ||
588 | |||
534 | static int | 589 | static int |
535 | ftrace_code_disable(struct dyn_ftrace *rec) | 590 | ftrace_code_disable(struct dyn_ftrace *rec) |
536 | { | 591 | { |
@@ -541,10 +596,27 @@ ftrace_code_disable(struct dyn_ftrace *rec) | |||
541 | ip = rec->ip; | 596 | ip = rec->ip; |
542 | 597 | ||
543 | nop = ftrace_nop_replace(); | 598 | nop = ftrace_nop_replace(); |
544 | call = ftrace_call_replace(ip, MCOUNT_ADDR); | 599 | call = ftrace_call_replace(ip, mcount_addr); |
545 | 600 | ||
546 | failed = ftrace_modify_code(ip, call, nop); | 601 | failed = ftrace_modify_code(ip, call, nop); |
547 | if (failed) { | 602 | if (failed) { |
603 | switch (failed) { | ||
604 | case 1: | ||
605 | WARN_ON_ONCE(1); | ||
606 | pr_info("ftrace faulted on modifying "); | ||
607 | print_ip_sym(ip); | ||
608 | break; | ||
609 | case 2: | ||
610 | WARN_ON_ONCE(1); | ||
611 | pr_info("ftrace failed to modify "); | ||
612 | print_ip_sym(ip); | ||
613 | print_ip_ins(" expected: ", call); | ||
614 | print_ip_ins(" actual: ", (unsigned char *)ip); | ||
615 | print_ip_ins(" replace: ", nop); | ||
616 | printk(KERN_CONT "\n"); | ||
617 | break; | ||
618 | } | ||
619 | |||
548 | rec->flags |= FTRACE_FL_FAILED; | 620 | rec->flags |= FTRACE_FL_FAILED; |
549 | return 0; | 621 | return 0; |
550 | } | 622 | } |
@@ -792,47 +864,7 @@ static int ftrace_update_code(void) | |||
792 | return 1; | 864 | return 1; |
793 | } | 865 | } |
794 | 866 | ||
795 | static int ftraced(void *ignore) | 867 | static int __init ftrace_dyn_table_alloc(unsigned long num_to_init) |
796 | { | ||
797 | unsigned long usecs; | ||
798 | |||
799 | while (!kthread_should_stop()) { | ||
800 | |||
801 | set_current_state(TASK_INTERRUPTIBLE); | ||
802 | |||
803 | /* check once a second */ | ||
804 | schedule_timeout(HZ); | ||
805 | |||
806 | if (unlikely(ftrace_disabled)) | ||
807 | continue; | ||
808 | |||
809 | mutex_lock(&ftrace_sysctl_lock); | ||
810 | mutex_lock(&ftraced_lock); | ||
811 | if (!ftraced_suspend && !ftraced_stop && | ||
812 | ftrace_update_code()) { | ||
813 | usecs = nsecs_to_usecs(ftrace_update_time); | ||
814 | if (ftrace_update_tot_cnt > 100000) { | ||
815 | ftrace_update_tot_cnt = 0; | ||
816 | pr_info("hm, dftrace overflow: %lu change%s" | ||
817 | " (%lu total) in %lu usec%s\n", | ||
818 | ftrace_update_cnt, | ||
819 | ftrace_update_cnt != 1 ? "s" : "", | ||
820 | ftrace_update_tot_cnt, | ||
821 | usecs, usecs != 1 ? "s" : ""); | ||
822 | ftrace_disabled = 1; | ||
823 | WARN_ON_ONCE(1); | ||
824 | } | ||
825 | } | ||
826 | mutex_unlock(&ftraced_lock); | ||
827 | mutex_unlock(&ftrace_sysctl_lock); | ||
828 | |||
829 | ftrace_shutdown_replenish(); | ||
830 | } | ||
831 | __set_current_state(TASK_RUNNING); | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | static int __init ftrace_dyn_table_alloc(void) | ||
836 | { | 868 | { |
837 | struct ftrace_page *pg; | 869 | struct ftrace_page *pg; |
838 | int cnt; | 870 | int cnt; |
@@ -859,7 +891,9 @@ static int __init ftrace_dyn_table_alloc(void) | |||
859 | 891 | ||
860 | pg = ftrace_pages = ftrace_pages_start; | 892 | pg = ftrace_pages = ftrace_pages_start; |
861 | 893 | ||
862 | cnt = NR_TO_INIT / ENTRIES_PER_PAGE; | 894 | cnt = num_to_init / ENTRIES_PER_PAGE; |
895 | pr_info("ftrace: allocating %ld hash entries in %d pages\n", | ||
896 | num_to_init, cnt); | ||
863 | 897 | ||
864 | for (i = 0; i < cnt; i++) { | 898 | for (i = 0; i < cnt; i++) { |
865 | pg->next = (void *)get_zeroed_page(GFP_KERNEL); | 899 | pg->next = (void *)get_zeroed_page(GFP_KERNEL); |
@@ -901,6 +935,8 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
901 | 935 | ||
902 | (*pos)++; | 936 | (*pos)++; |
903 | 937 | ||
938 | /* should not be called from interrupt context */ | ||
939 | spin_lock(&ftrace_lock); | ||
904 | retry: | 940 | retry: |
905 | if (iter->idx >= iter->pg->index) { | 941 | if (iter->idx >= iter->pg->index) { |
906 | if (iter->pg->next) { | 942 | if (iter->pg->next) { |
@@ -910,15 +946,13 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
910 | } | 946 | } |
911 | } else { | 947 | } else { |
912 | rec = &iter->pg->records[iter->idx++]; | 948 | rec = &iter->pg->records[iter->idx++]; |
913 | if ((!(iter->flags & FTRACE_ITER_FAILURES) && | 949 | if ((rec->flags & FTRACE_FL_FREE) || |
950 | |||
951 | (!(iter->flags & FTRACE_ITER_FAILURES) && | ||
914 | (rec->flags & FTRACE_FL_FAILED)) || | 952 | (rec->flags & FTRACE_FL_FAILED)) || |
915 | 953 | ||
916 | ((iter->flags & FTRACE_ITER_FAILURES) && | 954 | ((iter->flags & FTRACE_ITER_FAILURES) && |
917 | (!(rec->flags & FTRACE_FL_FAILED) || | 955 | !(rec->flags & FTRACE_FL_FAILED)) || |
918 | (rec->flags & FTRACE_FL_FREE))) || | ||
919 | |||
920 | ((iter->flags & FTRACE_ITER_FILTER) && | ||
921 | !(rec->flags & FTRACE_FL_FILTER)) || | ||
922 | 956 | ||
923 | ((iter->flags & FTRACE_ITER_NOTRACE) && | 957 | ((iter->flags & FTRACE_ITER_NOTRACE) && |
924 | !(rec->flags & FTRACE_FL_NOTRACE))) { | 958 | !(rec->flags & FTRACE_FL_NOTRACE))) { |
@@ -926,6 +960,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
926 | goto retry; | 960 | goto retry; |
927 | } | 961 | } |
928 | } | 962 | } |
963 | spin_unlock(&ftrace_lock); | ||
929 | 964 | ||
930 | iter->pos = *pos; | 965 | iter->pos = *pos; |
931 | 966 | ||
@@ -1039,8 +1074,8 @@ static void ftrace_filter_reset(int enable) | |||
1039 | unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; | 1074 | unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; |
1040 | unsigned i; | 1075 | unsigned i; |
1041 | 1076 | ||
1042 | /* keep kstop machine from running */ | 1077 | /* should not be called from interrupt context */ |
1043 | preempt_disable(); | 1078 | spin_lock(&ftrace_lock); |
1044 | if (enable) | 1079 | if (enable) |
1045 | ftrace_filtered = 0; | 1080 | ftrace_filtered = 0; |
1046 | pg = ftrace_pages_start; | 1081 | pg = ftrace_pages_start; |
@@ -1053,7 +1088,7 @@ static void ftrace_filter_reset(int enable) | |||
1053 | } | 1088 | } |
1054 | pg = pg->next; | 1089 | pg = pg->next; |
1055 | } | 1090 | } |
1056 | preempt_enable(); | 1091 | spin_unlock(&ftrace_lock); |
1057 | } | 1092 | } |
1058 | 1093 | ||
1059 | static int | 1094 | static int |
@@ -1165,8 +1200,8 @@ ftrace_match(unsigned char *buff, int len, int enable) | |||
1165 | } | 1200 | } |
1166 | } | 1201 | } |
1167 | 1202 | ||
1168 | /* keep kstop machine from running */ | 1203 | /* should not be called from interrupt context */ |
1169 | preempt_disable(); | 1204 | spin_lock(&ftrace_lock); |
1170 | if (enable) | 1205 | if (enable) |
1171 | ftrace_filtered = 1; | 1206 | ftrace_filtered = 1; |
1172 | pg = ftrace_pages_start; | 1207 | pg = ftrace_pages_start; |
@@ -1203,7 +1238,7 @@ ftrace_match(unsigned char *buff, int len, int enable) | |||
1203 | } | 1238 | } |
1204 | pg = pg->next; | 1239 | pg = pg->next; |
1205 | } | 1240 | } |
1206 | preempt_enable(); | 1241 | spin_unlock(&ftrace_lock); |
1207 | } | 1242 | } |
1208 | 1243 | ||
1209 | static ssize_t | 1244 | static ssize_t |
@@ -1556,6 +1591,114 @@ static __init int ftrace_init_debugfs(void) | |||
1556 | 1591 | ||
1557 | fs_initcall(ftrace_init_debugfs); | 1592 | fs_initcall(ftrace_init_debugfs); |
1558 | 1593 | ||
1594 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD | ||
1595 | static int ftrace_convert_nops(unsigned long *start, | ||
1596 | unsigned long *end) | ||
1597 | { | ||
1598 | unsigned long *p; | ||
1599 | unsigned long addr; | ||
1600 | unsigned long flags; | ||
1601 | |||
1602 | p = start; | ||
1603 | while (p < end) { | ||
1604 | addr = ftrace_call_adjust(*p++); | ||
1605 | /* should not be called from interrupt context */ | ||
1606 | spin_lock(&ftrace_lock); | ||
1607 | ftrace_record_ip(addr); | ||
1608 | spin_unlock(&ftrace_lock); | ||
1609 | ftrace_shutdown_replenish(); | ||
1610 | } | ||
1611 | |||
1612 | /* p is ignored */ | ||
1613 | local_irq_save(flags); | ||
1614 | __ftrace_update_code(p); | ||
1615 | local_irq_restore(flags); | ||
1616 | |||
1617 | return 0; | ||
1618 | } | ||
1619 | |||
1620 | void ftrace_init_module(unsigned long *start, unsigned long *end) | ||
1621 | { | ||
1622 | if (ftrace_disabled || start == end) | ||
1623 | return; | ||
1624 | ftrace_convert_nops(start, end); | ||
1625 | } | ||
1626 | |||
1627 | extern unsigned long __start_mcount_loc[]; | ||
1628 | extern unsigned long __stop_mcount_loc[]; | ||
1629 | |||
1630 | void __init ftrace_init(void) | ||
1631 | { | ||
1632 | unsigned long count, addr, flags; | ||
1633 | int ret; | ||
1634 | |||
1635 | /* Keep the ftrace pointer to the stub */ | ||
1636 | addr = (unsigned long)ftrace_stub; | ||
1637 | |||
1638 | local_irq_save(flags); | ||
1639 | ftrace_dyn_arch_init(&addr); | ||
1640 | local_irq_restore(flags); | ||
1641 | |||
1642 | /* ftrace_dyn_arch_init places the return code in addr */ | ||
1643 | if (addr) | ||
1644 | goto failed; | ||
1645 | |||
1646 | count = __stop_mcount_loc - __start_mcount_loc; | ||
1647 | |||
1648 | ret = ftrace_dyn_table_alloc(count); | ||
1649 | if (ret) | ||
1650 | goto failed; | ||
1651 | |||
1652 | last_ftrace_enabled = ftrace_enabled = 1; | ||
1653 | |||
1654 | ret = ftrace_convert_nops(__start_mcount_loc, | ||
1655 | __stop_mcount_loc); | ||
1656 | |||
1657 | return; | ||
1658 | failed: | ||
1659 | ftrace_disabled = 1; | ||
1660 | } | ||
1661 | #else /* CONFIG_FTRACE_MCOUNT_RECORD */ | ||
1662 | static int ftraced(void *ignore) | ||
1663 | { | ||
1664 | unsigned long usecs; | ||
1665 | |||
1666 | while (!kthread_should_stop()) { | ||
1667 | |||
1668 | set_current_state(TASK_INTERRUPTIBLE); | ||
1669 | |||
1670 | /* check once a second */ | ||
1671 | schedule_timeout(HZ); | ||
1672 | |||
1673 | if (unlikely(ftrace_disabled)) | ||
1674 | continue; | ||
1675 | |||
1676 | mutex_lock(&ftrace_sysctl_lock); | ||
1677 | mutex_lock(&ftraced_lock); | ||
1678 | if (!ftraced_suspend && !ftraced_stop && | ||
1679 | ftrace_update_code()) { | ||
1680 | usecs = nsecs_to_usecs(ftrace_update_time); | ||
1681 | if (ftrace_update_tot_cnt > 100000) { | ||
1682 | ftrace_update_tot_cnt = 0; | ||
1683 | pr_info("hm, dftrace overflow: %lu change%s" | ||
1684 | " (%lu total) in %lu usec%s\n", | ||
1685 | ftrace_update_cnt, | ||
1686 | ftrace_update_cnt != 1 ? "s" : "", | ||
1687 | ftrace_update_tot_cnt, | ||
1688 | usecs, usecs != 1 ? "s" : ""); | ||
1689 | ftrace_disabled = 1; | ||
1690 | WARN_ON_ONCE(1); | ||
1691 | } | ||
1692 | } | ||
1693 | mutex_unlock(&ftraced_lock); | ||
1694 | mutex_unlock(&ftrace_sysctl_lock); | ||
1695 | |||
1696 | ftrace_shutdown_replenish(); | ||
1697 | } | ||
1698 | __set_current_state(TASK_RUNNING); | ||
1699 | return 0; | ||
1700 | } | ||
1701 | |||
1559 | static int __init ftrace_dynamic_init(void) | 1702 | static int __init ftrace_dynamic_init(void) |
1560 | { | 1703 | { |
1561 | struct task_struct *p; | 1704 | struct task_struct *p; |
@@ -1572,7 +1715,7 @@ static int __init ftrace_dynamic_init(void) | |||
1572 | goto failed; | 1715 | goto failed; |
1573 | } | 1716 | } |
1574 | 1717 | ||
1575 | ret = ftrace_dyn_table_alloc(); | 1718 | ret = ftrace_dyn_table_alloc(NR_TO_INIT); |
1576 | if (ret) | 1719 | if (ret) |
1577 | goto failed; | 1720 | goto failed; |
1578 | 1721 | ||
@@ -1593,6 +1736,8 @@ static int __init ftrace_dynamic_init(void) | |||
1593 | } | 1736 | } |
1594 | 1737 | ||
1595 | core_initcall(ftrace_dynamic_init); | 1738 | core_initcall(ftrace_dynamic_init); |
1739 | #endif /* CONFIG_FTRACE_MCOUNT_RECORD */ | ||
1740 | |||
1596 | #else | 1741 | #else |
1597 | # define ftrace_startup() do { } while (0) | 1742 | # define ftrace_startup() do { } while (0) |
1598 | # define ftrace_shutdown() do { } while (0) | 1743 | # define ftrace_shutdown() do { } while (0) |