Skip to content

Commit 8a56d77

Browse files
committed
ftrace: Fix function graph with loading of modules
Commit 8c4f3c3 "ftrace: Check module functions being traced on reload" fixed module loading and unloading with respect to function tracing, but it missed the function graph tracer. If you perform the following # cd /sys/kernel/debug/tracing # echo function_graph > current_tracer # modprobe nfsd # echo nop > current_tracer You'll get the following oops message: ------------[ cut here ]------------ WARNING: CPU: 2 PID: 2910 at /linux.git/kernel/trace/ftrace.c:1640 __ftrace_hash_rec_update.part.35+0x168/0x1b9() Modules linked in: nfsd exportfs nfs_acl lockd ipt_MASQUERADE sunrpc ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 ip6table_filter ip6_tables uinput snd_hda_codec_idt CPU: 2 PID: 2910 Comm: bash Not tainted 3.13.0-rc1-test #7 Hardware name: To Be Filled By O.E.M. To Be Filled By O.E.M./To be filled by O.E.M., BIOS SDBLI944.86P 05/08/2007 0000000000000668 ffff8800787efcf8 ffffffff814fe193 ffff88007d500000 0000000000000000 ffff8800787efd38 ffffffff8103b80a 0000000000000668 ffffffff810b2b9a ffffffff81a48370 0000000000000001 ffff880037aea000 Call Trace: [<ffffffff814fe193>] dump_stack+0x4f/0x7c [<ffffffff8103b80a>] warn_slowpath_common+0x81/0x9b [<ffffffff810b2b9a>] ? __ftrace_hash_rec_update.part.35+0x168/0x1b9 [<ffffffff8103b83e>] warn_slowpath_null+0x1a/0x1c [<ffffffff810b2b9a>] __ftrace_hash_rec_update.part.35+0x168/0x1b9 [<ffffffff81502f89>] ? __mutex_lock_slowpath+0x364/0x364 [<ffffffff810b2cc2>] ftrace_shutdown+0xd7/0x12b [<ffffffff810b47f0>] unregister_ftrace_graph+0x49/0x78 [<ffffffff810c4b30>] graph_trace_reset+0xe/0x10 [<ffffffff810bf393>] tracing_set_tracer+0xa7/0x26a [<ffffffff810bf5e1>] tracing_set_trace_write+0x8b/0xbd [<ffffffff810c501c>] ? ftrace_return_to_handler+0xb2/0xde [<ffffffff811240a8>] ? __sb_end_write+0x5e/0x5e [<ffffffff81122aed>] vfs_write+0xab/0xf6 [<ffffffff8150a185>] ftrace_graph_caller+0x85/0x85 [<ffffffff81122dbd>] SyS_write+0x59/0x82 [<ffffffff8150a185>] ftrace_graph_caller+0x85/0x85 [<ffffffff8150a2d2>] system_call_fastpath+0x16/0x1b ---[ end trace 940358030751eafb ]--- The above mentioned commit didn't go far enough. Well, it covered the function tracer by adding checks in __register_ftrace_function(). The problem is that the function graph tracer circumvents that (for a slight efficiency gain when function graph trace is running with a function tracer. The gain was not worth this). The problem came with ftrace_startup() which should always be called after __register_ftrace_function(), if you want this bug to be completely fixed. Anyway, this solution moves __register_ftrace_function() inside of ftrace_startup() and removes the need to call them both. Reported-by: Dave Wysochanski <dwysocha@redhat.com> Fixes: ed926f9 ("ftrace: Use counters to enable functions to trace") Cc: stable@vger.kernel.org # 3.0+ Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
1 parent 4e58e54 commit 8a56d77

File tree

1 file changed

+35
-29
lines changed

1 file changed

+35
-29
lines changed

