From: Vincent Donnefort <vdonnefort@google.com>
To: rostedt@goodmis.org, mhiramat@kernel.org,
linux-trace-kernel@vger.kernel.org
Cc: mathieu.desnoyers@efficios.com, kernel-team@android.com,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v6 2/2] ring-buffer: Improve nr_pages type
Date: Mon, 17 Aug 2026 11:27:01 +0100 [thread overview]
Message-ID: <aoLh9djyr-3PFSvj@google.com> (raw)
In-Reply-To: <20260814154823.755406-3-vdonnefort@google.com>
On Fri, Aug 14, 2026 at 04:48:23PM +0100, Vincent Donnefort wrote:
> If ring_buffer_per_cpu::nr_pages is defined as unsigned long, it is
> capped to 32-bits in a few places, limiting the operations possible on a
> very large buffer.
>
> Make sure nr_pages is never capped to 32-bits (that includes nr_subbufs)
> and reject a value over 32-bits for the user-mapped, persistent buffer
> and remote buffer cases where the limiting factor is the shared
> meta-data member for the number of pages/subbufs.
>
> While at it, make sure subbuf_size is 'unsigned int'.
>
> Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
> ---
> kernel/trace/ring_buffer.c | 46 ++++++++++++++++++++++++--------------
> 1 file changed, 29 insertions(+), 17 deletions(-)
>
> diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> index ec13779922ff..ec127e2ad052 100644
> --- a/kernel/trace/ring_buffer.c
> +++ b/kernel/trace/ring_buffer.c
> @@ -1669,7 +1669,7 @@ static void rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer)
> * This is used to help find the next per cpu subbuffer within a mapped range.
> */
> static unsigned long
> -rb_range_align_subbuf(unsigned long addr, int subbuf_size, int nr_subbufs)
> +rb_range_align_subbuf(unsigned long addr, unsigned int subbuf_size, unsigned long nr_subbufs)
> {
> addr += sizeof(struct ring_buffer_cpu_meta) +
> sizeof(int) * nr_subbufs;
> @@ -1679,13 +1679,12 @@ rb_range_align_subbuf(unsigned long addr, int subbuf_size, int nr_subbufs)
> /*
> * Return the ring_buffer_meta for a given @cpu.
> */
> -static void *rb_range_meta(struct trace_buffer *buffer, int nr_pages, int cpu)
> +static void *rb_range_meta(struct trace_buffer *buffer, unsigned long nr_pages, int cpu)
> {
> - int subbuf_size = rb_subbuf_size(buffer);
> + unsigned int subbuf_size = rb_subbuf_size(buffer);
> struct ring_buffer_cpu_meta *meta;
> struct ring_buffer_meta *bmeta;
> - unsigned long ptr;
> - int nr_subbufs;
> + unsigned long ptr, nr_subbufs;
>
> bmeta = buffer->meta;
> if (!bmeta)
> @@ -1731,7 +1730,7 @@ static void *rb_range_meta(struct trace_buffer *buffer, int nr_pages, int cpu)
> /* Return the start of subbufs given the meta pointer */
> static void *rb_subbufs_from_meta(struct ring_buffer_cpu_meta *meta)
> {
> - int subbuf_size = meta->subbuf_size;
> + unsigned int subbuf_size = meta->subbuf_size;
> unsigned long ptr;
>
> ptr = (unsigned long)meta;
> @@ -1746,8 +1745,8 @@ static void *rb_subbufs_from_meta(struct ring_buffer_cpu_meta *meta)
> static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, int idx)
> {
> struct ring_buffer_cpu_meta *meta;
> + unsigned int subbuf_size;
> unsigned long ptr;
> - int subbuf_size;
>
> meta = rb_range_meta(cpu_buffer->buffer, 0, cpu_buffer->cpu);
> if (!meta)
> @@ -1840,10 +1839,10 @@ static bool rb_meta_init(struct trace_buffer *buffer, int scratch_size)
> * must be the same.
> */
> static bool rb_cpu_meta_valid(struct ring_buffer_cpu_meta *meta, int cpu,
> - struct trace_buffer *buffer, int nr_pages,
> + struct trace_buffer *buffer, unsigned long nr_pages,
> unsigned long *subbuf_mask)
> {
> - int subbuf_size = PAGE_SIZE;
> + unsigned int subbuf_size = PAGE_SIZE;
> unsigned long buffers_start;
> unsigned long buffers_end;
> int i;
> @@ -2231,7 +2230,8 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
> }
> }
>
> -static void rb_range_meta_init(struct trace_buffer *buffer, int nr_pages, int scratch_size)
> +static void rb_range_meta_init(struct trace_buffer *buffer,
> + unsigned long nr_pages, int scratch_size)
> {
> struct ring_buffer_cpu_meta *meta;
> unsigned long *subbuf_mask;
> @@ -2417,7 +2417,7 @@ static void *ring_buffer_desc_page(struct ring_buffer_desc *desc, unsigned int p
> }
>
> static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
> - long nr_pages, struct list_head *pages)
> + unsigned long nr_pages, struct list_head *pages)
> {
> struct trace_buffer *buffer = cpu_buffer->buffer;
> struct ring_buffer_cpu_meta *meta = NULL;
> @@ -2545,7 +2545,7 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
> }
>
> static struct ring_buffer_per_cpu *
> -rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
> +rb_allocate_cpu_buffer(struct trace_buffer *buffer, unsigned long nr_pages, int cpu)
> {
> struct ring_buffer_per_cpu *cpu_buffer __free(kfree) =
> alloc_cpu_buffer(cpu);
> @@ -2702,8 +2702,8 @@ static void rb_test_inject_invalid_pages(struct trace_buffer *buffer)
> struct ring_buffer_cpu_meta *meta;
> struct buffer_data_page *dpage;
> unsigned long entry_bytes = 0;
> + unsigned int subbuf_size;
> unsigned long ptr;
> - int subbuf_size;
> int invalid = 0;
> int cpu;
> int i;
> @@ -2773,8 +2773,8 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
> struct ring_buffer_remote *remote)
> {
> struct trace_buffer *buffer __free(kfree) = NULL;
> - long nr_pages;
> - int subbuf_size;
> + unsigned int subbuf_size;
> + unsigned long nr_pages;
> int bsize;
> int cpu;
> int ret;
> @@ -2837,6 +2837,10 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
> */
> nr_pages = (size - sizeof(struct ring_buffer_cpu_meta)) /
> (subbuf_size + sizeof(int));
> +
> + /* limited by ring_buffer_cpu_meta::nr_subbufs */
> + if (nr_pages > U32_MAX - 1)
> + goto fail_free_buffers;
> /* Need at least two pages plus the reader page */
> if (nr_pages < 3)
> goto fail_free_buffers;
> @@ -2869,6 +2873,10 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
> /* The writer is remote. This ring-buffer is read-only */
> atomic_inc(&buffer->record_disabled);
> nr_pages = desc->nr_page_va - 1;
> +
> + /* limited by ring_buffer_desc::nr_page_va */
> + if (nr_pages > U32_MAX - 1)
> + goto fail_free_buffers;
> if (nr_pages < 2)
> goto fail_free_buffers;
> } else {
> @@ -7421,8 +7429,8 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
> struct ring_buffer_per_cpu *cpu_buffer;
> struct buffer_page *bpage, *tmp;
> unsigned int old_capacity;
> + unsigned long nr_pages;
> int old_order;
> - int nr_pages;
> int psize;
> int err;
> int cpu;
> @@ -7604,7 +7612,7 @@ static void rb_setup_ids_meta_page(struct ring_buffer_per_cpu *cpu_buffer,
> struct buffer_page **subbuf_ids)
> {
> struct trace_buffer_meta *meta = cpu_buffer->meta_page;
> - unsigned int nr_subbufs = cpu_buffer->nr_pages + 1;
> + unsigned long nr_subbufs = cpu_buffer->nr_pages + 1;
> struct buffer_page *first_subbuf, *subbuf;
> int cnt = 0;
> int id = 0;
> @@ -7834,6 +7842,10 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
> /* prevent another thread from changing buffer/sub-buffer sizes */
> guard(mutex)(&buffer->mutex);
>
> + /* limited by trace_buffer_meta::nr_subbufs */
And actually I have realised the limiting factor is bpage::id which is only
30-bits.
> + if (cpu_buffer->nr_pages > U32_MAX - 1)
> + return -E2BIG;
> +
> err = rb_alloc_meta_page(cpu_buffer);
> if (err)
> return err;
> --
> 2.55.0.691.gc56d675ccc-goog
>
--
Vincent
prev parent reply other threads:[~2026-08-17 10:27 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-14 15:48 [PATCH v6 0/2] ring-buffer: Fixes for subbuf resizing and persistent buffers Vincent Donnefort
2026-08-14 15:48 ` [PATCH v6 1/2] tracing: Fix subbuf resize races with trace_pipe_raw readers Vincent Donnefort
2026-08-14 16:01 ` sashiko-bot
2026-08-17 8:59 ` Vincent Donnefort
2026-08-14 15:48 ` [PATCH v6 2/2] ring-buffer: Improve nr_pages type Vincent Donnefort
2026-08-14 15:59 ` sashiko-bot
2026-08-17 10:14 ` Vincent Donnefort
2026-08-17 10:27 ` Vincent Donnefort [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aoLh9djyr-3PFSvj@google.com \
--to=vdonnefort@google.com \
--cc=kernel-team@android.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=mhiramat@kernel.org \
--cc=rostedt@goodmis.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox