diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
| -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) |
