Skip to content

Commit

Permalink
ftrace: Allow function_graph tracer to be enabled in instances
Browse files Browse the repository at this point in the history
Now that function graph tracing can handle more than one user, allow it to
be enabled in the ftrace instances. Note, the filtering of the functions is
still joined by the top level set_ftrace_filter and friends, as well as the
graph and nograph files.

Co-developed with Masami Hiramatsu:
Link: https://lore.kernel.org/linux-trace-kernel/171509099743.162236.1699959255446248163.stgit@devnote2
Link: https://lore.kernel.org/linux-trace-kernel/20240603190822.190630762@goodmis.org

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Cc: Florent Revest <revest@chromium.org>
Cc: Martin KaFai Lau <martin.lau@linux.dev>
Cc: bpf <bpf@vger.kernel.org>
Cc: Sven Schnelle <svens@linux.ibm.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Alan Maguire <alan.maguire@oracle.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Guo Ren <guoren@kernel.org>
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
  • Loading branch information
Steven Rostedt (VMware) committed Jun 4, 2024
1 parent 37238ab commit 26dda56
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 28 deletions.
1 change: 1 addition & 0 deletions include/linux/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,7 @@ extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace, struct fgraph
struct fgraph_ops {
trace_func_graph_ent_t entryfunc;
trace_func_graph_ret_t retfunc;
void *private;
int idx;
};

Expand Down
1 change: 1 addition & 0 deletions kernel/trace/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -7327,6 +7327,7 @@ __init void ftrace_init_global_array_ops(struct trace_array *tr)
tr->ops = &global_ops;
tr->ops->private = tr;
ftrace_init_trace_array(tr);
init_array_fgraph_ops(tr);
}

void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func)
Expand Down
13 changes: 12 additions & 1 deletion kernel/trace/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,9 @@ struct trace_array {
struct ftrace_ops *ops;
struct trace_pid_list __rcu *function_pids;
struct trace_pid_list __rcu *function_no_pids;
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
struct fgraph_ops *gops;
#endif
#ifdef CONFIG_DYNAMIC_FTRACE
/* All of these are protected by the ftrace_lock */
struct list_head func_probes;
Expand Down Expand Up @@ -681,7 +684,6 @@ void print_trace_header(struct seq_file *m, struct trace_iterator *iter);

void trace_graph_return(struct ftrace_graph_ret *trace, struct fgraph_ops *gops);
int trace_graph_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops);
void set_graph_array(struct trace_array *tr);

void tracing_start_cmdline_record(void);
void tracing_stop_cmdline_record(void);
Expand Down Expand Up @@ -892,6 +894,9 @@ extern int __trace_graph_entry(struct trace_array *tr,
extern void __trace_graph_return(struct trace_array *tr,
struct ftrace_graph_ret *trace,
unsigned int trace_ctx);
extern void init_array_fgraph_ops(struct trace_array *tr);
extern int allocate_fgraph_ops(struct trace_array *tr);
extern void free_fgraph_ops(struct trace_array *tr);

#ifdef CONFIG_DYNAMIC_FTRACE
extern struct ftrace_hash __rcu *ftrace_graph_hash;
Expand Down Expand Up @@ -1004,6 +1009,12 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags)
{
return TRACE_TYPE_UNHANDLED;
}
static inline void init_array_fgraph_ops(struct trace_array *tr) { }
static inline int allocate_fgraph_ops(struct trace_array *tr)
{
return 0;
}
static inline void free_fgraph_ops(struct trace_array *tr) { }
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */

