Introducing trace buffer mapping by user-space
Subsystems (4)
Vincent Donnefort
maintainerv12 cover Introducing trace buffer mapping by user-space
The tracing ring-buffers can be stored on disk or sent to network without any copy via splice. However the later doesn't allow real time processing of the traces. A solution is to give userspace direct access to the ring-buffer pages via a mapping. An application can now become a consumer of the ring-buffer, in a similar fashion to what trace_pipe offers.
Support for this new feature can already be found in libtracefs from version 1.8, when built with EXTRA_CFLAGS=-DFORCE_MMAP_ENABLE.
Vincent
v11 -> v12:
* Fix code sample mmap bug.
* Add logging in sample code.
* Reset tracer in selftest.
* Add a refcount for the snapshot users.
* Prevent mapping when there are snapshot users and vice versa.
* Refine the meta-page.
* Fix types in the meta-page.
* Collect Reviewed-by.
v10 -> v11:
* Add Documentation and code sample.
* Add a selftest.
* Move all the update to the meta-page into a single
rb_update_meta_page().
* rb_update_meta_page() is now called from ring_buffer_map_get_reader() to fix NOBLOCK callers.
* kerneldoc for struct trace_meta_page.
* Add a patch to zero all the ring-buffer allocations.
v9 -> v10:
* Refactor rb_update_meta_page()
* In-loop declaration for foreach_subbuf_page()
* Check for cpu_buffer->mapped overflow
v8 -> v9:
* Fix the unlock path in ring_buffer_map()
* Fix cpu_buffer cast with rb_work_rq->is_cpu_buffer
* Rebase on linux-trace/for-next (3cb3091138ca0921c4569bcf7ffa062519639b6a)
v7 -> v8:
* Drop the subbufs renaming into bpages
* Use subbuf as a name when relevant
v6 -> v7:
* Rebase onto lore.kernel.org/lkml/[email protected]/
* Support for subbufs
* Rename subbufs into bpages
v5 -> v6:
* Rebase on next-20230802.
* (unsigned long) -> (void *) cast for virt_to_page().
* Add a wait for the GET_READER_PAGE ioctl.
* Move writer fields update (overrun/pages_lost/entries/pages_touched) in the irq_work.
* Rearrange id in struct buffer_page.
* Rearrange the meta-page.
* ring_buffer_meta_page -> trace_buffer_meta_page.
* Add meta_struct_len into the meta-page.
v4 -> v5:
* Trivial rebase onto 6.5-rc3 (previously 6.4-rc3)
v3 -> v4:
* Add to the meta-page:
- pages_lost / pages_read (allow to compute how full is the ring-buffer)
- read (allow to compute how many entries can be read)
- A reader_page struct.
* Rename ring_buffer_meta_header -> ring_buffer_meta
* Rename ring_buffer_get_reader_page -> ring_buffer_map_get_reader_page
* Properly consume events on ring_buffer_map_get_reader_page() with rb_advance_reader().
v2 -> v3:
* Remove data page list (for non-consuming read)
** Implies removing order > 0 meta-page
* Add a new meta page field ->read
* Rename ring_buffer_meta_page_header into ring_buffer_meta_header
v1 -> v2:
* Hide data_pages from the userspace struct
* Fix META_PAGE_MAX_PAGES
* Support for order > 0 meta-page
* Add missing page->mapping.
Vincent Donnefort (6):
ring-buffer: Zero ring-buffer sub-buffers
ring-buffer: Introducing ring-buffer mapping functions
tracing: Add snapshot refcount
tracing: Allow user-space mapping of the ring-buffer
Documentation: tracing: Add ring-buffer mapping ring-buffer/selftest: Add ring-buffer mapping test
Documentation/trace/index.rst | 1 + Documentation/trace/ring-buffer-map.rst | 106 ++++++ include/linux/ring_buffer.h | 7 + include/uapi/linux/trace_mmap.h | 46 +++ kernel/trace/ring_buffer.c | 338 +++++++++++++++++- kernel/trace/trace.c | 208 ++++++++++- kernel/trace/trace.h | 6 + kernel/trace/trace_events_trigger.c | 57 ++- tools/testing/selftests/ring-buffer/Makefile | 8 + tools/testing/selftests/ring-buffer/config | 1 + .../testing/selftests/ring-buffer/map_test.c | 188 ++++++++++ 11 files changed, 925 insertions(+), 41 deletions(-) create mode 100644 Documentation/trace/ring-buffer-map.rst create mode 100644 include/uapi/linux/trace_mmap.h create mode 100644 tools/testing/selftests/ring-buffer/Makefile create mode 100644 tools/testing/selftests/ring-buffer/config create mode 100644 tools/testing/selftests/ring-buffer/map_test.c
base-commit: 4f1991a92cfe89096b2d1f5583a2e093bdd55c37
Signature · 1 line
2.43.0.429.g432eaa2c6b-goog
Vincent Donnefort
maintainerPATCH v12 1/6 ring-buffer: Zero ring-buffer sub-buffers
In preparation for the ring-buffer memory mapping where each subbuf will be accessible to user-space, zero all the page allocations.
kernel/trace/ring_buffer.c +6 -3
@@ -1466,7 +1466,8 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,list_add (&bpage->list, pages); - page =alloc_pages_node (cpu_to_node (cpu_buffer->cpu), mflags, + page =alloc_pages_node (cpu_to_node (cpu_buffer->cpu), + mflags | __GFP_ZERO, cpu_buffer->buffer->subbuf_order);if (!page) goto free_pages;
@@ -1551,7 +1552,8 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu) cpu_buffer->reader_page = bpage; - page =alloc_pages_node (cpu_to_node (cpu),GFP_KERNEL , cpu_buffer->buffer->subbuf_order); + page =alloc_pages_node (cpu_to_node (cpu),GFP_KERNEL | __GFP_ZERO, + cpu_buffer->buffer->subbuf_order);if (!page) goto fail_free_reader; bpage->page =page_address (page);
@@ -5525,7 +5527,8 @@ ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu)if (bpage->data) goto out; - page =alloc_pages_node (cpu_to_node (cpu),GFP_KERNEL | __GFP_NORETRY, + page =alloc_pages_node (cpu_to_node (cpu), +GFP_KERNEL | __GFP_NORETRY | __GFP_ZERO, cpu_buffer->buffer->subbuf_order);if (!page) {kfree (bpage);
Signature · 1 line
2.43.0.429.g432eaa2c6b-goog
Vincent Donnefort
maintainerPATCH v12 2/6 ring-buffer: Introducing ring-buffer mapping functions
In reply to Vincent DonnefortIn preparation for allowing the user-space to map a ring-buffer, add a set of mapping functions:
ring_buffer_{map,unmap}()
ring_buffer_map_fault()
And controls on the ring-buffer:
ring_buffer_map_get_reader() /* swap reader and head */
Mapping the ring-buffer also involves:
A unique ID for each subbuf of the ring-buffer, currently they are only identified through their in-kernel VA.
A meta-page, where are stored ring-buffer statistics and a description for the current reader
The linear mapping exposes the meta-page, and each subbuf of the ring-buffer, ordered following their unique ID, assigned during the first mapping.
Once mapped, no subbuf can get in or out of the ring-buffer: the buffer size will remain unmodified and the splice enabling functions will in reality simply memcpy the data instead of swapping subbufs.
include/linux/ring_buffer.h +7 -0
@@ -6,6 +6,8 @@#include <linux/seq_file.h> #include <linux/poll.h> +#include <uapi/linux/trace_mmap.h> +struct trace_buffer ;struct ring_buffer_iter ;
@@ -221,4 +223,9 @@ int trace_rb_cpu_prepare(unsigned int cpu, struct hlist_node *node);#define trace_rb_cpu_prepare NULL#endif +int ring_buffer_map (struct trace_buffer *buffer,int cpu); +int ring_buffer_unmap (struct trace_buffer *buffer,int cpu); +struct page *ring_buffer_map_fault (struct trace_buffer *buffer,int cpu, +unsigned long pgoff); +int ring_buffer_map_get_reader (struct trace_buffer *buffer,int cpu);#endif /* _LINUX_RING_BUFFER_H */
include/uapi/linux/trace_mmap.h new file +44 -0
44 lines not on this page · raw message
kernel/trace/ring_buffer.c +328 -1
383 lines not on this page · raw message
Signature · 1 line
2.43.0.429.g432eaa2c6b-goog
Steven Rostedt
maintainerRe: [PATCH v12 2/6] ring-buffer: Introducing ring-buffer mapping functions
Quoted 17 lines · On Tue, 23 Jan 2024 11:07:53 +0000 Vincent Donnefort <[email protected]>…
index 000000000000..5468afc94be7
include/uapi/linux/trace_mmap.h new file +13
-0@@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _TRACE_MMAP_H_ +#define _TRACE_MMAP_H_ + +#include <linux/types.h> + +/** +* struct trace_buffer_meta - Ring-buffer Meta-page description +* @meta_page_size: Size of this meta-page. +* @meta_struct_len: Size of this structure. +* @subbuf_size: Size of each subbuf, including the header. +* @nr_subbufs: Number of subbfs in the ring-buffer. +* @reader.lost_events: Number of events lost at the time of the reader swap.
include/uapi/linux/trace_mmap.h line 21
Quoted 10 lines
include/uapi/linux/trace_mmap.h new file +8
-0+* @reader.id: subbuf ID of the current reader. From 0 to @nr_subbufs - 1 +* @reader.read: Number of bytes read on the reader subbuf. +* @entries: Number of entries in the ring-buffer. +* @overrun: Number of entries lost in the ring-buffer. +* @read: Number of entries that have been read. +* @subbufs_touched: Number of subbufs that have been filled. +* @subbufs_lost: Number of subbufs lost to overrun. +* @subbufs_read: Number of subbufs that have been read.
Do we actually need the above 3 fields?
What's the use case for them? I don't want to expose internals in the API unless they are needed.
-- Steve
Vincent Donnefort
maintainerRe: [PATCH v12 2/6] ring-buffer: Introducing ring-buffer mapping functions
Quoted 27 lines · Steven Rostedt
Quoted 22 lines · On Tue, 23 Jan 2024 11:07:53 +0000 Vincent Donnefort <[email protected]>…
index 000000000000..5468afc94be7
include/uapi/linux/trace_mmap.h new file +18
-0@@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _TRACE_MMAP_H_ +#define _TRACE_MMAP_H_ + +#include <linux/types.h> + +/** +* struct trace_buffer_meta - Ring-buffer Meta-page description +* @meta_page_size: Size of this meta-page. +* @meta_struct_len: Size of this structure. +* @subbuf_size: Size of each subbuf, including the header. +* @nr_subbufs: Number of subbfs in the ring-buffer. +* @reader.lost_events: Number of events lost at the time of the reader swap. +* @reader.id: subbuf ID of the current reader. From 0 to @nr_subbufs - 1 +* @reader.read: Number of bytes read on the reader subbuf. +* @entries: Number of entries in the ring-buffer. +* @overrun: Number of entries lost in the ring-buffer. +* @read: Number of entries that have been read.
Quoted 8 lines
include/uapi/linux/trace_mmap.h line 21
Quoted 3 lines
include/uapi/linux/trace_mmap.h new file +3
-0+* @subbufs_touched: Number of subbufs that have been filled. +* @subbufs_lost: Number of subbufs lost to overrun. +* @subbufs_read: Number of subbufs that have been read. Do we actually need the above 3 fields?
What's the use case for them? I don't want to expose internals in the API unless they are needed.
subbufs_read is gone, I just forgot to remove it here :-\.
The two other ones are used for tracing with the hypervisor. That's why I preemptively added them.
I can remove them and add just append this struct later ... or just overload this struct with another one, only shared between the kernel and the hypervisor?
Quoted 2 lines
-- Steve
Steven Rostedt
maintainerRe: [PATCH v12 2/6] ring-buffer: Introducing ring-buffer mapping functions
Quoted 9 lines · On Tue, 23 Jan 2024 17:48:17 +0000 Vincent Donnefort <[email protected]>…
Quoted 8 lines
Quoted 3 lines
+ * @subbufs_touched: Number of subbufs that have been filled.
+ * @subbufs_lost: Number of subbufs lost to overrun.
+ * @subbufs_read: Number of subbufs that have been read.Do we actually need the above 3 fields?
What's the use case for them? I don't want to expose internals in the API unless they are needed.
Quoted 7 lines
subbufs_readis gone, I just forgot to remove it here :-\.The two other ones are used for tracing with the hypervisor. That's why I preemptively added them.
I can remove them and add just append this struct later ... or just overload this struct with another one, only shared between the kernel and the hypervisor?
Yes, let's have them be different for now. Or we could just make them "reserved" and say that they are not used for now.
I also think we should add a flags value too, so that when they are no longer reserved, a flag can be set to say that they are active.
struct trace_buffer_meta {
__u32 meta_page_size;
__u32 meta_struct_len;
__u32 subbuf_size;
__u32 nr_subbufs;
struct {
__u64 lost_events;
__u32 id;
__u32 read;
} reader;
__u64 flags;
__u64 entries;
__u64 overrun;
__u64 read;
__u64 Reserved1;
__u64 Reserved2;
};And that way the hypervisor would still have those available, and updated, but they are not filled for user space. The hypervisor could even set the flag field saying it's using them.
That is, the first flag is:
enum {
TRACE_BUFFER_META_FL_SUBUF_INFO = (1 << 0),
};And if that's set, those fields are available. But we just don't set them now ;-)
-- Steve
Vincent Donnefort
maintainerPATCH v12 3/6 tracing: Add snapshot refcount
In reply to Vincent DonnefortWhen a ring-buffer is memory mapped by user-space, no trace or ring-buffer swap is possible. This means the snapshot feature is mutually exclusive with the memory mapping. Having a refcount on snapshot users will help to know if a mapping is possible or not.
kernel/trace/trace.c +75 -15
@@ -1300,6 +1300,52 @@ static void free_snapshot(struct trace_array *tr) tr->allocated_snapshot = false; } +static int tracing_arm_snapshot_locked (struct trace_array *tr) +{ +int ret; + +lockdep_assert_held (&trace_types_lock); + +if (tr->snapshot ==UINT_MAX ) +return -EBUSY ; + + ret =tracing_alloc_snapshot_instance (tr); +if (ret) +return ret; + + tr->snapshot++; + +return 0 ; +} + +static void tracing_disarm_snapshot_locked (struct trace_array *tr) +{ +lockdep_assert_held (&trace_types_lock); + +if (WARN_ON (!tr->snapshot)) +return ; + + tr->snapshot--; +} + +int tracing_arm_snapshot (struct trace_array *tr) +{ +int ret; + +mutex_lock (&trace_types_lock); + ret =tracing_arm_snapshot_locked (tr); +mutex_unlock (&trace_types_lock); + +return ret; +} + +void tracing_disarm_snapshot (struct trace_array *tr) +{ +mutex_lock (&trace_types_lock); +tracing_disarm_snapshot_locked (tr); +mutex_unlock (&trace_types_lock); +} +/** * tracing_alloc_snapshot - allocate snapshot buffer. *
@@ -1373,10 +1419,6 @@ int tracing_snapshot_cond_enable(struct trace_array *tr, void *cond_data,mutex_lock (&trace_types_lock); - ret =tracing_alloc_snapshot_instance (tr); -if (ret) - goto fail_unlock; -if (tr->current_trace->use_max_tr) { ret = -EBUSY ; goto fail_unlock;
@@ -1395,6 +1437,10 @@ int tracing_snapshot_cond_enable(struct trace_array *tr, void *cond_data, goto fail_unlock; } + ret =tracing_arm_snapshot_locked (tr); +if (ret) + goto fail_unlock; +local_irq_disable ();arch_spin_lock (&tr->max_lock); tr->cond_snapshot = cond_snapshot;
@@ -1439,6 +1485,8 @@ int tracing_snapshot_cond_disable(struct trace_array *tr)arch_spin_unlock (&tr->max_lock);local_irq_enable (); +tracing_disarm_snapshot (tr); +return ret; }EXPORT_SYMBOL_GPL (tracing_snapshot_cond_disable);
@@ -6579,11 +6627,12 @@ int tracing_set_tracer(struct trace_array *tr, const char *buf)*/ synchronize_rcu ();free_snapshot (tr); + tracing_disarm_snapshot_locked(tr); } -if (t->use_max_tr && !tr->allocated_snapshot) { - ret =tracing_alloc_snapshot_instance (tr); -if (ret <0 ) +if (t->use_max_tr) { + ret =tracing_arm_snapshot_locked (tr); +if (ret) goto out; }#else
@@ -6592,8 +6641,11 @@ int tracing_set_tracer(struct trace_array *tr, const char *buf)if (t->init) { ret =tracer_init (t, tr); -if (ret) +if (ret) { +if (t->use_max_tr) +tracing_disarm_snapshot_locked (tr); goto out; + } } tr->current_trace = t;
@@ -7695,10 +7747,11 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,if (tr->allocated_snapshot) ret =resize_buffer_duplicate_size (&tr->max_buffer, &tr->array_buffer, iter->cpu_file); -else - ret =tracing_alloc_snapshot_instance (tr); -if (ret <0 ) + + ret =tracing_arm_snapshot_locked (tr); +if (ret)break ; +/* Now, we're going to swap */ if (iter->cpu_file ==RING_BUFFER_ALL_CPUS ) {local_irq_disable ();
@@ -7708,6 +7761,7 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,smp_call_function_single (iter->cpu_file, tracing_swap_cpu_buffer, (void *)tr,1 ); } +tracing_disarm_snapshot_locked (tr);break ;default :if (tr->allocated_snapshot) {
@@ -8832,8 +8886,13 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash, ops = param ? &snapshot_count_probe_ops : &snapshot_probe_ops; -if (glob[0 ] =='!' ) -return unregister_ftrace_function_probe_func (glob+1 , tr, ops); +if (glob[0 ] =='!' ) { + ret =unregister_ftrace_function_probe_func (glob+1 , tr, ops); +if (!ret) +tracing_disarm_snapshot (tr); + +return ret; + }if (!param) goto out_reg;
@@ -8852,12 +8911,13 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash,return ret; out_reg: - ret =tracing_alloc_snapshot_instance (tr); + ret =tracing_arm_snapshot (tr);if (ret <0 ) goto out; ret =register_ftrace_function_probe (glob, tr, ops, count); - +if (ret <0 ) +tracing_disarm_snapshot (tr); out:return ret <0 ? ret :0 ; }
kernel/trace/trace.h +5 -0
@@ -334,6 +334,7 @@ struct trace_array {*/ struct array_buffer max_buffer;bool allocated_snapshot; +unsigned int snapshot;#endif #ifdef CONFIG_TRACER_MAX_TRACE unsigned long max_latency;
@@ -1973,12 +1974,16 @@ static inline void trace_event_eval_update(struct trace_eval_map **map, int len)#ifdef CONFIG_TRACER_SNAPSHOT void tracing_snapshot_instance (struct trace_array *tr);int tracing_alloc_snapshot_instance (struct trace_array *tr); +int tracing_arm_snapshot (struct trace_array *tr); +void tracing_disarm_snapshot (struct trace_array *tr);#else static inline void tracing_snapshot_instance (struct trace_array *tr) { }static inline int tracing_alloc_snapshot_instance (struct trace_array *tr) {return 0 ; } +static inline int tracing_arm_snapshot (struct trace_array *tr) {return 0 ; } +static inline void tracing_disarm_snapshot (struct trace_array *tr) { }#endif #ifdef CONFIG_PREEMPT_TRACER
kernel/trace/trace_events_trigger.c +39 -18
86 lines not on this page · raw message
Signature · 1 line
2.43.0.429.g432eaa2c6b-goog
Masami Hiramatsu (Google)
maintainerRe: [PATCH v12 3/6] tracing: Add snapshot refcount
On Tue, 23 Jan 2024 11:07:54 +0000
Vincent Donnefort <[email protected]> wrote:
[...]
kernel/trace/trace.c int tracing_set_tracer(struct trace_array *tr, const char *buf) · line 6646
Quoted 8 lines
kernel/trace/trace.c +3
-1@@ -6592,8 +6641,11 @@ int tracing_set_tracer(struct trace_array *tr, const char *buf)if (t->init) { ret =tracer_init (t, tr); -if (ret) +if (ret) { +if (t->use_max_tr) +tracing_disarm_snapshot_locked (tr);
This part is out of CONFIG_TRACER_MAX_TRACE, so it may cause a compile error if CONFIG_TRACER_MAX_TRACE is not set.
Quoted 5 lines
kernel/trace/trace.c +1
-0goto out; + } } tr->current_trace = t;
[...]
Quoted 12 lines
kernel/trace/trace_events_trigger.c +0
-4@@ -597,20 +597,9 @@ static int register_trigger(char *glob,return ret; } -/** -* unregister_trigger - Generic event_command @unreg implementation -* @glob: The raw string used to register the trigger -* @test: Trigger-specific data used to find the trigger to remove
kernel/trace/trace_events_trigger.c static int register_trigger(char *glob, · line 613
Quoted 10 lines
kernel/trace/trace_events_trigger.c +0
-10-* @file: The trace_event_file associated with the event -* -* Common implementation for event trigger unregistration. -* -* Usually used directly as the @unreg method in event command -* implementations. -*/ -static void unregister_trigger (char *glob, -struct event_trigger_data *test, -struct trace_event_file *file)
OK, so __unregister_trigger returns true if data exists, but unregister_trigger() ignores results. (I want some comment here)
Quoted 42 lines
kernel/trace/trace_events_trigger.c +29
-2+static bool __unregister_trigger (char *glob, +struct event_trigger_data *test, +struct trace_event_file *file) {struct event_trigger_data *data =NULL , *iter;@@ -626,8 +615,32 @@ static void unregister_trigger(char *glob, } } -if (data && data->ops->free) - data->ops->free (data); +if (data) { +if (data->ops->free) + data->ops->free (data); + +return true; + } + +return false; +} + +/** +* unregister_trigger - Generic event_command @unreg implementation +* @glob: The raw string used to register the trigger +* @test: Trigger-specific data used to find the trigger to remove +* @file: The trace_event_file associated with the event +* +* Common implementation for event trigger unregistration. +* +* Usually used directly as the @unreg method in event command +* implementations. +*/ +static void unregister_trigger (char *glob, +struct event_trigger_data *test, +struct trace_event_file *file) +{ +__unregister_trigger (glob, test, file); }/*
kernel/trace/trace_events_trigger.c register_snapshot_trigger(char *glob, · line 1487
Quoted 6 lines
kernel/trace/trace_events_trigger.c +1
-1@@ -1470,12 +1483,20 @@ register_snapshot_trigger(char *glob, struct event_trigger_data *data, struct trace_event_file *file) { - if (tracing_alloc_snapshot_instance(file->tr) != 0) + if (tracing_arm_snapshot(file->tr)) return 0;
BTW, is this return value correct? It seems that the register_*_trigger() will return error code when it fails.
Thanks,
Quoted 27 lines
kernel/trace/trace_events_trigger.c +9
-1return register_trigger (glob, data, file); } +static void unregister_snapshot_trigger (char *glob, +struct event_trigger_data *data, +struct trace_event_file *file) +{ +if (__unregister_trigger (glob, data, file)) +tracing_disarm_snapshot (file->tr); +} +static int snapshot_trigger_print (struct seq_file *m,struct event_trigger_data *data) {@@ -1508,7 +1529,7 @@ static struct event_command trigger_snapshot_cmd = { .trigger_type = ETT_SNAPSHOT, .parse = event_trigger_parse, .reg = register_snapshot_trigger, - .unreg = unregister_trigger, + .unreg = unregister_snapshot_trigger, .get_trigger_ops = snapshot_get_trigger_ops, .set_filter = set_trigger_filter, };Signature · 1 line
2.43.0.429.g432eaa2c6b-goog
Signature · 1 line
Masami Hiramatsu (Google) <[email protected]>
Vincent Donnefort
maintainerRe: [PATCH v12 3/6] tracing: Add snapshot refcount
Hi Masami,
Thanks for taking the time to look at those changes.
Quoted 6 lines · Masami Hiramatsu
On Tue, 23 Jan 2024 11:07:54 +0000
Vincent Donnefort <[email protected]> wrote:[...]
Quoted 2 lines
(quoted diff) +0
-0@@ -6592,8 +6641,11 @@ int tracing_set_tracer(struct trace_array *tr, const char *buf)
Quoted 9 lines
kernel/trace/trace.c int tracing_set_tracer(struct trace_array *tr, const char *buf) · line 6646
Quoted 6 lines
kernel/trace/trace.c +3
-1if (t->init) { ret =tracer_init (t, tr); -if (ret) +if (ret) { +if (t->use_max_tr) +tracing_disarm_snapshot_locked (tr);This part is out of
CONFIG_TRACER_MAX_TRACE, so it may cause a compile error ifCONFIG_TRACER_MAX_TRACEis not set.
Duh, yes it must depends on TRACER_MAX_TRACE :-\
Quoted 24 lines
Quoted 6 lines
kernel/trace/trace.c +1
-0goto out; + } } tr->current_trace = t;[...]
Quoted 17 lines
kernel/trace/trace_events_trigger.c +0
-9@@ -597,20 +597,9 @@ static int register_trigger(char *glob,return ret; } -/** -* unregister_trigger - Generic event_command @unreg implementation -* @glob: The raw string used to register the trigger -* @test: Trigger-specific data used to find the trigger to remove -* @file: The trace_event_file associated with the event -* -* Common implementation for event trigger unregistration. -* -* Usually used directly as the @unreg method in event command
Quoted 8 lines
kernel/trace/trace_events_trigger.c static int register_trigger(char *glob, · line 613
Quoted 5 lines
kernel/trace/trace_events_trigger.c +0
-5-* implementations. -*/ -static void unregister_trigger (char *glob, -struct event_trigger_data *test, -struct trace_event_file *file)OK, so
__unregister_triggerreturns true if data exists, butunregister_trigger()ignores results. (I want some comment here)
Will add something for the __unregister_trigger flavour.
Quoted 41 lines
Quoted 41 lines
kernel/trace/trace_events_trigger.c +29
-2+static bool __unregister_trigger (char *glob, +struct event_trigger_data *test, +struct trace_event_file *file) {struct event_trigger_data *data =NULL , *iter;@@ -626,8 +615,32 @@ static void unregister_trigger(char *glob, } } -if (data && data->ops->free) - data->ops->free (data); +if (data) { +if (data->ops->free) + data->ops->free (data); + +return true; + } + +return false; +} + +/** +* unregister_trigger - Generic event_command @unreg implementation +* @glob: The raw string used to register the trigger +* @test: Trigger-specific data used to find the trigger to remove +* @file: The trace_event_file associated with the event +* +* Common implementation for event trigger unregistration. +* +* Usually used directly as the @unreg method in event command +* implementations. +*/ +static void unregister_trigger (char *glob, +struct event_trigger_data *test, +struct trace_event_file *file) +{ +__unregister_trigger (glob, test, file); }
Quoted 11 lines
kernel/trace/trace_events_trigger.c register_snapshot_trigger(char *glob, · line 1487
Quoted 8 lines
kernel/trace/trace_events_trigger.c +1
-1/* @@ -1470,12 +1483,20 @@ register_snapshot_trigger(char *glob, struct event_trigger_data *data, struct trace_event_file *file) { - if (tracing_alloc_snapshot_instance(file->tr) != 0) + if (tracing_arm_snapshot(file->tr)) return 0;BTW, is this return value correct? It seems that the register_*_trigger() will return error code when it fails.
It should indeed be
ret = tracing_arm_snapshot()
if (ret)
return ret;
Quoted 34 lines
Thanks,
Quoted 27 lines
kernel/trace/trace_events_trigger.c +9
-1return register_trigger (glob, data, file); } +static void unregister_snapshot_trigger (char *glob, +struct event_trigger_data *data, +struct trace_event_file *file) +{ +if (__unregister_trigger (glob, data, file)) +tracing_disarm_snapshot (file->tr); +} +static int snapshot_trigger_print (struct seq_file *m,struct event_trigger_data *data) {@@ -1508,7 +1529,7 @@ static struct event_command trigger_snapshot_cmd = { .trigger_type = ETT_SNAPSHOT, .parse = event_trigger_parse, .reg = register_snapshot_trigger, - .unreg = unregister_trigger, + .unreg = unregister_snapshot_trigger, .get_trigger_ops = snapshot_get_trigger_ops, .set_filter = set_trigger_filter, };Signature · 1 line
2.43.0.429.g432eaa2c6b-googSignature · 1 line
Masami Hiramatsu (Google) <[email protected]>
Masami Hiramatsu (Google)
maintainerRe: [PATCH v12 3/6] tracing: Add snapshot refcount
Hi Vincent,
Quoted 11 lines · On Thu, 25 Jan 2024 14:53:40 +0000 Vincent Donnefort <[email protected]>…
Quoted 10 lines
kernel/trace/trace_events_trigger.c register_snapshot_trigger(char *glob, · line 1487
Quoted 7 lines
kernel/trace/trace_events_trigger.c +1
-1@@ -1470,12 +1483,20 @@ register_snapshot_trigger(char *glob, struct event_trigger_data *data, struct trace_event_file *file) { - if (tracing_alloc_snapshot_instance(file->tr) != 0) + if (tracing_arm_snapshot(file->tr)) return 0;BTW, is this return value correct? It seems that the register_*_trigger() will return error code when it fails.
Quoted 5 lines
It should indeed be
ret =
tracing_arm_snapshot()
if (ret)return ret;
OK, then there is a bug. We need to fix it before changing this for backporting.
Thank you,
Signature · 1 line
Masami Hiramatsu (Google) <[email protected]>
Masami Hiramatsu (Google)
maintainerPATCH 1/1 tracing/trigger: Fix to return error if failed to alloc snapshot
In reply to Vincent DonnefortFrom: Masami Hiramatsu (Google) <[email protected]>
Fix register_snapshot_trigger() to return error code if it failed to allocate a snapshot instead of 0 (success). Unless that, it will register snapshot trigger without an error.
--- kernel/trace/trace_events_trigger.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
kernel/trace/trace_events_trigger.c +4 -2
@@ -1470,8 +1470,10 @@ register_snapshot_trigger(char *glob,struct event_trigger_data *data, struct trace_event_file *file) { - if (tracing_alloc_snapshot_instance(file->tr) != 0) - return 0; + int ret = tracing_alloc_snapshot_instance(file->tr); + +if (ret <0 ) +return ret;return register_trigger (glob, data, file); }
Steven Rostedt
maintainerRe: [PATCH] tracing/trigger: Fix to return error if failed to alloc snapshot
Quoted 9 lines · On Fri, 26 Jan 2024 09:42:58 +0900 "Masami Hiramatsu (Google)"…
From: Masami Hiramatsu (Google) <[email protected]>
Fix
register_snapshot_trigger()to return error code if it failed to allocate a snapshot instead of 0 (success). Unless that, it will register snapshot trigger without an error.Fixes 0bbe7f719985 ("tracing: Fix the race between registering 'snapshot' event trigger and triggering 'snapshot' operation")Signed-off-by Masami Hiramatsu (Google) <[email protected]>
Thanks Masami, I'll apply this.
-- Steve
Quoted 21 lines
--- kernel/trace/trace_events_trigger.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)kernel/trace/trace_events_trigger.c +4
-2@@ -1470,8 +1470,10 @@ register_snapshot_trigger(char *glob,struct event_trigger_data *data, struct trace_event_file *file) { - if (tracing_alloc_snapshot_instance(file->tr) != 0) - return 0; + int ret = tracing_alloc_snapshot_instance(file->tr); + +if (ret <0 ) +return ret;return register_trigger (glob, data, file); }
kernel test robot
build botRe: [PATCH v12 3/6] tracing: Add snapshot refcount
In reply to Vincent Donnefortkernel test robot noticed the following build errors:
Hi Vincent,
kernel test robot noticed the following build errors:
[auto build test ERROR on 4f1991a92cfe89096b2d1f5583a2e093bdd55c37]
url: https://github.com/intel-lab-lkp/linux/commits/Vincent-Donnefort/ring-buffer-Zero-ring-buffer-sub-buffers/20240123-191131 base: 4f1991a92cfe89096b2d1f5583a2e093bdd55c37 patch link: https://lore.kernel.org/r/20240123110757.3657908-4-vdonnefort%40google.com patch subject: [PATCH v12 3/6] tracing: Add snapshot refcount config: i386-buildonly-randconfig-005-20240126 (https://download.01.org/0day-ci/archive/20240126/[email protected]/config) compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240126/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
>> kernel/trace/trace.c:6645:11: error: no member named 'use_max_tr' in 'struct tracer'
6645 | if (t->use_max_tr)
| ~ ^
>> kernel/trace/trace.c:6646:5: error: call to undeclared function 'tracing_disarm_snapshot_locked'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
6646 | tracing_disarm_snapshot_locked(tr);
| ^
kernel/trace/trace.c:6646:5: note: did you mean 'tracing_disarm_snapshot'?
kernel/trace/trace.h:1986:20: note: 'tracing_disarm_snapshot' declared here
1986 | static inline void tracing_disarm_snapshot(struct trace_array *tr) { }
| ^2 errors generated.
vim +6645 kernel/trace/trace.c
6641
6642 if (t->init) {
6643 ret = tracer_init(t, tr);
6644 if (ret) {
> 6645 if (t->use_max_tr) > 6646 tracing_disarm_snapshot_locked(tr);
6647 goto out;
6648 }
6649 }
6650
6651 tr->current_trace = t;
6652 tr->current_trace->enabled++;
6653 trace_branch_enable(tr);
6654 out:
6655 mutex_unlock(&trace_types_lock);
6656
6657 return ret;
6658 }
6659
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
kernel test robot
build botRe: [PATCH v12 3/6] tracing: Add snapshot refcount
In reply to Vincent Donnefortkernel test robot noticed the following build errors:
Hi Vincent,
kernel test robot noticed the following build errors:
[auto build test ERROR on 4f1991a92cfe89096b2d1f5583a2e093bdd55c37]
url: https://github.com/intel-lab-lkp/linux/commits/Vincent-Donnefort/ring-buffer-Zero-ring-buffer-sub-buffers/20240123-191131 base: 4f1991a92cfe89096b2d1f5583a2e093bdd55c37 patch link: https://lore.kernel.org/r/20240123110757.3657908-4-vdonnefort%40google.com patch subject: [PATCH v12 3/6] tracing: Add snapshot refcount config: i386-randconfig-012-20240126 (https://download.01.org/0day-ci/archive/20240126/[email protected]/config) compiler: gcc-9 (Debian 9.3.0-22) 9.3.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240126/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
kernel/trace/trace.c: In function 'tracing_set_tracer':
>> kernel/trace/trace.c:6645:9: error: 'struct tracer' has no member named 'use_max_tr'
6645 | if (t->use_max_tr)
| ^~
>> kernel/trace/trace.c:6646:5: error: implicit declaration of function 'tracing_disarm_snapshot_locked'; did you mean 'tracing_disarm_snapshot'? [-Werror=implicit-function-declaration]
6646 | tracing_disarm_snapshot_locked(tr);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| tracing_disarm_snapshotcc1: some warnings being treated as errors
vim +6645 kernel/trace/trace.c
6641
6642 if (t->init) {
6643 ret = tracer_init(t, tr);
6644 if (ret) {
> 6645 if (t->use_max_tr) > 6646 tracing_disarm_snapshot_locked(tr);
6647 goto out;
6648 }
6649 }
6650
6651 tr->current_trace = t;
6652 tr->current_trace->enabled++;
6653 trace_branch_enable(tr);
6654 out:
6655 mutex_unlock(&trace_types_lock);
6656
6657 return ret;
6658 }
6659
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
Vincent Donnefort
maintainerPATCH v12 4/6 tracing: Allow user-space mapping of the ring-buffer
In reply to Vincent DonnefortCurrently, user-space extracts data from the ring-buffer via splice, which is handy for storage or network sharing. However, due to splice limitations, it is imposible to do real-time analysis without a copy.
A solution for that problem is to let the user-space map the ring-buffer directly.
The mapping is exposed via the per-CPU file trace_pipe_raw. The first element of the mapping is the meta-page. It is followed by each subbuffer constituting the ring-buffer, ordered by their unique page ID:
* Meta-page -- include/uapi/linux/trace_mmap.h for a description
* Subbuf ID 0
* Subbuf ID 1
...
It is therefore easy to translate a subbuf ID into an offset in the mapping:
reader_id = meta->reader->id; reader_offset = meta->meta_page_size + reader_id * meta->subbuf_size;
When new data is available, the mapper must call a newly introduced ioctl:TRACE_MMAP_IOCTL_GET_READER. This will update the Meta-page reader ID to point to the next reader containing unread data.
include/uapi/linux/trace_mmap.h +2 -0
@@ -41,4 +41,6 @@ struct trace_buffer_meta { __u64 subbufs_lost; }; +#define TRACE_MMAP_IOCTL_GET_READER _IO('T', 0x1) +#endif /* _TRACE_MMAP_H_ */
kernel/trace/trace.c +114 -4
160 lines not on this page · raw message
kernel/trace/trace.h +1 -0
@@ -335,6 +335,7 @@ struct trace_array {struct array_buffer max_buffer;bool allocated_snapshot;unsigned int snapshot; +int mapped;#endif #ifdef CONFIG_TRACER_MAX_TRACE unsigned long max_latency;
Signature · 1 line
2.43.0.429.g432eaa2c6b-goog
Vincent Donnefort
maintainerPATCH v12 5/6 Documentation: tracing: Add ring-buffer mapping
In reply to Vincent DonnefortIt is now possible to mmap() a ring-buffer to stream its content. Add some documentation and a code example.
Documentation/trace/index.rst +1 -0
@@ -29,6 +29,7 @@ Linux Tracing Technologies timerlat-tracer intel_th ring-buffer-design + ring-buffer-map stm sys-t coresight/index
Documentation/trace/ring-buffer-map.rst new file +106 -0
106 lines not on this page · raw message
Signature · 1 line
2.43.0.429.g432eaa2c6b-goog
Vincent Donnefort
maintainerPATCH v12 6/6 ring-buffer/selftest: Add ring-buffer mapping test
In reply to Vincent DonnefortThis test maps a ring-buffer and validate the meta-page after reset and after emitting few events.
tools/testing/selftests/ring-buffer/Makefile new file +8 -0
@@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +CFLAGS += -Wl,-no-as-needed -Wall +CFLAGS += $(KHDR_INCLUDES) +CFLAGS += -D_GNU_SOURCE + +TEST_GEN_PROGS = map_test + +include ../lib.mk
tools/testing/selftests/ring-buffer/config new file +1 -0
@@ -0,0 +1 @@ +CONFIG_FTRACE=y
tools/testing/selftests/ring-buffer/map_test.c new file +188 -0
188 lines not on this page · raw message
Signature · 1 line
2.43.0.429.g432eaa2c6b-goog