Commit c1aa3daa authored by Donghyeok Choe's avatar Donghyeok Choe Committed by Petr Mladek
Browse files

printk/panic: Add option to allow non-panic CPUs to write to the ring buffer.

Commit 779dbc2e ("printk: Avoid non-panic CPUs writing to ringbuffer")
aimed to isolate panic-related messages. However, when panic() itself
malfunctions, messages from non-panic CPUs become crucial for debugging.

While commit bcc954c6 ("printk/panic: Allow cpu backtraces to
be written into ringbuffer during panic") enables non-panic CPU
backtraces, it may not provide sufficient diagnostic information.

Introduce the "debug_non_panic_cpus" command-line option, enabling
non-panic CPU messages to be stored in the ring buffer during a panic.
This also prevents discarding non-finalized messages from non-panic CPUs
during console flushing, providing a more comprehensive view of system
state during critical failures.

Link: https://lore.kernel.org/all/Z8cLEkqLL2IOyNIj@pathway/


Signed-off-by: default avatarDonghyeok Choe <d7271.choe@samsung.com>
Reviewed-by: default avatarPetr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20250318022320.2428155-1-d7271.choe@samsung.com


[pmladek@suse.com: Added documentation, added module_parameter, removed printk_ prefix.]
Tested-by: default avatarPetr Mladek <pmladek@suse.com>
Signed-off-by: default avatarPetr Mladek <pmladek@suse.com>
parent 2f1f7787
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -5013,6 +5013,14 @@
			Format: <bool>
			default: 0 (auto_verbose is enabled)

	printk.debug_non_panic_cpus=
			Allows storing messages from non-panic CPUs into
			the printk log buffer during panic(). They are
			flushed to consoles by the panic-CPU on
			a best-effort basis.
			Format: <bool> (1/Y/y=enable, 0/N/n=disable)
			Default: disabled

	printk.devkmsg={on,off,ratelimit}
			Control writing to /dev/kmsg.
			on - unlimited logging to /dev/kmsg from userspace
+1 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ struct dev_printk_info;

extern struct printk_ringbuffer *prb;
extern bool printk_kthreads_running;
extern bool debug_non_panic_cpus;

__printf(4, 0)
int vprintk_store(int facility, int level,
+19 −1
Original line number Diff line number Diff line
@@ -2375,6 +2375,22 @@ void printk_legacy_allow_panic_sync(void)
	}
}

bool __read_mostly debug_non_panic_cpus;

#ifdef CONFIG_PRINTK_CALLER
static int __init debug_non_panic_cpus_setup(char *str)
{
	debug_non_panic_cpus = true;
	pr_info("allow messages from non-panic CPUs in panic()\n");

	return 0;
}
early_param("debug_non_panic_cpus", debug_non_panic_cpus_setup);
module_param(debug_non_panic_cpus, bool, 0644);
MODULE_PARM_DESC(debug_non_panic_cpus,
		 "allow messages from non-panic CPUs in panic()");
#endif

asmlinkage int vprintk_emit(int facility, int level,
			    const struct dev_printk_info *dev_info,
			    const char *fmt, va_list args)
@@ -2391,7 +2407,9 @@ asmlinkage int vprintk_emit(int facility, int level,
	 * non-panic CPUs are generating any messages, they will be
	 * silently dropped.
	 */
	if (other_cpu_in_panic() && !panic_triggering_all_cpu_backtrace)
	if (other_cpu_in_panic() &&
	    !debug_non_panic_cpus &&
	    !panic_triggering_all_cpu_backtrace)
		return 0;

	printk_get_console_flush_type(&ft);
+8 −5
Original line number Diff line number Diff line
@@ -2133,9 +2133,9 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq,
			 * there may be other finalized records beyond that
			 * need to be printed for a panic situation. If this
			 * is the panic CPU, skip this
			 * non-existent/non-finalized record unless it is
			 * at or beyond the head, in which case it is not
			 * possible to continue.
			 * non-existent/non-finalized record unless non-panic
			 * CPUs are still running and their debugging is
			 * explicitly enabled.
			 *
			 * Note that new messages printed on panic CPU are
			 * finalized when we are here. The only exception
@@ -2143,12 +2143,15 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq,
			 * But it would have the sequence number returned
			 * by "prb_next_reserve_seq() - 1".
			 */
			if (this_cpu_in_panic() && ((*seq + 1) < prb_next_reserve_seq(rb)))
			if (this_cpu_in_panic() &&
			    (!debug_non_panic_cpus || legacy_allow_panic_sync) &&
			    ((*seq + 1) < prb_next_reserve_seq(rb))) {
				(*seq)++;
			else
			} else {
				return false;
			}
		}
	}

	return true;
}