Commit 950032ff authored by Steven Rostedt (Google)'s avatar Steven Rostedt (Google)
Browse files

ring-buffer: Add output of ring buffer meta page

Add a buffer_meta per-cpu file for the trace instance that is mapped to
boot memory. This shows the current meta-data and can be used by user
space tools to record off the current mappings to help reconstruct the
ring buffer after a reboot.

It does not expose any virtual addresses, just indexes into the sub-buffer
pages.

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



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: Daniel Bristot de Oliveira <bristot@redhat.com>
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: Youssef Esmat <youssefesmat@google.com>
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>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent 2124de79
Loading
Loading
Loading
Loading
+77 −0
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@
#include <asm/local64.h>
#include <asm/local.h>

#include "trace.h"

/*
 * The "absolute" timestamp in the buffer is only 59 bits.
 * If a clock has the 5 MSBs set, it needs to be saved and
@@ -1647,6 +1649,81 @@ static void rb_range_meta_init(struct trace_buffer *buffer, int nr_pages)
	}
}

static void *rbm_start(struct seq_file *m, loff_t *pos)
{
	struct ring_buffer_per_cpu *cpu_buffer = m->private;
	struct ring_buffer_meta *meta = cpu_buffer->ring_meta;
	unsigned long val;

	if (!meta)
		return NULL;

	if (*pos > meta->nr_subbufs)
		return NULL;

	val = *pos;
	val++;

	return (void *)val;
}

static void *rbm_next(struct seq_file *m, void *v, loff_t *pos)
{
	(*pos)++;

	return rbm_start(m, pos);
}

static int rb_meta_subbuf_idx(struct ring_buffer_meta *meta, void *subbuf);

static int rbm_show(struct seq_file *m, void *v)
{
	struct ring_buffer_per_cpu *cpu_buffer = m->private;
	struct ring_buffer_meta *meta = cpu_buffer->ring_meta;
	unsigned long val = (unsigned long)v;

	if (val == 1) {
		seq_printf(m, "head_buffer:   %d\n",
			   rb_meta_subbuf_idx(meta, (void *)meta->head_buffer));
		seq_printf(m, "commit_buffer: %d\n",
			   rb_meta_subbuf_idx(meta, (void *)meta->commit_buffer));
		seq_printf(m, "subbuf_size:   %d\n", meta->subbuf_size);
		seq_printf(m, "nr_subbufs:    %d\n", meta->nr_subbufs);
		return 0;
	}

	val -= 2;
	seq_printf(m, "buffer[%ld]:    %d\n", val, meta->buffers[val]);

	return 0;
}

static void rbm_stop(struct seq_file *m, void *p)
{
}

static const struct seq_operations rb_meta_seq_ops = {
	.start		= rbm_start,
	.next		= rbm_next,
	.show		= rbm_show,
	.stop		= rbm_stop,
};

int ring_buffer_meta_seq_init(struct file *file, struct trace_buffer *buffer, int cpu)
{
	struct seq_file *m;
	int ret;

	ret = seq_open(file, &rb_meta_seq_ops);
	if (ret)
		return ret;

	m = file->private_data;
	m->private = buffer->buffers[cpu];

	return 0;
}

static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
		long nr_pages, struct list_head *pages)
{
+28 −2
Original line number Diff line number Diff line
@@ -5018,7 +5018,7 @@ static int show_traces_open(struct inode *inode, struct file *file)
	return 0;
}

static int show_traces_release(struct inode *inode, struct file *file)
static int tracing_seq_release(struct inode *inode, struct file *file)
{
	struct trace_array *tr = inode->i_private;

@@ -5059,7 +5059,7 @@ static const struct file_operations show_traces_fops = {
	.open		= show_traces_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= show_traces_release,
	.release	= tracing_seq_release,
};

static ssize_t
@@ -6860,6 +6860,22 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}

static int tracing_buffer_meta_open(struct inode *inode, struct file *filp)
{
	struct trace_array *tr = inode->i_private;
	int cpu = tracing_get_cpu(inode);
	int ret;

	ret = tracing_check_open_get_tr(tr);
	if (ret)
		return ret;

	ret = ring_buffer_meta_seq_init(filp, tr->array_buffer.buffer, cpu);
	if (ret < 0)
		__trace_array_put(tr);
	return ret;
}

static ssize_t
tracing_free_buffer_write(struct file *filp, const char __user *ubuf,
			  size_t cnt, loff_t *ppos)
@@ -7436,6 +7452,13 @@ static const struct file_operations tracing_entries_fops = {
	.release	= tracing_release_generic_tr,
};

static const struct file_operations tracing_buffer_meta_fops = {
	.open		= tracing_buffer_meta_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= tracing_seq_release,
};

static const struct file_operations tracing_total_entries_fops = {
	.open		= tracing_open_generic_tr,
	.read		= tracing_total_entries_read,
@@ -8668,6 +8691,9 @@ tracing_init_tracefs_percpu(struct trace_array *tr, long cpu)
	trace_create_cpu_file("buffer_size_kb", TRACE_MODE_READ, d_cpu,
				tr, cpu, &tracing_entries_fops);

	if (tr->range_addr_start)
		trace_create_cpu_file("buffer_meta", TRACE_MODE_READ, d_cpu,
				      tr, cpu, &tracing_buffer_meta_fops);
#ifdef CONFIG_TRACER_SNAPSHOT
	if (!tr->range_addr_start) {
		trace_create_cpu_file("snapshot", TRACE_MODE_WRITE, d_cpu,
+2 −0
Original line number Diff line number Diff line
@@ -645,6 +645,8 @@ trace_buffer_lock_reserve(struct trace_buffer *buffer,
			  unsigned long len,
			  unsigned int trace_ctx);

int ring_buffer_meta_seq_init(struct file *file, struct trace_buffer *buffer, int cpu);

struct trace_entry *tracing_get_trace_entry(struct trace_array *tr,
						struct trace_array_cpu *data);