Skip to content

Commit 57a7e6d

Browse files
committed
tracing/fprobe: Support raw tracepoints on future loaded modules
Support raw tracepoint events on future loaded (unloaded) modules. This allows user to create raw tracepoint events which can be used from module's __init functions. Note: since the kernel does not have any information about the tracepoints in the unloaded modules, fprobe events can not check whether the tracepoint exists nor extend the BTF based arguments. Link: https://lore.kernel.org/all/172397780593.286558.18360375226968537828.stgit@devnote2/ Suggested-by: Mathieu Desnoyers <[email protected]> Signed-off-by: Masami Hiramatsu (Google) <[email protected]>
1 parent 67e9a9e commit 57a7e6d

File tree

2 files changed

+101
-51
lines changed

2 files changed

+101
-51
lines changed

kernel/trace/trace_fprobe.c

Lines changed: 101 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#define FPROBE_EVENT_SYSTEM "fprobes"
2222
#define TRACEPOINT_EVENT_SYSTEM "tracepoints"
2323
#define RETHOOK_MAXACTIVE_MAX 4096
24+
#define TRACEPOINT_STUB ERR_PTR(-ENOENT)
2425

2526
static int trace_fprobe_create(const char *raw_command);
2627
static int trace_fprobe_show(struct seq_file *m, struct dyn_event *ev);
@@ -674,6 +675,24 @@ static int unregister_fprobe_event(struct trace_fprobe *tf)
674675
return trace_probe_unregister_event_call(&tf->tp);
675676
}
676677

678+
static int __regsiter_tracepoint_fprobe(struct trace_fprobe *tf)
679+
{
680+
struct tracepoint *tpoint = tf->tpoint;
681+
unsigned long ip = (unsigned long)tpoint->probestub;
682+
int ret;
683+
684+
/*
685+
* Here, we do 2 steps to enable fprobe on a tracepoint.
686+
* At first, put __probestub_##TP function on the tracepoint
687+
* and put a fprobe on the stub function.
688+
*/
689+
ret = tracepoint_probe_register_prio_may_exist(tpoint,
690+
tpoint->probestub, NULL, 0);
691+
if (ret < 0)
692+
return ret;
693+
return register_fprobe_ips(&tf->fp, &ip, 1);
694+
}
695+
677696
/* Internal register function - just handle fprobe and flags */
678697
static int __register_trace_fprobe(struct trace_fprobe *tf)
679698
{
@@ -700,18 +719,12 @@ static int __register_trace_fprobe(struct trace_fprobe *tf)
700719
tf->fp.flags |= FPROBE_FL_DISABLED;
701720

702721
if (trace_fprobe_is_tracepoint(tf)) {
703-
struct tracepoint *tpoint = tf->tpoint;
704-
unsigned long ip = (unsigned long)tpoint->probestub;
705-
/*
706-
* Here, we do 2 steps to enable fprobe on a tracepoint.
707-
* At first, put __probestub_##TP function on the tracepoint
708-
* and put a fprobe on the stub function.
709-
*/
710-
ret = tracepoint_probe_register_prio_may_exist(tpoint,
711-
tpoint->probestub, NULL, 0);
712-
if (ret < 0)
713-
return ret;
714-
return register_fprobe_ips(&tf->fp, &ip, 1);
722+
723+
/* This tracepoint is not loaded yet */
724+
if (tf->tpoint == TRACEPOINT_STUB)
725+
return 0;
726+
727+
return __regsiter_tracepoint_fprobe(tf);
715728
}
716729

717730
/* TODO: handle filter, nofilter or symbol list */
@@ -864,36 +877,6 @@ static int register_trace_fprobe(struct trace_fprobe *tf)
864877
return ret;
865878
}
866879

