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:
committed by
Keir Fraser
parent
3239f7d23b
commit
162c11d25b
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user