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

Commit 12f275cd authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker
Browse files

NFSv4: Retry CLOSE and DELEGRETURN on NFS4ERR_OLD_STATEID.



If we're racing with an OPEN, then retry the operation instead of
declaring it a success.

Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
[Andrew W Elble: Fix a typo in nfs4_refresh_open_stateid]
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent d803224c
Loading
Loading
Loading
Loading
+27 −0
Original line number Original line Diff line number Diff line
@@ -1040,6 +1040,33 @@ int nfs_delegations_present(struct nfs_client *clp)
	return ret;
	return ret;
}
}


/**
 * nfs4_refresh_delegation_stateid - Update delegation stateid seqid
 * @dst: stateid to refresh
 * @inode: inode to check
 *
 * Returns "true" and updates "dst->seqid" * if inode had a delegation
 * that matches our delegation stateid. Otherwise "false" is returned.
 */
bool nfs4_refresh_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
{
	struct nfs_delegation *delegation;
	bool ret = false;
	if (!inode)
		goto out;

	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
	if (delegation != NULL &&
	    nfs4_stateid_match_other(dst, &delegation->stateid)) {
		dst->seqid = delegation->stateid.seqid;
		return ret;
	}
	rcu_read_unlock();
out:
	return ret;
}

/**
/**
 * nfs4_copy_delegation_stateid - Copy inode's state ID information
 * nfs4_copy_delegation_stateid - Copy inode's state ID information
 * @inode: inode to check
 * @inode: inode to check
+1 −0
Original line number Original line Diff line number Diff line
@@ -61,6 +61,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid, fmode_t type);
int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid, fmode_t type);
int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid);
int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid);
bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, nfs4_stateid *dst, struct rpc_cred **cred);
bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, nfs4_stateid *dst, struct rpc_cred **cred);
bool nfs4_refresh_delegation_stateid(nfs4_stateid *dst, struct inode *inode);


void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
int nfs4_have_delegation(struct inode *inode, fmode_t flags);
int nfs4_have_delegation(struct inode *inode, fmode_t flags);
+2 −0
Original line number Original line Diff line number Diff line
@@ -460,6 +460,8 @@ extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
		const struct nfs_lock_context *, nfs4_stateid *,
		const struct nfs_lock_context *, nfs4_stateid *,
		struct rpc_cred **);
		struct rpc_cred **);
extern bool nfs4_refresh_open_stateid(nfs4_stateid *dst,
		struct nfs4_state *state);


extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
+19 −2
Original line number Original line Diff line number Diff line
@@ -3199,13 +3199,21 @@ static void nfs4_close_done(struct rpc_task *task, void *data)


			}
			}
			break;
			break;
		case -NFS4ERR_OLD_STATEID:
			/* Did we race with OPEN? */
			if (nfs4_refresh_open_stateid(&calldata->arg.stateid,
						state)) {
				task->tk_status = 0;
				rpc_restart_call_prepare(task);
			}
			goto out_release;
		case -NFS4ERR_ADMIN_REVOKED:
		case -NFS4ERR_ADMIN_REVOKED:
		case -NFS4ERR_STALE_STATEID:
		case -NFS4ERR_STALE_STATEID:
		case -NFS4ERR_EXPIRED:
		case -NFS4ERR_EXPIRED:
			nfs4_free_revoked_stateid(server,
			nfs4_free_revoked_stateid(server,
					&calldata->arg.stateid,
					&calldata->arg.stateid,
					task->tk_msg.rpc_cred);
					task->tk_msg.rpc_cred);
		case -NFS4ERR_OLD_STATEID:
			/* Fallthrough */
		case -NFS4ERR_BAD_STATEID:
		case -NFS4ERR_BAD_STATEID:
			if (!nfs4_stateid_match(&calldata->arg.stateid,
			if (!nfs4_stateid_match(&calldata->arg.stateid,
						&state->open_stateid)) {
						&state->open_stateid)) {
@@ -3214,6 +3222,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
			}
			}
			if (calldata->arg.fmode == 0)
			if (calldata->arg.fmode == 0)
				break;
				break;
			/* Fallthrough */
		default:
		default:
			if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN) {
			if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN) {
				rpc_restart_call_prepare(task);
				rpc_restart_call_prepare(task);
@@ -5793,11 +5802,19 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
		nfs4_free_revoked_stateid(data->res.server,
		nfs4_free_revoked_stateid(data->res.server,
				data->args.stateid,
				data->args.stateid,
				task->tk_msg.rpc_cred);
				task->tk_msg.rpc_cred);
		/* Fallthrough */
	case -NFS4ERR_BAD_STATEID:
	case -NFS4ERR_BAD_STATEID:
	case -NFS4ERR_OLD_STATEID:
	case -NFS4ERR_STALE_STATEID:
	case -NFS4ERR_STALE_STATEID:
		task->tk_status = 0;
		task->tk_status = 0;
		break;
		break;
	case -NFS4ERR_OLD_STATEID:
		if (nfs4_refresh_delegation_stateid(&data->stateid, data->inode)) {
			task->tk_status = 0;
			rpc_restart_call_prepare(task);
			return;
		}
		task->tk_status = 0;
		break;
	case -NFS4ERR_ACCESS:
	case -NFS4ERR_ACCESS:
		if (data->args.bitmask) {
		if (data->args.bitmask) {
			data->args.bitmask = NULL;
			data->args.bitmask = NULL;
+16 −0
Original line number Original line Diff line number Diff line
@@ -986,6 +986,22 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
	return ret;
	return ret;
}
}


bool nfs4_refresh_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
{
	bool ret;
	int seq;

	do {
		ret = false;
		seq = read_seqbegin(&state->seqlock);
		if (nfs4_state_match_open_stateid_other(state, dst)) {
			dst->seqid = state->open_stateid.seqid;
			ret = true;
		}
	} while (read_seqretry(&state->seqlock, seq));
	return ret;
}

static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
{
{
	const nfs4_stateid *src;
	const nfs4_stateid *src;