1) wake_q_add() contains a memory barrier, and callers such as ipc/mqueue.c rely on this barrier. Unfortunately, this is documented in ipc/mqueue.c, and not in the description of wake_q_add(). Therefore: Update the documentation. Removing/updating ipc/mqueue.c will happen with the next patch in the series.
2) wake_up_q() relies on the memory barrier in try_to_wake_up(). Add a comment, to simplify searching. 3) wake_q.next is accessed without synchroniyation by wake_q_add(), using cmpxchg_relaxed(), and by wake_up_q(). Therefore: Use WRITE_ONCE in wake_up_q(), to ensure that the compiler doesn't perform any tricks. Signed-off-by: Manfred Spraul <manf...@colorfullife.com> Cc: Davidlohr Bueso <d...@stgolabs.net> --- kernel/sched/core.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index dd05a378631a..2cf3f7321303 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -440,8 +440,11 @@ static bool __wake_q_add(struct wake_q_head *head, struct task_struct *task) * @task: the task to queue for 'later' wakeup * * Queue a task for later wakeup, most likely by the wake_up_q() call in the - * same context, _HOWEVER_ this is not guaranteed, the wakeup can come - * instantly. + * same context, _HOWEVER_ this is not guaranteed. Especially, the wakeup + * may happen before the function returns. + * + * What is guaranteed is that there is a memory barrier before the wakeup, + * callers may rely on this barrier. * * This function must be used as-if it were wake_up_process(); IOW the task * must be ready to be woken at this location. @@ -486,11 +489,14 @@ void wake_up_q(struct wake_q_head *head) BUG_ON(!task); /* Task can safely be re-inserted now: */ node = node->next; - task->wake_q.next = NULL; + + WRITE_ONCE(task->wake_q.next, NULL); /* * wake_up_process() executes a full barrier, which pairs with * the queueing in wake_q_add() so as not to miss wakeups. + * The barrier is the smp_mb__after_spinlock() in + * try_to_wake_up(). */ wake_up_process(task); put_task_struct(task); -- 2.21.0