lkml.org 
[lkml]   [2011]   [Aug]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[05/50] SUNRPC: Fix a race between work-queue and rpc_killall_tasks
    2.6.33-longterm review patch.  If anyone has any objections, please let us know.

    ------------------

    From: Trond Myklebust <Trond.Myklebust@netapp.com>

    commit b55c59892e1f3b6c7d4b9ccffb4263e1486fb990 upstream.

    Since rpc_killall_tasks may modify the rpc_task's tk_action field
    without any locking, we need to be careful when dereferencing it.

    Reported-by: Ben Greear <greearb@candelatech.com>
    Tested-by: Ben Greear <greearb@candelatech.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    net/sunrpc/sched.c | 27 +++++++++++----------------
    1 file changed, 11 insertions(+), 16 deletions(-)

    --- a/net/sunrpc/sched.c
    +++ b/net/sunrpc/sched.c
    @@ -628,30 +628,25 @@ static void __rpc_execute(struct rpc_tas
    BUG_ON(RPC_IS_QUEUED(task));

    for (;;) {
    + void (*do_action)(struct rpc_task *);

    /*
    - * Execute any pending callback.
    + * Execute any pending callback first.
    */
    - if (task->tk_callback) {
    - void (*save_callback)(struct rpc_task *);
    -
    - /*
    - * We set tk_callback to NULL before calling it,
    - * in case it sets the tk_callback field itself:
    - */
    - save_callback = task->tk_callback;
    - task->tk_callback = NULL;
    - save_callback(task);
    - } else {
    + do_action = task->tk_callback;
    + task->tk_callback = NULL;
    + if (do_action == NULL) {
    /*
    * Perform the next FSM step.
    - * tk_action may be NULL when the task has been killed
    - * by someone else.
    + * tk_action may be NULL if the task has been killed.
    + * In particular, note that rpc_killall_tasks may
    + * do this at any time, so beware when dereferencing.
    */
    - if (task->tk_action == NULL)
    + do_action = task->tk_action;
    + if (do_action == NULL)
    break;
    - task->tk_action(task);
    }
    + do_action(task);

    /*
    * Lockless check for whether task is sleeping or not.



    \
     
     \ /
      Last update: 2011-08-06 02:19    [W:0.019 / U:18.912 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site