Messages in this thread Patch in this message | | | From | Davidlohr Bueso <> | Subject | [PATCH 4/4] locking/rwsem: Rework zeroing reader waiter->task | Date | Sun, 8 May 2016 21:56:10 -0700 |
| |
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 <dbueso@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
| |