* hotplug thread issues
@ 2014-11-06 15:01 Peter Zijlstra
2014-11-07 9:39 ` Thomas Gleixner
0 siblings, 1 reply; 5+ messages in thread
From: Peter Zijlstra @ 2014-11-06 15:01 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Subbaraman Narayanamurthy, daniel, yuyang.du, linux-kernel,
Oleg Nesterov, Steven Rostedt
Hi Thomas,
So there have been some reports on hitting:
BUG_ON(td->cpu != smp_processor_id());
in smpboot_thread_fn.
Now I've been staring at this for a wee bit today and I've found two
issues, but I'm not sure either are enough to explain the observed.
1) smpboot_register_percpu_thread() seems to lack serialization against
hotplug. It has a for_each_online() loop, but no get_online_cpus() --
unlike smpboot_unregister_percpu_thread, which does.
Typical usage like spawn_ksoftirqd() should be fine, they're early
init calls and those run before we bring up the other CPUs. Therefore
this does not explain the observation that its ksoftirqd/n triggering
the BUG.
However, the usage in proc_dowatchdog() is susceptible to this race
and its entirely possible to go wrong there.
2) the usage of __set_current_state(TASK_PARKED) in __kthread_parkme()
is wrong AFAICT, one should always use set_current_state() for
setting !TASK_RUNNING state. The comment with set_current_state()
explains why.
This would've allowed the test_bit(KTHREAD_SHOULD_PARK) load to have
been satisfied before the store of TASK_PARKED.
In any case, I'm not sure either of these are enough, I'll go stare at
it a bit more I suppose.
---
kernel/kthread.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 10e489c448fe..9787244d43ec 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -156,12 +156,12 @@ void *probe_kthread_data(struct task_struct *task)
static void __kthread_parkme(struct kthread *self)
{
- __set_current_state(TASK_PARKED);
+ set_current_state(TASK_PARKED);
while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) {
if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags))
complete(&self->parked);
schedule();
- __set_current_state(TASK_PARKED);
+ set_current_state(TASK_PARKED);
}
clear_bit(KTHREAD_IS_PARKED, &self->flags);
__set_current_state(TASK_RUNNING);
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: hotplug thread issues
2014-11-06 15:01 hotplug thread issues Peter Zijlstra
@ 2014-11-07 9:39 ` Thomas Gleixner
2014-11-07 10:28 ` [PATCH]: kthread: Fix memory ordering in __kthread_parkme Peter Zijlstra
0 siblings, 1 reply; 5+ messages in thread
From: Thomas Gleixner @ 2014-11-07 9:39 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Subbaraman Narayanamurthy, daniel, yuyang.du, linux-kernel,
Oleg Nesterov, Steven Rostedt
On Thu, 6 Nov 2014, Peter Zijlstra wrote:
> Hi Thomas,
>
> So there have been some reports on hitting:
>
> BUG_ON(td->cpu != smp_processor_id());
>
> in smpboot_thread_fn.
>
> Now I've been staring at this for a wee bit today and I've found two
> issues, but I'm not sure either are enough to explain the observed.
>
> 1) smpboot_register_percpu_thread() seems to lack serialization against
> hotplug. It has a for_each_online() loop, but no get_online_cpus() --
> unlike smpboot_unregister_percpu_thread, which does.
>
> Typical usage like spawn_ksoftirqd() should be fine, they're early
> init calls and those run before we bring up the other CPUs. Therefore
> this does not explain the observation that its ksoftirqd/n triggering
> the BUG.
>
> However, the usage in proc_dowatchdog() is susceptible to this race
> and its entirely possible to go wrong there.
Hmm. Need to have a look.
>
> 2) the usage of __set_current_state(TASK_PARKED) in __kthread_parkme()
> is wrong AFAICT, one should always use set_current_state() for
> setting !TASK_RUNNING state. The comment with set_current_state()
> explains why.
>
> This would've allowed the test_bit(KTHREAD_SHOULD_PARK) load to have
> been satisfied before the store of TASK_PARKED.
My bad. Can you send a proper patch addressing that issue please? That
should be tagged stable as well I guess.
Thanks,
tglx
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH]: kthread: Fix memory ordering in __kthread_parkme
2014-11-07 9:39 ` Thomas Gleixner
@ 2014-11-07 10:28 ` Peter Zijlstra
2014-11-07 18:41 ` Oleg Nesterov
0 siblings, 1 reply; 5+ messages in thread
From: Peter Zijlstra @ 2014-11-07 10:28 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Subbaraman Narayanamurthy, daniel, yuyang.du, linux-kernel,
Oleg Nesterov, Steven Rostedt
On Fri, Nov 07, 2014 at 10:39:48AM +0100, Thomas Gleixner wrote:
> > 2) the usage of __set_current_state(TASK_PARKED) in __kthread_parkme()
> > is wrong AFAICT, one should always use set_current_state() for
> > setting !TASK_RUNNING state. The comment with set_current_state()
> > explains why.
> >
> > This would've allowed the test_bit(KTHREAD_SHOULD_PARK) load to have
> > been satisfied before the store of TASK_PARKED.
>
> My bad. Can you send a proper patch addressing that issue please? That
> should be tagged stable as well I guess.
Sure thing, something like so then?
---
Subject: kthread: Fix memory ordering in __kthread_parkme
One should always use set_current_state() to set !TASK_RUNNING states.
set_current_state(TASK_*); cond = true;
/* mb */ /* wmb */
if (!cond) wake_up_state(, TASK_*);
schedule();
By not having the mb we allow for the cond load to be satisfied before
the state store, this can result in:
if (!cond)
cond = true;
wake_up_state(, TASK_*);
__set_current_state(TASK_*);
schedule();
Which would block 'forever', since the cond is still false and the
wakeup would not have seen the !TASK_RUNNING state.
Cc: stable@vger.kernel.org
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
kernel/kthread.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 10e489c448fe..9787244d43ec 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -156,12 +156,12 @@ void *probe_kthread_data(struct task_struct *task)
static void __kthread_parkme(struct kthread *self)
{
- __set_current_state(TASK_PARKED);
+ set_current_state(TASK_PARKED);
while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) {
if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags))
complete(&self->parked);
schedule();
- __set_current_state(TASK_PARKED);
+ set_current_state(TASK_PARKED);
}
clear_bit(KTHREAD_IS_PARKED, &self->flags);
__set_current_state(TASK_RUNNING);
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH]: kthread: Fix memory ordering in __kthread_parkme
2014-11-07 10:28 ` [PATCH]: kthread: Fix memory ordering in __kthread_parkme Peter Zijlstra
@ 2014-11-07 18:41 ` Oleg Nesterov
2014-11-07 21:27 ` Peter Zijlstra
0 siblings, 1 reply; 5+ messages in thread
From: Oleg Nesterov @ 2014-11-07 18:41 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Thomas Gleixner, Subbaraman Narayanamurthy, daniel, yuyang.du,
linux-kernel, Steven Rostedt
On 11/07, Peter Zijlstra wrote:
>
> static void __kthread_parkme(struct kthread *self)
> {
> - __set_current_state(TASK_PARKED);
> + set_current_state(TASK_PARKED);
> while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) {
> if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags))
> complete(&self->parked);
> schedule();
> - __set_current_state(TASK_PARKED);
> + set_current_state(TASK_PARKED);
> }
Perhaps it makses sense to do set_current_state(PARKED) once at the start
of "for (;;)" loop, but this is cosmetic.
What if kthread_unpark() is called right after test_bit(KTHREAD_SHOULD_PARK)
and KTHREAD_IS_PARKED is not set? It seems that __kthread_unpark() should
call wake_up_state() unconditionally ?
Oleg.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH]: kthread: Fix memory ordering in __kthread_parkme
2014-11-07 18:41 ` Oleg Nesterov
@ 2014-11-07 21:27 ` Peter Zijlstra
0 siblings, 0 replies; 5+ messages in thread
From: Peter Zijlstra @ 2014-11-07 21:27 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Thomas Gleixner, Subbaraman Narayanamurthy, daniel, yuyang.du,
linux-kernel, Steven Rostedt
On Fri, Nov 07, 2014 at 07:41:03PM +0100, Oleg Nesterov wrote:
> On 11/07, Peter Zijlstra wrote:
> >
> > static void __kthread_parkme(struct kthread *self)
> > {
> > - __set_current_state(TASK_PARKED);
> > + set_current_state(TASK_PARKED);
> > while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) {
> > if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags))
> > complete(&self->parked);
> > schedule();
> > - __set_current_state(TASK_PARKED);
> > + set_current_state(TASK_PARKED);
> > }
>
> Perhaps it makses sense to do set_current_state(PARKED) once at the start
> of "for (;;)" loop, but this is cosmetic.
Yeah, we should probably clean that up, it looks a bit odd. But I didn't
want to do too many changes.
> What if kthread_unpark() is called right after test_bit(KTHREAD_SHOULD_PARK)
> and KTHREAD_IS_PARKED is not set? It seems that __kthread_unpark() should
> call wake_up_state() unconditionally ?
set_current_state(TASK_PARKED)
while (test_bit(KTHREAD_SHOULD_PARK, ..)) {
clear_bit(KTHREAD_SHOULD_PARK, ..);
if (test_and_clear_bit(KTHREAD_IS_PARKED, ..) {
...
wake_up_state(, TASK_PARKED);
}
if (!test_and_set_bit(KTHREAD_IS_PARKED, ..))
complete(..);
schedule();
Then yes we'll miss the wakeup, but we also miss the __kthread_bind().
Now I don't think this'll actually happen because kthread_park() waits
for the completion under the hotplug and smpboot_threads_lock lock, and
we do the unpark under the hotplug lock as well, so its fully serialized
But yes, we should probably clean this up as well.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2014-11-07 21:27 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-06 15:01 hotplug thread issues Peter Zijlstra
2014-11-07 9:39 ` Thomas Gleixner
2014-11-07 10:28 ` [PATCH]: kthread: Fix memory ordering in __kthread_parkme Peter Zijlstra
2014-11-07 18:41 ` Oleg Nesterov
2014-11-07 21:27 ` Peter Zijlstra
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox