]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ring-buffer: Flush and stop persistent ring buffer on panic
authorMasami Hiramatsu (Google) <mhiramat@kernel.org>
Thu, 30 Apr 2026 03:28:16 +0000 (12:28 +0900)
committerSteven Rostedt <rostedt@goodmis.org>
Thu, 21 May 2026 12:20:58 +0000 (08:20 -0400)
On real hardware, panic and machine reboot may not flush hardware cache
to memory. This means the persistent ring buffer, which relies on a
coherent state of memory, may not have its events written to the buffer
and they may be lost. Moreover, there may be inconsistency with the
counters which are used for validation of the integrity of the
persistent ring buffer which may cause all data to be discarded.

To avoid this issue, stop recording of the ring buffer on panic and
flush the cache of the ring buffer's memory.

Fixes: e645535a954a ("tracing: Add option to use memmapped memory for trace boot instance")
Cc: stable@vger.kernel.org
Cc: Will Deacon <will@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Ian Rogers <irogers@google.com>
Link: https://patch.msgid.link/177751969602.2136606.12031934362587643488.stgit@mhiramat.tok.corp.google.com
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
23 files changed:
arch/alpha/include/asm/Kbuild
arch/arc/include/asm/Kbuild
arch/arm/include/asm/Kbuild
arch/arm64/include/asm/ring_buffer.h [new file with mode: 0644]
arch/csky/include/asm/Kbuild
arch/hexagon/include/asm/Kbuild
arch/loongarch/include/asm/Kbuild
arch/m68k/include/asm/Kbuild
arch/microblaze/include/asm/Kbuild
arch/mips/include/asm/Kbuild
arch/nios2/include/asm/Kbuild
arch/openrisc/include/asm/Kbuild
arch/parisc/include/asm/Kbuild
arch/powerpc/include/asm/Kbuild
arch/riscv/include/asm/Kbuild
arch/s390/include/asm/Kbuild
arch/sh/include/asm/Kbuild
arch/sparc/include/asm/Kbuild
arch/um/include/asm/Kbuild
arch/x86/include/asm/Kbuild
arch/xtensa/include/asm/Kbuild
include/asm-generic/ring_buffer.h [new file with mode: 0644]
kernel/trace/ring_buffer.c

index 483965c5a4de2d3015a49e21e5b95716131b8fe7..b154b4e3dfa86e06b4be27a8dae40e1ce15c16e8 100644 (file)
@@ -5,4 +5,5 @@ generic-y += agp.h
 generic-y += asm-offsets.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
+generic-y += ring_buffer.h
 generic-y += text-patching.h
index 4c69522e0328ee87ae2576ebf9f63b9434d13515..483caacc69884496abd61c58c7b81e16c8deba46 100644 (file)
@@ -5,5 +5,6 @@ generic-y += extable.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
 generic-y += parport.h
+generic-y += ring_buffer.h
 generic-y += user.h
 generic-y += text-patching.h
index 03657ff8fbe3d202563184b8902aa181e7474a5e..decad5f2c826faf13bc9ed5fd6fefbf26d261aea 100644 (file)
@@ -3,6 +3,7 @@ generic-y += early_ioremap.h
 generic-y += extable.h
 generic-y += flat.h
 generic-y += parport.h
+generic-y += ring_buffer.h
 
 generated-y += mach-types.h
 generated-y += unistd-nr.h
diff --git a/arch/arm64/include/asm/ring_buffer.h b/arch/arm64/include/asm/ring_buffer.h
new file mode 100644 (file)
index 0000000..62316c4
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_ARM64_RING_BUFFER_H
+#define _ASM_ARM64_RING_BUFFER_H
+
+#include <asm/cacheflush.h>
+
+/* Flush D-cache on persistent ring buffer */
+#define arch_ring_buffer_flush_range(start, end)       dcache_clean_pop(start, end)
+
+#endif /* _ASM_ARM64_RING_BUFFER_H */
index 3a5c7f6e5aacbe85978b5aa09ee1846d5a73a7eb..7dca0c6cdc848af5a9107e7f62694dfd07f4a19a 100644 (file)
@@ -9,6 +9,7 @@ generic-y += qrwlock.h
 generic-y += qrwlock_types.h
 generic-y += qspinlock.h
 generic-y += parport.h
+generic-y += ring_buffer.h
 generic-y += user.h
 generic-y += vmlinux.lds.h
 generic-y += text-patching.h
index 1efa1e993d4b9a7c7582d7415825abcb62a2e191..0f887d4238edd3867fc26fb98786fc8459a9db74 100644 (file)
@@ -5,4 +5,5 @@ generic-y += extable.h
 generic-y += iomap.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
