Skip to content

Commit

Permalink
NFSv4: Fix atomicity problems with lock stateid updates
Browse files Browse the repository at this point in the history
When we update the lock stateid, we really do need to ensure that this is
done under the state->state_lock, and that we are indeed only updating
confirmed locks with a newer version of the same stateid.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
  • Loading branch information
Trond Myklebust committed Jan 24, 2015
1 parent 63f5f79 commit 39071e6
Showing 1 changed file with 29 additions and 13 deletions.
42 changes: 29 additions & 13 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1297,6 +1297,23 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat
return ret;
}

static bool nfs4_update_lock_stateid(struct nfs4_lock_state *lsp,
const nfs4_stateid *stateid)
{
struct nfs4_state *state = lsp->ls_state;
bool ret = false;

spin_lock(&state->state_lock);
if (!nfs4_stateid_match_other(stateid, &lsp->ls_stateid))
goto out_noupdate;
if (!nfs4_stateid_is_newer(stateid, &lsp->ls_stateid))
goto out_noupdate;
nfs4_stateid_copy(&lsp->ls_stateid, stateid);
ret = true;
out_noupdate:
spin_unlock(&state->state_lock);
return ret;
}

static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmode)
{
Expand Down Expand Up @@ -5403,9 +5420,9 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
return;
switch (task->tk_status) {
case 0:
nfs4_stateid_copy(&calldata->lsp->ls_stateid,
&calldata->res.stateid);
renew_lease(calldata->server, calldata->timestamp);
nfs4_update_lock_stateid(calldata->lsp,
&calldata->res.stateid);
break;
case -NFS4ERR_BAD_STATEID:
case -NFS4ERR_OLD_STATEID:
Expand Down Expand Up @@ -5626,25 +5643,24 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
static void nfs4_lock_done(struct rpc_task *task, void *calldata)
{
struct nfs4_lockdata *data = calldata;
struct nfs4_lock_state *lsp = data->lsp;

dprintk("%s: begin!\n", __func__);

if (!nfs4_sequence_done(task, &data->res.seq_res))
return;

data->rpc_status = task->tk_status;
if (data->arg.new_lock_owner != 0) {
if (data->rpc_status == 0)
nfs_confirm_seqid(&data->lsp->ls_seqid, 0);
else
goto out;
}
if (data->rpc_status == 0) {
nfs4_stateid_copy(&data->lsp->ls_stateid, &data->res.stateid);
set_bit(NFS_LOCK_INITIALIZED, &data->lsp->ls_flags);
renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);
if (task->tk_status == 0) {
renew_lease(NFS_SERVER(data->ctx->dentry->d_inode),
data->timestamp);
if (data->arg.new_lock_owner != 0) {
nfs_confirm_seqid(&lsp->ls_seqid, 0);
nfs4_stateid_copy(&lsp->ls_stateid, &data->res.stateid);
set_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
} else if (!nfs4_update_lock_stateid(lsp, &data->res.stateid))
rpc_restart_call_prepare(task);
}
out:
dprintk("%s: done, ret = %d!\n", __func__, data->rpc_status);
}

Expand Down

0 comments on commit 39071e6

Please sign in to comment.