mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
ring-buffer: Make cpu_buffer::free_page a buffer_data_read_page
Discarding a cached reader page after a concurrent ring buffer resize
uses the new global subbuf_order for the free_pages() call. This
mismatched order may crashes the kernel or leaks memory because the cached
page was allocated under the old size.
Save the actual free_page order alongside the page address to ensure we
always refer to the correct value and do not rely on the potentially
stalled cpu_buffer->subbuf_order value. The simplest is to make
free_page a buffer_data_read_page which already covers exactly what we
need: a page address and a page order.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260813131152.3589632-4-vdonnefort@google.com
Fixes: 8e7b58c27b ("ring-buffer: Just update the subbuffers when changing their allocation order")
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
parent
24974bd0da
commit
7a1fb95de5
|
|
@ -507,7 +507,7 @@ struct ring_buffer_per_cpu {
|
|||
raw_spinlock_t reader_lock; /* serialize readers */
|
||||
arch_spinlock_t lock;
|
||||
struct lock_class_key lock_key;
|
||||
struct buffer_data_page *free_page;
|
||||
struct buffer_data_read_page free_page;
|
||||
unsigned long nr_pages;
|
||||
unsigned int current_context;
|
||||
struct list_head *pages;
|
||||
|
|
@ -2631,7 +2631,7 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
|
|||
free_buffer_page(bpage);
|
||||
}
|
||||
|
||||
free_pages((unsigned long)cpu_buffer->free_page, cpu_buffer->buffer->subbuf_order);
|
||||
free_pages((unsigned long)cpu_buffer->free_page.data, cpu_buffer->free_page.order);
|
||||
|
||||
kfree(cpu_buffer);
|
||||
}
|
||||
|
|
@ -6962,9 +6962,9 @@ ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu)
|
|||
local_irq_save(flags);
|
||||
arch_spin_lock(&cpu_buffer->lock);
|
||||
|
||||
if (cpu_buffer->free_page) {
|
||||
bpage->data = cpu_buffer->free_page;
|
||||
cpu_buffer->free_page = NULL;
|
||||
if (cpu_buffer->free_page.data) {
|
||||
*bpage = cpu_buffer->free_page;
|
||||
cpu_buffer->free_page.data = NULL;
|
||||
}
|
||||
|
||||
arch_spin_unlock(&cpu_buffer->lock);
|
||||
|
|
@ -7016,8 +7016,8 @@ void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu,
|
|||
local_irq_save(flags);
|
||||
arch_spin_lock(&cpu_buffer->lock);
|
||||
|
||||
if (!cpu_buffer->free_page) {
|
||||
cpu_buffer->free_page = dpage;
|
||||
if (!cpu_buffer->free_page.data) {
|
||||
cpu_buffer->free_page = *data_page;
|
||||
dpage = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -7390,7 +7390,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
|
|||
}
|
||||
|
||||
for_each_buffer_cpu(buffer, cpu) {
|
||||
struct buffer_data_page *old_free_data_page;
|
||||
struct buffer_data_read_page old_free_data_page;
|
||||
struct list_head old_pages;
|
||||
unsigned long flags;
|
||||
|
||||
|
|
@ -7433,7 +7433,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
|
|||
|
||||
arch_spin_lock(&cpu_buffer->lock);
|
||||
old_free_data_page = cpu_buffer->free_page;
|
||||
cpu_buffer->free_page = NULL;
|
||||
cpu_buffer->free_page.data = NULL;
|
||||
arch_spin_unlock(&cpu_buffer->lock);
|
||||
|
||||
rb_head_page_activate(cpu_buffer);
|
||||
|
|
@ -7445,7 +7445,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
|
|||
list_del_init(&bpage->list);
|
||||
free_buffer_page(bpage);
|
||||
}
|
||||
free_pages((unsigned long)old_free_data_page, old_order);
|
||||
free_pages((unsigned long)old_free_data_page.data, old_free_data_page.order);
|
||||
|
||||
rb_check_pages(cpu_buffer);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user