diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 179 |
1 files changed, 119 insertions, 60 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 908038f5744..798b16cd40f 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -32,7 +32,6 @@ | |||
32 | 32 | ||
33 | #include <trace/events/sched.h> | 33 | #include <trace/events/sched.h> |
34 | 34 | ||
35 | #include <asm/ftrace.h> | ||
36 | #include <asm/setup.h> | 35 | #include <asm/setup.h> |
37 | 36 | ||
38 | #include "trace_output.h" | 37 | #include "trace_output.h" |
@@ -82,14 +81,14 @@ static int ftrace_disabled __read_mostly; | |||
82 | 81 | ||
83 | static DEFINE_MUTEX(ftrace_lock); | 82 | static DEFINE_MUTEX(ftrace_lock); |
84 | 83 | ||
85 | static struct ftrace_ops ftrace_list_end __read_mostly = | 84 | static struct ftrace_ops ftrace_list_end __read_mostly = { |
86 | { | ||
87 | .func = ftrace_stub, | 85 | .func = ftrace_stub, |
88 | }; | 86 | }; |
89 | 87 | ||
90 | static struct ftrace_ops *ftrace_global_list __read_mostly = &ftrace_list_end; | 88 | static struct ftrace_ops *ftrace_global_list __read_mostly = &ftrace_list_end; |
91 | static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end; | 89 | static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end; |
92 | ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; | 90 | ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; |
91 | static ftrace_func_t __ftrace_trace_function_delay __read_mostly = ftrace_stub; | ||
93 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; | 92 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; |
94 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; | 93 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; |
95 | static struct ftrace_ops global_ops; | 94 | static struct ftrace_ops global_ops; |
@@ -148,6 +147,7 @@ void clear_ftrace_function(void) | |||
148 | { | 147 | { |
149 | ftrace_trace_function = ftrace_stub; | 148 | ftrace_trace_function = ftrace_stub; |
150 | __ftrace_trace_function = ftrace_stub; | 149 | __ftrace_trace_function = ftrace_stub; |
150 | __ftrace_trace_function_delay = ftrace_stub; | ||
151 | ftrace_pid_function = ftrace_stub; | 151 | ftrace_pid_function = ftrace_stub; |
152 | } | 152 | } |
153 | 153 | ||
@@ -210,7 +210,12 @@ static void update_ftrace_function(void) | |||
210 | #ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST | 210 | #ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST |
211 | ftrace_trace_function = func; | 211 | ftrace_trace_function = func; |
212 | #else | 212 | #else |
213 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
214 | /* do not update till all functions have been modified */ | ||
215 | __ftrace_trace_function_delay = func; | ||
216 | #else | ||
213 | __ftrace_trace_function = func; | 217 | __ftrace_trace_function = func; |
218 | #endif | ||
214 | ftrace_trace_function = ftrace_test_stop_func; | 219 | ftrace_trace_function = ftrace_test_stop_func; |
215 | #endif | 220 | #endif |
216 | } | 221 | } |
@@ -785,8 +790,7 @@ static void unregister_ftrace_profiler(void) | |||
785 | unregister_ftrace_graph(); | 790 | unregister_ftrace_graph(); |
786 | } | 791 | } |
787 | #else | 792 | #else |
788 | static struct ftrace_ops ftrace_profile_ops __read_mostly = | 793 | static struct ftrace_ops ftrace_profile_ops __read_mostly = { |
789 | { | ||
790 | .func = function_profile_call, | 794 | .func = function_profile_call, |
791 | }; | 795 | }; |
792 | 796 | ||
@@ -806,19 +810,10 @@ ftrace_profile_write(struct file *filp, const char __user *ubuf, | |||
806 | size_t cnt, loff_t *ppos) | 810 | size_t cnt, loff_t *ppos) |
807 | { | 811 | { |
808 | unsigned long val; | 812 | unsigned long val; |
809 | char buf[64]; /* big enough to hold a number */ | ||
810 | int ret; | 813 | int ret; |
811 | 814 | ||
812 | if (cnt >= sizeof(buf)) | 815 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); |
813 | return -EINVAL; | 816 | if (ret) |
814 | |||
815 | if (copy_from_user(&buf, ubuf, cnt)) | ||
816 | return -EFAULT; | ||
817 | |||
818 | buf[cnt] = 0; | ||
819 | |||
820 | ret = strict_strtoul(buf, 10, &val); | ||
821 | if (ret < 0) | ||
822 | return ret; | 817 | return ret; |
823 | 818 | ||
824 | val = !!val; | 819 | val = !!val; |
@@ -952,7 +947,7 @@ struct ftrace_func_probe { | |||
952 | }; | 947 | }; |
953 | 948 | ||
954 | enum { | 949 | enum { |
955 | FTRACE_ENABLE_CALLS = (1 << 0), | 950 | FTRACE_UPDATE_CALLS = (1 << 0), |
956 | FTRACE_DISABLE_CALLS = (1 << 1), | 951 | FTRACE_DISABLE_CALLS = (1 << 1), |
957 | FTRACE_UPDATE_TRACE_FUNC = (1 << 2), | 952 | FTRACE_UPDATE_TRACE_FUNC = (1 << 2), |
958 | FTRACE_START_FUNC_RET = (1 << 3), | 953 | FTRACE_START_FUNC_RET = (1 << 3), |
@@ -1182,8 +1177,14 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash) | |||
1182 | return NULL; | 1177 | return NULL; |
1183 | } | 1178 | } |
1184 | 1179 | ||
1180 | static void | ||
1181 | ftrace_hash_rec_disable(struct ftrace_ops *ops, int filter_hash); | ||
1182 | static void | ||
1183 | ftrace_hash_rec_enable(struct ftrace_ops *ops, int filter_hash); | ||
1184 | |||
1185 | static int | 1185 | static int |
1186 | ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) | 1186 | ftrace_hash_move(struct ftrace_ops *ops, int enable, |
1187 | struct ftrace_hash **dst, struct ftrace_hash *src) | ||
1187 | { | 1188 | { |
1188 | struct ftrace_func_entry *entry; | 1189 | struct ftrace_func_entry *entry; |
1189 | struct hlist_node *tp, *tn; | 1190 | struct hlist_node *tp, *tn; |
@@ -1193,9 +1194,16 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) | |||
1193 | unsigned long key; | 1194 | unsigned long key; |
1194 | int size = src->count; | 1195 | int size = src->count; |
1195 | int bits = 0; | 1196 | int bits = 0; |
1197 | int ret; | ||
1196 | int i; | 1198 | int i; |
1197 | 1199 | ||
1198 | /* | 1200 | /* |
1201 | * Remove the current set, update the hash and add | ||
1202 | * them back. | ||
1203 | */ | ||
1204 | ftrace_hash_rec_disable(ops, enable); | ||
1205 | |||
1206 | /* | ||
1199 | * If the new source is empty, just free dst and assign it | 1207 | * If the new source is empty, just free dst and assign it |
1200 | * the empty_hash. | 1208 | * the empty_hash. |
1201 | */ | 1209 | */ |
@@ -1215,9 +1223,10 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) | |||
1215 | if (bits > FTRACE_HASH_MAX_BITS) | 1223 | if (bits > FTRACE_HASH_MAX_BITS) |
1216 | bits = FTRACE_HASH_MAX_BITS; | 1224 | bits = FTRACE_HASH_MAX_BITS; |
1217 | 1225 | ||
1226 | ret = -ENOMEM; | ||
1218 | new_hash = alloc_ftrace_hash(bits); | 1227 | new_hash = alloc_ftrace_hash(bits); |
1219 | if (!new_hash) | 1228 | if (!new_hash) |
1220 | return -ENOMEM; | 1229 | goto out; |
1221 | 1230 | ||
1222 | size = 1 << src->size_bits; | 1231 | size = 1 << src->size_bits; |
1223 | for (i = 0; i < size; i++) { | 1232 | for (i = 0; i < size; i++) { |
@@ -1236,7 +1245,16 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) | |||
1236 | rcu_assign_pointer(*dst, new_hash); | 1245 | rcu_assign_pointer(*dst, new_hash); |
1237 | free_ftrace_hash_rcu(old_hash); | 1246 | free_ftrace_hash_rcu(old_hash); |
1238 | 1247 | ||
1239 | return 0; | 1248 | ret = 0; |
1249 | out: | ||
1250 | /* | ||
1251 | * Enable regardless of ret: | ||
1252 | * On success, we enable the new hash. | ||
1253 | * On failure, we re-enable the original hash. | ||
1254 | */ | ||
1255 | ftrace_hash_rec_enable(ops, enable); | ||
1256 | |||
1257 | return ret; | ||
1240 | } | 1258 | } |
1241 | 1259 | ||
1242 | /* | 1260 | /* |
@@ -1498,7 +1516,7 @@ int ftrace_text_reserved(void *start, void *end) | |||
1498 | 1516 | ||
1499 | 1517 | ||
1500 | static int | 1518 | static int |
1501 | __ftrace_replace_code(struct dyn_ftrace *rec, int enable) | 1519 | __ftrace_replace_code(struct dyn_ftrace *rec, int update) |
1502 | { | 1520 | { |
1503 | unsigned long ftrace_addr; | 1521 | unsigned long ftrace_addr; |
1504 | unsigned long flag = 0UL; | 1522 | unsigned long flag = 0UL; |
@@ -1506,17 +1524,17 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) | |||
1506 | ftrace_addr = (unsigned long)FTRACE_ADDR; | 1524 | ftrace_addr = (unsigned long)FTRACE_ADDR; |
1507 | 1525 | ||
1508 | /* | 1526 | /* |
1509 | * If we are enabling tracing: | 1527 | * If we are updating calls: |
1510 | * | 1528 | * |
1511 | * If the record has a ref count, then we need to enable it | 1529 | * If the record has a ref count, then we need to enable it |
1512 | * because someone is using it. | 1530 | * because someone is using it. |
1513 | * | 1531 | * |
1514 | * Otherwise we make sure its disabled. | 1532 | * Otherwise we make sure its disabled. |
1515 | * | 1533 | * |
1516 | * If we are disabling tracing, then disable all records that | 1534 | * If we are disabling calls, then disable all records that |
1517 | * are enabled. | 1535 | * are enabled. |
1518 | */ | 1536 | */ |
1519 | if (enable && (rec->flags & ~FTRACE_FL_MASK)) | 1537 | if (update && (rec->flags & ~FTRACE_FL_MASK)) |
1520 | flag = FTRACE_FL_ENABLED; | 1538 | flag = FTRACE_FL_ENABLED; |
1521 | 1539 | ||
1522 | /* If the state of this record hasn't changed, then do nothing */ | 1540 | /* If the state of this record hasn't changed, then do nothing */ |
@@ -1532,7 +1550,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) | |||
1532 | return ftrace_make_nop(NULL, rec, ftrace_addr); | 1550 | return ftrace_make_nop(NULL, rec, ftrace_addr); |
1533 | } | 1551 | } |
1534 | 1552 | ||
1535 | static void ftrace_replace_code(int enable) | 1553 | static void ftrace_replace_code(int update) |
1536 | { | 1554 | { |
1537 | struct dyn_ftrace *rec; | 1555 | struct dyn_ftrace *rec; |
1538 | struct ftrace_page *pg; | 1556 | struct ftrace_page *pg; |
@@ -1546,7 +1564,7 @@ static void ftrace_replace_code(int enable) | |||
1546 | if (rec->flags & FTRACE_FL_FREE) | 1564 | if (rec->flags & FTRACE_FL_FREE) |
1547 | continue; | 1565 | continue; |
1548 | 1566 | ||
1549 | failed = __ftrace_replace_code(rec, enable); | 1567 | failed = __ftrace_replace_code(rec, update); |
1550 | if (failed) { | 1568 | if (failed) { |
1551 | ftrace_bug(failed, rec->ip); | 1569 | ftrace_bug(failed, rec->ip); |
1552 | /* Stop processing */ | 1570 | /* Stop processing */ |
@@ -1596,7 +1614,13 @@ static int __ftrace_modify_code(void *data) | |||
1596 | { | 1614 | { |
1597 | int *command = data; | 1615 | int *command = data; |
1598 | 1616 | ||
1599 | if (*command & FTRACE_ENABLE_CALLS) | 1617 | /* |
1618 | * Do not call function tracer while we update the code. | ||
1619 | * We are in stop machine, no worrying about races. | ||
1620 | */ | ||
1621 | function_trace_stop++; | ||
1622 | |||
1623 | if (*command & FTRACE_UPDATE_CALLS) | ||
1600 | ftrace_replace_code(1); | 1624 | ftrace_replace_code(1); |
1601 | else if (*command & FTRACE_DISABLE_CALLS) | 1625 | else if (*command & FTRACE_DISABLE_CALLS) |
1602 | ftrace_replace_code(0); | 1626 | ftrace_replace_code(0); |
@@ -1609,6 +1633,18 @@ static int __ftrace_modify_code(void *data) | |||
1609 | else if (*command & FTRACE_STOP_FUNC_RET) | 1633 | else if (*command & FTRACE_STOP_FUNC_RET) |
1610 | ftrace_disable_ftrace_graph_caller(); | 1634 | ftrace_disable_ftrace_graph_caller(); |
1611 | 1635 | ||
1636 | #ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST | ||
1637 | /* | ||
1638 | * For archs that call ftrace_test_stop_func(), we must | ||
1639 | * wait till after we update all the function callers | ||
1640 | * before we update the callback. This keeps different | ||
1641 | * ops that record different functions from corrupting | ||
1642 | * each other. | ||
1643 | */ | ||
1644 | __ftrace_trace_function = __ftrace_trace_function_delay; | ||
1645 | #endif | ||
1646 | function_trace_stop--; | ||
1647 | |||
1612 | return 0; | 1648 | return 0; |
1613 | } | 1649 | } |
1614 | 1650 | ||
@@ -1652,7 +1688,7 @@ static int ftrace_startup(struct ftrace_ops *ops, int command) | |||
1652 | return -ENODEV; | 1688 | return -ENODEV; |
1653 | 1689 | ||
1654 | ftrace_start_up++; | 1690 | ftrace_start_up++; |
1655 | command |= FTRACE_ENABLE_CALLS; | 1691 | command |= FTRACE_UPDATE_CALLS; |
1656 | 1692 | ||
1657 | /* ops marked global share the filter hashes */ | 1693 | /* ops marked global share the filter hashes */ |
1658 | if (ops->flags & FTRACE_OPS_FL_GLOBAL) { | 1694 | if (ops->flags & FTRACE_OPS_FL_GLOBAL) { |
@@ -1704,8 +1740,7 @@ static void ftrace_shutdown(struct ftrace_ops *ops, int command) | |||
1704 | if (ops != &global_ops || !global_start_up) | 1740 | if (ops != &global_ops || !global_start_up) |
1705 | ops->flags &= ~FTRACE_OPS_FL_ENABLED; | 1741 | ops->flags &= ~FTRACE_OPS_FL_ENABLED; |
1706 | 1742 | ||
1707 | if (!ftrace_start_up) | 1743 | command |= FTRACE_UPDATE_CALLS; |
1708 | command |= FTRACE_DISABLE_CALLS; | ||
1709 | 1744 | ||
1710 | if (saved_ftrace_func != ftrace_trace_function) { | 1745 | if (saved_ftrace_func != ftrace_trace_function) { |
1711 | saved_ftrace_func = ftrace_trace_function; | 1746 | saved_ftrace_func = ftrace_trace_function; |
@@ -1727,7 +1762,7 @@ static void ftrace_startup_sysctl(void) | |||
1727 | saved_ftrace_func = NULL; | 1762 | saved_ftrace_func = NULL; |
1728 | /* ftrace_start_up is true if we want ftrace running */ | 1763 | /* ftrace_start_up is true if we want ftrace running */ |
1729 | if (ftrace_start_up) | 1764 | if (ftrace_start_up) |
1730 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); | 1765 | ftrace_run_update_code(FTRACE_UPDATE_CALLS); |
1731 | } | 1766 | } |
1732 | 1767 | ||
1733 | static void ftrace_shutdown_sysctl(void) | 1768 | static void ftrace_shutdown_sysctl(void) |
@@ -1744,10 +1779,36 @@ static cycle_t ftrace_update_time; | |||
1744 | static unsigned long ftrace_update_cnt; | 1779 | static unsigned long ftrace_update_cnt; |
1745 | unsigned long ftrace_update_tot_cnt; | 1780 | unsigned long ftrace_update_tot_cnt; |
1746 | 1781 | ||
1782 | static int ops_traces_mod(struct ftrace_ops *ops) | ||
1783 | { | ||
1784 | struct ftrace_hash *hash; | ||
1785 | |||
1786 | hash = ops->filter_hash; | ||
1787 | return !!(!hash || !hash->count); | ||
1788 | } | ||
1789 | |||
1747 | static int ftrace_update_code(struct module *mod) | 1790 | static int ftrace_update_code(struct module *mod) |
1748 | { | 1791 | { |
1749 | struct dyn_ftrace *p; | 1792 | struct dyn_ftrace *p; |
1750 | cycle_t start, stop; | 1793 | cycle_t start, stop; |
1794 | unsigned long ref = 0; | ||
1795 | |||
1796 | /* | ||
1797 | * When adding a module, we need to check if tracers are | ||
1798 | * currently enabled and if they are set to trace all functions. | ||
1799 | * If they are, we need to enable the module functions as well | ||
1800 | * as update the reference counts for those function records. | ||
1801 | */ | ||
1802 | if (mod) { | ||
1803 | struct ftrace_ops *ops; | ||
1804 | |||
1805 | for (ops = ftrace_ops_list; | ||
1806 | ops != &ftrace_list_end; ops = ops->next) { | ||
1807 | if (ops->flags & FTRACE_OPS_FL_ENABLED && | ||
1808 | ops_traces_mod(ops)) | ||
1809 | ref++; | ||
1810 | } | ||
1811 | } | ||
1751 | 1812 | ||
1752 | start = ftrace_now(raw_smp_processor_id()); | 1813 | start = ftrace_now(raw_smp_processor_id()); |
1753 | ftrace_update_cnt = 0; | 1814 | ftrace_update_cnt = 0; |
@@ -1760,7 +1821,7 @@ static int ftrace_update_code(struct module *mod) | |||
1760 | 1821 | ||
1761 | p = ftrace_new_addrs; | 1822 | p = ftrace_new_addrs; |
1762 | ftrace_new_addrs = p->newlist; | 1823 | ftrace_new_addrs = p->newlist; |
1763 | p->flags = 0L; | 1824 | p->flags = ref; |
1764 | 1825 | ||
1765 | /* | 1826 | /* |
1766 | * Do the initial record conversion from mcount jump | 1827 | * Do the initial record conversion from mcount jump |
@@ -1783,7 +1844,7 @@ static int ftrace_update_code(struct module *mod) | |||
1783 | * conversion puts the module to the correct state, thus | 1844 | * conversion puts the module to the correct state, thus |
1784 | * passing the ftrace_make_call check. | 1845 | * passing the ftrace_make_call check. |
1785 | */ | 1846 | */ |
1786 | if (ftrace_start_up) { | 1847 | if (ftrace_start_up && ref) { |
1787 | int failed = __ftrace_replace_code(p, 1); | 1848 | int failed = __ftrace_replace_code(p, 1); |
1788 | if (failed) { | 1849 | if (failed) { |
1789 | ftrace_bug(failed, p->ip); | 1850 | ftrace_bug(failed, p->ip); |
@@ -2407,10 +2468,9 @@ ftrace_match_module_records(struct ftrace_hash *hash, char *buff, char *mod) | |||
2407 | */ | 2468 | */ |
2408 | 2469 | ||
2409 | static int | 2470 | static int |
2410 | ftrace_mod_callback(char *func, char *cmd, char *param, int enable) | 2471 | ftrace_mod_callback(struct ftrace_hash *hash, |
2472 | char *func, char *cmd, char *param, int enable) | ||
2411 | { | 2473 | { |
2412 | struct ftrace_ops *ops = &global_ops; | ||
2413 | struct ftrace_hash *hash; | ||
2414 | char *mod; | 2474 | char *mod; |
2415 | int ret = -EINVAL; | 2475 | int ret = -EINVAL; |
2416 | 2476 | ||
@@ -2430,11 +2490,6 @@ ftrace_mod_callback(char *func, char *cmd, char *param, int enable) | |||
2430 | if (!strlen(mod)) | 2490 | if (!strlen(mod)) |
2431 | return ret; | 2491 | return ret; |
2432 | 2492 | ||
2433 | if (enable) | ||
2434 | hash = ops->filter_hash; | ||
2435 | else | ||
2436 | hash = ops->notrace_hash; | ||
2437 | |||
2438 | ret = ftrace_match_module_records(hash, func, mod); | 2493 | ret = ftrace_match_module_records(hash, func, mod); |
2439 | if (!ret) | 2494 | if (!ret) |
2440 | ret = -EINVAL; | 2495 | ret = -EINVAL; |
@@ -2760,7 +2815,7 @@ static int ftrace_process_regex(struct ftrace_hash *hash, | |||
2760 | mutex_lock(&ftrace_cmd_mutex); | 2815 | mutex_lock(&ftrace_cmd_mutex); |
2761 | list_for_each_entry(p, &ftrace_commands, list) { | 2816 | list_for_each_entry(p, &ftrace_commands, list) { |
2762 | if (strcmp(p->name, command) == 0) { | 2817 | if (strcmp(p->name, command) == 0) { |
2763 | ret = p->func(func, command, next, enable); | 2818 | ret = p->func(hash, func, command, next, enable); |
2764 | goto out_unlock; | 2819 | goto out_unlock; |
2765 | } | 2820 | } |
2766 | } | 2821 | } |
@@ -2857,7 +2912,11 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, | |||
2857 | ftrace_match_records(hash, buf, len); | 2912 | ftrace_match_records(hash, buf, len); |
2858 | 2913 | ||
2859 | mutex_lock(&ftrace_lock); | 2914 | mutex_lock(&ftrace_lock); |
2860 | ret = ftrace_hash_move(orig_hash, hash); | 2915 | ret = ftrace_hash_move(ops, enable, orig_hash, hash); |
2916 | if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED | ||
2917 | && ftrace_enabled) | ||
2918 | ftrace_run_update_code(FTRACE_UPDATE_CALLS); | ||
2919 | |||
2861 | mutex_unlock(&ftrace_lock); | 2920 | mutex_unlock(&ftrace_lock); |
2862 | 2921 | ||
2863 | mutex_unlock(&ftrace_regex_lock); | 2922 | mutex_unlock(&ftrace_regex_lock); |
@@ -3040,18 +3099,12 @@ ftrace_regex_release(struct inode *inode, struct file *file) | |||
3040 | orig_hash = &iter->ops->notrace_hash; | 3099 | orig_hash = &iter->ops->notrace_hash; |
3041 | 3100 | ||
3042 | mutex_lock(&ftrace_lock); | 3101 | mutex_lock(&ftrace_lock); |
3043 | /* | 3102 | ret = ftrace_hash_move(iter->ops, filter_hash, |
3044 | * Remove the current set, update the hash and add | 3103 | orig_hash, iter->hash); |
3045 | * them back. | 3104 | if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED) |
3046 | */ | 3105 | && ftrace_enabled) |
3047 | ftrace_hash_rec_disable(iter->ops, filter_hash); | 3106 | ftrace_run_update_code(FTRACE_UPDATE_CALLS); |
3048 | ret = ftrace_hash_move(orig_hash, iter->hash); | 3107 | |
3049 | if (!ret) { | ||
3050 | ftrace_hash_rec_enable(iter->ops, filter_hash); | ||
3051 | if (iter->ops->flags & FTRACE_OPS_FL_ENABLED | ||
3052 | && ftrace_enabled) | ||
3053 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); | ||
3054 | } | ||
3055 | mutex_unlock(&ftrace_lock); | 3108 | mutex_unlock(&ftrace_lock); |
3056 | } | 3109 | } |
3057 | free_ftrace_hash(iter->hash); | 3110 | free_ftrace_hash(iter->hash); |
@@ -3330,7 +3383,7 @@ static int ftrace_process_locs(struct module *mod, | |||
3330 | { | 3383 | { |
3331 | unsigned long *p; | 3384 | unsigned long *p; |
3332 | unsigned long addr; | 3385 | unsigned long addr; |
3333 | unsigned long flags; | 3386 | unsigned long flags = 0; /* Shut up gcc */ |
3334 | 3387 | ||
3335 | mutex_lock(&ftrace_lock); | 3388 | mutex_lock(&ftrace_lock); |
3336 | p = start; | 3389 | p = start; |
@@ -3348,12 +3401,18 @@ static int ftrace_process_locs(struct module *mod, | |||
3348 | } | 3401 | } |
3349 | 3402 | ||
3350 | /* | 3403 | /* |
3351 | * Disable interrupts to prevent interrupts from executing | 3404 | * We only need to disable interrupts on start up |
3352 | * code that is being modified. | 3405 | * because we are modifying code that an interrupt |
3406 | * may execute, and the modification is not atomic. | ||
3407 | * But for modules, nothing runs the code we modify | ||
3408 | * until we are finished with it, and there's no | ||
3409 | * reason to cause large interrupt latencies while we do it. | ||
3353 | */ | 3410 | */ |
3354 | local_irq_save(flags); | 3411 | if (!mod) |
3412 | local_irq_save(flags); | ||
3355 | ftrace_update_code(mod); | 3413 | ftrace_update_code(mod); |
3356 | local_irq_restore(flags); | 3414 | if (!mod) |
3415 | local_irq_restore(flags); | ||
3357 | mutex_unlock(&ftrace_lock); | 3416 | mutex_unlock(&ftrace_lock); |
3358 | 3417 | ||
3359 | return 0; | 3418 | return 0; |