Skip to content

Commit 1d18538

Browse files
committed
tracing: Have dynamic events have a ref counter
As dynamic events are not created by modules, if something is attached to one, calling "try_module_get()" on its "mod" field, is not going to keep the dynamic event from going away. Since dynamic events do not need the "mod" pointer of the event structure, make a union out of it in order to save memory (there's one structure for each of the thousand+ events in the kernel), and have any event with the DYNAMIC flag set to use a ref counter instead. Link: https://lore.kernel.org/linux-trace-devel/[email protected]/ Link: https://lkml.kernel.org/r/[email protected] Suggested-by: Masami Hiramatsu <[email protected]> Acked-by: Masami Hiramatsu <[email protected]> Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent 8b0e6c7 commit 1d18538

File tree

9 files changed

+124
-24
lines changed

9 files changed

+124
-24
lines changed

include/linux/trace_events.h

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,14 @@ struct trace_event_call {
350350
struct trace_event event;
351351
char *print_fmt;
352352
struct event_filter *filter;
353-
void *mod;
353+
/*
354+
* Static events can disappear with modules,
355+
* where as dynamic ones need their own ref count.
356+
*/
357+
union {
358+
void *module;
359+
atomic_t refcnt;
360+
};
354361
void *data;
355362

356363
/* See the TRACE_EVENT_FL_* flags above */
@@ -366,6 +373,42 @@ struct trace_event_call {
366373
#endif
367374
};
368375

376+
#ifdef CONFIG_DYNAMIC_EVENTS
377+
bool trace_event_dyn_try_get_ref(struct trace_event_call *call);
378+
void trace_event_dyn_put_ref(struct trace_event_call *call);
379+
bool trace_event_dyn_busy(struct trace_event_call *call);
380+
#else
381+
static inline bool trace_event_dyn_try_get_ref(struct trace_event_call *call)
382+
{
383+
/* Without DYNAMIC_EVENTS configured, nothing should be calling this */
384+
return false;
385+
}
386+
static inline void trace_event_dyn_put_ref(struct trace_event_call *call)
387+
{
388+
}
389+
static inline bool trace_event_dyn_busy(struct trace_event_call *call)
390+
{
391+
/* Nothing should call this without DYNAIMIC_EVENTS configured. */
392+
return true;
393+
}
394+
#endif
395+
396+
static inline bool trace_event_try_get_ref(struct trace_event_call *call)
397+
{
398+
if (call->flags & TRACE_EVENT_FL_DYNAMIC)
399+
return trace_event_dyn_try_get_ref(call);
400+
else
401+
return try_module_get(call->module);
402+
}
403+
404+
static inline void trace_event_put_ref(struct trace_event_call *call)
405+
{
406+
if (call->flags & TRACE_EVENT_FL_DYNAMIC)
407+
trace_event_dyn_put_ref(call);
408+
else
409+
module_put(call->module);
410+
}
411+
369412
#ifdef CONFIG_PERF_EVENTS
370413
static inline bool bpf_prog_array_valid(struct trace_event_call *call)
371414
{

kernel/trace/trace.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3697,11 +3697,11 @@ static bool trace_safe_str(struct trace_iterator *iter, const char *str)
36973697
return false;
36983698

36993699
event = container_of(trace_event, struct trace_event_call, event);
3700-
if (!event->mod)
3700+
if ((event->flags & TRACE_EVENT_FL_DYNAMIC) || !event->module)
37013701
return false;
37023702

37033703
/* Would rather have rodata, but this will suffice */
3704-
if (within_module_core(addr, event->mod))
3704+
if (within_module_core(addr, event->module))
37053705
return true;
37063706

37073707
return false;

kernel/trace/trace_dynevent.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,49 @@
1313
#include <linux/tracefs.h>
1414

1515
#include "trace.h"
16+
#include "trace_output.h" /* for trace_event_sem */
1617
#include "trace_dynevent.h"
1718

1819
static DEFINE_MUTEX(dyn_event_ops_mutex);
1920
static LIST_HEAD(dyn_event_ops_list);
2021

22+
bool trace_event_dyn_try_get_ref(struct trace_event_call *dyn_call)
23+
{
24+
struct trace_event_call *call;
25+
bool ret = false;
26+
27+
if (WARN_ON_ONCE(!(dyn_call->flags & TRACE_EVENT_FL_DYNAMIC)))
28+
return false;
29+
30+
down_read(&trace_event_sem);
31+
list_for_each_entry(call, &ftrace_events, list) {
32+
if (call == dyn_call) {
33+
atomic_inc(&dyn_call->refcnt);
34+
ret = true;
35+
}
36+
}
37+
up_read(&trace_event_sem);
38+
return ret;
39+
}
40+
41+
void trace_event_dyn_put_ref(struct trace_event_call *call)
42+
{
43+
if (WARN_ON_ONCE(!(call->flags & TRACE_EVENT_FL_DYNAMIC)))
44+
return;
45+
46+
if (WARN_ON_ONCE(atomic_read(&call->refcnt) <= 0)) {
47+
atomic_set(&call->refcnt, 0);
48+
return;
49+
}
50+
51+
atomic_dec(&call->refcnt);
52+
}
53+
54+
bool trace_event_dyn_busy(struct trace_event_call *call)
55+
{
56+
return atomic_read(&call->refcnt) != 0;
57+
}
58+
2159
int dyn_event_register(struct dyn_event_operations *ops)
2260
{
2361
if (!ops || !ops->create || !ops->show || !ops->is_busy ||

kernel/trace/trace_event_perf.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ static void perf_trace_event_unreg(struct perf_event *p_event)
177177
}
178178
}
179179
out:
180-
module_put(tp_event->mod);
180+
trace_event_put_ref(tp_event);
181181
}
182182

183183
static int perf_trace_event_open(struct perf_event *p_event)
@@ -224,10 +224,10 @@ int perf_trace_init(struct perf_event *p_event)
224224
list_for_each_entry(tp_event, &ftrace_events, list) {
225225
if (tp_event->event.type == event_id &&
226226
tp_event->class && tp_event->class->reg &&
227-
try_module_get(tp_event->mod)) {
227+
trace_event_try_get_ref(tp_event)) {
228228
ret = perf_trace_event_init(tp_event, p_event);
229229
if (ret)
230-
module_put(tp_event->mod);
230+
trace_event_put_ref(tp_event);
231231
break;
232232
}
233233
}

kernel/trace/trace_events.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2525,7 +2525,10 @@ __register_event(struct trace_event_call *call, struct module *mod)
25252525
return ret;
25262526

25272527
list_add(&call->list, &ftrace_events);
2528-
call->mod = mod;
2528+
if (call->flags & TRACE_EVENT_FL_DYNAMIC)
2529+
atomic_set(&call->refcnt, 0);
2530+
else
2531+
call->module = mod;
25292532

25302533
return 0;
25312534
}
@@ -2839,7 +2842,9 @@ static void trace_module_remove_events(struct module *mod)
28392842

28402843
down_write(&trace_event_sem);
28412844
list_for_each_entry_safe(call, p, &ftrace_events, list) {
2842-
if (call->mod == mod)
2845+
if ((call->flags & TRACE_EVENT_FL_DYNAMIC) || !call->module)
2846+
continue;
2847+
if (call->module == mod)
28432848
__trace_remove_event_call(call);
28442849
}
28452850
up_write(&trace_event_sem);
@@ -2982,7 +2987,7 @@ struct trace_event_file *trace_get_event_file(const char *instance,
29822987
}
29832988

29842989
/* Don't let event modules unload while in use */
2985-
ret = try_module_get(file->event_call->mod);
2990+
ret = trace_event_try_get_ref(file->event_call);
29862991
if (!ret) {
29872992
trace_array_put(tr);
29882993
ret = -EBUSY;
@@ -3012,7 +3017,7 @@ EXPORT_SYMBOL_GPL(trace_get_event_file);
30123017
void trace_put_event_file(struct trace_event_file *file)
30133018
{
30143019
mutex_lock(&event_mutex);
3015-
module_put(file->event_call->mod);
3020+
trace_event_put_ref(file->event_call);
30163021
mutex_unlock(&event_mutex);
30173022

30183023
trace_array_put(file->tr);
@@ -3147,7 +3152,7 @@ static int free_probe_data(void *data)
31473152
if (!edata->ref) {
31483153
/* Remove the SOFT_MODE flag */
31493154
__ftrace_event_enable_disable(edata->file, 0, 1);
3150-
module_put(edata->file->event_call->mod);
3155+
trace_event_put_ref(edata->file->event_call);
31513156
kfree(edata);
31523157
}
31533158
return 0;
@@ -3280,7 +3285,7 @@ event_enable_func(struct trace_array *tr, struct ftrace_hash *hash,
32803285

32813286
out_reg:
32823287
/* Don't let event modules unload while probe registered */
3283-
ret = try_module_get(file->event_call->mod);
3288+
ret = trace_event_try_get_ref(file->event_call);
32843289
if (!ret) {
32853290
ret = -EBUSY;
32863291
goto out_free;
@@ -3310,7 +3315,7 @@ event_enable_func(struct trace_array *tr, struct ftrace_hash *hash,
33103315
out_disable:
33113316
__ftrace_event_enable_disable(file, 0, 1);
33123317
out_put:
3313-
module_put(file->event_call->mod);
3318+
trace_event_put_ref(file->event_call);
33143319
out_free:
33153320
kfree(data);
33163321
goto out;
@@ -3376,7 +3381,8 @@ void __trace_early_add_events(struct trace_array *tr)
33763381

33773382
list_for_each_entry(call, &ftrace_events, list) {
33783383
/* Early boot up should not have any modules loaded */
3379-
if (WARN_ON_ONCE(call->mod))
3384+
if (!(call->flags & TRACE_EVENT_FL_DYNAMIC) &&
3385+
WARN_ON_ONCE(call->module))
33803386
continue;
33813387

33823388
ret = __trace_early_add_new_event(call, tr);

kernel/trace/trace_events_synth.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,13 +1369,15 @@ static int destroy_synth_event(struct synth_event *se)
13691369
int ret;
13701370

13711371
if (se->ref)
1372-
ret = -EBUSY;
1373-
else {
1374-
ret = unregister_synth_event(se);
1375-
if (!ret) {
1376-
dyn_event_remove(&se->devent);
1377-
free_synth_event(se);
1378-
}
1372+
return -EBUSY;
1373+
1374+
if (trace_event_dyn_busy(&se->call))
1375+
return -EBUSY;
1376+
1377+
ret = unregister_synth_event(se);
1378+
if (!ret) {
1379+
dyn_event_remove(&se->devent);
1380+
free_synth_event(se);
13791381
}
13801382

13811383
return ret;
@@ -2102,6 +2104,9 @@ static int synth_event_release(struct dyn_event *ev)
21022104
if (event->ref)
21032105
return -EBUSY;
21042106

2107+
if (trace_event_dyn_busy(&event->call))
2108+
return -EBUSY;
2109+
21052110
ret = unregister_synth_event(event);
21062111
if (ret)
21072112
return ret;

kernel/trace/trace_events_trigger.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ void event_enable_trigger_free(struct event_trigger_ops *ops,
13341334
if (!data->ref) {
13351335
/* Remove the SOFT_MODE flag */
13361336
trace_event_enable_disable(enable_data->file, 0, 1);
1337-
module_put(enable_data->file->event_call->mod);
1337+
trace_event_put_ref(enable_data->file->event_call);
13381338
trigger_data_free(data);
13391339
kfree(enable_data);
13401340
}
@@ -1481,7 +1481,7 @@ int event_enable_trigger_func(struct event_command *cmd_ops,
14811481

14821482
out_reg:
14831483
/* Don't let event modules unload while probe registered */
1484-
ret = try_module_get(event_enable_file->event_call->mod);
1484+
ret = trace_event_try_get_ref(event_enable_file->event_call);
14851485
if (!ret) {
14861486
ret = -EBUSY;
14871487
goto out_free;
@@ -1510,7 +1510,7 @@ int event_enable_trigger_func(struct event_command *cmd_ops,
15101510
out_disable:
15111511
trace_event_enable_disable(event_enable_file, 0, 1);
15121512
out_put:
1513-
module_put(event_enable_file->event_call->mod);
1513+
trace_event_put_ref(event_enable_file->event_call);
15141514
out_free:
15151515
if (cmd_ops->set_filter)
15161516
cmd_ops->set_filter(NULL, trigger_data, NULL);

kernel/trace/trace_kprobe.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,10 @@ static int unregister_trace_kprobe(struct trace_kprobe *tk)
543543
if (trace_probe_is_enabled(&tk->tp))
544544
return -EBUSY;
545545

546+
/* If there's a reference to the dynamic event */
547+
if (trace_event_dyn_busy(trace_probe_event_call(&tk->tp)))
548+
return -EBUSY;
549+
546550
/* Will fail if probe is being used by ftrace or perf */
547551
if (unregister_kprobe_event(tk))
548552
return -EBUSY;

kernel/trace/trace_uprobe.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,10 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu)
393393
if (trace_probe_has_sibling(&tu->tp))
394394
goto unreg;
395395

396+
/* If there's a reference to the dynamic event */
397+
if (trace_event_dyn_busy(trace_probe_event_call(&tu->tp)))
398+
return -EBUSY;
399+
396400
ret = unregister_uprobe_event(tu);
397401
if (ret)
398402
return ret;

0 commit comments

Comments
 (0)