aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/ftrace.c
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-07-14 23:02:27 -0400
committerSteven Rostedt <rostedt@goodmis.org>2011-07-14 23:02:27 -0400
commitf7bc8b61f65726ff98f52e286b28e294499d7a08 (patch)
tree88ef0c943d27aa9f69824d87faa990731cc2ebfe /kernel/trace/ftrace.c
parent04da85b86188f224cc9b391b5bdd92a3ba20ffcf (diff)
ftrace: Fix regression where ftrace breaks when modules are loaded
Enabling function tracer to trace all functions, then load a module and then disable function tracing will cause ftrace to fail. This can also happen by enabling function tracing on the command line: ftrace=function and during boot up, modules are loaded, then you disable function tracing with 'echo nop > current_tracer' you will trigger a bug in ftrace that will shut itself down. The reason is, the new ftrace code keeps ref counts of all ftrace_ops that are registered for tracing. When one or more ftrace_ops are registered, all the records that represent the functions that the ftrace_ops will trace have a ref count incremented. If this ref count is not zero, when the code modification runs, that function will be enabled for tracing. If the ref count is zero, that function will be disabled from tracing. To make sure the accounting was working, FTRACE_WARN_ON()s were added to updating of the ref counts. If the ref count hits its max (> 2^30 ftrace_ops added), or if the ref count goes below zero, a FTRACE_WARN_ON() is triggered which disables all modification of code. Since it is common for ftrace_ops to trace all functions in the kernel, instead of creating > 20,000 hash items for the ftrace_ops, the hash count is just set to zero, and it represents that the ftrace_ops is to trace all functions. This is where the issues arrise. If you enable function tracing to trace all functions, and then add a module, the modules function records do not get the ref count updated. When the function tracer is disabled, all function records ref counts are subtracted. Since the modules never had their ref counts incremented, they go below zero and the FTRACE_WARN_ON() is triggered. The solution to this is rather simple. When modules are loaded, and their functions are added to the the ftrace pool, look to see if any ftrace_ops are registered that trace all functions. And for those, update the ref count for the module function records. Reported-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r--kernel/trace/ftrace.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 1c4c0b087e1d..ef9271b69b4f 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1744,10 +1744,36 @@ static cycle_t ftrace_update_time;
1744static unsigned long ftrace_update_cnt; 1744static unsigned long ftrace_update_cnt;
1745unsigned long ftrace_update_tot_cnt; 1745unsigned long ftrace_update_tot_cnt;
1746 1746
1747static int ops_traces_mod(struct ftrace_ops *ops)
1748{
1749 struct ftrace_hash *hash;
1750
1751 hash = ops->filter_hash;
1752 return !!(!hash || !hash->count);
1753}
1754
1747static int ftrace_update_code(struct module *mod) 1755static int ftrace_update_code(struct module *mod)
1748{ 1756{
1749 struct dyn_ftrace *p; 1757 struct dyn_ftrace *p;
1750 cycle_t start, stop; 1758 cycle_t start, stop;
1759 unsigned long ref = 0;
1760
1761 /*
1762 * When adding a module, we need to check if tracers are
1763 * currently enabled and if they are set to trace all functions.
1764 * If they are, we need to enable the module functions as well
1765 * as update the reference counts for those function records.
1766 */
1767 if (mod) {
1768 struct ftrace_ops *ops;
1769
1770 for (ops = ftrace_ops_list;
1771 ops != &ftrace_list_end; ops = ops->next) {
1772 if (ops->flags & FTRACE_OPS_FL_ENABLED &&
1773 ops_traces_mod(ops))
1774 ref++;
1775 }
1776 }
1751 1777
1752 start = ftrace_now(raw_smp_processor_id()); 1778 start = ftrace_now(raw_smp_processor_id());
1753 ftrace_update_cnt = 0; 1779 ftrace_update_cnt = 0;
@@ -1760,7 +1786,7 @@ static int ftrace_update_code(struct module *mod)
1760 1786
1761 p = ftrace_new_addrs; 1787 p = ftrace_new_addrs;
1762 ftrace_new_addrs = p->newlist; 1788 ftrace_new_addrs = p->newlist;
1763 p->flags = 0L; 1789 p->flags = ref;
1764 1790
1765 /* 1791 /*
1766 * Do the initial record conversion from mcount jump 1792 * Do the initial record conversion from mcount jump
@@ -1783,7 +1809,7 @@ static int ftrace_update_code(struct module *mod)
1783 * conversion puts the module to the correct state, thus 1809 * conversion puts the module to the correct state, thus
1784 * passing the ftrace_make_call check. 1810 * passing the ftrace_make_call check.
1785 */ 1811 */
1786 if (ftrace_start_up) { 1812 if (ftrace_start_up && ref) {
1787 int failed = __ftrace_replace_code(p, 1); 1813 int failed = __ftrace_replace_code(p, 1);
1788 if (failed) { 1814 if (failed) {
1789 ftrace_bug(failed, p->ip); 1815 ftrace_bug(failed, p->ip);