mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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
					
				
					 2 changed files with 57 additions and 24 deletions
				
			
		| 
						 | 
					@ -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…
	
		Reference in a new issue