Skip to content

Commit 994b15b

Browse files
trondmyamschuma-ntap
authored andcommitted
NFSv4.1 fix infinite loop on I/O.
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 <trond.myklebust@hammerspace.com> Cc: stable@vger.kernel.org # v4.11+ Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
1 parent 2edaead commit 994b15b

File tree

2 files changed

+9
-3
lines changed

2 files changed

+9
-3
lines changed

fs/nfs/nfs4proc.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2676,14 +2676,18 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
26762676
}
26772677

26782678
nfs4_stateid_copy(&stateid, &delegation->stateid);
2679-
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) ||
2680-
!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
2681-
&delegation->flags)) {
2679+
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
26822680
rcu_read_unlock();
26832681
nfs_finish_clear_delegation_stateid(state, &stateid);
26842682
return;
26852683
}
26862684

2685+
if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
2686+
&delegation->flags)) {
2687+
rcu_read_unlock();
2688+
return;
2689+
}
2690+
26872691
cred = get_rpccred(delegation->cred);
26882692
rcu_read_unlock();
26892693
status = nfs41_test_and_free_expired_stateid(server, &stateid, cred);

fs/nfs/nfs4state.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,8 @@ int nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_
13901390

13911391
if (!nfs4_state_mark_reclaim_nograce(clp, state))
13921392
return -EBADF;
1393+
nfs_inode_find_delegation_state_and_recover(state->inode,
1394+
&state->stateid);
13931395
dprintk("%s: scheduling stateid recovery for server %s\n", __func__,
13941396
clp->cl_hostname);
13951397
nfs4_schedule_state_manager(clp);

0 commit comments

Comments
 (0)