[PATCH RT 2/3] swait: Add memory barrier before checking list empty

From: Steven Rostedt
Date: Mon Aug 19 2013 - 11:36:31 EST


From: Steven Rostedt <rostedt@xxxxxxxxxxx>

There's a race condition with swait wakeups and adding to the list. The
__swait_wake() does a check for swait_head_has_waiters(), and if it is
empty it will exit without doing any wake ups. The problem is that the
check does not include any memory barriers before it makes a decision
to wake up or not.

CPU0 CPU1
---- ----

condition = 1

load h->list (is empty)
raw_spin_lock(hlist->lock)
hlist_add();
__set_current_state();
raw_spin_unlock(hlist->lock)
swait_wake()
swait_head_has_waiters()
(sees h->list as empty and returns)

check_condition (sees condition = 0)

store condition = 1

schedule()

Now the task on CPU1 has just missed its wakeup. By adding a memory
barrier before the list empty check, we fix the problem of miss seeing
the list not empty as well as pushing out the condition for the other
task to see.

Reviewed-by: Paul E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Steven Rostedt <rostedt@xxxxxxxxxxx>
---
kernel/wait-simple.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/kernel/wait-simple.c b/kernel/wait-simple.c
index 4b9a0b5..9725a11 100644
--- a/kernel/wait-simple.c
+++ b/kernel/wait-simple.c
@@ -27,6 +27,8 @@ static inline void __swait_dequeue(struct swaiter *w)
/* Check whether a head has waiters enqueued */
static inline bool swait_head_has_waiters(struct swait_head *h)
{
+ /* Make sure the condition is visible before checking list_empty() */
+ smp_mb();
return !list_empty(&h->list);
}

--
1.7.10.4


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