Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'trace-ringbuffer-v6.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull ring-buffer fixes from Steven Rostedt:

- Fix ref counter of buffers assigned at boot up

A tracing instance can be created from the kernel command line. If it
maps to memory, it is considered permanent and should not be deleted,
or bad things can happen. If it is not mapped to memory, then the
user is fine to delete it via rmdir from the instances directory. But
the ref counts assumed 0 was free to remove and greater than zero was
not. But this was not the case. When an instance is created, it
should have the reference of 1, and if it should not be removed, it
must be greater than 1. The boot up code set normal instances with a
ref count of 0, which could get removed if something accessed it and
then released it. And memory mapped instances had a ref count of 1
which meant it could be deleted, and bad things happen. Keep normal
instances ref count as 1, and set memory mapped instances ref count
to 2.

- Protect sub buffer size (order) updates from other modifications

When a ring buffer is changing the size of its sub-buffers, no other
operations should be performed on the ring buffer. That includes
reading it. But the locking only grabbed the buffer->mutex that keeps
some operations from touching the ring buffer. It also must hold the
cpu_buffer->reader_lock as well when updates happen as other paths
use that to do some operations on the ring buffer.

* tag 'trace-ringbuffer-v6.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
ring-buffer: Fix reader locking when changing the sub buffer order
ring-buffer: Fix refcount setting of boot mapped buffers

+29 -21
+26 -18
kernel/trace/ring_buffer.c
··· 6728 6728 } 6729 6729 6730 6730 for_each_buffer_cpu(buffer, cpu) { 6731 + struct buffer_data_page *old_free_data_page; 6732 + struct list_head old_pages; 6733 + unsigned long flags; 6731 6734 6732 6735 if (!cpumask_test_cpu(cpu, buffer->cpumask)) 6733 6736 continue; 6734 6737 6735 6738 cpu_buffer = buffer->buffers[cpu]; 6736 6739 6740 + raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags); 6741 + 6737 6742 /* Clear the head bit to make the link list normal to read */ 6738 6743 rb_head_page_deactivate(cpu_buffer); 6739 6744 6740 - /* Now walk the list and free all the old sub buffers */ 6741 - list_for_each_entry_safe(bpage, tmp, cpu_buffer->pages, list) { 6742 - list_del_init(&bpage->list); 6743 - free_buffer_page(bpage); 6744 - } 6745 - /* The above loop stopped an the last page needing to be freed */ 6746 - bpage = list_entry(cpu_buffer->pages, struct buffer_page, list); 6747 - free_buffer_page(bpage); 6748 - 6749 - /* Free the current reader page */ 6750 - free_buffer_page(cpu_buffer->reader_page); 6745 + /* 6746 + * Collect buffers from the cpu_buffer pages list and the 6747 + * reader_page on old_pages, so they can be freed later when not 6748 + * under a spinlock. The pages list is a linked list with no 6749 + * head, adding old_pages turns it into a regular list with 6750 + * old_pages being the head. 6751 + */ 6752 + list_add(&old_pages, cpu_buffer->pages); 6753 + list_add(&cpu_buffer->reader_page->list, &old_pages); 6751 6754 6752 6755 /* One page was allocated for the reader page */ 6753 6756 cpu_buffer->reader_page = list_entry(cpu_buffer->new_pages.next, 6754 6757 struct buffer_page, list); 6755 6758 list_del_init(&cpu_buffer->reader_page->list); 6756 6759 6757 - /* The cpu_buffer pages are a link list with no head */ 6760 + /* Install the new pages, remove the head from the list */ 6758 6761 cpu_buffer->pages = cpu_buffer->new_pages.next; 6759 - cpu_buffer->new_pages.next->prev = cpu_buffer->new_pages.prev; 6760 - cpu_buffer->new_pages.prev->next = cpu_buffer->new_pages.next; 6761 - 6762 - /* Clear the new_pages list */ 6763 - INIT_LIST_HEAD(&cpu_buffer->new_pages); 6762 + list_del_init(&cpu_buffer->new_pages); 6764 6763 6765 6764 cpu_buffer->head_page 6766 6765 = list_entry(cpu_buffer->pages, struct buffer_page, list); ··· 6768 6769 cpu_buffer->nr_pages = cpu_buffer->nr_pages_to_update; 6769 6770 cpu_buffer->nr_pages_to_update = 0; 6770 6771 6771 - free_pages((unsigned long)cpu_buffer->free_page, old_order); 6772 + old_free_data_page = cpu_buffer->free_page; 6772 6773 cpu_buffer->free_page = NULL; 6773 6774 6774 6775 rb_head_page_activate(cpu_buffer); 6776 + 6777 + raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); 6778 + 6779 + /* Free old sub buffers */ 6780 + list_for_each_entry_safe(bpage, tmp, &old_pages, list) { 6781 + list_del_init(&bpage->list); 6782 + free_buffer_page(bpage); 6783 + } 6784 + free_pages((unsigned long)old_free_data_page, old_order); 6775 6785 6776 6786 rb_check_pages(cpu_buffer); 6777 6787 }
+3 -3
kernel/trace/trace.c
··· 10621 10621 * cannot be deleted by user space, so keep the reference 10622 10622 * to it. 10623 10623 */ 10624 - if (start) 10624 + if (start) { 10625 10625 tr->flags |= TRACE_ARRAY_FL_BOOT; 10626 - else 10627 - trace_array_put(tr); 10626 + tr->ref++; 10627 + } 10628 10628 10629 10629 while ((tok = strsep(&curr_str, ","))) { 10630 10630 early_enable_events(tr, tok, true);