Skip to content

Commit

Permalink
NFSv4: Update of VFS byte range lock must be atomic with the stateid …
Browse files Browse the repository at this point in the history
…update

Ensure that we test the lock stateid remained unchanged while we were
updating the VFS tracking of the byte range lock. Have the process
replay the lock to the server if we detect that was not the case.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
  • Loading branch information
Trond Myklebust committed Jan 24, 2015
1 parent 425c1d4 commit c69899a
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 22 deletions.
37 changes: 15 additions & 22 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -5420,9 +5420,10 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
switch (task->tk_status) {
case 0:
renew_lease(calldata->server, calldata->timestamp);
nfs4_update_lock_stateid(calldata->lsp,
&calldata->res.stateid);
break;
do_vfs_lock(calldata->fl.fl_file, &calldata->fl);
if (nfs4_update_lock_stateid(calldata->lsp,
&calldata->res.stateid))
break;
case -NFS4ERR_BAD_STATEID:
case -NFS4ERR_OLD_STATEID:
case -NFS4ERR_STALE_STATEID:
Expand Down Expand Up @@ -5661,6 +5662,13 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
case 0:
renew_lease(NFS_SERVER(data->ctx->dentry->d_inode),
data->timestamp);
if (data->arg.new_lock) {
data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS);
if (do_vfs_lock(data->fl.fl_file, &data->fl) < 0) {
rpc_restart_call_prepare(task);
break;
}
}
if (data->arg.new_lock_owner != 0) {
nfs_confirm_seqid(&lsp->ls_seqid, 0);
nfs4_stateid_copy(&lsp->ls_stateid, &data->res.stateid);
Expand Down Expand Up @@ -5760,7 +5768,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
if (recovery_type == NFS_LOCK_RECLAIM)
data->arg.reclaim = NFS_LOCK_RECLAIM;
nfs4_set_sequence_privileged(&data->arg.seq_args);
}
} else
data->arg.new_lock = 1;
task = rpc_run_task(&task_setup_data);
if (IS_ERR(task))
return PTR_ERR(task);
Expand Down Expand Up @@ -5884,10 +5893,8 @@ static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *reques

static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
{
struct nfs4_state_owner *sp = state->owner;
struct nfs_inode *nfsi = NFS_I(state->inode);
unsigned char fl_flags = request->fl_flags;
unsigned int seq;
int status = -ENOLCK;

if ((fl_flags & FL_POSIX) &&
Expand All @@ -5907,25 +5914,11 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
/* ...but avoid races with delegation recall... */
request->fl_flags = fl_flags & ~FL_SLEEP;
status = do_vfs_lock(request->fl_file, request);
goto out_unlock;
}
seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
up_read(&nfsi->rwsem);
status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
if (status != 0)
up_read(&nfsi->rwsem);
goto out;
down_read(&nfsi->rwsem);
if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) {
status = -NFS4ERR_DELAY;
goto out_unlock;
}
/* Note: we always want to sleep here! */
request->fl_flags = fl_flags | FL_SLEEP;
if (do_vfs_lock(request->fl_file, request) < 0)
printk(KERN_WARNING "NFS: %s: VFS is out of sync with lock "
"manager!\n", __func__);
out_unlock:
up_read(&nfsi->rwsem);
status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
out:
request->fl_flags = fl_flags;
return status;
Expand Down
1 change: 1 addition & 0 deletions include/linux/nfs_xdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ struct nfs_lock_args {
struct nfs_lowner lock_owner;
unsigned char block : 1;
unsigned char reclaim : 1;
unsigned char new_lock : 1;
unsigned char new_lock_owner : 1;
};

Expand Down

0 comments on commit c69899a

Please sign in to comment.