RPC: killing RPC tasks races fixed
authorStanislav Kinsbursky <skinsbursky@parallels.com>
Thu, 17 Mar 2011 15:54:23 +0000 (18:54 +0300)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 17 Mar 2011 16:39:00 +0000 (12:39 -0400)
commit8e26de238fd794c8ea56a5c98bf67c40cfeb051d
tree3c8d0e6b1e6e0782b13221ee6c39e5be09552dd9
parentba3c578de274a5438bafbce03f9225936698051c
RPC: killing RPC tasks races fixed

RPC task RPC_TASK_QUEUED bit is set must be checked before trying to wake up
task rpc_killall_tasks() because task->tk_waitqueue can not be set (equal to
NULL).
Also, as Trond Myklebust mentioned, such approach (instead of checking
tk_waitqueue to NULL) allows us to "optimise away the call to
rpc_wake_up_queued_task() altogether for those
tasks that aren't queued".

Here is an example of dereferencing of tk_waitqueue equal to NULL:

CPU 0                CPU 1 CPU 2
-------------------- --------------------- --------------------------
nfs4_run_open_task
rpc_run_task
rpc_execute
rpc_set_active
rpc_make_runnable
(waiting)
rpc_async_schedule
nfs4_open_prepare
nfs_wait_on_sequence
nfs_umount_begin
rpc_killall_tasks
rpc_wake_up_task
rpc_wake_up_queued_task
spin_lock(tk_waitqueue == NULL)
BUG()
rpc_sleep_on
spin_lock(&q->lock)
__rpc_sleep_on
task->tk_waitqueue = q

Signed-off-by: Stanislav Kinsbursky <skinsbursky@openvz.org>
Cc: stable@kernel.org
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
net/sunrpc/clnt.c