aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched/completion.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sched/completion.c')
-rw-r--r--kernel/sched/completion.c11
1 files changed, 4 insertions, 7 deletions
diff --git a/kernel/sched/completion.c b/kernel/sched/completion.c
index 13fc5ae9bf2f..c9524d2d9316 100644
--- a/kernel/sched/completion.c
+++ b/kernel/sched/completion.c
@@ -300,6 +300,8 @@ EXPORT_SYMBOL(try_wait_for_completion);
300 */ 300 */
301bool completion_done(struct completion *x) 301bool completion_done(struct completion *x)
302{ 302{
303 unsigned long flags;
304
303 if (!READ_ONCE(x->done)) 305 if (!READ_ONCE(x->done))
304 return false; 306 return false;
305 307
@@ -307,14 +309,9 @@ bool completion_done(struct completion *x)
307 * If ->done, we need to wait for complete() to release ->wait.lock 309 * If ->done, we need to wait for complete() to release ->wait.lock
308 * otherwise we can end up freeing the completion before complete() 310 * otherwise we can end up freeing the completion before complete()
309 * is done referencing it. 311 * is done referencing it.
310 *
311 * The RMB pairs with complete()'s RELEASE of ->wait.lock and orders
312 * the loads of ->done and ->wait.lock such that we cannot observe
313 * the lock before complete() acquires it while observing the ->done
314 * after it's acquired the lock.
315 */ 312 */
316 smp_rmb(); 313 spin_lock_irqsave(&x->wait.lock, flags);
317 spin_unlock_wait(&x->wait.lock); 314 spin_unlock_irqrestore(&x->wait.lock, flags);
318 return true; 315 return true;
319} 316}
320EXPORT_SYMBOL(completion_done); 317EXPORT_SYMBOL(completion_done);