]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
NFSv4.1: Fix an ABBA locking issue with session and state serialisation
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 12 Feb 2013 00:01:21 +0000 (19:01 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 28 Feb 2013 13:38:32 +0000 (05:38 -0800)
commit c8da19b9866ea84e9ad1c369393ea95d54ee7845 upstream.

Ensure that if nfs_wait_on_sequence() causes our rpc task to wait for
an NFSv4 state serialisation lock, then we also drop the session slot.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/nfs/nfs4proc.c

index cf747ef8665078a2a684b256402ab63484a77665..124d0c5ba32df3ed2a784d44e1daff7405c745dc 100644 (file)
@@ -1463,7 +1463,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
        struct nfs4_state_owner *sp = data->owner;
 
        if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0)
-               return;
+               goto out_wait;
        /*
         * Check if we still need to send an OPEN call, or if we can use
         * a delegation instead.
@@ -1498,6 +1498,7 @@ unlock_no_action:
        rcu_read_unlock();
 out_no_action:
        task->tk_action = NULL;
+out_wait:
        nfs4_sequence_done(task, &data->o_res.seq_res);
 }
 
@@ -2150,7 +2151,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
 
        dprintk("%s: begin!\n", __func__);
        if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
-               return;
+               goto out_wait;
 
        task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
        calldata->arg.fmode = FMODE_READ|FMODE_WRITE;
@@ -2172,16 +2173,14 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
 
        if (!call_close) {
                /* Note: exit _without_ calling nfs4_close_done */
-               task->tk_action = NULL;
-               nfs4_sequence_done(task, &calldata->res.seq_res);
-               goto out;
+               goto out_no_action;
        }
 
        if (calldata->arg.fmode == 0) {
                task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
                if (calldata->roc &&
                    pnfs_roc_drain(inode, &calldata->roc_barrier, task))
-                       goto out;
+                       goto out_wait;
        }
 
        nfs_fattr_init(calldata->res.fattr);
@@ -2191,8 +2190,12 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                                &calldata->res.seq_res,
                                task) != 0)
                nfs_release_seqid(calldata->arg.seqid);
-out:
        dprintk("%s: done!\n", __func__);
+       return;
+out_no_action:
+       task->tk_action = NULL;
+out_wait:
+       nfs4_sequence_done(task, &calldata->res.seq_res);
 }
 
 static const struct rpc_call_ops nfs4_close_ops = {
@@ -4423,12 +4426,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
        struct nfs4_unlockdata *calldata = data;
 
        if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
-               return;
+               goto out_wait;
        if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
                /* Note: exit _without_ running nfs4_locku_done */
-               task->tk_action = NULL;
-               nfs4_sequence_done(task, &calldata->res.seq_res);
-               return;
+               goto out_no_action;
        }
        calldata->timestamp = jiffies;
        if (nfs4_setup_sequence(calldata->server,
@@ -4436,6 +4437,11 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
                                &calldata->res.seq_res,
                                task) != 0)
                nfs_release_seqid(calldata->arg.seqid);
+       return;
+out_no_action:
+       task->tk_action = NULL;
+out_wait:
+       nfs4_sequence_done(task, &calldata->res.seq_res);
 }
 
 static const struct rpc_call_ops nfs4_locku_ops = {
@@ -4576,7 +4582,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
 
        dprintk("%s: begin!\n", __func__);
        if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
-               return;
+               goto out_wait;
        /* Do we need to do an open_to_lock_owner? */
        if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
                if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) {
@@ -4596,6 +4602,8 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
        nfs_release_seqid(data->arg.open_seqid);
 out_release_lock_seqid:
        nfs_release_seqid(data->arg.lock_seqid);
+out_wait:
+       nfs4_sequence_done(task, &data->res.seq_res);
        dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
 }