Skip to content

Commit 51069e4

Browse files
author
Trond Myklebust
committed
NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn
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: be36e18 ("NFSv4: nfs4_open_recover_helper() must set share access") Signed-off-by: Trond Myklebust <[email protected]>
1 parent e83458f commit 51069e4

File tree

1 file changed

+12
-7
lines changed

1 file changed

+12
-7
lines changed

fs/nfs/nfs4proc.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,18 +2131,18 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
21312131
}
21322132

21332133
static int nfs4_open_recover_helper(struct nfs4_opendata *opendata,
2134-
fmode_t fmode)
2134+
fmode_t fmode)
21352135
{
21362136
struct nfs4_state *newstate;
2137+
struct nfs_server *server = NFS_SB(opendata->dentry->d_sb);
2138+
int openflags = opendata->o_arg.open_flags;
21372139
int ret;
21382140

21392141
if (!nfs4_mode_match_open_stateid(opendata->state, fmode))
21402142
return 0;
2141-
opendata->o_arg.open_flags = 0;
21422143
opendata->o_arg.fmode = fmode;
2143-
opendata->o_arg.share_access = nfs4_map_atomic_open_share(
2144-
NFS_SB(opendata->dentry->d_sb),
2145-
fmode, 0);
2144+
opendata->o_arg.share_access =
2145+
nfs4_map_atomic_open_share(server, fmode, openflags);
21462146
memset(&opendata->o_res, 0, sizeof(opendata->o_res));
21472147
memset(&opendata->c_res, 0, sizeof(opendata->c_res));
21482148
nfs4_init_opendata_res(opendata);
@@ -2724,10 +2724,15 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s
27242724
struct nfs4_opendata *opendata;
27252725
int ret;
27262726

2727-
opendata = nfs4_open_recoverdata_alloc(ctx, state,
2728-
NFS4_OPEN_CLAIM_FH);
2727+
opendata = nfs4_open_recoverdata_alloc(ctx, state, NFS4_OPEN_CLAIM_FH);
27292728
if (IS_ERR(opendata))
27302729
return PTR_ERR(opendata);
2730+
/*
2731+
* We're not recovering a delegation, so ask for no delegation.
2732+
* Otherwise the recovery thread could deadlock with an outstanding
2733+
* delegation return.
2734+
*/
2735+
opendata->o_arg.open_flags = O_DIRECT;
27312736
ret = nfs4_open_recover(opendata, state);
27322737
if (ret == -ESTALE)
27332738
d_drop(ctx->dentry);

0 commit comments

Comments
 (0)