Commit 48d66b97 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

NFSv4: Fix a race in NFSv4.1 server trunking discovery



We do not want to allow a race with another NFS mount to cause
nfs41_walk_client_list() to establish a lease on our nfs_client before
we're done checking for trunking.

Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent ef070dcb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -433,7 +433,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat

static bool nfs_client_init_is_complete(const struct nfs_client *clp)
{
	return clp->cl_cons_state != NFS_CS_INITING;
	return clp->cl_cons_state <= NFS_CS_READY;
}

int nfs_wait_client_init_complete(const struct nfs_client *clp)
+4 −5
Original line number Diff line number Diff line
@@ -621,6 +621,9 @@ int nfs41_walk_client_list(struct nfs_client *new,
	spin_lock(&nn->nfs_client_lock);
	list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {

		if (pos == new)
			goto found;

		if (pos->rpc_ops != new->rpc_ops)
			continue;

@@ -639,10 +642,6 @@ int nfs41_walk_client_list(struct nfs_client *new,
			prev = pos;

			status = nfs_wait_client_init_complete(pos);
			if (pos->cl_cons_state == NFS_CS_SESSION_INITING) {
				nfs4_schedule_lease_recovery(pos);
				status = nfs4_wait_clnt_recover(pos);
			}
			spin_lock(&nn->nfs_client_lock);
			if (status < 0)
				break;
@@ -668,7 +667,7 @@ int nfs41_walk_client_list(struct nfs_client *new,
		 */
		if (!nfs4_match_client_owner_id(pos, new))
			continue;

found:
		atomic_inc(&pos->cl_count);
		*result = pos;
		status = 0;
+12 −2
Original line number Diff line number Diff line
@@ -346,9 +346,19 @@ int nfs41_discover_server_trunking(struct nfs_client *clp,
	status = nfs4_proc_exchange_id(clp, cred);
	if (status != NFS4_OK)
		return status;
	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);

	return nfs41_walk_client_list(clp, result, cred);
	status = nfs41_walk_client_list(clp, result, cred);
	if (status < 0)
		return status;
	if (clp != *result)
		return 0;

	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
	nfs4_schedule_state_manager(clp);
	status = nfs_wait_client_init_complete(clp);
	if (status < 0)
		nfs_put_client(clp);
	return status;
}

#endif /* CONFIG_NFS_V4_1 */