kernel/trace/ftrace.c

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,6 @@ static int remove_ftrace_list_ops(struct ftrace_ops **list,
367367

368368
static int __register_ftrace_function(struct ftrace_ops *ops)
369369
{
370-
if (unlikely(ftrace_disabled))
371-
return -ENODEV;
372-
373370
if (FTRACE_WARN_ON(ops == &global_ops))
374371
return -EINVAL;
375372

@@ -428,9 +425,6 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
428425
{
429426
int ret;
430427

431-
if (ftrace_disabled)
432-
return -ENODEV;
433-
434428
if (WARN_ON(!(ops->flags & FTRACE_OPS_FL_ENABLED)))
435429
return -EBUSY;
436430

@@ -2088,10 +2082,15 @@ static void ftrace_startup_enable(int command)
20882082
static int ftrace_startup(struct ftrace_ops *ops, int command)
20892083
{
20902084
bool hash_enable = true;
2085+
int ret;
20912086

20922087
if (unlikely(ftrace_disabled))
20932088
return -ENODEV;
20942089

2090+
ret = __register_ftrace_function(ops);
2091+
if (ret)
2092+
return ret;
2093+
20952094
ftrace_start_up++;
20962095
command |= FTRACE_UPDATE_CALLS;
20972096

@@ -2113,12 +2112,17 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)
21132112
return 0;
21142113
}
21152114

2116-
static void ftrace_shutdown(struct ftrace_ops *ops, int command)
2115+
static int ftrace_shutdown(struct ftrace_ops *ops, int command)
21172116
{
21182117
bool hash_disable = true;
2118+
int ret;
21192119

21202120
if (unlikely(ftrace_disabled))
2121-
return;
2121+
return -ENODEV;
2122+
2123+
ret = __unregister_ftrace_function(ops);
2124+
if (ret)
2125+
return ret;
21222126

21232127
ftrace_start_up--;
21242128
/*
@@ -2153,9 +2157,10 @@ static void ftrace_shutdown(struct ftrace_ops *ops, int command)
21532157
}
21542158

21552159
if (!command || !ftrace_enabled)
2156-
return;
2160+
return 0;
21572161

21582162
ftrace_run_update_code(command);
2163+
return 0;
21592164
}
21602165

21612166
static void ftrace_startup_sysctl(void)
@@ -3060,16 +3065,13 @@ static void __enable_ftrace_function_probe(void)
30603065
if (i == FTRACE_FUNC_HASHSIZE)
30613066
return;
30623067

3063-
ret = __register_ftrace_function(&trace_probe_ops);
3064-
if (!ret)
3065-
ret = ftrace_startup(&trace_probe_ops, 0);
3068+
ret = ftrace_startup(&trace_probe_ops, 0);
30663069

30673070
ftrace_probe_registered = 1;
30683071
}
30693072

30703073
static void __disable_ftrace_function_probe(void)
30713074
{
3072-
int ret;
30733075
int i;
30743076

30753077
if (!ftrace_probe_registered)
@@ -3082,9 +3084,7 @@ static void __disable_ftrace_function_probe(void)
30823084
}
30833085

30843086
/* no more funcs left */
3085-
ret = __unregister_ftrace_function(&trace_probe_ops);
3086-
if (!ret)
3087-
ftrace_shutdown(&trace_probe_ops, 0);
3087+
ftrace_shutdown(&trace_probe_ops, 0);
30883088

30893089
ftrace_probe_registered = 0;
30903090
}
@@ -4366,12 +4366,15 @@ core_initcall(ftrace_nodyn_init);
43664366
static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; }
43674367
static inline void ftrace_startup_enable(int command) { }
43684368
/* Keep as macros so we do not need to define the commands */
4369-
# define ftrace_startup(ops, command) \
4370-
({ \
4371-
(ops)->flags |= FTRACE_OPS_FL_ENABLED; \
4372-
0; \
4369+
# define ftrace_startup(ops, command) \
4370+
({ \
4371+
int ___ret = __register_ftrace_function(ops); \
4372+
if (!___ret) \
4373+
(ops)->flags |= FTRACE_OPS_FL_ENABLED; \
4374+
___ret; \
43734375
})
4374-
# define ftrace_shutdown(ops, command) do { } while (0)
4376+
# define ftrace_shutdown(ops, command) __unregister_ftrace_function(ops)
4377+
43754378
# define ftrace_startup_sysctl() do { } while (0)
43764379
# define ftrace_shutdown_sysctl() do { } while (0)
43774380

@@ -4780,9 +4783,7 @@ int register_ftrace_function(struct ftrace_ops *ops)
47804783

47814784
mutex_lock(&ftrace_lock);
47824785

4783-
ret = __register_ftrace_function(ops);
4784-
if (!ret)
4785-
ret = ftrace_startup(ops, 0);
4786+
ret = ftrace_startup(ops, 0);
47864787

47874788
mutex_unlock(&ftrace_lock);
47884789

@@ -4801,9 +4802,7 @@ int unregister_ftrace_function(struct ftrace_ops *ops)
48014802
int ret;
48024803

48034804
mutex_lock(&ftrace_lock);
4804-
ret = __unregister_ftrace_function(ops);
4805-
if (!ret)
4806-
ftrace_shutdown(ops, 0);
4805+
ret = ftrace_shutdown(ops, 0);
48074806
mutex_unlock(&ftrace_lock);
48084807

48094808
return ret;
@@ -4997,6 +4996,13 @@ ftrace_suspend_notifier_call(struct notifier_block *bl, unsigned long state,
49974996
return NOTIFY_DONE;
49984997
}
49994998

4999+
/* Just a place holder for function graph */
5000+
static struct ftrace_ops fgraph_ops __read_mostly = {
5001+
.func = ftrace_stub,
5002+
.flags = FTRACE_OPS_FL_STUB | FTRACE_OPS_FL_GLOBAL |
5003+
FTRACE_OPS_FL_RECURSION_SAFE,
5004+
};
5005+
50005006
int register_ftrace_graph(trace_func_graph_ret_t retfunc,
50015007
trace_func_graph_ent_t entryfunc)
50025008
{
@@ -5023,7 +5029,7 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
50235029
ftrace_graph_return = retfunc;
50245030
ftrace_graph_entry = entryfunc;
50255031

5026-
ret = ftrace_startup(&global_ops, FTRACE_START_FUNC_RET);
5032+
ret = ftrace_startup(&fgraph_ops, FTRACE_START_FUNC_RET);
50275033

50285034
out:
50295035
mutex_unlock(&ftrace_lock);
@@ -5040,7 +5046,7 @@ void unregister_ftrace_graph(void)
50405046
ftrace_graph_active--;
50415047
ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;
50425048
ftrace_graph_entry = ftrace_graph_entry_stub;
5043-
ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET);
5049+
ftrace_shutdown(&fgraph_ops, FTRACE_STOP_FUNC_RET);
50445050
unregister_pm_notifier(&ftrace_suspend_notifier);
50455051
unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
50465052

0 commit comments

Comments
 (0)