* [PATCH 0/4] ring-buffer: Use kvmalloc variants for big allocations
@ 2026-09-22 7:29 Vincent Donnefort
2026-09-22 7:29 ` [PATCH 1/4] ring-buffer: Use kvzalloc_objs for user mapping arrays Vincent Donnefort
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Vincent Donnefort @ 2026-09-22 7:29 UTC (permalink / raw)
To: rostedt, mhiramat, linux-trace-kernel
Cc: mathieu.desnoyers, kernel-team, linux-kernel, Vincent Donnefort
Several allocations in the ring buffer code scale with buffer capacity or
sub-buffer order and require high-order contiguous physical memory when
using plain kmalloc. Under memory fragmentation or with large buffers,
these allocations can fail unnecessarily.
This series converts those allocations to their kvmalloc equivalents.
Vincent Donnefort (4):
ring-buffer: Use kvzalloc_objs for user mapping arrays
ring-buffer: Use kvzalloc_objs for remote buffer subbuf_ids
ring-buffer: Drop redundant ring_buffer_iter::event_size
ring-buffer: Use kvmalloc for ring_buffer_iter::event
kernel/trace/ring_buffer.c | 35 +++++++++++++++++++----------------
1 file changed, 19 insertions(+), 16 deletions(-)
base-commit: 93f51579e7df248780214094418f205253383cc5
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/4] ring-buffer: Use kvzalloc_objs for user mapping arrays
2026-09-22 7:29 [PATCH 0/4] ring-buffer: Use kvmalloc variants for big allocations Vincent Donnefort
@ 2026-09-22 7:29 ` Vincent Donnefort
2026-09-22 7:29 ` [PATCH 2/4] ring-buffer: Use kvzalloc_objs for remote buffer subbuf_ids Vincent Donnefort
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Vincent Donnefort @ 2026-09-22 7:29 UTC (permalink / raw)
To: rostedt, mhiramat, linux-trace-kernel
Cc: mathieu.desnoyers, kernel-team, linux-kernel, Vincent Donnefort
Mapping a large trace buffer to user space requires allocating an array
of struct bpage and one of struct page. For large ring buffers, these
contiguous allocations are likely to fail with memory fragmentation.
Switch both to kvzalloc_objs() to use the vmalloc fallback under memory
pressure.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
kernel/trace/ring_buffer.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 04bb94c29f58..f9be87c2cc3d 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -7746,9 +7746,9 @@ static int __rb_map_vma(struct ring_buffer_per_cpu *cpu_buffer,
struct vm_area_struct *vma)
{
unsigned long nr_subbufs, nr_pages, nr_vma_pages;
- pgoff_t pgoff = vma_start_pgoff(vma);
+ struct page **pages __free(kvfree) = NULL;
unsigned int subbuf_pages, subbuf_order;
- struct page **pages __free(kfree) = NULL;
+ pgoff_t pgoff = vma_start_pgoff(vma);
int p = 0, s = 0;
int err;
@@ -7785,7 +7785,7 @@ static int __rb_map_vma(struct ring_buffer_per_cpu *cpu_buffer,
nr_pages = nr_vma_pages;
- pages = kzalloc_objs(*pages, nr_pages);
+ pages = kvzalloc_objs(*pages, nr_pages);
if (!pages)
return -ENOMEM;
@@ -7877,7 +7877,7 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
return err;
/* subbuf_ids includes the reader while nr_pages does not */
- subbuf_ids = kcalloc(cpu_buffer->nr_pages + 1, sizeof(*subbuf_ids), GFP_KERNEL);
+ subbuf_ids = kvzalloc_objs(*subbuf_ids, cpu_buffer->nr_pages + 1);
if (!subbuf_ids) {
rb_free_meta_page(cpu_buffer);
return -ENOMEM;
@@ -7901,7 +7901,7 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
cpu_buffer->user_mapped = 1;
raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
} else {
- kfree(cpu_buffer->subbuf_ids);
+ kvfree(cpu_buffer->subbuf_ids);
cpu_buffer->subbuf_ids = NULL;
rb_free_meta_page(cpu_buffer);
atomic_dec(&cpu_buffer->resize_disabled);
@@ -7958,7 +7958,7 @@ int ring_buffer_unmap(struct trace_buffer *buffer, int cpu)
raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
- kfree(cpu_buffer->subbuf_ids);
+ kvfree(cpu_buffer->subbuf_ids);
cpu_buffer->subbuf_ids = NULL;
rb_free_meta_page(cpu_buffer);
atomic_dec(&cpu_buffer->resize_disabled);
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/4] ring-buffer: Use kvzalloc_objs for remote buffer subbuf_ids
2026-09-22 7:29 [PATCH 0/4] ring-buffer: Use kvmalloc variants for big allocations Vincent Donnefort
2026-09-22 7:29 ` [PATCH 1/4] ring-buffer: Use kvzalloc_objs for user mapping arrays Vincent Donnefort
@ 2026-09-22 7:29 ` Vincent Donnefort
2026-09-22 7:29 ` [PATCH 3/4] ring-buffer: Drop redundant ring_buffer_iter::event_size Vincent Donnefort
2026-09-22 7:29 ` [PATCH 4/4] ring-buffer: Use kvmalloc for ring_buffer_iter::event Vincent Donnefort
3 siblings, 0 replies; 7+ messages in thread
From: Vincent Donnefort @ 2026-09-22 7:29 UTC (permalink / raw)
To: rostedt, mhiramat, linux-trace-kernel
Cc: mathieu.desnoyers, kernel-team, linux-kernel, Vincent Donnefort
Creating a remote ring buffer requires allocating an array of bpage. For
large ring buffers, this contiguous allocation is likely to fail with
memory fragmentation.
Switch it to kvzalloc_objs() to use the vmalloc fallback under memory
pressure.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
kernel/trace/ring_buffer.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index f9be87c2cc3d..1a158a24b3c8 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -2620,8 +2620,8 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, unsigned long nr_pages, int
cpu_buffer->remote = buffer->remote;
cpu_buffer->meta_page = (struct trace_buffer_meta *)(void *)desc->meta_va;
cpu_buffer->nr_pages = nr_pages;
- cpu_buffer->subbuf_ids = kzalloc_objs(*cpu_buffer->subbuf_ids,
- cpu_buffer->nr_pages + 1);
+ cpu_buffer->subbuf_ids = kvzalloc_objs(*cpu_buffer->subbuf_ids,
+ cpu_buffer->nr_pages + 1);
if (!cpu_buffer->subbuf_ids)
goto fail_free_reader;
@@ -2681,7 +2681,7 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, unsigned long nr_pages, int
return_ptr(cpu_buffer);
fail_free_reader:
- kfree(cpu_buffer->subbuf_ids);
+ kvfree(cpu_buffer->subbuf_ids);
free_buffer_page(cpu_buffer->reader_page);
return NULL;
@@ -2694,8 +2694,8 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
irq_work_sync(&cpu_buffer->irq_work.work);
- if (cpu_buffer->remote)
- kfree(cpu_buffer->subbuf_ids);
+ kvfree(cpu_buffer->subbuf_ids);
+ cpu_buffer->subbuf_ids = NULL;
free_buffer_page(cpu_buffer->reader_page);
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 3/4] ring-buffer: Drop redundant ring_buffer_iter::event_size
2026-09-22 7:29 [PATCH 0/4] ring-buffer: Use kvmalloc variants for big allocations Vincent Donnefort
2026-09-22 7:29 ` [PATCH 1/4] ring-buffer: Use kvzalloc_objs for user mapping arrays Vincent Donnefort
2026-09-22 7:29 ` [PATCH 2/4] ring-buffer: Use kvzalloc_objs for remote buffer subbuf_ids Vincent Donnefort
@ 2026-09-22 7:29 ` Vincent Donnefort
2026-11-04 19:07 ` Steven Rostedt
2026-09-22 7:29 ` [PATCH 4/4] ring-buffer: Use kvmalloc for ring_buffer_iter::event Vincent Donnefort
3 siblings, 1 reply; 7+ messages in thread
From: Vincent Donnefort @ 2026-09-22 7:29 UTC (permalink / raw)
To: rostedt, mhiramat, linux-trace-kernel
Cc: mathieu.desnoyers, kernel-team, linux-kernel, Vincent Donnefort
event_size contains the maximum size the iterator can read for each
event. It corresponds to the maximum capacity of a ring-buffer page.
During non-consuming read, resizing is disabled. It is therefore safe to
just use rb_subbuf_capacity(), making event_size redundant. Remove it.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
kernel/trace/ring_buffer.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 1a158a24b3c8..3129589e2d0e 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -680,7 +680,6 @@ struct ring_buffer_iter {
u64 read_stamp;
u64 page_stamp;
struct ring_buffer_event *event;
- size_t event_size;
int missed_events;
};
@@ -3558,9 +3557,11 @@ rb_iter_head_event(struct ring_buffer_iter *iter)
*/
barrier();
- if ((iter->head + length) > commit || length > iter->event_size)
+ if ((iter->head + length) > commit ||
+ length > rb_subbuf_capacity(iter->cpu_buffer->buffer)) {
/* Writer corrupted the read? */
goto reset;
+ }
memcpy(iter->event, event, length);
/*
@@ -6488,8 +6489,7 @@ ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags)
mutex_unlock(&buffer->mutex);
/* Holds the entire event: data and meta data. */
- iter->event_size = rb_page_capacity(READ_ONCE(cpu_buffer->reader_page));
- iter->event = kmalloc(iter->event_size, flags);
+ iter->event = kmalloc(rb_subbuf_capacity(buffer), flags);
if (!iter->event) {
atomic_dec(&cpu_buffer->resize_disabled);
return NULL;
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 4/4] ring-buffer: Use kvmalloc for ring_buffer_iter::event
2026-09-22 7:29 [PATCH 0/4] ring-buffer: Use kvmalloc variants for big allocations Vincent Donnefort
` (2 preceding siblings ...)
2026-09-22 7:29 ` [PATCH 3/4] ring-buffer: Drop redundant ring_buffer_iter::event_size Vincent Donnefort
@ 2026-09-22 7:29 ` Vincent Donnefort
3 siblings, 0 replies; 7+ messages in thread
From: Vincent Donnefort @ 2026-09-22 7:29 UTC (permalink / raw)
To: rostedt, mhiramat, linux-trace-kernel
Cc: mathieu.desnoyers, kernel-team, linux-kernel, Vincent Donnefort
The maximum size for an event correspond to the capacity of a single
ring buffer subbuf, which could be multiple pages, making this
contiguous allocation likely to fail with memory fragmentation
Switch it to kvmalloc() to use the vmalloc fallback under memory
pressure.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
kernel/trace/ring_buffer.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 3129589e2d0e..f03fb9ed3372 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -6467,6 +6467,7 @@ ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags)
{
struct ring_buffer_iter *iter __free(kfree) = kzalloc_obj(*iter, flags);
struct ring_buffer_per_cpu *cpu_buffer;
+ unsigned int max_event_size;
if (!iter)
return NULL;
@@ -6489,7 +6490,9 @@ ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags)
mutex_unlock(&buffer->mutex);
/* Holds the entire event: data and meta data. */
- iter->event = kmalloc(rb_subbuf_capacity(buffer), flags);
+ max_event_size = rb_subbuf_capacity(buffer);
+ iter->event = gfpflags_allow_blocking(flags) ?
+ kvmalloc(max_event_size, flags) : kmalloc(max_event_size, flags);
if (!iter->event) {
atomic_dec(&cpu_buffer->resize_disabled);
return NULL;
@@ -6520,7 +6523,7 @@ ring_buffer_read_finish(struct ring_buffer_iter *iter)
rb_check_pages(cpu_buffer);
atomic_dec(&cpu_buffer->resize_disabled);
- kfree(iter->event);
+ kvfree(iter->event);
kfree(iter);
}
EXPORT_SYMBOL_GPL(ring_buffer_read_finish);
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 3/4] ring-buffer: Drop redundant ring_buffer_iter::event_size
2026-09-22 7:29 ` [PATCH 3/4] ring-buffer: Drop redundant ring_buffer_iter::event_size Vincent Donnefort
@ 2026-11-04 19:07 ` Steven Rostedt
2026-11-05 9:21 ` Vincent Donnefort
0 siblings, 1 reply; 7+ messages in thread
From: Steven Rostedt @ 2026-11-04 19:07 UTC (permalink / raw)
To: Vincent Donnefort
Cc: mhiramat, linux-trace-kernel, mathieu.desnoyers, kernel-team,
linux-kernel
On Tue, 22 Sep 2026 08:29:43 +0100
Vincent Donnefort <vdonnefort@google.com> wrote:
> event_size contains the maximum size the iterator can read for each
> event. It corresponds to the maximum capacity of a ring-buffer page.
> During non-consuming read, resizing is disabled. It is therefore safe to
> just use rb_subbuf_capacity(), making event_size redundant. Remove it.
Hmm, I don't like the code dependency here. Yes, we disable resizing and
the event_size isn't going to change, but if in the future that is no
longer the case, then this becomes a hidden bug.
What's wrong with just having a field that keeps track of the size
allocated? It's more robust that way and doesn't have any hidden
dependencies.
-- Steve
>
> Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
> ---
> kernel/trace/ring_buffer.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> index 1a158a24b3c8..3129589e2d0e 100644
> --- a/kernel/trace/ring_buffer.c
> +++ b/kernel/trace/ring_buffer.c
> @@ -680,7 +680,6 @@ struct ring_buffer_iter {
> u64 read_stamp;
> u64 page_stamp;
> struct ring_buffer_event *event;
> - size_t event_size;
> int missed_events;
> };
>
> @@ -3558,9 +3557,11 @@ rb_iter_head_event(struct ring_buffer_iter *iter)
> */
> barrier();
>
> - if ((iter->head + length) > commit || length > iter->event_size)
> + if ((iter->head + length) > commit ||
> + length > rb_subbuf_capacity(iter->cpu_buffer->buffer)) {
> /* Writer corrupted the read? */
> goto reset;
> + }
>
> memcpy(iter->event, event, length);
> /*
> @@ -6488,8 +6489,7 @@ ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags)
> mutex_unlock(&buffer->mutex);
>
> /* Holds the entire event: data and meta data. */
> - iter->event_size = rb_page_capacity(READ_ONCE(cpu_buffer->reader_page));
> - iter->event = kmalloc(iter->event_size, flags);
> + iter->event = kmalloc(rb_subbuf_capacity(buffer), flags);
> if (!iter->event) {
> atomic_dec(&cpu_buffer->resize_disabled);
> return NULL;
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 3/4] ring-buffer: Drop redundant ring_buffer_iter::event_size
2026-11-04 19:07 ` Steven Rostedt
@ 2026-11-05 9:21 ` Vincent Donnefort
0 siblings, 0 replies; 7+ messages in thread
From: Vincent Donnefort @ 2026-11-05 9:21 UTC (permalink / raw)
To: Steven Rostedt
Cc: mhiramat, linux-trace-kernel, mathieu.desnoyers, kernel-team,
linux-kernel
On Wed, Nov 04, 2026 at 02:07:23PM -0500, Steven Rostedt wrote:
> On Tue, 22 Sep 2026 08:29:43 +0100
> Vincent Donnefort <vdonnefort@google.com> wrote:
>
> > event_size contains the maximum size the iterator can read for each
> > event. It corresponds to the maximum capacity of a ring-buffer page.
> > During non-consuming read, resizing is disabled. It is therefore safe to
> > just use rb_subbuf_capacity(), making event_size redundant. Remove it.
>
> Hmm, I don't like the code dependency here. Yes, we disable resizing and
> the event_size isn't going to change, but if in the future that is no
> longer the case, then this becomes a hidden bug.
>
> What's wrong with just having a field that keeps track of the size
> allocated? It's more robust that way and doesn't have any hidden
> dependencies.
>
> -- Steve
Ack. It was just an attempt at cleaning up the struct, but indeed this makes an
additional assumption we didn't have before.
I can drop this patch.
--
Vincent
>
>
> >
> > Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
> > ---
> > kernel/trace/ring_buffer.c | 8 ++++----
> > 1 file changed, 4 insertions(+), 4 deletions(-)
> >
> > diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> > index 1a158a24b3c8..3129589e2d0e 100644
> > --- a/kernel/trace/ring_buffer.c
> > +++ b/kernel/trace/ring_buffer.c
> > @@ -680,7 +680,6 @@ struct ring_buffer_iter {
> > u64 read_stamp;
> > u64 page_stamp;
> > struct ring_buffer_event *event;
> > - size_t event_size;
> > int missed_events;
> > };
> >
> > @@ -3558,9 +3557,11 @@ rb_iter_head_event(struct ring_buffer_iter *iter)
> > */
> > barrier();
> >
> > - if ((iter->head + length) > commit || length > iter->event_size)
> > + if ((iter->head + length) > commit ||
> > + length > rb_subbuf_capacity(iter->cpu_buffer->buffer)) {
> > /* Writer corrupted the read? */
> > goto reset;
> > + }
> >
> > memcpy(iter->event, event, length);
> > /*
> > @@ -6488,8 +6489,7 @@ ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags)
> > mutex_unlock(&buffer->mutex);
> >
> > /* Holds the entire event: data and meta data. */
> > - iter->event_size = rb_page_capacity(READ_ONCE(cpu_buffer->reader_page));
> > - iter->event = kmalloc(iter->event_size, flags);
> > + iter->event = kmalloc(rb_subbuf_capacity(buffer), flags);
> > if (!iter->event) {
> > atomic_dec(&cpu_buffer->resize_disabled);
> > return NULL;
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-11-05 9:21 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-22 7:29 [PATCH 0/4] ring-buffer: Use kvmalloc variants for big allocations Vincent Donnefort
2026-09-22 7:29 ` [PATCH 1/4] ring-buffer: Use kvzalloc_objs for user mapping arrays Vincent Donnefort
2026-09-22 7:29 ` [PATCH 2/4] ring-buffer: Use kvzalloc_objs for remote buffer subbuf_ids Vincent Donnefort
2026-09-22 7:29 ` [PATCH 3/4] ring-buffer: Drop redundant ring_buffer_iter::event_size Vincent Donnefort
2026-11-04 19:07 ` Steven Rostedt
2026-11-05 9:21 ` Vincent Donnefort
2026-09-22 7:29 ` [PATCH 4/4] ring-buffer: Use kvmalloc for ring_buffer_iter::event Vincent Donnefort
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®