Update find_in_sessionid_hashtbl to: . skip client with CLIENT_EXPIRED flag; discarded courtesy client. . if courtesy client was found then clear CLIENT_COURTESY and set CLIENT_RECONNECTED so callers can take appropriate action. Update nfsd4_sequence and nfsd4_bind_conn_to_session to create client record for client with CLIENT_RECONNECTED set. Update nfsd4_destroy_session to discard client with CLIENT_RECONNECTED set. Signed-off-by: Dai Ngo <dai.ngo@xxxxxxxxxx> --- fs/nfsd/nfs4state.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 4990553180f8..5cef1a78cc28 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1935,10 +1935,31 @@ find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, { struct nfsd4_session *session; __be32 status = nfserr_badsession; + struct nfs4_client *clp; session = __find_in_sessionid_hashtbl(sessionid, net); if (!session) goto out; + clp = session->se_client; + if (clp) { + clear_bit(NFSD4_CLIENT_RECONNECTED, &clp->cl_flags); + /* need to sync with thread resolving lock/deleg conflict */ + spin_lock(&clp->cl_cs_lock); + if (test_bit(NFSD4_CLIENT_EXPIRED, &clp->cl_flags)) { + spin_unlock(&clp->cl_cs_lock); + session = NULL; + goto out; + } + if (test_bit(NFSD4_CLIENT_COURTESY, &clp->cl_flags)) { + /* + * clear CLIENT_COURTESY flag to prevent it from being + * destroyed by thread trying to resolve conflicts. + */ + clear_bit(NFSD4_CLIENT_COURTESY, &clp->cl_flags); + set_bit(NFSD4_CLIENT_RECONNECTED, &clp->cl_flags); + } + spin_unlock(&clp->cl_cs_lock); + } status = nfsd4_get_session_locked(session); if (status) session = NULL; @@ -3661,6 +3682,7 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, struct nfsd4_session *session; struct net *net = SVC_NET(rqstp); struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct nfs4_client *clp; if (!nfsd4_last_compound_op(rqstp)) return nfserr_not_only_op; @@ -3693,6 +3715,13 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, nfsd4_init_conn(rqstp, conn, session); status = nfs_ok; out: + clp = session->se_client; + if (test_bit(NFSD4_CLIENT_RECONNECTED, &clp->cl_flags)) { + if (status == nfs_ok) + nfsd4_client_record_create(clp); + else + nfsd4_discard_courtesy_clnt(clp); + } nfsd4_put_session(session); out_no_session: return status; @@ -3715,6 +3744,7 @@ nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate, int ref_held_by_me = 0; struct net *net = SVC_NET(r); struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct nfs4_client *clp; status = nfserr_not_only_op; if (nfsd4_compound_in_session(cstate, sessionid)) { @@ -3727,6 +3757,12 @@ nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate, ses = find_in_sessionid_hashtbl(sessionid, net, &status); if (!ses) goto out_client_lock; + clp = ses->se_client; + if (test_bit(NFSD4_CLIENT_RECONNECTED, &clp->cl_flags)) { + status = nfserr_badsession; + nfsd4_discard_courtesy_clnt(clp); + goto out_put_session; + } status = nfserr_wrong_cred; if (!nfsd4_mach_creds_match(ses->se_client, r)) goto out_put_session; @@ -3831,7 +3867,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_compoundres *resp = rqstp->rq_resp; struct xdr_stream *xdr = resp->xdr; struct nfsd4_session *session; - struct nfs4_client *clp; + struct nfs4_client *clp = NULL; struct nfsd4_slot *slot; struct nfsd4_conn *conn; __be32 status; @@ -3941,6 +3977,12 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (conn) free_conn(conn); spin_unlock(&nn->client_lock); + if (clp && test_bit(NFSD4_CLIENT_RECONNECTED, &clp->cl_flags)) { + if (status == nfs_ok) + nfsd4_client_record_create(clp); + else + nfsd4_discard_courtesy_clnt(clp); + } return status; out_put_session: nfsd4_put_session_locked(session); -- 2.9.5