Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFSv4.1: Clear the old state by our client id before establishing a new lease

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>

+17 -5
+11 -4
fs/nfs/nfs4proc.c
··· 6897 6897 6898 6898 if (status == 0) { 6899 6899 clp->cl_clientid = res.clientid; 6900 - clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R); 6901 - if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R)) 6900 + clp->cl_exchange_flags = res.flags; 6901 + /* Client ID is not confirmed */ 6902 + if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R)) { 6903 + clear_bit(NFS4_SESSION_ESTABLISHED, 6904 + &clp->cl_session->session_state); 6902 6905 clp->cl_seqid = res.seqid; 6906 + } 6903 6907 6904 6908 kfree(clp->cl_serverowner); 6905 6909 clp->cl_serverowner = res.server_owner; ··· 7235 7231 struct nfs41_create_session_res *res) 7236 7232 { 7237 7233 nfs4_copy_sessionid(&session->sess_id, &res->sessionid); 7234 + /* Mark client id and session as being confirmed */ 7235 + session->clp->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 7236 + set_bit(NFS4_SESSION_ESTABLISHED, &session->session_state); 7238 7237 session->flags = res->flags; 7239 7238 memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs)); 7240 7239 if (res->flags & SESSION4_BACK_CHAN) ··· 7333 7326 dprintk("--> nfs4_proc_destroy_session\n"); 7334 7327 7335 7328 /* session is still being setup */ 7336 - if (session->clp->cl_cons_state != NFS_CS_READY) 7337 - return status; 7329 + if (!test_and_clear_bit(NFS4_SESSION_ESTABLISHED, &session->session_state)) 7330 + return 0; 7338 7331 7339 7332 status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); 7340 7333 trace_nfs4_destroy_session(session->clp, status);
+1
fs/nfs/nfs4session.h
··· 70 70 71 71 enum nfs4_session_state { 72 72 NFS4_SESSION_INITING, 73 + NFS4_SESSION_ESTABLISHED, 73 74 }; 74 75 75 76 extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl,
+5 -1
fs/nfs/nfs4state.c
··· 353 353 if (clp != *result) 354 354 return 0; 355 355 356 - set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); 356 + /* Purge state if the client id was established in a prior instance */ 357 + if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R) 358 + set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state); 359 + else 360 + set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); 357 361 nfs4_schedule_state_manager(clp); 358 362 status = nfs_wait_client_init_complete(clp); 359 363 if (status < 0)