+generic-y += ring_buffer.h
 generic-y += text-patching.h
index 9034b583a88a692874b85ebc4a90f40909ec7f57..7e92957baf6a0b9ec17f9ce165bc4a509ba2c678 100644 (file)
@@ -10,5 +10,6 @@ generic-y += qrwlock.h
 generic-y += user.h
 generic-y += ioctl.h
 generic-y += mmzone.h
+generic-y += ring_buffer.h
 generic-y += statfs.h
 generic-y += text-patching.h
index b282e0dd8dc10e4b4d5e1dbd6c735b56b29ee595..62543bf305ff1aa88440eb512030a9c11daf08a4 100644 (file)
@@ -3,5 +3,6 @@ generated-y += syscall_table.h
 generic-y += extable.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
+generic-y += ring_buffer.h
 generic-y += spinlock.h
 generic-y += text-patching.h
index 7178f990e8b3d1353c7e684eca5727d4b6198f27..0030309b47ad89e232fd9174ddd979a340b5e3e5 100644 (file)
@@ -5,6 +5,7 @@ generic-y += extable.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
 generic-y += parport.h
+generic-y += ring_buffer.h
 generic-y += syscalls.h
 generic-y += tlb.h
 generic-y += user.h
index 684569b2ecd6b50e109c969ef4a3283ec8048d63..9771c3d85074ce5414ab7f44c6e35db01bc1ee73 100644 (file)
@@ -12,5 +12,6 @@ generic-y += mcs_spinlock.h
 generic-y += parport.h
 generic-y += qrwlock.h
 generic-y += qspinlock.h
+generic-y += ring_buffer.h
 generic-y += user.h
 generic-y += text-patching.h
index 28004301c236f7a47e45c057326ba4035238254d..0a25309644133e385d697da53f1f598b069de050 100644 (file)
@@ -5,6 +5,7 @@ generic-y += cmpxchg.h
 generic-y += extable.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
+generic-y += ring_buffer.h
 generic-y += spinlock.h
 generic-y += user.h
 generic-y += text-patching.h
index cef49d60d74c0f46f01cf46cc35e1e52404185f3..8aa34621702deae719ffbc67f5c367bb33f53da8 100644 (file)
@@ -8,4 +8,5 @@ generic-y += spinlock_types.h
 generic-y += spinlock.h
 generic-y += qrwlock_types.h
 generic-y += qrwlock.h
+generic-y += ring_buffer.h
 generic-y += user.h
index 4fb596d94c8932dd1e12a765a21af5b5099fbafd..d48d158f7241242dc45efe6eb3dce00392d5f36f 100644 (file)
@@ -4,4 +4,5 @@ generated-y += syscall_table_64.h
 generic-y += agp.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
+generic-y += ring_buffer.h
 generic-y += user.h
index 2e23533b67e30ab25908f8d3c9de77dc6f08bdf3..805b5aeebb6f3ac66e261c2c32d3afabcf1ea982 100644 (file)
@@ -5,4 +5,5 @@ generated-y += syscall_table_spu.h
 generic-y += agp.h
 generic-y += mcs_spinlock.h
 generic-y += qrwlock.h
+generic-y += ring_buffer.h
 generic-y += early_ioremap.h
index bd5fc940329534f45439d975498bcb1fb86444ac..7721b63642f413b682db0457b5a4188c237de6d5 100644 (file)
@@ -14,5 +14,6 @@ generic-y += ticket_spinlock.h
 generic-y += qrwlock.h
 generic-y += qrwlock_types.h
 generic-y += qspinlock.h
+generic-y += ring_buffer.h
 generic-y += user.h
 generic-y += vmlinux.lds.h
index 80bad7de7a04a6872089ae3d3c997855a3a8f2e9..0c1fc47c3ba0a4919f9b14942389b124aa1473a5 100644 (file)
@@ -7,3 +7,4 @@ generated-y += unistd_nr.h
 generic-y += asm-offsets.h
 generic-y += mcs_spinlock.h
 generic-y += mmzone.h
+generic-y += ring_buffer.h
index 4d3f10ed827581f8b8603b3b1a273de7f34eca67..f0403d3ee8ab8eb2bd390cef73a8f75eade5d1b6 100644 (file)
@@ -3,4 +3,5 @@ generated-y += syscall_table.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
 generic-y += parport.h
+generic-y += ring_buffer.h
 generic-y += text-patching.h
