While trying to track down some issues involving large numbers of delegations being recalled/revoked, I caught the server setting SEQ4_STATUS_CB_PATH_DOWN while the client was actively responding to CB_RECALLs. It turns out that the client had already done a TEST_STATEID and FREE_STATEID for a delegation being recalled by the time it received the CB_RECALL. Signed-off-by: Scott Mayhew <smayhew@xxxxxxxxxx> --- fs/nfsd/nfs4state.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6a45fb00c5fc..e88e429133a8 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3958,6 +3958,14 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, rpc_delay(task, 2 * HZ); return 0; } + /* + * Race: client may have done a FREE_STATEID before + * receiving the CB_RECALL. + */ + if (dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID && + refcount_read(&dp->dl_stid.sc_count) == 1 && + list_empty(&dp->dl_recall_lru)) + return 1; /*FALLTHRU*/ default: return -1; -- 2.17.2