mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-05 08:26:59 +00:00
NFSv4.1: Fix open stateid recovery
The logic for checking in nfs41_check_open_stateid() whether the state
is supported by a delegation is inverted. In addition, it makes more
sense to perform that check before we check for expired locks.
Fixes: 8a64c4ef10
("NFSv4.1: Even if the stateid is OK,...")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
parent
731c74dd98
commit
27a30cf64a
1 changed files with 38 additions and 27 deletions
|
@ -1683,6 +1683,14 @@ static void nfs_state_set_open_stateid(struct nfs4_state *state,
|
||||||
write_sequnlock(&state->seqlock);
|
write_sequnlock(&state->seqlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nfs_state_clear_open_state_flags(struct nfs4_state *state)
|
||||||
|
{
|
||||||
|
clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
||||||
|
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
||||||
|
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
||||||
|
clear_bit(NFS_OPEN_STATE, &state->flags);
|
||||||
|
}
|
||||||
|
|
||||||
static void nfs_state_set_delegation(struct nfs4_state *state,
|
static void nfs_state_set_delegation(struct nfs4_state *state,
|
||||||
const nfs4_stateid *deleg_stateid,
|
const nfs4_stateid *deleg_stateid,
|
||||||
fmode_t fmode)
|
fmode_t fmode)
|
||||||
|
@ -2074,13 +2082,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */
|
|
||||||
clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
||||||
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
||||||
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
||||||
/* memory barrier prior to reading state->n_* */
|
/* memory barrier prior to reading state->n_* */
|
||||||
clear_bit(NFS_DELEGATED_STATE, &state->flags);
|
|
||||||
clear_bit(NFS_OPEN_STATE, &state->flags);
|
|
||||||
smp_rmb();
|
smp_rmb();
|
||||||
ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
|
ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
|
@ -2156,6 +2158,8 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta
|
||||||
ctx = nfs4_state_find_open_context(state);
|
ctx = nfs4_state_find_open_context(state);
|
||||||
if (IS_ERR(ctx))
|
if (IS_ERR(ctx))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
clear_bit(NFS_DELEGATED_STATE, &state->flags);
|
||||||
|
nfs_state_clear_open_state_flags(state);
|
||||||
ret = nfs4_do_open_reclaim(ctx, state);
|
ret = nfs4_do_open_reclaim(ctx, state);
|
||||||
put_nfs_open_context(ctx);
|
put_nfs_open_context(ctx);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -2697,6 +2701,7 @@ static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
|
||||||
{
|
{
|
||||||
/* NFSv4.0 doesn't allow for delegation recovery on open expire */
|
/* NFSv4.0 doesn't allow for delegation recovery on open expire */
|
||||||
nfs40_clear_delegation_stateid(state);
|
nfs40_clear_delegation_stateid(state);
|
||||||
|
nfs_state_clear_open_state_flags(state);
|
||||||
return nfs4_open_expired(sp, state);
|
return nfs4_open_expired(sp, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2739,13 +2744,13 @@ static int nfs41_test_and_free_expired_stateid(struct nfs_server *server,
|
||||||
return -NFS4ERR_EXPIRED;
|
return -NFS4ERR_EXPIRED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs41_check_delegation_stateid(struct nfs4_state *state)
|
static int nfs41_check_delegation_stateid(struct nfs4_state *state)
|
||||||
{
|
{
|
||||||
struct nfs_server *server = NFS_SERVER(state->inode);
|
struct nfs_server *server = NFS_SERVER(state->inode);
|
||||||
nfs4_stateid stateid;
|
nfs4_stateid stateid;
|
||||||
struct nfs_delegation *delegation;
|
struct nfs_delegation *delegation;
|
||||||
const struct cred *cred = NULL;
|
const struct cred *cred = NULL;
|
||||||
int status;
|
int status, ret = NFS_OK;
|
||||||
|
|
||||||
/* Get the delegation credential for use by test/free_stateid */
|
/* Get the delegation credential for use by test/free_stateid */
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
@ -2753,20 +2758,15 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
|
||||||
if (delegation == NULL) {
|
if (delegation == NULL) {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
nfs_state_clear_delegation(state);
|
nfs_state_clear_delegation(state);
|
||||||
return;
|
return NFS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nfs4_stateid_copy(&stateid, &delegation->stateid);
|
nfs4_stateid_copy(&stateid, &delegation->stateid);
|
||||||
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
nfs_state_clear_delegation(state);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
|
if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
|
||||||
&delegation->flags)) {
|
&delegation->flags)) {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return;
|
return NFS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delegation->cred)
|
if (delegation->cred)
|
||||||
|
@ -2776,8 +2776,24 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
|
||||||
trace_nfs4_test_delegation_stateid(state, NULL, status);
|
trace_nfs4_test_delegation_stateid(state, NULL, status);
|
||||||
if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID)
|
if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID)
|
||||||
nfs_finish_clear_delegation_stateid(state, &stateid);
|
nfs_finish_clear_delegation_stateid(state, &stateid);
|
||||||
|
else
|
||||||
|
ret = status;
|
||||||
|
|
||||||
put_cred(cred);
|
put_cred(cred);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs41_delegation_recover_stateid(struct nfs4_state *state)
|
||||||
|
{
|
||||||
|
nfs4_stateid tmp;
|
||||||
|
|
||||||
|
if (test_bit(NFS_DELEGATED_STATE, &state->flags) &&
|
||||||
|
nfs4_copy_delegation_stateid(state->inode, state->state,
|
||||||
|
&tmp, NULL) &&
|
||||||
|
nfs4_stateid_match_other(&state->stateid, &tmp))
|
||||||
|
nfs_state_set_delegation(state, &tmp, state->state);
|
||||||
|
else
|
||||||
|
nfs_state_clear_delegation(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2847,21 +2863,12 @@ static int nfs41_check_open_stateid(struct nfs4_state *state)
|
||||||
const struct cred *cred = state->owner->so_cred;
|
const struct cred *cred = state->owner->so_cred;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (test_bit(NFS_OPEN_STATE, &state->flags) == 0) {
|
if (test_bit(NFS_OPEN_STATE, &state->flags) == 0)
|
||||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) {
|
|
||||||
if (nfs4_have_delegation(state->inode, state->state))
|
|
||||||
return NFS_OK;
|
|
||||||
return -NFS4ERR_OPENMODE;
|
|
||||||
}
|
|
||||||
return -NFS4ERR_BAD_STATEID;
|
return -NFS4ERR_BAD_STATEID;
|
||||||
}
|
|
||||||
status = nfs41_test_and_free_expired_stateid(server, stateid, cred);
|
status = nfs41_test_and_free_expired_stateid(server, stateid, cred);
|
||||||
trace_nfs4_test_open_stateid(state, NULL, status);
|
trace_nfs4_test_open_stateid(state, NULL, status);
|
||||||
if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) {
|
if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) {
|
||||||
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
nfs_state_clear_open_state_flags(state);
|
||||||
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
||||||
clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
||||||
clear_bit(NFS_OPEN_STATE, &state->flags);
|
|
||||||
stateid->type = NFS4_INVALID_STATEID_TYPE;
|
stateid->type = NFS4_INVALID_STATEID_TYPE;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -2874,7 +2881,11 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
nfs41_check_delegation_stateid(state);
|
status = nfs41_check_delegation_stateid(state);
|
||||||
|
if (status != NFS_OK)
|
||||||
|
return status;
|
||||||
|
nfs41_delegation_recover_stateid(state);
|
||||||
|
|
||||||
status = nfs41_check_expired_locks(state);
|
status = nfs41_check_expired_locks(state);
|
||||||
if (status != NFS_OK)
|
if (status != NFS_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
Loading…
Reference in a new issue