• Stanislav Kinsbursky's avatar
    RPC: killing RPC tasks races fixed · ba3ffdc6
    Stanislav Kinsbursky authored
    commit 8e26de23 upstream.
    
    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: default avatarStanislav Kinsbursky <skinsbursky@openvz.org>
    Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
    ba3ffdc6
clnt.c 44.2 KB