Commit a3c3cac5d31879cd9ae2de7874dc6544ca704aec
1 parent
774d5f14ee
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
SUNRPC: Prevent an rpc_task wakeup race
The lockless RPC_IS_QUEUED() test in __rpc_execute means that we need to be careful about ordering the calls to rpc_test_and_set_running(task) and rpc_clear_queued(task). If we get the order wrong, then we may end up testing the RPC_TASK_RUNNING flag after __rpc_execute() has looped and changed the state of the rpc_task. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: stable@vger.kernel.org
Showing 1 changed file with 7 additions and 1 deletions Side-by-side Diff
net/sunrpc/sched.c
... | ... | @@ -324,11 +324,17 @@ |
324 | 324 | * Note: If the task is ASYNC, and is being made runnable after sitting on an |
325 | 325 | * rpc_wait_queue, this must be called with the queue spinlock held to protect |
326 | 326 | * the wait queue operation. |
327 | + * Note the ordering of rpc_test_and_set_running() and rpc_clear_queued(), | |
328 | + * which is needed to ensure that __rpc_execute() doesn't loop (due to the | |
329 | + * lockless RPC_IS_QUEUED() test) before we've had a chance to test | |
330 | + * the RPC_TASK_RUNNING flag. | |
327 | 331 | */ |
328 | 332 | static void rpc_make_runnable(struct rpc_task *task) |
329 | 333 | { |
334 | + bool need_wakeup = !rpc_test_and_set_running(task); | |
335 | + | |
330 | 336 | rpc_clear_queued(task); |
331 | - if (rpc_test_and_set_running(task)) | |
337 | + if (!need_wakeup) | |
332 | 338 | return; |
333 | 339 | if (RPC_IS_ASYNC(task)) { |
334 | 340 | INIT_WORK(&task->u.tk_work, rpc_async_schedule); |