diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/ftrace.c | 148 |
1 files changed, 105 insertions, 43 deletions
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 | ||
795 | static int ftraced(void *ignore) | 795 | 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 | { | 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 | ||
1557 | fs_initcall(ftrace_init_debugfs); | 1519 | fs_initcall(ftrace_init_debugfs); |
1558 | 1520 | ||
1521 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD | ||
1522 | static 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 | |||
1544 | extern unsigned long __start_mcount_loc[]; | ||
1545 | extern unsigned long __stop_mcount_loc[]; | ||
1546 | |||
1547 | void __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 */ | ||
1579 | static 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 | |||
1559 | static int __init ftrace_dynamic_init(void) | 1619 | static 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 | ||
1595 | core_initcall(ftrace_dynamic_init); | 1655 | core_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) |