On Thu, 6 Aug 2026 10:07:01 +0900 "Masami Hiramatsu (Google)" <[email protected]> wrote:
> From: Masami Hiramatsu (Google) <[email protected]> > > Boot-time tracing currently supports kprobe-events and synthetic-events > under per-event configuration options. > > Extend boot-time tracing to support newly added dynamic probe types: > - event probes (eprobe) under the "eprobes" event group > - function probes (fprobe) under the "fprobes" event group > - tracepoint probes (tprobe) under the "tracepoints" or "tprobes" > event group > > To support this cleanly, update dyn_event_create() in trace_dynevent.c > so that passing NULL as the type parameter delegates to > create_dyn_event(), allowing generic creation of any registered > dynamic event type from a raw command string. > > Update Documentation/trace/boottime-trace.rst accordingly to describe > the new per-event bootconfig options. > > Assisted-by: Antigravity:gemini-3.6-flash > Signed-off-by: Masami Hiramatsu (Google) <[email protected]> > --- > Documentation/trace/boottime-trace.rst | 18 ++++- > kernel/trace/trace_boot.c | 113 > ++++++++++++++++++++++++++++++++ > kernel/trace/trace_dynevent.c | 5 + > 3 files changed, 133 insertions(+), 3 deletions(-) > > diff --git a/Documentation/trace/boottime-trace.rst > b/Documentation/trace/boottime-trace.rst > index 651f3a2c01de..2c3c1fedb92c 100644 > --- a/Documentation/trace/boottime-trace.rst > +++ b/Documentation/trace/boottime-trace.rst > @@ -121,9 +121,21 @@ ftrace.[instance.INSTANCE.]event.synthetic.EVENT.fields > = FIELD[, FIELD2[...]] > Defines new synthetic event with FIELDs. Each field should be > "type varname". > > -Note that kprobe and synthetic event definitions can be written under > -instance node, but those are also visible from other instances. So please > -take care for event name conflict. > +ftrace.[instance.INSTANCE.]event.eprobes.EVENT.probes = PROBE[, PROBE2[...]] > + Defines new event probe based on PROBEs. This option is available only > + for the event which group name is "eprobes". > + > +ftrace.[instance.INSTANCE.]event.fprobes.EVENT.probes = PROBE[, PROBE2[...]] > + Defines new fprobe event based on PROBEs. This option is available only > + for the event which group name is "fprobes". > + > +ftrace.[instance.INSTANCE.]event.tracepoints.EVENT.probes = PROBE[, > PROBE2[...]] > + Defines new tracepoint probe based on PROBEs. This option is available > only > + for the event which group name is "tracepoints" or "tprobes". > + > +Note that dynamic event definitions can be written under instance node, but > +those are also visible from other instances. So please take care for event > +name conflict. > > Ftrace Histogram Options > ------------------------ > diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c > index 2ca2541c8a58..6ecf1a035caa 100644 > --- a/kernel/trace/trace_boot.c > +++ b/kernel/trace/trace_boot.c > @@ -18,6 +18,7 @@ > #include <linux/trace_events.h> > > #include "trace.h" > +#include "trace_dynevent.h" > > #define MAX_BUF_LEN 256 > > @@ -172,6 +173,109 @@ trace_boot_add_synth_event(struct xbc_node *node, const > char *event) > } > #endif > > +#ifdef CONFIG_EPROBE_EVENTS > +static int __init > +trace_boot_add_eprobe_event(struct xbc_node *node, const char *group, > + const char *event) > +{ > + struct xbc_node *anode; > + char buf[MAX_BUF_LEN]; > + const char *val; > + int ret = 0; > + > + xbc_node_for_each_array_value(node, "probes", anode, val) { > + if (val[0] == 'e' && (val[1] == ':' || isdigit(val[1]))) Oops, I missed it, this isdigit is only required kretprobes... Let me fix it. Thank you, > + strscpy(buf, val, MAX_BUF_LEN); > + else > + snprintf(buf, MAX_BUF_LEN, "e:%s/%s %s", group, event, > val); > + > + ret = dyn_event_create(buf, NULL); > + if (ret) { > + pr_err("Failed to add eprobe: %s\n", buf); > + break; > + } > + } > + > + return ret; > +} > +#else > +static inline int __init > +trace_boot_add_eprobe_event(struct xbc_node *node, const char *group, > + const char *event) > +{ > + pr_err("Event probe is not supported.\n"); > + return -EOPNOTSUPP; > +} > +#endif > + > +#ifdef CONFIG_FPROBE_EVENTS > +static int __init > +trace_boot_add_fprobe_event(struct xbc_node *node, const char *group, > + const char *event) > +{ > + struct xbc_node *anode; > + char buf[MAX_BUF_LEN]; > + const char *val; > + int ret = 0; > + > + xbc_node_for_each_array_value(node, "probes", anode, val) { > + if (val[0] == 'f' && (val[1] == ':' || isdigit(val[1]))) > + strscpy(buf, val, MAX_BUF_LEN); > + else > + snprintf(buf, MAX_BUF_LEN, "f:%s/%s %s", group, event, > val); > + > + ret = dyn_event_create(buf, NULL); > + if (ret) { > + pr_err("Failed to add fprobe: %s\n", buf); > + break; > + } > + } > + > + return ret; > +} > + > +static int __init > +trace_boot_add_tprobe_event(struct xbc_node *node, const char *group, > + const char *event) > +{ > + struct xbc_node *anode; > + char buf[MAX_BUF_LEN]; > + const char *val; > + int ret = 0; > + > + xbc_node_for_each_array_value(node, "probes", anode, val) { > + if (val[0] == 't' && (val[1] == ':' || isdigit(val[1]))) > + strscpy(buf, val, MAX_BUF_LEN); > + else > + snprintf(buf, MAX_BUF_LEN, "t:%s/%s %s", group, event, > val); > + > + ret = dyn_event_create(buf, NULL); > + if (ret) { > + pr_err("Failed to add tprobe: %s\n", buf); > + break; > + } > + } > + > + return ret; > +} > +#else > +static inline int __init > +trace_boot_add_fprobe_event(struct xbc_node *node, const char *group, > + const char *event) > +{ > + pr_err("Fprobe event is not supported.\n"); > + return -EOPNOTSUPP; > +} > + > +static inline int __init > +trace_boot_add_tprobe_event(struct xbc_node *node, const char *group, > + const char *event) > +{ > + pr_err("Tracepoint probe is not supported.\n"); > + return -EOPNOTSUPP; > +} > +#endif > + > #ifdef CONFIG_HIST_TRIGGERS > static int __init __printf(3, 4) > append_printf(char **bufp, char *end, const char *fmt, ...) > @@ -477,6 +581,15 @@ trace_boot_init_one_event(struct trace_array *tr, struct > xbc_node *gnode, > if (!strcmp(group, "synthetic")) > if (trace_boot_add_synth_event(enode, event) < 0) > return; > + if (!strcmp(group, "eprobes")) > + if (trace_boot_add_eprobe_event(enode, group, event) < 0) > + return; > + if (!strcmp(group, "fprobes")) > + if (trace_boot_add_fprobe_event(enode, group, event) < 0) > + return; > + if (!strcmp(group, "tracepoints") || !strcmp(group, "tprobes")) > + if (trace_boot_add_tprobe_event(enode, group, event) < 0) > + return; > > mutex_lock(&event_mutex); > file = find_event_file(tr, group, event); > diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c > index c4dfbc293bae..6f2e39b797e5 100644 > --- a/kernel/trace/trace_dynevent.c > +++ b/kernel/trace/trace_dynevent.c > @@ -116,6 +116,8 @@ int dyn_event_release(const char *raw_command, struct > dyn_event_operations *type > return ret; > } > > +static int create_dyn_event(const char *raw_command); > + > /* > * Locked version of event creation. The event creation must be protected by > * dyn_event_ops_mutex because of protecting trace_probe_log. > @@ -124,6 +126,9 @@ int dyn_event_create(const char *raw_command, struct > dyn_event_operations *type) > { > int ret; > > + if (!type) > + return create_dyn_event(raw_command); > + > mutex_lock(&dyn_event_ops_mutex); > ret = type->create(raw_command); > mutex_unlock(&dyn_event_ops_mutex); > -- Masami Hiramatsu (Google) <[email protected]>
