aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-02-11 19:01:21 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-02-11 19:04:25 -0500
commitc8da19b9866ea84e9ad1c369393ea95d54ee7845 (patch)
tree31e00f66f682f2e27e21ade87e1d3e00cd07f6f7
parentc21443c2c792cd9b463646d982b0fe48aa6feb0f (diff)
NFSv4.1: Fix an ABBA locking issue with session and state serialisation
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> Cc: stable@vger.kernel.org
-rw-r--r--fs/nfs/nfs4proc.c32
1 files changed, 20 insertions, 12 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 7cbf7aa6c634..cf252dfd91f8 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1466,7 +1466,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
1466 struct nfs4_state_owner *sp = data->owner; 1466 struct nfs4_state_owner *sp = data->owner;
1467 1467
1468 if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) 1468 if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0)
1469 return; 1469 goto out_wait;
1470 /* 1470 /*
1471 * Check if we still need to send an OPEN call, or if we can use 1471 * Check if we still need to send an OPEN call, or if we can use
1472 * a delegation instead. 1472 * a delegation instead.
@@ -1501,6 +1501,7 @@ unlock_no_action:
1501 rcu_read_unlock(); 1501 rcu_read_unlock();
1502out_no_action: 1502out_no_action:
1503 task->tk_action = NULL; 1503 task->tk_action = NULL;
1504out_wait:
1504 nfs4_sequence_done(task, &data->o_res.seq_res); 1505 nfs4_sequence_done(task, &data->o_res.seq_res);
1505} 1506}
1506 1507
@@ -2179,7 +2180,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
2179 2180
2180 dprintk("%s: begin!\n", __func__); 2181 dprintk("%s: begin!\n", __func__);
2181 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) 2182 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
2182 return; 2183 goto out_wait;
2183 2184
2184 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; 2185 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
2185 calldata->arg.fmode = FMODE_READ|FMODE_WRITE; 2186 calldata->arg.fmode = FMODE_READ|FMODE_WRITE;
@@ -2201,16 +2202,14 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
2201 2202
2202 if (!call_close) { 2203 if (!call_close) {
2203 /* Note: exit _without_ calling nfs4_close_done */ 2204 /* Note: exit _without_ calling nfs4_close_done */
2204 task->tk_action = NULL; 2205 goto out_no_action;
2205 nfs4_sequence_done(task, &calldata->res.seq_res);
2206 goto out;
2207 } 2206 }
2208 2207
2209 if (calldata->arg.fmode == 0) { 2208 if (calldata->arg.fmode == 0) {
2210 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; 2209 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
2211 if (calldata->roc && 2210 if (calldata->roc &&
2212 pnfs_roc_drain(inode, &calldata->roc_barrier, task)) 2211 pnfs_roc_drain(inode, &calldata->roc_barrier, task))
2213 goto out; 2212 goto out_wait;
2214 } 2213 }
2215 2214
2216 nfs_fattr_init(calldata->res.fattr); 2215 nfs_fattr_init(calldata->res.fattr);
@@ -2220,8 +2219,12 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
2220 &calldata->res.seq_res, 2219 &calldata->res.seq_res,
2221 task) != 0) 2220 task) != 0)
2222 nfs_release_seqid(calldata->arg.seqid); 2221 nfs_release_seqid(calldata->arg.seqid);
2223out:
2224 dprintk("%s: done!\n", __func__); 2222 dprintk("%s: done!\n", __func__);
2223 return;
2224out_no_action:
2225 task->tk_action = NULL;
2226out_wait:
2227 nfs4_sequence_done(task, &calldata->res.seq_res);
2225} 2228}
2226 2229
2227static const struct rpc_call_ops nfs4_close_ops = { 2230static const struct rpc_call_ops nfs4_close_ops = {
@@ -4452,12 +4455,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
4452 struct nfs4_unlockdata *calldata = data; 4455 struct nfs4_unlockdata *calldata = data;
4453 4456
4454 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) 4457 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
4455 return; 4458 goto out_wait;
4456 if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) { 4459 if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
4457 /* Note: exit _without_ running nfs4_locku_done */ 4460 /* Note: exit _without_ running nfs4_locku_done */
4458 task->tk_action = NULL; 4461 goto out_no_action;
4459 nfs4_sequence_done(task, &calldata->res.seq_res);
4460 return;
4461 } 4462 }
4462 calldata->timestamp = jiffies; 4463 calldata->timestamp = jiffies;
4463 if (nfs4_setup_sequence(calldata->server, 4464 if (nfs4_setup_sequence(calldata->server,
@@ -4465,6 +4466,11 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
4465 &calldata->res.seq_res, 4466 &calldata->res.seq_res,
4466 task) != 0) 4467 task) != 0)
4467 nfs_release_seqid(calldata->arg.seqid); 4468 nfs_release_seqid(calldata->arg.seqid);
4469 return;
4470out_no_action:
4471 task->tk_action = NULL;
4472out_wait:
4473 nfs4_sequence_done(task, &calldata->res.seq_res);
4468} 4474}
4469 4475
4470static const struct rpc_call_ops nfs4_locku_ops = { 4476static const struct rpc_call_ops nfs4_locku_ops = {
@@ -4612,7 +4618,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
4612 4618
4613 dprintk("%s: begin!\n", __func__); 4619 dprintk("%s: begin!\n", __func__);
4614 if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) 4620 if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
4615 return; 4621 goto out_wait;
4616 /* Do we need to do an open_to_lock_owner? */ 4622 /* Do we need to do an open_to_lock_owner? */
4617 if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { 4623 if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
4618 if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) { 4624 if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) {
@@ -4632,6 +4638,8 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
4632 nfs_release_seqid(data->arg.open_seqid); 4638 nfs_release_seqid(data->arg.open_seqid);
4633out_release_lock_seqid: 4639out_release_lock_seqid:
4634 nfs_release_seqid(data->arg.lock_seqid); 4640 nfs_release_seqid(data->arg.lock_seqid);
4641out_wait:
4642 nfs4_sequence_done(task, &data->res.seq_res);
4635 dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); 4643 dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
4636} 4644}
4637 4645