On Thu, 21 Aug 2025 09:13:51 +0100
Vincent Donnefort <vdonnef...@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 <vdonnef...@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;
> +}


Reply via email to