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: John Ogness <john.ogness@linutronix.de> Suggested-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Shimoyashiki Taichi <taichi.shimoyashiki@sony.com> Reviewed-by: John Ogness <john.ogness@linutronix.de> Signed-off-by: Sreenath Vijayan <sreenath.vijayan@sony.com> Link: https://lore.kernel.org/r/90ee131c643a5033d117b556c0792de65129d4c3.1710220326.git.sreenath.vijayan@sony.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
25ca2d573e
commit
693f75b91a
@ -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_lvl(const char *log_lvl) __cold;
|
||||||
extern asmlinkage void dump_stack(void) __cold;
|
extern asmlinkage void dump_stack(void) __cold;
|
||||||
void printk_trigger_flush(void);
|
void printk_trigger_flush(void);
|
||||||
|
void console_replay_all(void);
|
||||||
#else
|
#else
|
||||||
static inline __printf(1, 0)
|
static inline __printf(1, 0)
|
||||||
int vprintk(const char *s, va_list args)
|
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 printk_trigger_flush(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
static inline void console_replay_all(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool this_cpu_in_panic(void);
|
bool this_cpu_in_panic(void);
|
||||||
|
@ -3161,6 +3161,40 @@ void console_unblank(void)
|
|||||||
pr_flush(1000, true);
|
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
|
* console_flush_on_panic - flush console content on panic
|
||||||
* @mode: flush all messages in buffer or just the pending ones
|
* @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;
|
console_may_schedule = 0;
|
||||||
|
|
||||||
if (mode == CONSOLE_REPLAY_ALL) {
|
if (mode == CONSOLE_REPLAY_ALL)
|
||||||
struct console *c;
|
__console_rewind_all();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
console_flush_all(false, &next_seq, &handover);
|
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);
|
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
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
Loading…
x
Reference in New Issue
Block a user