NFSv4.1: Clear the old state by our client id before establishing a new lease
authorTrond Myklebust <trond.myklebust@primarydata.com>
Wed, 4 Mar 2015 01:35:31 +0000 (20:35 -0500)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Wed, 4 Mar 2015 02:52:30 +0000 (21:52 -0500)
If the call to exchange-id returns with the EXCHGID4_FLAG_CONFIRMED_R flag
set, then that means our lease was established by a previous mount instance.
Ensure that we detect this situation, and that we clear the state held by
that mount.

Reported-by: Jorge Mora <Jorge.Mora@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/nfs4proc.c
fs/nfs/nfs4session.h
fs/nfs/nfs4state.c

index 732526e04cd59bd63d1dc3990a5a3c5e5c111449..627f37c44456752d6bd90a8882ae373ec6d70718 100644 (file)
@@ -6897,9 +6897,13 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
 
        if (status == 0) {
                clp->cl_clientid = res.clientid;
-               clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R);
-               if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R))
+               clp->cl_exchange_flags = res.flags;
+               /* Client ID is not confirmed */
+               if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R)) {
+                       clear_bit(NFS4_SESSION_ESTABLISHED,
+                                       &clp->cl_session->session_state);
                        clp->cl_seqid = res.seqid;
+               }
 
                kfree(clp->cl_serverowner);
                clp->cl_serverowner = res.server_owner;
@@ -7231,6 +7235,9 @@ static void nfs4_update_session(struct nfs4_session *session,
                struct nfs41_create_session_res *res)
 {
        nfs4_copy_sessionid(&session->sess_id, &res->sessionid);
+       /* Mark client id and session as being confirmed */
+       session->clp->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
+       set_bit(NFS4_SESSION_ESTABLISHED, &session->session_state);
        session->flags = res->flags;
        memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs));
        if (res->flags & SESSION4_BACK_CHAN)
@@ -7326,8 +7333,8 @@ int nfs4_proc_destroy_session(struct nfs4_session *session,
        dprintk("--> nfs4_proc_destroy_session\n");
 
        /* session is still being setup */
-       if (session->clp->cl_cons_state != NFS_CS_READY)
-               return status;
+       if (!test_and_clear_bit(NFS4_SESSION_ESTABLISHED, &session->session_state))
+               return 0;
 
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
        trace_nfs4_destroy_session(session->clp, status);
index fc46c745589863425bff271942b76f7812db5aea..e3ea2c5324d68e92591058e896bf478538302a5a 100644 (file)
@@ -70,6 +70,7 @@ struct nfs4_session {
 
 enum nfs4_session_state {
        NFS4_SESSION_INITING,
+       NFS4_SESSION_ESTABLISHED,
 };
 
 extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl,
index d8b43f0e08fc62b9f99d341f57faea7a14d7420f..f95e3b58bbc304ae381df2a5f1721d8074789c51 100644 (file)
@@ -353,7 +353,11 @@ int nfs41_discover_server_trunking(struct nfs_client *clp,
        if (clp != *result)
                return 0;
 
-       set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+       /* Purge state if the client id was established in a prior instance */
+       if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R)
+               set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
+       else
+               set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
        nfs4_schedule_state_manager(clp);
        status = nfs_wait_client_init_complete(clp);
        if (status < 0)