Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c69899a1 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent 425c1d4e
Loading
Loading
Loading
Loading
+15 −22
Original line number Diff line number Diff line
@@ -5420,8 +5420,9 @@ 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);
			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:
@@ -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);
@@ -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);
@@ -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) &&
@@ -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)
		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;
+1 −0
Original line number Diff line number Diff line
@@ -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;
};