mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-15 21:30:43 +00:00
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
|
||||
* return early in the blocking case.
|
||||
*/
|
||||
if (!ACCESS_ONCE(x->done))
|
||||
if (!READ_ONCE(x->done))
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&x->wait.lock, flags);
|
||||
@ -297,6 +297,21 @@ EXPORT_SYMBOL(try_wait_for_completion);
|
||||
*/
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user