diff options
Diffstat (limited to 'kernel/kexec_core.c')
| -rw-r--r-- | kernel/kexec_core.c | 30 | 
1 files changed, 29 insertions, 1 deletions
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index 11b64a63c0f8..c823f3001e12 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -853,7 +853,12 @@ struct kimage *kexec_image;  struct kimage *kexec_crash_image;  int kexec_load_disabled; -void crash_kexec(struct pt_regs *regs) +/* + * No panic_cpu check version of crash_kexec().  This function is called + * only when panic_cpu holds the current CPU number; this is the only CPU + * which processes crash_kexec routines. + */ +void __crash_kexec(struct pt_regs *regs)  {  	/* Take the kexec_mutex here to prevent sys_kexec_load  	 * running on one cpu from replacing the crash kernel @@ -876,6 +881,29 @@ void crash_kexec(struct pt_regs *regs)  	}  } +void crash_kexec(struct pt_regs *regs) +{ +	int old_cpu, this_cpu; + +	/* +	 * Only one CPU is allowed to execute the crash_kexec() code as with +	 * panic().  Otherwise parallel calls of panic() and crash_kexec() +	 * may stop each other.  To exclude them, we use panic_cpu here too. +	 */ +	this_cpu = raw_smp_processor_id(); +	old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu); +	if (old_cpu == PANIC_CPU_INVALID) { +		/* This is the 1st CPU which comes here, so go ahead. */ +		__crash_kexec(regs); + +		/* +		 * Reset panic_cpu to allow another panic()/crash_kexec() +		 * call. +		 */ +		atomic_set(&panic_cpu, PANIC_CPU_INVALID); +	} +} +  size_t crash_get_memory_size(void)  {  	size_t size = 0;  | 
