@@ -701,6 +701,22 @@ __nfs4_file_get_access(struct nfs4_file *fp, u32 access)
atomic_inc(&fp->fi_access[O_RDONLY]);
}
+static void
+nfsd4_reactivate_courtesy_client(struct nfs4_client *clp, __be32 status)
+{
+ spin_lock(&clp->cl_cs_lock);
+ if (clp->cl_cs_client_state == NFSD4_CLIENT_RECONNECTED) {
+ if (status == nfs_ok) {
+ clp->cl_cs_client_state = NFSD4_CLIENT_ACTIVE;
+ spin_unlock(&clp->cl_cs_lock);
+ nfsd4_client_record_create(clp);
+ return;
+ }
+ clp->cl_cs_client_state = NFSD4_CLIENT_EXPIRED;
+ }
+ spin_unlock(&clp->cl_cs_lock);
+}
+
/*
* Check if courtesy clients have conflicting access and resolve it if possible
*
@@ -1994,13 +2010,22 @@ 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 (nfsd4_courtesy_clnt_expired(clp)) {
+ session = NULL;
+ goto out;
+ }
status = nfsd4_get_session_locked(session);
- if (status)
+ if (status) {
session = NULL;
+ if (clp->cl_cs_client_state == NFSD4_CLIENT_RECONNECTED)
+ nfsd4_discard_courtesy_clnt(clp);
+ }
out:
*ret = status;
return session;
@@ -3702,6 +3727,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;
@@ -3734,6 +3760,8 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
nfsd4_init_conn(rqstp, conn, session);
status = nfs_ok;
out:
+ clp = session->se_client;
+ nfsd4_reactivate_courtesy_client(clp, status);
nfsd4_put_session(session);
out_no_session:
return status;
@@ -3756,6 +3784,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)) {
@@ -3768,6 +3797,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 (clp->cl_cs_client_state == NFSD4_CLIENT_RECONNECTED) {
+ 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;
@@ -3872,7 +3907,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;
@@ -3982,6 +4017,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (conn)
free_conn(conn);
spin_unlock(&nn->client_lock);
+ if (clp)
+ nfsd4_reactivate_courtesy_client(clp, status);
return status;
out_put_session:
nfsd4_put_session_locked(session);
Update find_in_sessionid_hashtbl to: . skip client with CLIENT_EXPIRED state; discarded courtesy client. . if courtesy client was found then set CLIENT_RECONNECTED so caller can take appropriate action. Update nfsd4_sequence and nfsd4_bind_conn_to_session to create client record for courtesy client with CLIENT_RECONNECTED state. Update nfsd4_destroy_session to discard courtesy client with CLIENT_RECONNECTED state. Signed-off-by: Dai Ngo <dai.ngo@oracle.com> --- fs/nfsd/nfs4state.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-)