• Steven Rostedt (Google)'s avatar
    ring-buffer: Just update the subbuffers when changing their allocation order · 8e7b58c2
    Steven Rostedt (Google) authored
    The ring_buffer_subbuf_order_set() was creating ring_buffer_per_cpu
    cpu_buffers with the new subbuffers with the updated order, and if they
    all successfully were created, then they the ring_buffer's per_cpu buffers
    would be freed and replaced by them.
    
    The problem is that the freed per_cpu buffers contains state that would be
    lost. Running the following commands:
    
    1. # echo 3 > /sys/kernel/tracing/buffer_subbuf_order
    2. # echo 0 > /sys/kernel/tracing/tracing_cpumask
    3. # echo 1 > /sys/kernel/tracing/snapshot
    4. # echo ff > /sys/kernel/tracing/tracing_cpumask
    5. # echo test > /sys/kernel/tracing/trace_marker
    
    Would result in:
    
     -bash: echo: write error: Bad file descriptor
    
    That's because the state of the per_cpu buffers of the snapshot buffer is
    lost when the order is changed (the order of a freed snapshot buffer goes
    to 0 to save memory, and when the snapshot buffer is allocated again, it
    goes back to what the main buffer is).
    
    In operation 2, the snapshot buffers were set to "disable" (as all the
    ring buffers CPUs were disabled).
    
    In operation 3, the snapshot is allocated and a call to
    ring_buffer_subbuf_order_set() replaced the per_cpu buffers losing the
    "record_disable" count.
    
    When it was enabled again, the atomic_dec(&cpu_buffer->record_disable) was
    decrementing a zero, setting it to -1. Writing 1 into the snapshot would
    swap the snapshot buffer with the main buffer, so now the main buffer is
    "disabled", and nothing can write to the ring buffer anymore.
    
    Instead of creating new per_cpu buffers and losing the state of the old
    buffers, basically do what the resize does and just allocate new subbuf
    pages into the new_pages link list of the per_cpu buffer and if they all
    succeed, then replace the old sub buffers with the new ones. This keeps
    the per_cpu buffer descriptor in tact and by doing so, keeps its state.
    
    Link: https://lore.kernel.org/linux-trace-kernel/20231219185630.944104939@goodmis.org
    
    Cc: Masami Hiramatsu <mhiramat@kernel.org>
    Cc: Mark Rutland <mark.rutland@arm.com>
    Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
    Cc: Andrew Morton <akpm@linux-foundation.org>
    Cc: Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
    Cc: Vincent Donnefort <vdonnefort@google.com>
    Cc: Kent Overstreet <kent.overstreet@gmail.com>
    Fixes: f9b94daa ("ring-buffer: Set new size of the ring buffer sub page")
    Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
    8e7b58c2
ring_buffer.c 169 KB