aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/asm-x86/ftrace.h10
-rw-r--r--include/linux/ftrace.h6
-rw-r--r--init/main.c3
-rw-r--r--kernel/trace/ftrace.c148
4 files changed, 124 insertions, 43 deletions
diff --git a/include/asm-x86/ftrace.h b/include/asm-x86/ftrace.h
index be0e004ad148..1bb6f9bbe1ab 100644
--- a/include/asm-x86/ftrace.h
+++ b/include/asm-x86/ftrace.h
@@ -7,6 +7,16 @@
7 7
8#ifndef __ASSEMBLY__ 8#ifndef __ASSEMBLY__
9extern void mcount(void); 9extern void mcount(void);
10
11static inline unsigned long ftrace_call_adjust(unsigned long addr)
12{
13 /*
14 * call mcount is "e8 <4 byte offset>"
15 * The addr points to the 4 byte offset and the caller of this
16 * function wants the pointer to e8. Simply subtract one.
17 */
18 return addr - 1;
19}
10#endif 20#endif
11 21
12#endif /* CONFIG_FTRACE */ 22#endif /* CONFIG_FTRACE */
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index bb384068272e..d4d6ab453b78 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -162,4 +162,10 @@ static inline void
162ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { } 162ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { }
163#endif 163#endif
164 164
165#ifdef CONFIG_FTRACE_MCOUNT_RECORD
166extern void ftrace_init(void);
167#else
168static inline void ftrace_init(void) { }
169#endif
170
165#endif /* _LINUX_FTRACE_H */ 171#endif /* _LINUX_FTRACE_H */
diff --git a/init/main.c b/init/main.c
index 3820323c4c84..ded1fae965ab 100644
--- a/init/main.c
+++ b/init/main.c
@@ -60,6 +60,7 @@
60#include <linux/sched.h> 60#include <linux/sched.h>
61#include <linux/signal.h> 61#include <linux/signal.h>
62#include <linux/idr.h> 62#include <linux/idr.h>
63#include <linux/ftrace.h>
63 64
64#include <asm/io.h> 65#include <asm/io.h>
65#include <asm/bugs.h> 66#include <asm/bugs.h>
@@ -687,6 +688,8 @@ asmlinkage void __init start_kernel(void)
687 688
688 acpi_early_init(); /* before LAPIC and SMP init */ 689 acpi_early_init(); /* before LAPIC and SMP init */
689 690
691 ftrace_init();
692
690 /* Do the rest non-__init'ed, we're now alive */ 693 /* Do the rest non-__init'ed, we're now alive */
691 rest_init(); 694 rest_init();
692} 695}
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index f6e3af31b403..df96d5990c04 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -792,47 +792,7 @@ static int ftrace_update_code(void)
792 return 1; 792 return 1;
793} 793}
794 794
795static int ftraced(void *ignore) 795static 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
835static int __init ftrace_dyn_table_alloc(void)
836{ 796{
837 struct ftrace_page *pg; 797 struct ftrace_page *pg;
838 int cnt; 798 int cnt;
@@ -859,7 +819,9 @@ static int __init ftrace_dyn_table_alloc(void)
859 819
860 pg = ftrace_pages = ftrace_pages_start; 820 pg = ftrace_pages = ftrace_pages_start;
861 821
862 cnt = NR_TO_INIT / ENTRIES_PER_PAGE; 822 cnt = num_to_init / ENTRIES_PER_PAGE;
823 pr_info("ftrace: allocating %ld hash entries in %d pages\n",
824 num_to_init, cnt);
863 825
864 for (i = 0; i < cnt; i++) { 826 for (i = 0; i < cnt; i++) {
865 pg->next = (void *)get_zeroed_page(GFP_KERNEL); 827 pg->next = (void *)get_zeroed_page(GFP_KERNEL);
@@ -1556,6 +1518,104 @@ static __init int ftrace_init_debugfs(void)
1556 1518
1557fs_initcall(ftrace_init_debugfs); 1519fs_initcall(ftrace_init_debugfs);
1558 1520
1521#ifdef CONFIG_FTRACE_MCOUNT_RECORD
1522static int ftrace_convert_nops(unsigned long *start,
1523 unsigned long *end)
1524{
1525 unsigned long *p;
1526 unsigned long addr;
1527 unsigned long flags;
1528
1529 p = start;
1530 while (p < end) {
1531 addr = ftrace_call_adjust(*p++);
1532 ftrace_record_ip(addr);
1533 ftrace_shutdown_replenish();
1534 }
1535
1536 /* p is ignored */
1537 local_irq_save(flags);
1538 __ftrace_update_code(p);
1539 local_irq_restore(flags);
1540
1541 return 0;
1542}
1543
1544extern unsigned long __start_mcount_loc[];
1545extern unsigned long __stop_mcount_loc[];
1546
1547void __init ftrace_init(void)
1548{
1549 unsigned long count, addr, flags;
1550 int ret;
1551
1552 /* Keep the ftrace pointer to the stub */
1553 addr = (unsigned long)ftrace_stub;
1554
1555 local_irq_save(flags);
1556 ftrace_dyn_arch_init(&addr);
1557 local_irq_restore(flags);
1558
1559 /* ftrace_dyn_arch_init places the return code in addr */
1560 if (addr)
1561 goto failed;
1562
1563 count = __stop_mcount_loc - __start_mcount_loc;
1564
1565 ret = ftrace_dyn_table_alloc(count);
1566 if (ret)
1567 goto failed;
1568
1569 last_ftrace_enabled = ftrace_enabled = 1;
1570
1571 ret = ftrace_convert_nops(__start_mcount_loc,
1572 __stop_mcount_loc);
1573
1574 return;
1575 failed:
1576 ftrace_disabled = 1;
1577}
1578#else /* CONFIG_FTRACE_MCOUNT_RECORD */
1579static int ftraced(void *ignore)
1580{
1581 unsigned long usecs;
1582
1583 while (!kthread_should_stop()) {
1584
1585 set_current_state(TASK_INTERRUPTIBLE);
1586
1587 /* check once a second */
1588 schedule_timeout(HZ);
1589
1590 if (unlikely(ftrace_disabled))
1591 continue;
1592
1593 mutex_lock(&ftrace_sysctl_lock);
1594 mutex_lock(&ftraced_lock);
1595 if (!ftraced_suspend && !ftraced_stop &&
1596 ftrace_update_code()) {
1597 usecs = nsecs_to_usecs(ftrace_update_time);
1598 if (ftrace_update_tot_cnt > 100000) {
1599 ftrace_update_tot_cnt = 0;
1600 pr_info("hm, dftrace overflow: %lu change%s"
1601 " (%lu total) in %lu usec%s\n",
1602 ftrace_update_cnt,
1603 ftrace_update_cnt != 1 ? "s" : "",
1604 ftrace_update_tot_cnt,
1605 usecs, usecs != 1 ? "s" : "");
1606 ftrace_disabled = 1;
1607 WARN_ON_ONCE(1);
1608 }
1609 }
1610 mutex_unlock(&ftraced_lock);
1611 mutex_unlock(&ftrace_sysctl_lock);
1612
1613 ftrace_shutdown_replenish();
1614 }
1615 __set_current_state(TASK_RUNNING);
1616 return 0;
1617}
1618
1559static int __init ftrace_dynamic_init(void) 1619static int __init ftrace_dynamic_init(void)
1560{ 1620{
1561 struct task_struct *p; 1621 struct task_struct *p;
@@ -1572,7 +1632,7 @@ static int __init ftrace_dynamic_init(void)
1572 goto failed; 1632 goto failed;
1573 } 1633 }
1574 1634
1575 ret = ftrace_dyn_table_alloc(); 1635 ret = ftrace_dyn_table_alloc(NR_TO_INIT);
1576 if (ret) 1636 if (ret)
1577 goto failed; 1637 goto failed;
1578 1638
@@ -1593,6 +1653,8 @@ static int __init ftrace_dynamic_init(void)
1593} 1653}
1594 1654
1595core_initcall(ftrace_dynamic_init); 1655core_initcall(ftrace_dynamic_init);
1656#endif /* CONFIG_FTRACE_MCOUNT_RECORD */
1657
1596#else 1658#else
1597# define ftrace_startup() do { } while (0) 1659# define ftrace_startup() do { } while (0)
1598# define ftrace_shutdown() do { } while (0) 1660# define ftrace_shutdown() do { } while (0)