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
This commit is contained in:
parent
c21443c2c7
commit
c8da19b986
@ -1466,7 +1466,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
|
|||||||
struct nfs4_state_owner *sp = data->owner;
|
struct nfs4_state_owner *sp = data->owner;
|
||||||
|
|
||||||
if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0)
|
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
|
* Check if we still need to send an OPEN call, or if we can use
|
||||||
* a delegation instead.
|
* a delegation instead.
|
||||||
@ -1501,6 +1501,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
|
|||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
out_no_action:
|
out_no_action:
|
||||||
task->tk_action = NULL;
|
task->tk_action = NULL;
|
||||||
|
out_wait:
|
||||||
nfs4_sequence_done(task, &data->o_res.seq_res);
|
nfs4_sequence_done(task, &data->o_res.seq_res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2179,7 +2180,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
|||||||
|
|
||||||
dprintk("%s: begin!\n", __func__);
|
dprintk("%s: begin!\n", __func__);
|
||||||
if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
|
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];
|
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
|
||||||
calldata->arg.fmode = FMODE_READ|FMODE_WRITE;
|
calldata->arg.fmode = FMODE_READ|FMODE_WRITE;
|
||||||
@ -2201,16 +2202,14 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
|||||||
|
|
||||||
if (!call_close) {
|
if (!call_close) {
|
||||||
/* Note: exit _without_ calling nfs4_close_done */
|
/* Note: exit _without_ calling nfs4_close_done */
|
||||||
task->tk_action = NULL;
|
goto out_no_action;
|
||||||
nfs4_sequence_done(task, &calldata->res.seq_res);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calldata->arg.fmode == 0) {
|
if (calldata->arg.fmode == 0) {
|
||||||
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
|
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
|
||||||
if (calldata->roc &&
|
if (calldata->roc &&
|
||||||
pnfs_roc_drain(inode, &calldata->roc_barrier, task))
|
pnfs_roc_drain(inode, &calldata->roc_barrier, task))
|
||||||
goto out;
|
goto out_wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
nfs_fattr_init(calldata->res.fattr);
|
nfs_fattr_init(calldata->res.fattr);
|
||||||
@ -2220,8 +2219,12 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
|||||||
&calldata->res.seq_res,
|
&calldata->res.seq_res,
|
||||||
task) != 0)
|
task) != 0)
|
||||||
nfs_release_seqid(calldata->arg.seqid);
|
nfs_release_seqid(calldata->arg.seqid);
|
||||||
out:
|
|
||||||
dprintk("%s: done!\n", __func__);
|
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 = {
|
static const struct rpc_call_ops nfs4_close_ops = {
|
||||||
@ -4452,12 +4455,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
|
|||||||
struct nfs4_unlockdata *calldata = data;
|
struct nfs4_unlockdata *calldata = data;
|
||||||
|
|
||||||
if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
|
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) {
|
if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
|
||||||
/* Note: exit _without_ running nfs4_locku_done */
|
/* Note: exit _without_ running nfs4_locku_done */
|
||||||
task->tk_action = NULL;
|
goto out_no_action;
|
||||||
nfs4_sequence_done(task, &calldata->res.seq_res);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
calldata->timestamp = jiffies;
|
calldata->timestamp = jiffies;
|
||||||
if (nfs4_setup_sequence(calldata->server,
|
if (nfs4_setup_sequence(calldata->server,
|
||||||
@ -4465,6 +4466,11 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
|
|||||||
&calldata->res.seq_res,
|
&calldata->res.seq_res,
|
||||||
task) != 0)
|
task) != 0)
|
||||||
nfs_release_seqid(calldata->arg.seqid);
|
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 = {
|
static const struct rpc_call_ops nfs4_locku_ops = {
|
||||||
@ -4612,7 +4618,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
|
|||||||
|
|
||||||
dprintk("%s: begin!\n", __func__);
|
dprintk("%s: begin!\n", __func__);
|
||||||
if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
|
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? */
|
/* Do we need to do an open_to_lock_owner? */
|
||||||
if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
|
if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
|
||||||
if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) {
|
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)
|
|||||||
nfs_release_seqid(data->arg.open_seqid);
|
nfs_release_seqid(data->arg.open_seqid);
|
||||||
out_release_lock_seqid:
|
out_release_lock_seqid:
|
||||||
nfs_release_seqid(data->arg.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);
|
dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user