Skip to content

Commit

Permalink
NFSv4.1 fix infinite loop on I/O.
Browse files Browse the repository at this point in the history
The previous fix broke recovery of delegated stateids because it assumes
that if we did not mark the delegation as suspect, then the delegation has
effectively been revoked, and so it removes that delegation irrespectively
of whether or not it is valid and still in use. While this is "mostly
harmless" for ordinary I/O, we've seen pNFS fail with LAYOUTGET spinning
in an infinite loop while complaining that we're using an invalid stateid
(in this case the all-zero stateid).

What we rather want to do here is ensure that the delegation is always
correctly marked as needing testing when that is the case. So we want
to close the loophole offered by nfs4_schedule_stateid_recovery(),
which marks the state as needing to be reclaimed, but not the
delegation that may be backing it.

Fixes: 0e3d3e5 ("NFSv4.1 fix infinite loop on IO BAD_STATEID error")
Signed-off-by: Trond Myklebust <[email protected]>
Cc: [email protected] # v4.11+
Signed-off-by: Anna Schumaker <[email protected]>
  • Loading branch information
trondmy authored and amschuma-ntap committed Sep 14, 2018
1 parent 2edaead commit 994b15b
Showing 2 changed files with 9 additions and 3 deletions.
10 changes: 7 additions & 3 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
@@ -2676,14 +2676,18 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
}

nfs4_stateid_copy(&stateid, &delegation->stateid);
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) ||
!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
&delegation->flags)) {
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
rcu_read_unlock();
nfs_finish_clear_delegation_stateid(state, &stateid);
return;
}

if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
&delegation->flags)) {
rcu_read_unlock();
return;
}

cred = get_rpccred(delegation->cred);
rcu_read_unlock();
status = nfs41_test_and_free_expired_stateid(server, &stateid, cred);
2 changes: 2 additions & 0 deletions fs/nfs/nfs4state.c
Original file line number Diff line number Diff line change
@@ -1390,6 +1390,8 @@ int nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_

if (!nfs4_state_mark_reclaim_nograce(clp, state))
return -EBADF;
nfs_inode_find_delegation_state_and_recover(state->inode,
&state->stateid);
dprintk("%s: scheduling stateid recovery for server %s\n", __func__,
clp->cl_hostname);
nfs4_schedule_state_manager(clp);

0 comments on commit 994b15b

Please sign in to comment.