Commit 693f75b9 authored by Sreenath Vijayan's avatar Sreenath Vijayan Committed by Greg Kroah-Hartman
Browse files

printk: Add function to replay kernel log on consoles



Add a generic function console_replay_all() for replaying
the kernel log on consoles, in any context. It would allow
viewing the logs on an unresponsive terminal via sysrq.

Reuse the existing code from console_flush_on_panic() for
resetting the sequence numbers, by introducing a new helper
function __console_rewind_all(). It is safe to be called
under console_lock().

Try to acquire lock on the console subsystem without waiting.
If successful, reset the sequence number to oldest available
record on all consoles and call console_unlock() which will
automatically flush the messages to the consoles.

Suggested-by: default avatarJohn Ogness <john.ogness@linutronix.de>
Suggested-by: default avatarPetr Mladek <pmladek@suse.com>
Signed-off-by: default avatarShimoyashiki Taichi <taichi.shimoyashiki@sony.com>
Reviewed-by: default avatarJohn Ogness <john.ogness@linutronix.de>
Signed-off-by: default avatarSreenath Vijayan <sreenath.vijayan@sony.com>
Link: https://lore.kernel.org/r/90ee131c643a5033d117b556c0792de65129d4c3.1710220326.git.sreenath.vijayan@sony.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 25ca2d57
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -195,6 +195,7 @@ void show_regs_print_info(const char *log_lvl);
extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
extern asmlinkage void dump_stack(void) __cold;
void printk_trigger_flush(void);
void console_replay_all(void);
#else
static inline __printf(1, 0)
int vprintk(const char *s, va_list args)
@@ -274,6 +275,9 @@ static inline void dump_stack(void)
static inline void printk_trigger_flush(void)
{
}
static inline void console_replay_all(void)
{
}
#endif

bool this_cpu_in_panic(void);
+53 −24
Original line number Diff line number Diff line
@@ -3161,6 +3161,40 @@ void console_unblank(void)
		pr_flush(1000, true);
}

/*
 * Rewind all consoles to the oldest available record.
 *
 * IMPORTANT: The function is safe only when called under
 *            console_lock(). It is not enforced because
 *            it is used as a best effort in panic().
 */
static void __console_rewind_all(void)
{
	struct console *c;
	short flags;
	int cookie;
	u64 seq;

	seq = prb_first_valid_seq(prb);

	cookie = console_srcu_read_lock();
	for_each_console_srcu(c) {
		flags = console_srcu_read_flags(c);

		if (flags & CON_NBCON) {
			nbcon_seq_force(c, seq);
		} else {
			/*
			 * This assignment is safe only when called under
			 * console_lock(). On panic, legacy consoles are
			 * only best effort.
			 */
			c->seq = seq;
		}
	}
	console_srcu_read_unlock(cookie);
}

/**
 * console_flush_on_panic - flush console content on panic
 * @mode: flush all messages in buffer or just the pending ones
@@ -3189,30 +3223,8 @@ void console_flush_on_panic(enum con_flush_mode mode)
	 */
	console_may_schedule = 0;

	if (mode == CONSOLE_REPLAY_ALL) {
		struct console *c;
		short flags;
		int cookie;
		u64 seq;

		seq = prb_first_valid_seq(prb);

		cookie = console_srcu_read_lock();
		for_each_console_srcu(c) {
			flags = console_srcu_read_flags(c);

			if (flags & CON_NBCON) {
				nbcon_seq_force(c, seq);
			} else {
				/*
				 * This is an unsynchronized assignment. On
				 * panic legacy consoles are only best effort.
				 */
				c->seq = seq;
			}
		}
		console_srcu_read_unlock(cookie);
	}
	if (mode == CONSOLE_REPLAY_ALL)
		__console_rewind_all();

	console_flush_all(false, &next_seq, &handover);
}
@@ -4301,6 +4313,23 @@ void kmsg_dump_rewind(struct kmsg_dump_iter *iter)
}
EXPORT_SYMBOL_GPL(kmsg_dump_rewind);

/**
 * console_replay_all - replay kernel log on consoles
 *
 * Try to obtain lock on console subsystem and replay all
 * available records in printk buffer on the consoles.
 * Does nothing if lock is not obtained.
 *
 * Context: Any context.
 */
void console_replay_all(void)
{
	if (console_trylock()) {
		__console_rewind_all();
		/* Consoles are flushed as part of console_unlock(). */
		console_unlock();
	}
}
#endif

#ifdef CONFIG_SMP