Re: [RFC] locking/rwsem: Avoid issuing wakeup before setting the reader waiter to nil

From: Peter Zijlstra
Date: Thu Nov 29 2018 - 11:06:39 EST


On Thu, Nov 29, 2018 at 10:21:58AM -0500, Waiman Long wrote:

> >> diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c
> >> index 09b1800..50d9af6 100644
> >> --- a/kernel/locking/rwsem-xadd.c
> >> +++ b/kernel/locking/rwsem-xadd.c
> >> @@ -198,15 +198,22 @@ static void __rwsem_mark_wake(struct rw_semaphore *sem,
> >> woken++;
> >> tsk = waiter->task;
> >>
> >> - wake_q_add(wake_q, tsk);
> >> + get_task_struct(tsk);
> >> list_del(&waiter->list);
> >> /*
> >> - * Ensure that the last operation is setting the reader
> >> + * Ensure calling get_task_struct() before setting the reader
> >> * waiter to nil such that rwsem_down_read_failed() cannot
> >> * race with do_exit() by always holding a reference count
> >> * to the task to wakeup.
> >> */
> >> smp_store_release(&waiter->task, NULL);
> >> + /*
> >> + * Ensure issuing the wakeup (either by us or someone else)
> >> + * after setting the reader waiter to nil.
> >> + */
> >> + wake_q_add(wake_q, tsk);
> >> + /* wake_q_add() already take the task ref */
> >> + put_task_struct(tsk);
> >> }
> >>
> >> adjustment = woken * RWSEM_ACTIVE_READ_BIAS - adjustment;
>
> I doubt putting wake_q_add() after clearing waiter->task can really fix

Why; at that point we know the wakeup will happen after, which is all we
require.