aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2008-08-14 15:45:08 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-14 04:34:44 -0400
commit68bf21aa15c85d2e9b623dcda2b1ed8893275fa1 (patch)
tree54d4d4f7e8311b77f3166a8807a635347d479081
parent8da3821ba5634497da63d58a69e24a97697c4a2b (diff)
ftrace: mcount call site on boot nops core
This is the infrastructure to the converting the mcount call sites recorded by the __mcount_loc section into nops on boot. It also allows for using these sites to enable tracing as normal. When the __mcount_loc section is used, the "ftraced" kernel thread is disabled. This uses the current infrastructure to record the mcount call sites as well as convert them to nops. The mcount function is kept as a stub on boot up and not converted to the ftrace_record_ip function. We use the ftrace_record_ip to only record from the table. This patch does not handle modules. That comes with a later patch. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-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)