FROMLIST: ring-buffer: Introducing ring-buffer writer

A ring-buffer writer is an entity outside of the kernel (most likely a
firmware or a hypervisor) capable of writing events in a ring-buffer
following the same format as the tracefs ring-buffer.

To setup the ring-buffer on the kernel side, a description of the pages
(struct trace_page_desc) is necessary. A callback (get_reader_page) must
also be provided. It is called whenever it is done reading the previous
reader page.

It is expected from the writer to keep the meta-page updated.

Bug: 357781595
Link: https://lore.kernel.org/all/20240911093029.3279154-3-vdonnefort@google.com/
Change-Id: Ib006ff19d79a5b2559b09661fba7bcd426ef8cba
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
This commit is contained in:
Vincent Donnefort
2024-09-11 10:30:18 +01:00
committed by Keir Fraser
parent 3239f7d23b
commit 162c11d25b
2 changed files with 257 additions and 13 deletions
+58 -5
View File
@@ -83,11 +83,14 @@ u64 ring_buffer_event_time_stamp(struct trace_buffer *buffer,
void ring_buffer_discard_commit(struct trace_buffer *buffer,
struct ring_buffer_event *event);
struct ring_buffer_writer;
/*
* size is in bytes for each per CPU buffer.
*/
struct trace_buffer *
__ring_buffer_alloc(unsigned long size, unsigned flags, struct lock_class_key *key);
__ring_buffer_alloc(unsigned long size, unsigned flags, struct lock_class_key *key,
struct ring_buffer_writer *writer);
struct trace_buffer *__ring_buffer_alloc_range(unsigned long size, unsigned flags,
int order, unsigned long start,
@@ -102,10 +105,10 @@ bool ring_buffer_last_boot_delta(struct trace_buffer *buffer, long *text,
* traced by ftrace, it can produce lockdep warnings. We need to keep each
* ring buffer's lock class separate.
*/
#define ring_buffer_alloc(size, flags) \
({ \
static struct lock_class_key __key; \
__ring_buffer_alloc((size), (flags), &__key); \
#define ring_buffer_alloc(size, flags) \
({ \
static struct lock_class_key __key; \
__ring_buffer_alloc((size), (flags), &__key, NULL); \
})
/*
@@ -248,4 +251,54 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
struct vm_area_struct *vma);
int ring_buffer_unmap(struct trace_buffer *buffer, int cpu);
int ring_buffer_map_get_reader(struct trace_buffer *buffer, int cpu);
#define meta_pages_lost(__meta) \
((__meta)->Reserved1)
#define meta_pages_touched(__meta) \
((__meta)->Reserved2)
struct rb_page_desc {
int cpu;
int nr_page_va; /* exclude the meta page */
unsigned long meta_va;
unsigned long page_va[];
};
struct trace_page_desc {
int nr_cpus;
char __data[]; /* list of rb_page_desc */
};
static inline
struct rb_page_desc *__next_rb_page_desc(struct rb_page_desc *pdesc)
{
size_t len = struct_size(pdesc, page_va, pdesc->nr_page_va);
return (struct rb_page_desc *)((void *)pdesc + len);
}
static inline
struct rb_page_desc *__first_rb_page_desc(struct trace_page_desc *trace_pdesc)
{
return (struct rb_page_desc *)(&trace_pdesc->__data[0]);
}
#define for_each_rb_page_desc(__pdesc, __cpu, __trace_pdesc) \
for (__pdesc = __first_rb_page_desc(__trace_pdesc), __cpu = 0; \
__cpu < (__trace_pdesc)->nr_cpus; \
__cpu++, __pdesc = __next_rb_page_desc(__pdesc))
struct ring_buffer_writer {
struct trace_page_desc *pdesc;
int (*get_reader_page)(int cpu);
int (*reset)(int cpu);
};
int ring_buffer_poll_writer(struct trace_buffer *buffer, int cpu);
#define ring_buffer_reader(writer) \
({ \
static struct lock_class_key __key; \
__ring_buffer_alloc(0, RB_FL_OVERWRITE, &__key, writer);\
})
#endif /* _LINUX_RING_BUFFER_H */