tracing: Allow boot instances to have snapshot buffers

Add to ftrace_boot_snapshot, "=<instance>" name, where the instance will
get a snapshot buffer, and will take a snapshot at the end of boot (which
will save the boot traces).

Link: https://lkml.kernel.org/r/20230207173026.792774721@goodmis.org

Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: default avatarRoss Zwisler <zwisler@google.com>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent d503b8f7
...@@ -1532,6 +1532,15 @@ ...@@ -1532,6 +1532,15 @@
boot up that is likely to be overridden by user space boot up that is likely to be overridden by user space
start up functionality. start up functionality.
Optionally, the snapshot can also be defined for a tracing
instance that was created by the trace_instance= command
line parameter.
trace_instance=foo,sched_switch ftrace_boot_snapshot=foo
The above will cause the "foo" tracing instance to trigger
a snapshot at the end of boot up.
ftrace_dump_on_oops[=orig_cpu] ftrace_dump_on_oops[=orig_cpu]
[FTRACE] will dump the trace buffers on oops. [FTRACE] will dump the trace buffers on oops.
If no parameter is passed, ftrace will dump If no parameter is passed, ftrace will dump
......
...@@ -191,6 +191,9 @@ static bool snapshot_at_boot; ...@@ -191,6 +191,9 @@ static bool snapshot_at_boot;
static char boot_instance_info[COMMAND_LINE_SIZE] __initdata; static char boot_instance_info[COMMAND_LINE_SIZE] __initdata;
static int boot_instance_index; static int boot_instance_index;
static char boot_snapshot_info[COMMAND_LINE_SIZE] __initdata;
static int boot_snapshot_index;
static int __init set_cmdline_ftrace(char *str) static int __init set_cmdline_ftrace(char *str)
{ {
strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE);
...@@ -227,9 +230,22 @@ __setup("traceoff_on_warning", stop_trace_on_warning); ...@@ -227,9 +230,22 @@ __setup("traceoff_on_warning", stop_trace_on_warning);
static int __init boot_alloc_snapshot(char *str) static int __init boot_alloc_snapshot(char *str)
{ {
allocate_snapshot = true; char *slot = boot_snapshot_info + boot_snapshot_index;
/* We also need the main ring buffer expanded */ int left = sizeof(boot_snapshot_info) - boot_snapshot_index;
ring_buffer_expanded = true; int ret;
if (str[0] == '=') {
str++;
if (strlen(str) >= left)
return -1;
ret = snprintf(slot, left, "%s\t", str);
boot_snapshot_index += ret;
} else {
allocate_snapshot = true;
/* We also need the main ring buffer expanded */
ring_buffer_expanded = true;
}
return 1; return 1;
} }
__setup("alloc_snapshot", boot_alloc_snapshot); __setup("alloc_snapshot", boot_alloc_snapshot);
...@@ -9254,10 +9270,6 @@ static int allocate_trace_buffers(struct trace_array *tr, int size) ...@@ -9254,10 +9270,6 @@ static int allocate_trace_buffers(struct trace_array *tr, int size)
} }
tr->allocated_snapshot = allocate_snapshot; tr->allocated_snapshot = allocate_snapshot;
/*
* Only the top level trace array gets its snapshot allocated
* from the kernel command line.
*/
allocate_snapshot = false; allocate_snapshot = false;
#endif #endif
...@@ -10173,6 +10185,47 @@ ssize_t trace_parse_run_command(struct file *file, const char __user *buffer, ...@@ -10173,6 +10185,47 @@ ssize_t trace_parse_run_command(struct file *file, const char __user *buffer,
return ret; return ret;
} }
#ifdef CONFIG_TRACER_MAX_TRACE
__init static bool tr_needs_alloc_snapshot(const char *name)
{
char *test;
int len = strlen(name);
bool ret;
if (!boot_snapshot_index)
return false;
if (strncmp(name, boot_snapshot_info, len) == 0 &&
boot_snapshot_info[len] == '\t')
return true;
test = kmalloc(strlen(name) + 3, GFP_KERNEL);
if (!test)
return false;
sprintf(test, "\t%s\t", name);
ret = strstr(boot_snapshot_info, test) == NULL;
kfree(test);
return ret;
}
__init static void do_allocate_snapshot(const char *name)
{
if (!tr_needs_alloc_snapshot(name))
return;
/*
* When allocate_snapshot is set, the next call to
* allocate_trace_buffers() (called by trace_array_get_by_name())
* will allocate the snapshot buffer. That will alse clear
* this flag.
*/
allocate_snapshot = true;
}
#else
static inline void do_allocate_snapshot(const char *name) { }
#endif
__init static void enable_instances(void) __init static void enable_instances(void)
{ {
struct trace_array *tr; struct trace_array *tr;
...@@ -10188,6 +10241,9 @@ __init static void enable_instances(void) ...@@ -10188,6 +10241,9 @@ __init static void enable_instances(void)
tok = strsep(&curr_str, ","); tok = strsep(&curr_str, ",");
if (IS_ENABLED(CONFIG_TRACER_MAX_TRACE))
do_allocate_snapshot(tok);
tr = trace_array_get_by_name(tok); tr = trace_array_get_by_name(tok);
if (!tr) { if (!tr) {
pr_warn("Failed to create instance buffer %s\n", curr_str); pr_warn("Failed to create instance buffer %s\n", curr_str);
...@@ -10335,10 +10391,19 @@ __init static int tracer_alloc_buffers(void) ...@@ -10335,10 +10391,19 @@ __init static int tracer_alloc_buffers(void)
void __init ftrace_boot_snapshot(void) void __init ftrace_boot_snapshot(void)
{ {
struct trace_array *tr;
if (snapshot_at_boot) { if (snapshot_at_boot) {
tracing_snapshot(); tracing_snapshot();
internal_trace_puts("** Boot snapshot taken **\n"); internal_trace_puts("** Boot snapshot taken **\n");
} }
list_for_each_entry(tr, &ftrace_trace_arrays, list) {
if (tr == &global_trace)
continue;
trace_array_puts(tr, "** Boot snapshot taken **\n");
tracing_snapshot_instance(tr);
}
} }
void __init early_trace_init(void) void __init early_trace_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment