aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (VMware) <rostedt@goodmis.org>2017-08-31 17:03:47 -0400
committerSteven Rostedt (VMware) <rostedt@goodmis.org>2017-08-31 17:47:38 -0400
commit065e63f951432068ba89a844fcbff68ea16ee186 (patch)
tree396e5e08c41f0adc32d74a4384890daa5d7c5730
parent60361e12d01676e23a8de89a5ef4a349ae97f616 (diff)
tracing: Only have rmmod clear buffers that its events were active in
Currently, when a module event is enabled, when that module is removed, it clears all ring buffers. This is to prevent another module from being loaded and having one of its trace event IDs from reusing a trace event ID of the removed module. This could cause undesirable effects as the trace event of the new module would be using its own processing algorithms to process raw data of another event. To prevent this, when a module is loaded, if any of its events have been used (signified by the WAS_ENABLED event call flag, which is never cleared), all ring buffers are cleared, just in case any one of them contains event data of the removed event. The problem is, there's no reason to clear all ring buffers if only one (or less than all of them) uses one of the events. Instead, only clear the ring buffers that recorded the events of a module that is being removed. To do this, instead of keeping the WAS_ENABLED flag with the trace event call, move it to the per instance (per ring buffer) event file descriptor. The event file descriptor maps each event to a separate ring buffer instance. Then when the module is removed, only the ring buffers that activated one of the module's events get cleared. The rest are not touched. Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-rw-r--r--include/linux/trace_events.h8
-rw-r--r--kernel/trace/trace.c3
-rw-r--r--kernel/trace/trace.h1
-rw-r--r--kernel/trace/trace_events.c15
4 files changed, 14 insertions, 13 deletions
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index 536c80ff7ad9..3702b9cb5dc8 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -217,7 +217,6 @@ enum {
217 TRACE_EVENT_FL_CAP_ANY_BIT, 217 TRACE_EVENT_FL_CAP_ANY_BIT,
218 TRACE_EVENT_FL_NO_SET_FILTER_BIT, 218 TRACE_EVENT_FL_NO_SET_FILTER_BIT,
219 TRACE_EVENT_FL_IGNORE_ENABLE_BIT, 219 TRACE_EVENT_FL_IGNORE_ENABLE_BIT,
220 TRACE_EVENT_FL_WAS_ENABLED_BIT,
221 TRACE_EVENT_FL_TRACEPOINT_BIT, 220 TRACE_EVENT_FL_TRACEPOINT_BIT,
222 TRACE_EVENT_FL_KPROBE_BIT, 221 TRACE_EVENT_FL_KPROBE_BIT,
223 TRACE_EVENT_FL_UPROBE_BIT, 222 TRACE_EVENT_FL_UPROBE_BIT,
@@ -229,9 +228,6 @@ enum {
229 * CAP_ANY - Any user can enable for perf 228 * CAP_ANY - Any user can enable for perf
230 * NO_SET_FILTER - Set when filter has error and is to be ignored 229 * NO_SET_FILTER - Set when filter has error and is to be ignored
231 * IGNORE_ENABLE - For trace internal events, do not enable with debugfs file 230 * IGNORE_ENABLE - For trace internal events, do not enable with debugfs file
232 * WAS_ENABLED - Set and stays set when an event was ever enabled
233 * (used for module unloading, if a module event is enabled,
234 * it is best to clear the buffers that used it).
235 * TRACEPOINT - Event is a tracepoint 231 * TRACEPOINT - Event is a tracepoint
236 * KPROBE - Event is a kprobe 232 * KPROBE - Event is a kprobe
237 * UPROBE - Event is a uprobe 233 * UPROBE - Event is a uprobe
@@ -241,7 +237,6 @@ enum {
241 TRACE_EVENT_FL_CAP_ANY = (1 << TRACE_EVENT_FL_CAP_ANY_BIT), 237 TRACE_EVENT_FL_CAP_ANY = (1 << TRACE_EVENT_FL_CAP_ANY_BIT),
242 TRACE_EVENT_FL_NO_SET_FILTER = (1 << TRACE_EVENT_FL_NO_SET_FILTER_BIT), 238 TRACE_EVENT_FL_NO_SET_FILTER = (1 << TRACE_EVENT_FL_NO_SET_FILTER_BIT),
243 TRACE_EVENT_FL_IGNORE_ENABLE = (1 << TRACE_EVENT_FL_IGNORE_ENABLE_BIT), 239 TRACE_EVENT_FL_IGNORE_ENABLE = (1 << TRACE_EVENT_FL_IGNORE_ENABLE_BIT),
244 TRACE_EVENT_FL_WAS_ENABLED = (1 << TRACE_EVENT_FL_WAS_ENABLED_BIT),
245 TRACE_EVENT_FL_TRACEPOINT = (1 << TRACE_EVENT_FL_TRACEPOINT_BIT), 240 TRACE_EVENT_FL_TRACEPOINT = (1 << TRACE_EVENT_FL_TRACEPOINT_BIT),
246 TRACE_EVENT_FL_KPROBE = (1 << TRACE_EVENT_FL_KPROBE_BIT), 241 TRACE_EVENT_FL_KPROBE = (1 << TRACE_EVENT_FL_KPROBE_BIT),
247 TRACE_EVENT_FL_UPROBE = (1 << TRACE_EVENT_FL_UPROBE_BIT), 242 TRACE_EVENT_FL_UPROBE = (1 << TRACE_EVENT_FL_UPROBE_BIT),
@@ -306,6 +301,7 @@ enum {
306 EVENT_FILE_FL_TRIGGER_MODE_BIT, 301 EVENT_FILE_FL_TRIGGER_MODE_BIT,
307 EVENT_FILE_FL_TRIGGER_COND_BIT, 302 EVENT_FILE_FL_TRIGGER_COND_BIT,
308 EVENT_FILE_FL_PID_FILTER_BIT, 303 EVENT_FILE_FL_PID_FILTER_BIT,
304 EVENT_FILE_FL_WAS_ENABLED_BIT,
309}; 305};
310 306
311/* 307/*
@@ -321,6 +317,7 @@ enum {
321 * TRIGGER_MODE - When set, invoke the triggers associated with the event 317 * TRIGGER_MODE - When set, invoke the triggers associated with the event
322 * TRIGGER_COND - When set, one or more triggers has an associated filter 318 * TRIGGER_COND - When set, one or more triggers has an associated filter
323 * PID_FILTER - When set, the event is filtered based on pid 319 * PID_FILTER - When set, the event is filtered based on pid
320 * WAS_ENABLED - Set when enabled to know to clear trace on module removal
324 */ 321 */
325enum { 322enum {
326 EVENT_FILE_FL_ENABLED = (1 << EVENT_FILE_FL_ENABLED_BIT), 323 EVENT_FILE_FL_ENABLED = (1 << EVENT_FILE_FL_ENABLED_BIT),
@@ -333,6 +330,7 @@ enum {
333 EVENT_FILE_FL_TRIGGER_MODE = (1 << EVENT_FILE_FL_TRIGGER_MODE_BIT), 330 EVENT_FILE_FL_TRIGGER_MODE = (1 << EVENT_FILE_FL_TRIGGER_MODE_BIT),
334 EVENT_FILE_FL_TRIGGER_COND = (1 << EVENT_FILE_FL_TRIGGER_COND_BIT), 331 EVENT_FILE_FL_TRIGGER_COND = (1 << EVENT_FILE_FL_TRIGGER_COND_BIT),
335 EVENT_FILE_FL_PID_FILTER = (1 << EVENT_FILE_FL_PID_FILTER_BIT), 332 EVENT_FILE_FL_PID_FILTER = (1 << EVENT_FILE_FL_PID_FILTER_BIT),
333 EVENT_FILE_FL_WAS_ENABLED = (1 << EVENT_FILE_FL_WAS_ENABLED_BIT),
336}; 334};
337 335
338struct trace_event_file { 336struct trace_event_file {
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 44004d8aa3b3..30338a835a51 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1702,6 +1702,9 @@ void tracing_reset_all_online_cpus(void)
1702 struct trace_array *tr; 1702 struct trace_array *tr;
1703 1703
1704 list_for_each_entry(tr, &ftrace_trace_arrays, list) { 1704 list_for_each_entry(tr, &ftrace_trace_arrays, list) {
1705 if (!tr->clear_trace)
1706 continue;
1707 tr->clear_trace = false;
1705 tracing_reset_online_cpus(&tr->trace_buffer); 1708 tracing_reset_online_cpus(&tr->trace_buffer);
1706#ifdef CONFIG_TRACER_MAX_TRACE 1709#ifdef CONFIG_TRACER_MAX_TRACE
1707 tracing_reset_online_cpus(&tr->max_buffer); 1710 tracing_reset_online_cpus(&tr->max_buffer);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 490ba229931d..fb5d54d0d1b3 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -245,6 +245,7 @@ struct trace_array {
245 int stop_count; 245 int stop_count;
246 int clock_id; 246 int clock_id;
247 int nr_topts; 247 int nr_topts;
248 bool clear_trace;
248 struct tracer *current_trace; 249 struct tracer *current_trace;
249 unsigned int trace_flags; 250 unsigned int trace_flags;
250 unsigned char trace_flags_index[TRACE_FLAGS_MAX_SIZE]; 251 unsigned char trace_flags_index[TRACE_FLAGS_MAX_SIZE];
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 36132f9280e6..c93540c5df21 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -466,7 +466,7 @@ static int __ftrace_event_enable_disable(struct trace_event_file *file,
466 set_bit(EVENT_FILE_FL_ENABLED_BIT, &file->flags); 466 set_bit(EVENT_FILE_FL_ENABLED_BIT, &file->flags);
467 467
468 /* WAS_ENABLED gets set but never cleared. */ 468 /* WAS_ENABLED gets set but never cleared. */
469 call->flags |= TRACE_EVENT_FL_WAS_ENABLED; 469 set_bit(EVENT_FILE_FL_WAS_ENABLED_BIT, &file->flags);
470 } 470 }
471 break; 471 break;
472 } 472 }
@@ -2058,6 +2058,10 @@ static void event_remove(struct trace_event_call *call)
2058 do_for_each_event_file(tr, file) { 2058 do_for_each_event_file(tr, file) {
2059 if (file->event_call != call) 2059 if (file->event_call != call)
2060 continue; 2060 continue;
2061
2062 if (file->flags & EVENT_FILE_FL_WAS_ENABLED)
2063 tr->clear_trace = true;
2064
2061 ftrace_event_enable_disable(file, 0); 2065 ftrace_event_enable_disable(file, 0);
2062 /* 2066 /*
2063 * The do_for_each_event_file() is 2067 * The do_for_each_event_file() is
@@ -2396,15 +2400,11 @@ static void trace_module_add_events(struct module *mod)
2396static void trace_module_remove_events(struct module *mod) 2400static void trace_module_remove_events(struct module *mod)
2397{ 2401{
2398 struct trace_event_call *call, *p; 2402 struct trace_event_call *call, *p;
2399 bool clear_trace = false;
2400 2403
2401 down_write(&trace_event_sem); 2404 down_write(&trace_event_sem);
2402 list_for_each_entry_safe(call, p, &ftrace_events, list) { 2405 list_for_each_entry_safe(call, p, &ftrace_events, list) {
2403 if (call->mod == mod) { 2406 if (call->mod == mod)
2404 if (call->flags & TRACE_EVENT_FL_WAS_ENABLED)
2405 clear_trace = true;
2406 __trace_remove_event_call(call); 2407 __trace_remove_event_call(call);
2407 }
2408 } 2408 }
2409 up_write(&trace_event_sem); 2409 up_write(&trace_event_sem);
2410 2410
@@ -2416,8 +2416,7 @@ static void trace_module_remove_events(struct module *mod)
2416 * over from this module may be passed to the new module events and 2416 * over from this module may be passed to the new module events and
2417 * unexpected results may occur. 2417 * unexpected results may occur.
2418 */ 2418 */
2419 if (clear_trace) 2419 tracing_reset_all_online_cpus();
2420 tracing_reset_all_online_cpus();
2421} 2420}
2422 2421
2423static int trace_module_notify(struct notifier_block *self, 2422static int trace_module_notify(struct notifier_block *self,