extern struct list_head ftrace_pids;
Expand Down
8 changes: 8 additions & 0 deletions kernel/trace/trace_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ void ftrace_free_ftrace_ops(struct trace_array *tr)
int ftrace_create_function_files(struct trace_array *tr,
struct dentry *parent)
{
int ret;
/*
* The top level array uses the "global_ops", and the files are
* created on boot up.
Expand All @@ -90,6 +91,12 @@ int ftrace_create_function_files(struct trace_array *tr,
if (!tr->ops)
return -EINVAL;

ret = allocate_fgraph_ops(tr);
if (ret) {
kfree(tr->ops);
return ret;
}

ftrace_create_filter_files(tr->ops, parent);

return 0;
Expand All @@ -99,6 +106,7 @@ void ftrace_destroy_function_files(struct trace_array *tr)
{
ftrace_destroy_filter_files(tr->ops);
ftrace_free_ftrace_ops(tr);
free_fgraph_ops(tr);
}

static ftrace_func_t select_trace_function(u32 flags_val)
Expand Down
65 changes: 40 additions & 25 deletions kernel/trace/trace_functions_graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ static struct tracer_flags tracer_flags = {
.opts = trace_opts
};

static struct trace_array *graph_array;

/*
* DURATION column is being also used to display IRQ signs,
* following values are used by print_graph_irq and others
Expand Down Expand Up @@ -132,7 +130,7 @@ static inline int ftrace_graph_ignore_irqs(void)
int trace_graph_entry(struct ftrace_graph_ent *trace,
struct fgraph_ops *gops)
{
struct trace_array *tr = graph_array;
struct trace_array *tr = gops->private;
struct trace_array_cpu *data;
unsigned long flags;
unsigned int trace_ctx;
Expand Down Expand Up @@ -242,7 +240,7 @@ void __trace_graph_return(struct trace_array *tr,
void trace_graph_return(struct ftrace_graph_ret *trace,
struct fgraph_ops *gops)
{
struct trace_array *tr = graph_array;
struct trace_array *tr = gops->private;
struct trace_array_cpu *data;
unsigned long flags;
unsigned int trace_ctx;
Expand All @@ -268,15 +266,6 @@ void trace_graph_return(struct ftrace_graph_ret *trace,
local_irq_restore(flags);
}

void set_graph_array(struct trace_array *tr)
{
graph_array = tr;

/* Make graph_array visible before we start tracing */

smp_mb();
}

static void trace_graph_thresh_return(struct ftrace_graph_ret *trace,
struct fgraph_ops *gops)
{
Expand All @@ -294,25 +283,53 @@ static void trace_graph_thresh_return(struct ftrace_graph_ret *trace,
trace_graph_return(trace, gops);
}

static struct fgraph_ops funcgraph_thresh_ops = {
.entryfunc = &trace_graph_entry,
.retfunc = &trace_graph_thresh_return,
};

static struct fgraph_ops funcgraph_ops = {
.entryfunc = &trace_graph_entry,
.retfunc = &trace_graph_return,
};

int allocate_fgraph_ops(struct trace_array *tr)
{
struct fgraph_ops *gops;

gops = kzalloc(sizeof(*gops), GFP_KERNEL);
if (!gops)
return -ENOMEM;

gops->entryfunc = &trace_graph_entry;
gops->retfunc = &trace_graph_return;

tr->gops = gops;
gops->private = tr;
return 0;
}

void free_fgraph_ops(struct trace_array *tr)
{
kfree(tr->gops);
}

__init void init_array_fgraph_ops(struct trace_array *tr)
{
tr->gops = &funcgraph_ops;
funcgraph_ops.private = tr;
}

static int graph_trace_init(struct trace_array *tr)
{
int ret;

set_graph_array(tr);
tr->gops->entryfunc = trace_graph_entry;

if (tracing_thresh)
ret = register_ftrace_graph(&funcgraph_thresh_ops);
tr->gops->retfunc = trace_graph_thresh_return;
else
ret = register_ftrace_graph(&funcgraph_ops);
tr->gops->retfunc = trace_graph_return;

/* Make gops functions are visible before we start tracing */
smp_mb();

ret = register_ftrace_graph(tr->gops);
if (ret)
return ret;
tracing_start_cmdline_record();
Expand All @@ -323,10 +340,7 @@ static int graph_trace_init(struct trace_array *tr)
static void graph_trace_reset(struct trace_array *tr)
{
tracing_stop_cmdline_record();
if (tracing_thresh)
unregister_ftrace_graph(&funcgraph_thresh_ops);
else
unregister_ftrace_graph(&funcgraph_ops);
unregister_ftrace_graph(tr->gops);
}

static int graph_trace_update_thresh(struct trace_array *tr)
Expand Down Expand Up @@ -1365,6 +1379,7 @@ static struct tracer graph_trace __tracer_data = {
.print_header = print_graph_headers,
.flags = &tracer_flags,
.set_flag = func_graph_set_flag,
.allow_instances = true,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_function_graph,
#endif
Expand Down
4 changes: 2 additions & 2 deletions kernel/trace/trace_selftest.c
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,7 @@ trace_selftest_startup_function_graph(struct tracer *trace,
* to detect and recover from possible hangs
*/
tracing_reset_online_cpus(&tr->array_buffer);
set_graph_array(tr);
fgraph_ops.private = tr;
ret = register_ftrace_graph(&fgraph_ops);
if (ret) {
warn_failed_init_tracer(trace, ret);
Expand Down Expand Up @@ -856,7 +856,7 @@ trace_selftest_startup_function_graph(struct tracer *trace,
cond_resched();

tracing_reset_online_cpus(&tr->array_buffer);
set_graph_array(tr);
fgraph_ops.private = tr;

/*
* Some archs *cough*PowerPC*cough* add characters to the
Expand Down

0 comments on commit 26dda56

Please sign in to comment.