diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c index a11dc60299fb..3054921b0877 100644 --- a/kernel/trace/trace_boot.c +++ b/kernel/trace/trace_boot.c @@ -118,6 +118,50 @@ trace_boot_add_kprobe_event(struct xbc_node *node, const char *event) } #endif +#ifdef CONFIG_HIST_TRIGGERS +extern int synth_event_run_command(const char *command); + +static int __init +trace_boot_add_synth_event(struct xbc_node *node, const char *event) +{ + struct xbc_node *anode; + char buf[MAX_BUF_LEN], *q; + const char *p; + int len, delta, ret; + + len = ARRAY_SIZE(buf); + delta = snprintf(buf, len, "%s", event); + if (delta >= len) { + pr_err("Event name is too long: %s\n", event); + return -E2BIG; + } + len -= delta; q = buf + delta; + + xbc_node_for_each_array_value(node, "fields", anode, p) { + delta = snprintf(q, len, " %s;", p); + if (delta >= len) { + pr_err("fields string is too long: %s\n", p); + return -E2BIG; + } + len -= delta; q += delta; + } + + ret = synth_event_run_command(buf); + if (ret < 0) + pr_err("Failed to add synthetic event: %s\n", buf); + + + return ret; +} +#else +static inline int __init +trace_boot_add_synth_event(struct xbc_node *node, const char *event) +{ + pr_err("Synthetic event is not supported.\n"); + return -ENOTSUPP; +} +#endif + static void __init trace_boot_init_one_event(struct trace_array *tr, struct xbc_node *gnode, struct xbc_node *enode) @@ -133,6 +177,9 @@ trace_boot_init_one_event(struct trace_array *tr, struct xbc_node *gnode, if (!strcmp(group, "kprobes")) if (trace_boot_add_kprobe_event(enode, event) < 0) return; + if (!strcmp(group, "synthetic")) + if (trace_boot_add_synth_event(enode, event) < 0) + return; mutex_lock(&event_mutex); file = find_event_file(tr, group, event); diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 1cb4c4c8e5b7..8e90f1ada437 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -1384,6 +1384,11 @@ static int create_or_delete_synth_event(int argc, char **argv) return ret == -ECANCELED ? -EINVAL : ret; } +int synth_event_run_command(const char *command) +{ + return trace_run_command(command, create_or_delete_synth_event); +} + static int synth_event_create(int argc, const char **argv) { const char *name = argv[0];