diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-02-11 19:01:21 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-02-11 19:04:25 -0500 |
commit | c8da19b9866ea84e9ad1c369393ea95d54ee7845 (patch) | |
tree | 31e00f66f682f2e27e21ade87e1d3e00cd07f6f7 /fs/nfs/nfs4proc.c | |
parent | c21443c2c792cd9b463646d982b0fe48aa6feb0f (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
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 32 |
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(); |
1502 | out_no_action: | 1502 | out_no_action: |
1503 | task->tk_action = NULL; | 1503 | task->tk_action = NULL; |
1504 | out_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); |
2223 | out: | ||
2224 | dprintk("%s: done!\n", __func__); | 2222 | dprintk("%s: done!\n", __func__); |
2223 | return; | ||
2224 | out_no_action: | ||
2225 | task->tk_action = NULL; | ||
2226 | out_wait: | ||
2227 | nfs4_sequence_done(task, &calldata->res.seq_res); | ||
2225 | } | 2228 | } |
2226 | 2229 | ||
2227 | static const struct rpc_call_ops nfs4_close_ops = { | 2230 | static 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; | ||
4470 | out_no_action: | ||
4471 | task->tk_action = NULL; | ||
4472 | out_wait: | ||
4473 | nfs4_sequence_done(task, &calldata->res.seq_res); | ||
4468 | } | 4474 | } |
4469 | 4475 | ||
4470 | static const struct rpc_call_ops nfs4_locku_ops = { | 4476 | static 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); |
4633 | out_release_lock_seqid: | 4639 | out_release_lock_seqid: |
4634 | nfs_release_seqid(data->arg.lock_seqid); | 4640 | nfs_release_seqid(data->arg.lock_seqid); |
4641 | out_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 | ||