X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=net%2Fsunrpc%2Fsched.c;h=5356b120dbf8e2fe61ba88081d1fab1941f135a9;hb=fdc0b43fbb0e0958f13d3453dfb9df707c0af904;hp=f8529fc8e54275c5b7b9809f0219f20608ffb472;hpb=c98cac899b6cd8ce5908c1d87708d78b41f6472d;p=~andy%2Flinux diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index f8529fc8e54..5356b120dbf 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -324,11 +324,17 @@ EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task); * Note: If the task is ASYNC, and is being made runnable after sitting on an * rpc_wait_queue, this must be called with the queue spinlock held to protect * the wait queue operation. + * Note the ordering of rpc_test_and_set_running() and rpc_clear_queued(), + * which is needed to ensure that __rpc_execute() doesn't loop (due to the + * lockless RPC_IS_QUEUED() test) before we've had a chance to test + * the RPC_TASK_RUNNING flag. */ static void rpc_make_runnable(struct rpc_task *task) { + bool need_wakeup = !rpc_test_and_set_running(task); + rpc_clear_queued(task); - if (rpc_test_and_set_running(task)) + if (!need_wakeup) return; if (RPC_IS_ASYNC(task)) { INIT_WORK(&task->u.tk_work, rpc_async_schedule);