mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
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: be36e185bd
("NFSv4: nfs4_open_recover_helper() must set share access")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
parent
e83458fce0
commit
51069e4aef
@ -2131,18 +2131,18 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int nfs4_open_recover_helper(struct nfs4_opendata *opendata,
|
static int nfs4_open_recover_helper(struct nfs4_opendata *opendata,
|
||||||
fmode_t fmode)
|
fmode_t fmode)
|
||||||
{
|
{
|
||||||
struct nfs4_state *newstate;
|
struct nfs4_state *newstate;
|
||||||
|
struct nfs_server *server = NFS_SB(opendata->dentry->d_sb);
|
||||||
|
int openflags = opendata->o_arg.open_flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!nfs4_mode_match_open_stateid(opendata->state, fmode))
|
if (!nfs4_mode_match_open_stateid(opendata->state, fmode))
|
||||||
return 0;
|
return 0;
|
||||||
opendata->o_arg.open_flags = 0;
|
|
||||||
opendata->o_arg.fmode = fmode;
|
opendata->o_arg.fmode = fmode;
|
||||||
opendata->o_arg.share_access = nfs4_map_atomic_open_share(
|
opendata->o_arg.share_access =
|
||||||
NFS_SB(opendata->dentry->d_sb),
|
nfs4_map_atomic_open_share(server, fmode, openflags);
|
||||||
fmode, 0);
|
|
||||||
memset(&opendata->o_res, 0, sizeof(opendata->o_res));
|
memset(&opendata->o_res, 0, sizeof(opendata->o_res));
|
||||||
memset(&opendata->c_res, 0, sizeof(opendata->c_res));
|
memset(&opendata->c_res, 0, sizeof(opendata->c_res));
|
||||||
nfs4_init_opendata_res(opendata);
|
nfs4_init_opendata_res(opendata);
|
||||||
@ -2724,10 +2724,15 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s
|
|||||||
struct nfs4_opendata *opendata;
|
struct nfs4_opendata *opendata;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
opendata = nfs4_open_recoverdata_alloc(ctx, state,
|
opendata = nfs4_open_recoverdata_alloc(ctx, state, NFS4_OPEN_CLAIM_FH);
|
||||||
NFS4_OPEN_CLAIM_FH);
|
|
||||||
if (IS_ERR(opendata))
|
if (IS_ERR(opendata))
|
||||||
return PTR_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);
|
ret = nfs4_open_recover(opendata, state);
|
||||||
if (ret == -ESTALE)
|
if (ret == -ESTALE)
|
||||||
d_drop(ctx->dentry);
|
d_drop(ctx->dentry);
|
||||||
|
Loading…
Reference in New Issue
Block a user