Readers that are awoken will expect a nil ->task indicating that a wakeup has occurred. There is a mismatch between the smp_mb() and its documentation, in that the serialization is done between reading the task and the nil store. Furthermore, in addition to having the overlapping of loads and stores to waiter->task guaranteed to be ordered within that CPU, both wake_up_process() originally and now wake_q_add() already imply barriers upon successful calls, which serves the comment.
Just atomically do a xchg() and simplify the whole thing. We can use relaxed semantics as before mentioned in addition to the barrier provided by wake_q_add(), delaying there is no risk in reordering with the actual wakeup. Signed-off-by: Davidlohr Bueso <dbu...@suse.de> --- kernel/locking/rwsem-xadd.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 1b8c1285a2aa..96e53cb4a4db 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -126,7 +126,6 @@ __rwsem_mark_wake(struct rw_semaphore *sem, enum rwsem_wake_type wake_type, struct wake_q_head *wake_q) { struct rwsem_waiter *waiter; - struct task_struct *tsk; struct list_head *next; long oldcount, woken, loop, adjustment; @@ -190,24 +189,18 @@ __rwsem_mark_wake(struct rw_semaphore *sem, next = sem->wait_list.next; loop = woken; do { + struct task_struct *tsk; + waiter = list_entry(next, struct rwsem_waiter, list); next = waiter->list.next; - tsk = waiter->task; - /* - * Make sure we do not wakeup the next reader before - * setting the nil condition to grant the next reader; - * otherwise we could miss the wakeup on the other - * side and end up sleeping again. See the pairing - * in rwsem_down_read_failed(). - */ - smp_mb(); - waiter->task = NULL; + + tsk = xchg_relaxed(&waiter->task, NULL); wake_q_add(wake_q, tsk); } while (--loop); sem->wait_list.next = next; next->prev = &sem->wait_list; - out: +out: return sem; } -- 2.8.1