index 17ee8a273aa6b4112818006630d8e0b1cf58fd18..49c6bb326b75befd1538bd103938ecf35931232e 100644 (file)
@@ -4,4 +4,5 @@ generated-y += syscall_table_64.h
 generic-y += agp.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
+generic-y += ring_buffer.h
 generic-y += text-patching.h
index 1b9b82bbe3220adcd818505a56b3e3627e020143..2a1629ba814047bfaf2546d29ddeb84c1399a42d 100644 (file)
@@ -17,6 +17,7 @@ generic-y += module.lds.h
 generic-y += parport.h
 generic-y += percpu.h
 generic-y += preempt.h
+generic-y += ring_buffer.h
 generic-y += runtime-const.h
 generic-y += softirq_stack.h
 generic-y += switch_to.h
index 4566000e15c446fbb971db0ae3df68b959e8814a..078fd2c0d69dfa0441e436a63ecc57556b2a55f1 100644 (file)
@@ -14,3 +14,4 @@ generic-y += early_ioremap.h
 generic-y += fprobe.h
 generic-y += mcs_spinlock.h
 generic-y += mmzone.h
+generic-y += ring_buffer.h
index 13fe45dea296146afb3abf79b12d70f66a007586..e57af619263a194aac46eb12b8b4407cc50f10c9 100644 (file)
@@ -6,5 +6,6 @@ generic-y += mcs_spinlock.h
 generic-y += parport.h
 generic-y += qrwlock.h
 generic-y += qspinlock.h
+generic-y += ring_buffer.h
 generic-y += user.h
 generic-y += text-patching.h
diff --git a/include/asm-generic/ring_buffer.h b/include/asm-generic/ring_buffer.h
new file mode 100644 (file)
index 0000000..201d2ae
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Generic arch dependent ring_buffer macros.
+ */
+#ifndef __ASM_GENERIC_RING_BUFFER_H__
+#define __ASM_GENERIC_RING_BUFFER_H__
+
+#include <linux/cacheflush.h>
+
+/* Flush cache on ring buffer range if needed. Do nothing by default. */
+#define arch_ring_buffer_flush_range(start, end)       do { } while (0)
+
+#endif /* __ASM_GENERIC_RING_BUFFER_H__ */
index fcd93d49851ec270f1bb4789c70c3aa300a6e21f..7b07d2004cc6f030dfd85d78ec0d7d233b24b7a4 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/ring_buffer_types.h>
 #include <linux/sched/isolation.h>
 #include <linux/trace_recursion.h>
+#include <linux/panic_notifier.h>
 #include <linux/trace_events.h>
 #include <linux/ring_buffer.h>
 #include <linux/trace_clock.h>
@@ -31,6 +32,7 @@
 #include <linux/oom.h>
 #include <linux/mm.h>
 
+#include <asm/ring_buffer.h>
 #include <asm/local64.h>
 #include <asm/local.h>
 #include <asm/setup.h>
@@ -559,6 +561,7 @@ struct trace_buffer {
 
        unsigned long                   range_addr_start;
        unsigned long                   range_addr_end;
+       struct notifier_block           flush_nb;
 
        struct ring_buffer_meta         *meta;
 
@@ -2521,6 +2524,16 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
        kfree(cpu_buffer);
 }
 
+/* Stop recording on a persistent buffer and flush cache if needed. */
+static int rb_flush_buffer_cb(struct notifier_block *nb, unsigned long event, void *data)
+{
+       struct trace_buffer *buffer = container_of(nb, struct trace_buffer, flush_nb);
+
+       ring_buffer_record_off(buffer);
+       arch_ring_buffer_flush_range(buffer->range_addr_start, buffer->range_addr_end);
+       return NOTIFY_DONE;
+}
+
 static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
                                         int order, unsigned long start,
                                         unsigned long end,
@@ -2651,6 +2664,12 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
 
        mutex_init(&buffer->mutex);
 
+       /* Persistent ring buffer needs to flush cache before reboot. */
+       if (start && end) {
+               buffer->flush_nb.notifier_call = rb_flush_buffer_cb;
+               atomic_notifier_chain_register(&panic_notifier_list, &buffer->flush_nb);
+       }
+
        return_ptr(buffer);
 
  fail_free_buffers:
@@ -2749,6 +2768,9 @@ ring_buffer_free(struct trace_buffer *buffer)
 {
        int cpu;
 
+       if (buffer->range_addr_start && buffer->range_addr_end)
+               atomic_notifier_chain_unregister(&panic_notifier_list, &buffer->flush_nb);
+
        cpuhp_state_remove_instance(CPUHP_TRACE_RB_PREPARE, &buffer->node);
 
        irq_work_sync(&buffer->irq_work.work);