sched/completion: Serialize completion_done() with complete()
Commitde30ec4730
"Remove unnecessary ->wait.lock serialization when reading completion state" was not correct, without lock/unlock the code like stop_machine_from_inactive_cpu() while (!completion_done()) cpu_relax(); can return before complete() finishes its spin_unlock() which writes to this memory. And spin_unlock_wait(). While at it, change try_wait_for_completion() to use READ_ONCE(). Reported-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Reported-by: Davidlohr Bueso <dave@stgolabs.net> Tested-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> [ Added a comment with the barrier. ] Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Nicholas Mc Guire <der.herr@hofr.at> Cc: raghavendra.kt@linux.vnet.ibm.com Cc: waiman.long@hp.com Fixes:de30ec4730
("sched/completion: Remove unnecessary ->wait.lock serialization when reading completion state") Link: http://lkml.kernel.org/r/20150212195913.GA30430@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
06b1f8083d
commit
bc9560155f
@ -274,7 +274,7 @@ bool try_wait_for_completion(struct completion *x)
|
|||||||
* first without taking the lock so we can
|
* first without taking the lock so we can
|
||||||
* return early in the blocking case.
|
* return early in the blocking case.
|
||||||
*/
|
*/
|
||||||
if (!ACCESS_ONCE(x->done))
|
if (!READ_ONCE(x->done))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&x->wait.lock, flags);
|
spin_lock_irqsave(&x->wait.lock, flags);
|
||||||
@ -297,6 +297,21 @@ EXPORT_SYMBOL(try_wait_for_completion);
|
|||||||
*/
|
*/
|
||||||
bool completion_done(struct completion *x)
|
bool completion_done(struct completion *x)
|
||||||
{
|
{
|
||||||
return !!ACCESS_ONCE(x->done);
|
if (!READ_ONCE(x->done))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If ->done, we need to wait for complete() to release ->wait.lock
|
||||||
|
* otherwise we can end up freeing the completion before complete()
|
||||||
|
* is done referencing it.
|
||||||
|
*
|
||||||
|
* The RMB pairs with complete()'s RELEASE of ->wait.lock and orders
|
||||||
|
* the loads of ->done and ->wait.lock such that we cannot observe
|
||||||
|
* the lock before complete() acquires it while observing the ->done
|
||||||
|
* after it's acquired the lock.
|
||||||
|
*/
|
||||||
|
smp_rmb();
|
||||||
|
spin_unlock_wait(&x->wait.lock);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(completion_done);
|
EXPORT_SYMBOL(completion_done);
|
||||||
|
Loading…
Reference in New Issue
Block a user