867-
#ifdef CONFIG_MODULES
868-
static int __tracepoint_probe_module_cb(struct notifier_block *self,
869-
unsigned long val, void *data)
870-
{
871-
struct tp_module *tp_mod = data;
872-
struct trace_fprobe *tf;
873-
struct dyn_event *pos;
874-
875-
if (val != MODULE_STATE_GOING)
876-
return NOTIFY_DONE;
877-
878-
mutex_lock(&event_mutex);
879-
for_each_trace_fprobe(tf, pos) {
880-
if (tp_mod->mod == tf->mod) {
881-
tracepoint_probe_unregister(tf->tpoint,
882-
tf->tpoint->probestub, NULL);
883-
tf->tpoint = NULL;
884-
tf->mod = NULL;
885-
}
886-
}
887-
mutex_unlock(&event_mutex);
888-
889-
return NOTIFY_DONE;
890-
}
891-
892-
static struct notifier_block tracepoint_module_nb = {
893-
.notifier_call = __tracepoint_probe_module_cb,
894-
};
895-
#endif /* CONFIG_MODULES */
896-
897880
struct __find_tracepoint_cb_data {
898881
const char *tp_name;
899882
struct tracepoint *tpoint;
@@ -906,10 +889,12 @@ static void __find_tracepoint_module_cb(struct tracepoint *tp, struct module *mo
906889

907890
if (!data->tpoint && !strcmp(data->tp_name, tp->name)) {
908891
data->tpoint = tp;
909-
data->mod = mod;
910-
if (!try_module_get(data->mod)) {
911-
data->tpoint = NULL;
912-
data->mod = NULL;
892+
if (!data->mod) {
893+
data->mod = mod;
894+
if (!try_module_get(data->mod)) {
895+
data->tpoint = NULL;
896+
data->mod = NULL;
897+
}
913898
}
914899
}
915900
}
@@ -947,6 +932,67 @@ static struct tracepoint *find_tracepoint(const char *tp_name,
947932
return data.tpoint;
948933
}
949934

935+
#ifdef CONFIG_MODULES
936+
static void reenable_trace_fprobe(struct trace_fprobe *tf)
937+
{
938+
struct trace_probe *tp = &tf->tp;
939+
940+
list_for_each_entry(tf, trace_probe_probe_list(tp), tp.list) {
941+
__enable_trace_fprobe(tf);
942+
}
943+
}
944+
945+
static struct tracepoint *find_tracepoint_in_module(struct module *mod,
946+
const char *tp_name)
947+
{
948+
struct __find_tracepoint_cb_data data = {
949+
.tp_name = tp_name,
950+
.mod = mod,
951+
};
952+
953+
for_each_tracepoint_in_module(mod, __find_tracepoint_module_cb, &data);
954+
return data.tpoint;
955+
}
956+
957+
static int __tracepoint_probe_module_cb(struct notifier_block *self,
958+
unsigned long val, void *data)
959+
{
960+
struct tp_module *tp_mod = data;
961+
struct tracepoint *tpoint;
962+
struct trace_fprobe *tf;
963+
struct dyn_event *pos;
964+
965+
if (val != MODULE_STATE_GOING && val != MODULE_STATE_COMING)
966+
return NOTIFY_DONE;
967+
968+
mutex_lock(&event_mutex);
969+
for_each_trace_fprobe(tf, pos) {
970+
if (val == MODULE_STATE_COMING && tf->tpoint == TRACEPOINT_STUB) {
971+
tpoint = find_tracepoint_in_module(tp_mod->mod, tf->symbol);
972+
if (tpoint) {
973+
tf->tpoint = tpoint;
974+
tf->mod = tp_mod->mod;
975+
if (!WARN_ON_ONCE(__regsiter_tracepoint_fprobe(tf)) &&
976+
trace_probe_is_enabled(&tf->tp))
977+
reenable_trace_fprobe(tf);
978+
}
979+
} else if (val == MODULE_STATE_GOING && tp_mod->mod == tf->mod) {
980+
tracepoint_probe_unregister(tf->tpoint,
981+
tf->tpoint->probestub, NULL);
982+
tf->tpoint = NULL;
983+
tf->mod = NULL;
984+
}
985+
}
986+
mutex_unlock(&event_mutex);
987+
988+
return NOTIFY_DONE;
989+
}
990+
991+
static struct notifier_block tracepoint_module_nb = {
992+
.notifier_call = __tracepoint_probe_module_cb,
993+
};
994+
#endif /* CONFIG_MODULES */
995+
950996
static int parse_symbol_and_return(int argc, const char *argv[],
951997
char **symbol, bool *is_return,
952998
bool is_tracepoint)
@@ -1113,14 +1159,19 @@ static int __trace_fprobe_create(int argc, const char *argv[])
11131159
if (is_tracepoint) {
11141160
ctx.flags |= TPARG_FL_TPOINT;
11151161
tpoint = find_tracepoint(symbol, &tp_mod);
1116-
if (!tpoint) {
1162+
if (tpoint) {
1163+
ctx.funcname = kallsyms_lookup(
1164+
(unsigned long)tpoint->probestub,
1165+
NULL, NULL, NULL, sbuf);
1166+
} else if (IS_ENABLED(CONFIG_MODULES)) {
1167+
/* This *may* be loaded afterwards */
1168+
tpoint = TRACEPOINT_STUB;
1169+
ctx.funcname = symbol;
1170+
} else {
11171171
trace_probe_log_set_index(1);
11181172
trace_probe_log_err(0, NO_TRACEPOINT);
11191173
goto parse_error;
11201174
}
1121-
ctx.funcname = kallsyms_lookup(
1122-
(unsigned long)tpoint->probestub,
1123-
NULL, NULL, NULL, sbuf);
11241175
} else
11251176
ctx.funcname = symbol;
11261177

tools/testing/selftests/ftrace/test.d/dynevent/tprobe_syntax_errors.tc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ check_error() { # command-with-error-pos-by-^
99

1010
check_error 't^100 kfree' # BAD_MAXACT_TYPE
1111

12-
check_error 't ^non_exist_tracepoint' # NO_TRACEPOINT
1312
check_error 't:^/bar kfree' # NO_GROUP_NAME
1413
check_error 't:^12345678901234567890123456789012345678901234567890123456789012345/bar kfree' # GROUP_TOO_LONG
1514

0 commit comments

Comments
 (0)