Skip to content

Commit 7c339fb

Browse files
Tze-nan Wurostedt
authored andcommitted
ring-buffer: Ensure proper resetting of atomic variables in ring_buffer_reset_online_cpus
In ring_buffer_reset_online_cpus, the buffer_size_kb write operation may permanently fail if the cpu_online_mask changes between two for_each_online_buffer_cpu loops. The number of increases and decreases on both cpu_buffer->resize_disabled and cpu_buffer->record_disabled may be inconsistent, causing some CPUs to have non-zero values for these atomic variables after the function returns. This issue can be reproduced by "echo 0 > trace" while hotplugging cpu. After reproducing success, we can find out buffer_size_kb will not be functional anymore. To prevent leaving 'resize_disabled' and 'record_disabled' non-zero after ring_buffer_reset_online_cpus returns, we ensure that each atomic variable has been set up before atomic_sub() to it. Link: https://lore.kernel.org/linux-trace-kernel/20230426062027.17451-1-Tze-nan.Wu@mediatek.com Cc: stable@vger.kernel.org Cc: <mhiramat@kernel.org> Cc: npiggin@gmail.com Fixes: b23d7a5 ("ring-buffer: speed up buffer resets by avoiding synchronize_rcu for each CPU") Reviewed-by: Cheng-Jui Wang <cheng-jui.wang@mediatek.com> Signed-off-by: Tze-nan Wu <Tze-nan.Wu@mediatek.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent fa359d0 commit 7c339fb

File tree

1 file changed

+13
-3
lines changed

1 file changed

+13
-3
lines changed

kernel/trace/ring_buffer.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5326,6 +5326,9 @@ void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu)
53265326
}
53275327
EXPORT_SYMBOL_GPL(ring_buffer_reset_cpu);
53285328

5329+
/* Flag to ensure proper resetting of atomic variables */
5330+
#define RESET_BIT (1 << 30)
5331+
53295332
/**
53305333
* ring_buffer_reset_online_cpus - reset a ring buffer per CPU buffer
53315334
* @buffer: The ring buffer to reset a per cpu buffer of
@@ -5342,20 +5345,27 @@ void ring_buffer_reset_online_cpus(struct trace_buffer *buffer)
53425345
for_each_online_buffer_cpu(buffer, cpu) {
53435346
cpu_buffer = buffer->buffers[cpu];
53445347

5345-
atomic_inc(&cpu_buffer->resize_disabled);
5348+
atomic_add(RESET_BIT, &cpu_buffer->resize_disabled);
53465349
atomic_inc(&cpu_buffer->record_disabled);
53475350
}
53485351

53495352
/* Make sure all commits have finished */
53505353
synchronize_rcu();
53515354

5352-
for_each_online_buffer_cpu(buffer, cpu) {
5355+
for_each_buffer_cpu(buffer, cpu) {
53535356
cpu_buffer = buffer->buffers[cpu];
53545357

5358+
/*
5359+
* If a CPU came online during the synchronize_rcu(), then
5360+
* ignore it.
5361+
*/
5362+
if (!(atomic_read(&cpu_buffer->resize_disabled) & RESET_BIT))
5363+
continue;
5364+
53555365
reset_disabled_cpu_buffer(cpu_buffer);
53565366

53575367
atomic_dec(&cpu_buffer->record_disabled);
5358-
atomic_dec(&cpu_buffer->resize_disabled);
5368+
atomic_sub(RESET_BIT, &cpu_buffer->resize_disabled);
53595369
}
53605370

53615371
mutex_unlock(&buffer->mutex);

0 commit comments

Comments
 (0)