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

Commit 5447f1ad authored by Trond Myklebust's avatar Trond Myklebust Committed by Greg Kroah-Hartman
Browse files

NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn



[ Upstream commit 51069e4aef6257b0454057359faed0ab0c9af083 ]

If we're asked to recover open state while a delegation return is
outstanding, then the state manager thread cannot use a cached open, so
if the server returns a delegation, we can end up deadlocked behind the
pending delegreturn.
To avoid this problem, let's just ask the server not to give us a
delegation unless we're explicitly reclaiming one.

Fixes: be36e185 ("NFSv4: nfs4_open_recover_helper() must set share access")
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent e53a7c28
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -2088,15 +2088,15 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata,
				    fmode_t fmode)
{
	struct nfs4_state *newstate;
	struct nfs_server *server = NFS_SB(opendata->dentry->d_sb);
	int openflags = opendata->o_arg.open_flags;
	int ret;

	if (!nfs4_mode_match_open_stateid(opendata->state, fmode))
		return 0;
	opendata->o_arg.open_flags = 0;
	opendata->o_arg.fmode = fmode;
	opendata->o_arg.share_access = nfs4_map_atomic_open_share(
			NFS_SB(opendata->dentry->d_sb),
			fmode, 0);
	opendata->o_arg.share_access =
		nfs4_map_atomic_open_share(server, fmode, openflags);
	memset(&opendata->o_res, 0, sizeof(opendata->o_res));
	memset(&opendata->c_res, 0, sizeof(opendata->c_res));
	nfs4_init_opendata_res(opendata);
@@ -2671,10 +2671,15 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s
	struct nfs4_opendata *opendata;
	int ret;

	opendata = nfs4_open_recoverdata_alloc(ctx, state,
			NFS4_OPEN_CLAIM_FH);
	opendata = nfs4_open_recoverdata_alloc(ctx, state, NFS4_OPEN_CLAIM_FH);
	if (IS_ERR(opendata))
		return PTR_ERR(opendata);
	/*
	 * We're not recovering a delegation, so ask for no delegation.
	 * Otherwise the recovery thread could deadlock with an outstanding
	 * delegation return.
	 */
	opendata->o_arg.open_flags = O_DIRECT;
	ret = nfs4_open_recover(opendata, state);
	if (ret == -ESTALE)
		d_drop(ctx->dentry);