aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2015-01-24 16:03:52 -0500
committerTrond Myklebust <trond.myklebust@primarydata.com>2015-01-24 18:46:47 -0500
commitc69899a17ca4836230720e65493942d9582a0424 (patch)
tree71d512aef12f51603adce636bfe0412ceda450e9 /fs/nfs/nfs4proc.c
parent425c1d4e5b6d4bd700eb94ad8318bdb05431fdc7 (diff)
NFSv4: Update of VFS byte range lock must be atomic with the stateid 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>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c37
1 files changed, 15 insertions, 22 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 41e7c2fc046e..9f6baf98942c 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -5420,9 +5420,10 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
5420 switch (task->tk_status) { 5420 switch (task->tk_status) {
5421 case 0: 5421 case 0:
5422 renew_lease(calldata->server, calldata->timestamp); 5422 renew_lease(calldata->server, calldata->timestamp);
5423 nfs4_update_lock_stateid(calldata->lsp, 5423 do_vfs_lock(calldata->fl.fl_file, &calldata->fl);
5424 &calldata->res.stateid); 5424 if (nfs4_update_lock_stateid(calldata->lsp,
5425 break; 5425 &calldata->res.stateid))
5426 break;
5426 case -NFS4ERR_BAD_STATEID: 5427 case -NFS4ERR_BAD_STATEID:
5427 case -NFS4ERR_OLD_STATEID: 5428 case -NFS4ERR_OLD_STATEID:
5428 case -NFS4ERR_STALE_STATEID: 5429 case -NFS4ERR_STALE_STATEID:
@@ -5661,6 +5662,13 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
5661 case 0: 5662 case 0:
5662 renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), 5663 renew_lease(NFS_SERVER(data->ctx->dentry->d_inode),
5663 data->timestamp); 5664 data->timestamp);
5665 if (data->arg.new_lock) {
5666 data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS);
5667 if (do_vfs_lock(data->fl.fl_file, &data->fl) < 0) {
5668 rpc_restart_call_prepare(task);
5669 break;
5670 }
5671 }
5664 if (data->arg.new_lock_owner != 0) { 5672 if (data->arg.new_lock_owner != 0) {
5665 nfs_confirm_seqid(&lsp->ls_seqid, 0); 5673 nfs_confirm_seqid(&lsp->ls_seqid, 0);
5666 nfs4_stateid_copy(&lsp->ls_stateid, &data->res.stateid); 5674 nfs4_stateid_copy(&lsp->ls_stateid, &data->res.stateid);
@@ -5760,7 +5768,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
5760 if (recovery_type == NFS_LOCK_RECLAIM) 5768 if (recovery_type == NFS_LOCK_RECLAIM)
5761 data->arg.reclaim = NFS_LOCK_RECLAIM; 5769 data->arg.reclaim = NFS_LOCK_RECLAIM;
5762 nfs4_set_sequence_privileged(&data->arg.seq_args); 5770 nfs4_set_sequence_privileged(&data->arg.seq_args);
5763 } 5771 } else
5772 data->arg.new_lock = 1;
5764 task = rpc_run_task(&task_setup_data); 5773 task = rpc_run_task(&task_setup_data);
5765 if (IS_ERR(task)) 5774 if (IS_ERR(task))
5766 return PTR_ERR(task); 5775 return PTR_ERR(task);
@@ -5884,10 +5893,8 @@ static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *reques
5884 5893
5885static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) 5894static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
5886{ 5895{
5887 struct nfs4_state_owner *sp = state->owner;
5888 struct nfs_inode *nfsi = NFS_I(state->inode); 5896 struct nfs_inode *nfsi = NFS_I(state->inode);
5889 unsigned char fl_flags = request->fl_flags; 5897 unsigned char fl_flags = request->fl_flags;
5890 unsigned int seq;
5891 int status = -ENOLCK; 5898 int status = -ENOLCK;
5892 5899
5893 if ((fl_flags & FL_POSIX) && 5900 if ((fl_flags & FL_POSIX) &&
@@ -5907,25 +5914,11 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
5907 /* ...but avoid races with delegation recall... */ 5914 /* ...but avoid races with delegation recall... */
5908 request->fl_flags = fl_flags & ~FL_SLEEP; 5915 request->fl_flags = fl_flags & ~FL_SLEEP;
5909 status = do_vfs_lock(request->fl_file, request); 5916 status = do_vfs_lock(request->fl_file, request);
5910 goto out_unlock; 5917 up_read(&nfsi->rwsem);
5911 }
5912 seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
5913 up_read(&nfsi->rwsem);
5914 status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
5915 if (status != 0)
5916 goto out; 5918 goto out;
5917 down_read(&nfsi->rwsem);
5918 if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) {
5919 status = -NFS4ERR_DELAY;
5920 goto out_unlock;
5921 } 5919 }
5922 /* Note: we always want to sleep here! */
5923 request->fl_flags = fl_flags | FL_SLEEP;
5924 if (do_vfs_lock(request->fl_file, request) < 0)
5925 printk(KERN_WARNING "NFS: %s: VFS is out of sync with lock "
5926 "manager!\n", __func__);
5927out_unlock:
5928 up_read(&nfsi->rwsem); 5920 up_read(&nfsi->rwsem);
5921 status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
5929out: 5922out:
5930 request->fl_flags = fl_flags; 5923 request->fl_flags = fl_flags;
5931 return status; 5924 return status;