Re: [PATCH v6 03/24] tracing: Introduce trace remotes

Steven Rostedt
2025-09-08T23:35:31Z

On Thu, 21 Aug 2025 09:13:51 +0100
Vincent Donnefort <vdonnefort@google.com> wrote:

> A trace remote relies on ring-buffer remotes to read and control
> compatible tracing buffers, written by entity such as firmware or
> hypervisor.
>
> Add a Tracefs directory remotes/ that contains all instances of trace
> remotes. Each instance follows the same hierarchy as any other to ease
> the support by existing user-space tools.
>
> This currently does not provide any event support, which will come
> later.
>
> Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
>
> diff --git a/include/linux/trace_remote.h b/include/linux/trace_remote.h
> new file mode 100644
> index 000000000000..de043a6f2fe0
> --- /dev/null
> +++ b/include/linux/trace_remote.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef _LINUX_TRACE_REMOTE_H
> +#define _LINUX_TRACE_REMOTE_H
> +
> +#include <linux/ring_buffer.h>
> +
> +struct trace_remote_callbacks {
> + struct trace_buffer_desc *
> + (*load_trace_buffer)(unsigned long size, void *priv);

I believe this is one of those cases where the 80 char limit is more of a
guildline than a rule. It looks better to keep the above as one line.

> + void (*unload_trace_buffer)(struct trace_buffer_desc *desc, void *priv);

Heck, this is already passed 80 characters ;-)

> + int (*enable_tracing)(bool enable, void *priv);
> + int (*swap_reader_page)(unsigned int cpu, void *priv);
> +};
> +
> +int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv);
> +int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t size,
> + const struct cpumask *cpumask);
> +void trace_remote_free_buffer(struct trace_buffer_desc *desc);
> +
> +#endif
> diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
> index d2c79da81e4f..99af56d39eaf 100644
> --- a/kernel/trace/Kconfig
> +++ b/kernel/trace/Kconfig
> @@ -1238,4 +1238,7 @@ config HIST_TRIGGERS_DEBUG
>

> +
> +int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv)
> +{
> + struct trace_remote *remote;
> +
> + remote = kzalloc(sizeof(*remote), GFP_KERNEL);
> + if (!remote)
> + return -ENOMEM;
> +
> + remote->cbs = cbs;
> + remote->priv = priv;
> + remote->trace_buffer_size = 7 << 10;
> + remote->poll_ms = 100;

What's with the magic numbers?

> + mutex_init(&remote->lock);
> +
> + if (trace_remote_init_tracefs(name, remote)) {
> + kfree(remote);
> + return -ENOMEM;
> + }
> +
> + return 0;
> +}
> +
> +void trace_remote_free_buffer(struct trace_buffer_desc *desc)
> +{
> + struct ring_buffer_desc *rb_desc;
> + int cpu;
> +
> + for_each_ring_buffer_desc(rb_desc, cpu, desc) {
> + unsigned int id;
> +
> + free_page(rb_desc->meta_va);
> +
> + for (id = 0; id < rb_desc->nr_page_va; id++)
> + free_page(rb_desc->page_va[id]);
> + }
> +}
> +
> +int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t size,
> + const struct cpumask *cpumask)
> +{
> + int nr_pages = (PAGE_ALIGN(size) / PAGE_SIZE) + 1;
> + struct ring_buffer_desc *rb_desc;
> + int cpu;
> +
> + desc->nr_cpus = 0;
> + desc->struct_len = offsetof(struct trace_buffer_desc, __data);

The above is better as:

desc->struct_len = struct_size(desc, __data, 0);

As it also does some other checks, like make sure __data is a flexible
array.

> +
> + rb_desc = (struct ring_buffer_desc *)&desc->__data[0];
> +
> + for_each_cpu(cpu, cpumask) {
> + unsigned int id;
> +
> + rb_desc->cpu = cpu;
> + rb_desc->nr_page_va = 0;
> + rb_desc->meta_va = (unsigned long)__get_free_page(GFP_KERNEL);
> + if (!rb_desc->meta_va)
> + goto err;
> +
> + for (id = 0; id < nr_pages; id++) {
> + rb_desc->page_va[id] = (unsigned long)__get_free_page(GFP_KERNEL);
> + if (!rb_desc->page_va[id])

What exactly are these pages allocated for? Is this what the remote will
use to write to? There should be more comments about how this is used.

> + goto err;
> +
> + rb_desc->nr_page_va++;
> + }
> + desc->nr_cpus++;
> + desc->struct_len += offsetof(struct ring_buffer_desc, page_va);
> + desc->struct_len += sizeof(rb_desc->page_va[0]) * rb_desc->nr_page_va;

Shouldn't the above be:

desc->struct_len += struct_size(rb_desc, page_va, rb_desc->nr_page_va);

?

> + rb_desc = __next_ring_buffer_desc(rb_desc);

Is there no check to make sure that the cpu mask matches what the rb_desc
will have?

-- Steve

> + }
> +
> + return 0;
> +
> +err:
> + trace_remote_free_buffer(desc);
> + return -ENOMEM;
> +}