Commit ddb8ea9e authored by Steven Rostedt's avatar Steven Rostedt Committed by Steven Rostedt (Google)

tracing: Allow trace_printk() to go to other instance buffers

Currently, trace_printk() just goes to the top level ring buffer. But
there may be times that it should go to one of the instances created by
the kernel command line.

Add a new trace_instance flag: traceprintk (also can use "printk" or
"trace_printk" as people tend to forget the actual flag name).

  trace_instance=foo^traceprintk

Will assign the trace_printk to this buffer at boot up.

Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Vincent Donnefort <vdonnefort@google.com>
Cc: Joel Fernandes <joel@joelfernandes.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vineeth Pillai <vineeth@bitbyteword.org>
Cc: Beau Belgrave <beaub@linux.microsoft.com>
Cc: Alexander Graf <graf@amazon.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: "Paul E. McKenney" <paulmck@kernel.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Guenter Roeck <linux@roeck-us.net>
Cc: Ross Zwisler <zwisler@google.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Alexander Aring <aahringo@redhat.com>
Cc: "Luis Claudio R. Goncalves" <lgoncalv@redhat.com>
Cc: Tomas Glozar <tglozar@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: "Jonathan Corbet" <corbet@lwn.net>
Link: https://lore.kernel.org/20240823014019.226694946@goodmis.orgSigned-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent b6fc31b6
...@@ -6744,11 +6744,17 @@ ...@@ -6744,11 +6744,17 @@
event, and all events under the "initcall" system. event, and all events under the "initcall" system.
Flags can be added to the instance to modify its behavior when it is Flags can be added to the instance to modify its behavior when it is
created. The flags are separated by '^'. Currently there's only one flag created. The flags are separated by '^'.
defined, and that's "traceoff", to have the tracing instance tracing
disabled after it is created.
trace_instance=foo^traceoff,sched,irq The available flags are:
traceoff - Have the tracing instance tracing disabled after it is created.
traceprintk - Have trace_printk() write into this trace instance
(note, "printk" and "trace_printk" can also be used)
Currently, traceprintk flag cannot be used for memory
mapped ring buffers as described below.
trace_instance=foo^traceoff^traceprintk,sched,irq
The flags must come before the defined events. The flags must come before the defined events.
......
...@@ -500,6 +500,8 @@ static struct trace_array global_trace = { ...@@ -500,6 +500,8 @@ static struct trace_array global_trace = {
.trace_flags = TRACE_DEFAULT_FLAGS, .trace_flags = TRACE_DEFAULT_FLAGS,
}; };
static struct trace_array *printk_trace = &global_trace;
void trace_set_ring_buffer_expanded(struct trace_array *tr) void trace_set_ring_buffer_expanded(struct trace_array *tr)
{ {
if (!tr) if (!tr)
...@@ -1117,7 +1119,7 @@ EXPORT_SYMBOL_GPL(__trace_array_puts); ...@@ -1117,7 +1119,7 @@ EXPORT_SYMBOL_GPL(__trace_array_puts);
*/ */
int __trace_puts(unsigned long ip, const char *str, int size) int __trace_puts(unsigned long ip, const char *str, int size)
{ {
return __trace_array_puts(&global_trace, ip, str, size); return __trace_array_puts(printk_trace, ip, str, size);
} }
EXPORT_SYMBOL_GPL(__trace_puts); EXPORT_SYMBOL_GPL(__trace_puts);
...@@ -1128,6 +1130,7 @@ EXPORT_SYMBOL_GPL(__trace_puts); ...@@ -1128,6 +1130,7 @@ EXPORT_SYMBOL_GPL(__trace_puts);
*/ */
int __trace_bputs(unsigned long ip, const char *str) int __trace_bputs(unsigned long ip, const char *str)
{ {
struct trace_array *tr = printk_trace;
struct ring_buffer_event *event; struct ring_buffer_event *event;
struct trace_buffer *buffer; struct trace_buffer *buffer;
struct bputs_entry *entry; struct bputs_entry *entry;
...@@ -1135,14 +1138,14 @@ int __trace_bputs(unsigned long ip, const char *str) ...@@ -1135,14 +1138,14 @@ int __trace_bputs(unsigned long ip, const char *str)
int size = sizeof(struct bputs_entry); int size = sizeof(struct bputs_entry);
int ret = 0; int ret = 0;
if (!(global_trace.trace_flags & TRACE_ITER_PRINTK)) if (!(tr->trace_flags & TRACE_ITER_PRINTK))
return 0; return 0;
if (unlikely(tracing_selftest_running || tracing_disabled)) if (unlikely(tracing_selftest_running || tracing_disabled))
return 0; return 0;
trace_ctx = tracing_gen_ctx(); trace_ctx = tracing_gen_ctx();
buffer = global_trace.array_buffer.buffer; buffer = tr->array_buffer.buffer;
ring_buffer_nest_start(buffer); ring_buffer_nest_start(buffer);
event = __trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size, event = __trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size,
...@@ -1155,7 +1158,7 @@ int __trace_bputs(unsigned long ip, const char *str) ...@@ -1155,7 +1158,7 @@ int __trace_bputs(unsigned long ip, const char *str)
entry->str = str; entry->str = str;
__buffer_unlock_commit(buffer, event); __buffer_unlock_commit(buffer, event);
ftrace_trace_stack(&global_trace, buffer, trace_ctx, 4, NULL); ftrace_trace_stack(tr, buffer, trace_ctx, 4, NULL);
ret = 1; ret = 1;
out: out:
...@@ -3025,7 +3028,7 @@ void trace_dump_stack(int skip) ...@@ -3025,7 +3028,7 @@ void trace_dump_stack(int skip)
/* Skip 1 to skip this function. */ /* Skip 1 to skip this function. */
skip++; skip++;
#endif #endif
__ftrace_trace_stack(global_trace.array_buffer.buffer, __ftrace_trace_stack(printk_trace->array_buffer.buffer,
tracing_gen_ctx(), skip, NULL); tracing_gen_ctx(), skip, NULL);
} }
EXPORT_SYMBOL_GPL(trace_dump_stack); EXPORT_SYMBOL_GPL(trace_dump_stack);
...@@ -3244,7 +3247,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) ...@@ -3244,7 +3247,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
struct trace_event_call *call = &event_bprint; struct trace_event_call *call = &event_bprint;
struct ring_buffer_event *event; struct ring_buffer_event *event;
struct trace_buffer *buffer; struct trace_buffer *buffer;
struct trace_array *tr = &global_trace; struct trace_array *tr = printk_trace;
struct bprint_entry *entry; struct bprint_entry *entry;
unsigned int trace_ctx; unsigned int trace_ctx;
char *tbuffer; char *tbuffer;
...@@ -3342,7 +3345,7 @@ __trace_array_vprintk(struct trace_buffer *buffer, ...@@ -3342,7 +3345,7 @@ __trace_array_vprintk(struct trace_buffer *buffer,
memcpy(&entry->buf, tbuffer, len + 1); memcpy(&entry->buf, tbuffer, len + 1);
if (!call_filter_check_discard(call, entry, buffer, event)) { if (!call_filter_check_discard(call, entry, buffer, event)) {
__buffer_unlock_commit(buffer, event); __buffer_unlock_commit(buffer, event);
ftrace_trace_stack(&global_trace, buffer, trace_ctx, 6, NULL); ftrace_trace_stack(printk_trace, buffer, trace_ctx, 6, NULL);
} }
out: out:
...@@ -3438,7 +3441,7 @@ int trace_array_printk_buf(struct trace_buffer *buffer, ...@@ -3438,7 +3441,7 @@ int trace_array_printk_buf(struct trace_buffer *buffer,
int ret; int ret;
va_list ap; va_list ap;
if (!(global_trace.trace_flags & TRACE_ITER_PRINTK)) if (!(printk_trace->trace_flags & TRACE_ITER_PRINTK))
return 0; return 0;
va_start(ap, fmt); va_start(ap, fmt);
...@@ -3450,7 +3453,7 @@ int trace_array_printk_buf(struct trace_buffer *buffer, ...@@ -3450,7 +3453,7 @@ int trace_array_printk_buf(struct trace_buffer *buffer,
__printf(2, 0) __printf(2, 0)
int trace_vprintk(unsigned long ip, const char *fmt, va_list args) int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
{ {
return trace_array_vprintk(&global_trace, ip, fmt, args); return trace_array_vprintk(printk_trace, ip, fmt, args);
} }
EXPORT_SYMBOL_GPL(trace_vprintk); EXPORT_SYMBOL_GPL(trace_vprintk);
...@@ -9666,6 +9669,9 @@ static int __remove_instance(struct trace_array *tr) ...@@ -9666,6 +9669,9 @@ static int __remove_instance(struct trace_array *tr)
set_tracer_flag(tr, 1 << i, 0); set_tracer_flag(tr, 1 << i, 0);
} }
if (printk_trace == tr)
printk_trace = &global_trace;
tracing_set_nop(tr); tracing_set_nop(tr);
clear_ftrace_function_probes(tr); clear_ftrace_function_probes(tr);
event_trace_del_tracer(tr); event_trace_del_tracer(tr);
...@@ -10468,6 +10474,7 @@ __init static void enable_instances(void) ...@@ -10468,6 +10474,7 @@ __init static void enable_instances(void)
phys_addr_t start = 0; phys_addr_t start = 0;
phys_addr_t size = 0; phys_addr_t size = 0;
unsigned long addr = 0; unsigned long addr = 0;
bool traceprintk = false;
bool traceoff = false; bool traceoff = false;
char *flag_delim; char *flag_delim;
char *addr_delim; char *addr_delim;
...@@ -10489,13 +10496,18 @@ __init static void enable_instances(void) ...@@ -10489,13 +10496,18 @@ __init static void enable_instances(void)
char *flag; char *flag;
while ((flag = strsep(&flag_delim, "^"))) { while ((flag = strsep(&flag_delim, "^"))) {
if (strcmp(flag, "traceoff") == 0) if (strcmp(flag, "traceoff") == 0) {
traceoff = true; traceoff = true;
else } else if ((strcmp(flag, "printk") == 0) ||
(strcmp(flag, "traceprintk") == 0) ||
(strcmp(flag, "trace_printk") == 0)) {
traceprintk = true;
} else {
pr_info("Tracing: Invalid instance flag '%s' for %s\n", pr_info("Tracing: Invalid instance flag '%s' for %s\n",
flag, name); flag, name);
} }
} }
}
tok = addr_delim; tok = addr_delim;
if (tok && isdigit(*tok)) { if (tok && isdigit(*tok)) {
...@@ -10548,6 +10560,18 @@ __init static void enable_instances(void) ...@@ -10548,6 +10560,18 @@ __init static void enable_instances(void)
if (traceoff) if (traceoff)
tracer_tracing_off(tr); tracer_tracing_off(tr);
if (traceprintk) {
/*
* The binary format of traceprintk can cause a crash if used
* by a buffer from another boot. Do not allow it for the
* memory mapped ring buffers.
*/
if (start)
pr_warn("Tracing: WARNING: memory mapped ring buffers cannot be used for trace_printk\n");
else
printk_trace = tr;
}
/* Only allow non mapped buffers to be deleted */ /* Only allow non mapped buffers to be deleted */
if (!start) if (!start)
trace_array_put(tr); trace_array_put(tr);
......
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