Re: [V2 PATCH 2/3] kexec: Fix race between panic() and crash_kexec() called directly

2015-07-27 Thread Hidehiro Kawai
Hi,

(2015/07/27 23:55), Michal Hocko wrote:
> On Mon 27-07-15 10:58:50, Hidehiro Kawai wrote:
> [...]
>> @@ -1472,6 +1472,18 @@ void __weak crash_unmap_reserved_pages(void)
>>  
>>  void crash_kexec(struct pt_regs *regs)
>>  {
>> +int old_cpu, this_cpu;
>> +
>> +/*
>> + * `old_cpu == -1' means we are the first comer and crash_kexec()
>> + * was called without entering panic().
>> + * `old_cpu == this_cpu' means crash_kexec() was called from panic().
>> + */
>> +this_cpu = raw_smp_processor_id();
>> +old_cpu = atomic_cmpxchg(&panicking_cpu, -1, this_cpu);
>> +if (old_cpu != -1 && old_cpu != this_cpu)
>> +return;
>> +
>>  /* Take the kexec_mutex here to prevent sys_kexec_load
>>   * running on one cpu from replacing the crash kernel
>>   * we are using after a panic on a different cpu.
>> @@ -1491,6 +1503,14 @@ void crash_kexec(struct pt_regs *regs)
>>  }
>>  mutex_unlock(&kexec_mutex);
>>  }
>> +
>> +/*
>> + * If we came here from panic(), we have to keep panicking_cpu
>> + * to prevent other cpus from entering panic().  Otherwise,
>> + * resetting it so that other cpus can enter panic()/crash_kexec().
>> + */
>> +if (old_cpu == this_cpu)
>> +atomic_set(&panicking_cpu, -1);
> 
> This do the opposite what the comment says, wouldn't it? You should
> check old_cpu == -1.

Sorry, you are right.  I performed same tests as for the
previous patch set, but I missed the test case for this
new logic.

> Also atomic_set doesn't imply memory barriers which
> might be a problem.

OK, I'll use atomic_xchg().

Regards,
-- 
Hidehiro Kawai
Hitachi, Ltd. Research & Development Group


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [V2 PATCH 2/3] kexec: Fix race between panic() and crash_kexec() called directly

2015-07-27 Thread Michal Hocko
On Mon 27-07-15 10:58:50, Hidehiro Kawai wrote:
[...]
> @@ -1472,6 +1472,18 @@ void __weak crash_unmap_reserved_pages(void)
>  
>  void crash_kexec(struct pt_regs *regs)
>  {
> + int old_cpu, this_cpu;
> +
> + /*
> +  * `old_cpu == -1' means we are the first comer and crash_kexec()
> +  * was called without entering panic().
> +  * `old_cpu == this_cpu' means crash_kexec() was called from panic().
> +  */
> + this_cpu = raw_smp_processor_id();
> + old_cpu = atomic_cmpxchg(&panicking_cpu, -1, this_cpu);
> + if (old_cpu != -1 && old_cpu != this_cpu)
> + return;
> +
>   /* Take the kexec_mutex here to prevent sys_kexec_load
>* running on one cpu from replacing the crash kernel
>* we are using after a panic on a different cpu.
> @@ -1491,6 +1503,14 @@ void crash_kexec(struct pt_regs *regs)
>   }
>   mutex_unlock(&kexec_mutex);
>   }
> +
> + /*
> +  * If we came here from panic(), we have to keep panicking_cpu
> +  * to prevent other cpus from entering panic().  Otherwise,
> +  * resetting it so that other cpus can enter panic()/crash_kexec().
> +  */
> + if (old_cpu == this_cpu)
> + atomic_set(&panicking_cpu, -1);

This do the opposite what the comment says, wouldn't it? You should
check old_cpu == -1. Also atomic_set doesn't imply memory barriers which
might be a problem.
-- 
Michal Hocko
SUSE Labs
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[V2 PATCH 2/3] kexec: Fix race between panic() and crash_kexec() called directly

2015-07-26 Thread Hidehiro Kawai
Currently, panic() and crash_kexec() can be called at the same time.
For example (x86 case):

CPU 0:
  oops_end()
crash_kexec()
  mutex_trylock() // acquired
nmi_shootdown_cpus() // stop other cpus

CPU 1:
  panic()
crash_kexec()
  mutex_trylock() // failed to acquire
smp_send_stop() // stop other cpus
infinite loop

If CPU 1 calls smp_send_stop() before nmi_shootdown_cpus(), kdump
fails.

In another case:

CPU 0:
  oops_end()
crash_kexec()
  mutex_trylock() // acquired

io_check_error()
  panic()
crash_kexec()
  mutex_trylock() // failed to acquire
infinite loop

Clearly, this is an undesirable result.

To fix this problem, this patch changes crash_kexec() to exclude
others by using atomic_t panicking_cpu.

V2:
- Use atomic_cmpxchg() instead of spin_trylock() on panic_lock
  to exclude concurrent accesses
- Don't introduce no-lock version of crash_kexec()

Signed-off-by: Hidehiro Kawai 
Cc: Eric Biederman 
Cc: Vivek Goyal 
Cc: Andrew Morton 
---
 kernel/kexec.c |   20 
 1 file changed, 20 insertions(+)

diff --git a/kernel/kexec.c b/kernel/kexec.c
index a785c10..ca40a19 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1472,6 +1472,18 @@ void __weak crash_unmap_reserved_pages(void)
 
 void crash_kexec(struct pt_regs *regs)
 {
+   int old_cpu, this_cpu;
+
+   /*
+* `old_cpu == -1' means we are the first comer and crash_kexec()
+* was called without entering panic().
+* `old_cpu == this_cpu' means crash_kexec() was called from panic().
+*/
+   this_cpu = raw_smp_processor_id();
+   old_cpu = atomic_cmpxchg(&panicking_cpu, -1, this_cpu);
+   if (old_cpu != -1 && old_cpu != this_cpu)
+   return;
+
/* Take the kexec_mutex here to prevent sys_kexec_load
 * running on one cpu from replacing the crash kernel
 * we are using after a panic on a different cpu.
@@ -1491,6 +1503,14 @@ void crash_kexec(struct pt_regs *regs)
}
mutex_unlock(&kexec_mutex);
}
+
+   /*
+* If we came here from panic(), we have to keep panicking_cpu
+* to prevent other cpus from entering panic().  Otherwise,
+* resetting it so that other cpus can enter panic()/crash_kexec().
+*/
+   if (old_cpu == this_cpu)
+   atomic_set(&panicking_cpu, -1);
 }
 
 size_t crash_get_memory_size(void)


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/