While rewriting the function probe code, I stumbled over a long standing
bug. This bug has been there sinc function tracing was added way back when. But my new development depends on this bug being fixed, and it should be fixed regardless as it causes ftrace to disable itself when triggered, and a reboot is required to enable it again. The bug is that the function probe does not disable itself properly if there's another probe of its type still enabled. For example: # cd /sys/kernel/debug/tracing # echo schedule:traceoff > set_ftrace_filter # echo do_IRQ:traceoff > set_ftrace_filter # echo \!do_IRQ:traceoff > /debug/tracing/set_ftrace_filter # echo do_IRQ:traceoff > set_ftrace_filter The above registers two traceoff probes (one for schedule and one for do_IRQ, and then removes do_IRQ. But since there still exists one for schedule, it is not done properly. When adding do_IRQ back, the breakage in the accounting is noticed by the ftrace self tests, and it causes a warning and disables ftrace. -----BEGIN PGP SIGNATURE----- iQExBAABCAAbBQJY8ovvFBxyb3N0ZWR0QGdvb2RtaXMub3JnAAoJEMm5BfJq2Y3L nkAH/jfsXUWIbZ6J0A7+nmGiBdIVwLwG0ZOJClcxjnCSpsNs+FO/0w6ragtIYCi2 Km+0s/slA5GOddG4Miga/dhtxGhDosyXnxqC+4GmD0maqJGLweJLbmiQ1xhra0hr XGDI+SXHM/n22zVkFEbkGXgxMvOHeR+X/sREZo3XmoXRLbc1QVtTEe/8TdlLXwE5 5Fs07xSQqx4TS7oBxIjipHnbHL/gIktEo0HiEmq73++r42MztIMYZPoV+cXuim37 C6xO4PxfPN0aRh9W5gdiMnbv6lummVBNQXwpMya0vTbxz/9WeUex8c+lcInQUJgA FhQWKaCGyi0UK4Pa2Pz/Dmxuti0= =LYLo -----END PGP SIGNATURE----- Merge tag 'trace-v4.11-rc5-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace Pull ftrace fix from Steven Rostedt: "While rewriting the function probe code, I stumbled over a long standing bug. This bug has been there sinc function tracing was added way back when. But my new development depends on this bug being fixed, and it should be fixed regardless as it causes ftrace to disable itself when triggered, and a reboot is required to enable it again. The bug is that the function probe does not disable itself properly if there's another probe of its type still enabled. For example: # cd /sys/kernel/debug/tracing # echo schedule:traceoff > set_ftrace_filter # echo do_IRQ:traceoff > set_ftrace_filter # echo \!do_IRQ:traceoff > /debug/tracing/set_ftrace_filter # echo do_IRQ:traceoff > set_ftrace_filter The above registers two traceoff probes (one for schedule and one for do_IRQ, and then removes do_IRQ. But since there still exists one for schedule, it is not done properly. When adding do_IRQ back, the breakage in the accounting is noticed by the ftrace self tests, and it causes a warning and disables ftrace" * tag 'trace-v4.11-rc5-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: ftrace: Fix removing of second function probe
This commit is contained in:
commit
48538861b9
@ -3755,23 +3755,24 @@ static void __enable_ftrace_function_probe(struct ftrace_ops_hash *old_hash)
|
||||
ftrace_probe_registered = 1;
|
||||
}
|
||||
|
||||
static void __disable_ftrace_function_probe(void)
|
||||
static bool __disable_ftrace_function_probe(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ftrace_probe_registered)
|
||||
return;
|
||||
return false;
|
||||
|
||||
for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
|
||||
struct hlist_head *hhd = &ftrace_func_hash[i];
|
||||
if (hhd->first)
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* no more funcs left */
|
||||
ftrace_shutdown(&trace_probe_ops, 0);
|
||||
|
||||
ftrace_probe_registered = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -3901,6 +3902,7 @@ static void
|
||||
__unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
|
||||
void *data, int flags)
|
||||
{
|
||||
struct ftrace_ops_hash old_hash_ops;
|
||||
struct ftrace_func_entry *rec_entry;
|
||||
struct ftrace_func_probe *entry;
|
||||
struct ftrace_func_probe *p;
|
||||
@ -3912,6 +3914,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
|
||||
struct hlist_node *tmp;
|
||||
char str[KSYM_SYMBOL_LEN];
|
||||
int i, ret;
|
||||
bool disabled;
|
||||
|
||||
if (glob && (strcmp(glob, "*") == 0 || !strlen(glob)))
|
||||
func_g.search = NULL;
|
||||
@ -3930,6 +3933,10 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
|
||||
|
||||
mutex_lock(&trace_probe_ops.func_hash->regex_lock);
|
||||
|
||||
old_hash_ops.filter_hash = old_hash;
|
||||
/* Probes only have filters */
|
||||
old_hash_ops.notrace_hash = NULL;
|
||||
|
||||
hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
|
||||
if (!hash)
|
||||
/* Hmm, should report this somehow */
|
||||
@ -3967,12 +3974,17 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
|
||||
}
|
||||
}
|
||||
mutex_lock(&ftrace_lock);
|
||||
__disable_ftrace_function_probe();
|
||||
disabled = __disable_ftrace_function_probe();
|
||||
/*
|
||||
* Remove after the disable is called. Otherwise, if the last
|
||||
* probe is removed, a null hash means *all enabled*.
|
||||
*/
|
||||
ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
|
||||
|
||||
/* still need to update the function call sites */
|
||||
if (ftrace_enabled && !disabled)
|
||||
ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS,
|
||||
&old_hash_ops);
|
||||
synchronize_sched();
|
||||
if (!ret)
|
||||
free_ftrace_hash_rcu(old_hash);
|
||||
|
Loading…
x
Reference in New Issue
Block a user