Skip to content

Commit 8169887

Browse files
oleg-nesterovgregkh
authored andcommitted
tracing: trace_remove_event_call() should fail if call/file is in use
commit 2816c55 upstream. Change trace_remove_event_call(call) to return the error if this call is active. This is what the callers assume but can't verify outside of the tracing locks. Both trace_kprobe.c/trace_uprobe.c need the additional changes, unregister_trace_probe() should abort if trace_remove_event_call() fails. The caller is going to free this call/file so we must ensure that nobody can use them after trace_remove_event_call() succeeds. debugfs should be fine after the previous changes and event_remove() does TRACE_REG_UNREGISTER, but still there are 2 reasons why we need the additional checks: - There could be a perf_event(s) attached to this tp_event, so the patch checks ->perf_refcount. - TRACE_REG_UNREGISTER can be suppressed by FTRACE_EVENT_FL_SOFT_MODE, so we simply check FTRACE_EVENT_FL_ENABLED protected by event_mutex. Link: http://lkml.kernel.org/r/[email protected] Reviewed-by: Masami Hiramatsu <[email protected]> Signed-off-by: Oleg Nesterov <[email protected]> Signed-off-by: Steven Rostedt <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 012dc15 commit 8169887

File tree

2 files changed

+34
-3
lines changed

2 files changed

+34
-3
lines changed

include/linux/ftrace_event.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ extern int trace_define_field(struct ftrace_event_call *call, const char *type,
334334
const char *name, int offset, int size,
335335
int is_signed, int filter_type);
336336
extern int trace_add_event_call(struct ftrace_event_call *call);
337-
extern void trace_remove_event_call(struct ftrace_event_call *call);
337+
extern int trace_remove_event_call(struct ftrace_event_call *call);
338338

339339
#define is_signed_type(type) (((type)(-1)) < (type)1)
340340

kernel/trace/trace_events.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1735,16 +1735,47 @@ static void __trace_remove_event_call(struct ftrace_event_call *call)
17351735
destroy_preds(call);
17361736
}
17371737

1738+
static int probe_remove_event_call(struct ftrace_event_call *call)
1739+
{
1740+
struct trace_array *tr;
1741+
struct ftrace_event_file *file;
1742+
1743+
#ifdef CONFIG_PERF_EVENTS
1744+
if (call->perf_refcount)
1745+
return -EBUSY;
1746+
#endif
1747+
do_for_each_event_file(tr, file) {
1748+
if (file->event_call != call)
1749+
continue;
1750+
/*
1751+
* We can't rely on ftrace_event_enable_disable(enable => 0)
1752+
* we are going to do, FTRACE_EVENT_FL_SOFT_MODE can suppress
1753+
* TRACE_REG_UNREGISTER.
1754+
*/
1755+
if (file->flags & FTRACE_EVENT_FL_ENABLED)
1756+
return -EBUSY;
1757+
break;
1758+
} while_for_each_event_file();
1759+
1760+
__trace_remove_event_call(call);
1761+
1762+
return 0;
1763+
}
1764+
17381765
/* Remove an event_call */
1739-
void trace_remove_event_call(struct ftrace_event_call *call)
1766+
int trace_remove_event_call(struct ftrace_event_call *call)
17401767
{
1768+
int ret;
1769+
17411770
mutex_lock(&trace_types_lock);
17421771
mutex_lock(&event_mutex);
17431772
down_write(&trace_event_sem);
1744-
__trace_remove_event_call(call);
1773+
ret = probe_remove_event_call(call);
17451774
up_write(&trace_event_sem);
17461775
mutex_unlock(&event_mutex);
17471776
mutex_unlock(&trace_types_lock);
1777+
1778+
return ret;
17481779
}
17491780

17501781
#define for_each_event(event, start, end) \

0 commit comments

Comments
 (0)