Write to buffer_size_kb can permanently fail due to cpu_online_mask changed between two for_each_online_buffer_cpu loops. The number of increasing and decreasing on cpu_buffer->resize_disable may be inconsistent, leading that the resize_disabled in some CPUs becoming none zero after ring_buffer_reset_online_cpus return.
This issue can be reproduced by "echo 0 > trace" and hotplug cpu at the same time. After reproducing success, we can find out buffer_size_kb will not be functional anymore.
This patch uses cpus_read_lock() to prevent cpu_online_mask being changed between two different "for_each_online_buffer_cpu".
Changes in v2: Use cpus_read_lock() instead of copying cpu_online_mask at the entry of function
Link: https://lore.kernel.org/lkml/20230408052226.25268-1-Tze-nan.Wu@mediatek.com/
Cc: stable@vger.kernel.org Signed-off-by: Tze-nan Wu Tze-nan.Wu@mediatek.com --- kernel/trace/ring_buffer.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 76a2d91eecad..44d833252fb0 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -5357,6 +5357,7 @@ void ring_buffer_reset_online_cpus(struct trace_buffer *buffer)
/* prevent another thread from changing buffer sizes */ mutex_lock(&buffer->mutex); + cpus_read_lock();
for_each_online_buffer_cpu(buffer, cpu) { cpu_buffer = buffer->buffers[cpu]; @@ -5377,6 +5378,7 @@ void ring_buffer_reset_online_cpus(struct trace_buffer *buffer) atomic_dec(&cpu_buffer->resize_disabled); }
+ cpus_read_unlock(); mutex_unlock(&buffer->mutex); }