@@ -2915,6 +2915,19 @@ find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions)
if (same_clid(&clp->cl_clientid, clid)) {
if ((bool)clp->cl_minorversion != sessions)
return NULL;
+
+ /* need to sync with thread resolving lock/deleg conflict */
+ clear_bit(NFSD4_CLIENT_RECONNECTED, &clp->cl_flags);
+ spin_lock(&clp->cl_cs_lock);
+ if (test_bit(NFSD4_CLIENT_EXPIRED, &clp->cl_flags)) {
+ spin_unlock(&clp->cl_cs_lock);
+ continue;
+ }
+ if (test_bit(NFSD4_CLIENT_COURTESY, &clp->cl_flags)) {
+ clear_bit(NFSD4_CLIENT_COURTESY, &clp->cl_flags);
+ set_bit(NFSD4_CLIENT_RECONNECTED, &clp->cl_flags);
+ }
+ spin_unlock(&clp->cl_cs_lock);
renew_client_locked(clp);
return clp;
}
@@ -2922,6 +2935,7 @@ find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions)
return NULL;
}
+
static void
nfsd4_discard_courtesy_clnt(struct nfs4_client *clp)
{
@@ -2934,9 +2948,15 @@ static struct nfs4_client *
find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
{
struct list_head *tbl = nn->conf_id_hashtbl;
+ struct nfs4_client *clp;
lockdep_assert_held(&nn->client_lock);
- return find_client_in_id_table(tbl, clid, sessions);
+ clp = find_client_in_id_table(tbl, clid, sessions);
+ if (clp && test_bit(NFSD4_CLIENT_RECONNECTED, &clp->cl_flags)) {
+ nfsd4_discard_courtesy_clnt(clp);
+ clp = NULL;
+ }
+ return clp;
}
static struct nfs4_client *
@@ -4867,9 +4887,10 @@ static struct nfs4_client *lookup_clientid(clientid_t *clid, bool sessions,
struct nfsd_net *nn)
{
struct nfs4_client *found;
+ struct list_head *tbl = nn->conf_id_hashtbl;
spin_lock(&nn->client_lock);
- found = find_confirmed_client(clid, sessions, nn);
+ found = find_client_in_id_table(tbl, clid, sessions);
if (found)
atomic_inc(&found->cl_rpc_users);
spin_unlock(&nn->client_lock);
@@ -4894,6 +4915,8 @@ static __be32 set_client(clientid_t *clid,
cstate->clp = lookup_clientid(clid, false, nn);
if (!cstate->clp)
return nfserr_expired;
+ if (test_bit(NFSD4_CLIENT_RECONNECTED, &cstate->clp->cl_flags))
+ nfsd4_client_record_create(cstate->clp);
return nfs_ok;
}
@@ -6222,6 +6245,13 @@ static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st,
found = lookup_clientid(&cps->cp_p_clid, true, nn);
if (!found)
goto out;
+ if (test_bit(NFSD4_CLIENT_RECONNECTED, &found->cl_flags)) {
+ nfsd4_discard_courtesy_clnt(found);
+ if (atomic_dec_and_lock(&found->cl_rpc_users,
+ &nn->client_lock))
+ spin_unlock(&nn->client_lock);
+ goto out;
+ }
*stid = find_stateid_by_type(found, &cps->cp_p_stateid,
NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID);
Update find_client_in_id_table to: . skip client with CLIENT_EXPIRED; discarded courtesy client . if courtesy client was found then clear CLIENT_COURTESY and set CLIENT_RECONNECTED flag so callers can take appropriate action. Update find_confirmed_client to discard courtesy client. Update lookup_clientid to call find_client_in_id_table directly. Update set_client to create client record for courtesy client. Update find_cpntf_state to discard courtesy client. Signed-off-by: Dai Ngo <dai.ngo@oracle.com> --- fs/nfsd/nfs4state.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-)