|
@@ -198,15 +198,22 @@ static void __rwsem_mark_wake(struct rw_semaphore *sem,
|
|
|
woken++;
|
|
woken++;
|
|
|
tsk = waiter->task;
|
|
tsk = waiter->task;
|
|
|
|
|
|
|
|
- wake_q_add(wake_q, tsk);
|
|
|
|
|
|
|
+ get_task_struct(tsk);
|
|
|
list_del(&waiter->list);
|
|
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
|
|
* waiter to nil such that rwsem_down_read_failed() cannot
|
|
|
* race with do_exit() by always holding a reference count
|
|
* race with do_exit() by always holding a reference count
|
|
|
* to the task to wakeup.
|
|
* to the task to wakeup.
|
|
|
*/
|
|
*/
|
|
|
smp_store_release(&waiter->task, NULL);
|
|
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;
|
|
adjustment = woken * RWSEM_ACTIVE_READ_BIAS - adjustment;
|