mirror of
				https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
				synced 2025-11-04 16:52:06 +10:00 
			
		
		
		
	kdump: fix crash_kexec()/smp_send_stop() race in panic()
When two CPUs call panic at the same time there is a possible race
condition that can stop kdump.  The first CPU calls crash_kexec() and the
second CPU calls smp_send_stop() in panic() before crash_kexec() finished
on the first CPU.  So the second CPU stops the first CPU and therefore
kdump fails:
1st CPU:
  panic()->crash_kexec()->mutex_trylock(&kexec_mutex)-> do kdump
2nd CPU:
  panic()->crash_kexec()->kexec_mutex already held by 1st CPU
       ->smp_send_stop()-> stop 1st CPU (stop kdump)
This patch fixes the problem by introducing a spinlock in panic that
allows only one CPU to process crash_kexec() and the subsequent panic
code.
All other CPUs call the weak function panic_smp_self_stop() that stops the
CPU itself.  This function can be overloaded by architecture code.  For
example "tile" can use their lower-power "nap" instruction for that.
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Acked-by: Chris Metcalf <cmetcalf@tilera.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
			
			
This commit is contained in:
		
							parent
							
								
									bec013c40b
								
							
						
					
					
						commit
						93e13a360b
					
				@ -49,6 +49,15 @@ static long no_blink(int state)
 | 
			
		||||
long (*panic_blink)(int state);
 | 
			
		||||
EXPORT_SYMBOL(panic_blink);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Stop ourself in panic -- architecture code may override this
 | 
			
		||||
 */
 | 
			
		||||
void __weak panic_smp_self_stop(void)
 | 
			
		||||
{
 | 
			
		||||
	while (1)
 | 
			
		||||
		cpu_relax();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *	panic - halt the system
 | 
			
		||||
 *	@fmt: The text string to print
 | 
			
		||||
@ -59,6 +68,7 @@ EXPORT_SYMBOL(panic_blink);
 | 
			
		||||
 */
 | 
			
		||||
void panic(const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	static DEFINE_SPINLOCK(panic_lock);
 | 
			
		||||
	static char buf[1024];
 | 
			
		||||
	va_list args;
 | 
			
		||||
	long i, i_next = 0;
 | 
			
		||||
@ -68,8 +78,14 @@ void panic(const char *fmt, ...)
 | 
			
		||||
	 * It's possible to come here directly from a panic-assertion and
 | 
			
		||||
	 * not have preempt disabled. Some functions called from here want
 | 
			
		||||
	 * preempt to be disabled. No point enabling it later though...
 | 
			
		||||
	 *
 | 
			
		||||
	 * Only one CPU is allowed to execute the panic code from here. For
 | 
			
		||||
	 * multiple parallel invocations of panic, all other CPUs either
 | 
			
		||||
	 * stop themself or will wait until they are stopped by the 1st CPU
 | 
			
		||||
	 * with smp_send_stop().
 | 
			
		||||
	 */
 | 
			
		||||
	preempt_disable();
 | 
			
		||||
	if (!spin_trylock(&panic_lock))
 | 
			
		||||
		panic_smp_self_stop();
 | 
			
		||||
 | 
			
		||||
	console_verbose();
 | 
			
		||||
	bust_spinlocks(1);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user