aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/nfs4state.c23
-rw-r--r--fs/nfsd/nfs4xdr.c6
2 files changed, 19 insertions, 10 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d44a4bf71cef..25ae6cedb73a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -97,19 +97,20 @@ nfs4_lock_state(void)
97 97
98static void free_session(struct nfsd4_session *); 98static void free_session(struct nfsd4_session *);
99 99
100void nfsd4_put_session(struct nfsd4_session *ses) 100static bool is_session_dead(struct nfsd4_session *ses)
101{ 101{
102 atomic_dec(&ses->se_ref); 102 return ses->se_flags & NFS4_SESSION_DEAD;
103} 103}
104 104
105static bool is_session_dead(struct nfsd4_session *ses) 105void nfsd4_put_session(struct nfsd4_session *ses)
106{ 106{
107 return ses->se_flags & NFS4_SESSION_DEAD; 107 if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
108 free_session(ses);
108} 109}
109 110
110static __be32 mark_session_dead_locked(struct nfsd4_session *ses) 111static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me)
111{ 112{
112 if (atomic_read(&ses->se_ref)) 113 if (atomic_read(&ses->se_ref) > ref_held_by_me)
113 return nfserr_jukebox; 114 return nfserr_jukebox;
114 ses->se_flags |= NFS4_SESSION_DEAD; 115 ses->se_flags |= NFS4_SESSION_DEAD;
115 return nfs_ok; 116 return nfs_ok;
@@ -2074,6 +2075,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
2074{ 2075{
2075 struct nfsd4_session *ses; 2076 struct nfsd4_session *ses;
2076 __be32 status; 2077 __be32 status;
2078 int ref_held_by_me = 0;
2077 struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); 2079 struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id);
2078 2080
2079 nfs4_lock_state(); 2081 nfs4_lock_state();
@@ -2081,6 +2083,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
2081 if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { 2083 if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
2082 if (!nfsd4_last_compound_op(r)) 2084 if (!nfsd4_last_compound_op(r))
2083 goto out; 2085 goto out;
2086 ref_held_by_me++;
2084 } 2087 }
2085 dump_sessionid(__func__, &sessionid->sessionid); 2088 dump_sessionid(__func__, &sessionid->sessionid);
2086 spin_lock(&nn->client_lock); 2089 spin_lock(&nn->client_lock);
@@ -2091,17 +2094,19 @@ nfsd4_destroy_session(struct svc_rqst *r,
2091 status = nfserr_wrong_cred; 2094 status = nfserr_wrong_cred;
2092 if (!mach_creds_match(ses->se_client, r)) 2095 if (!mach_creds_match(ses->se_client, r))
2093 goto out_client_lock; 2096 goto out_client_lock;
2094 status = mark_session_dead_locked(ses); 2097 nfsd4_get_session_locked(ses);
2098 status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
2095 if (status) 2099 if (status)
2096 goto out_client_lock; 2100 goto out_put_session;
2097 unhash_session(ses); 2101 unhash_session(ses);
2098 spin_unlock(&nn->client_lock); 2102 spin_unlock(&nn->client_lock);
2099 2103
2100 nfsd4_probe_callback_sync(ses->se_client); 2104 nfsd4_probe_callback_sync(ses->se_client);
2101 2105
2102 spin_lock(&nn->client_lock); 2106 spin_lock(&nn->client_lock);
2103 free_session(ses);
2104 status = nfs_ok; 2107 status = nfs_ok;
2108out_put_session:
2109 nfsd4_put_session(ses);
2105out_client_lock: 2110out_client_lock:
2106 spin_unlock(&nn->client_lock); 2111 spin_unlock(&nn->client_lock);
2107out: 2112out:
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index c102d2509a2a..0c0f3ea90de5 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3760,13 +3760,17 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
3760 iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; 3760 iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base;
3761 BUG_ON(iov->iov_len > PAGE_SIZE); 3761 BUG_ON(iov->iov_len > PAGE_SIZE);
3762 if (nfsd4_has_session(cs)) { 3762 if (nfsd4_has_session(cs)) {
3763 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
3764 struct nfs4_client *clp = cs->session->se_client;
3763 if (cs->status != nfserr_replay_cache) { 3765 if (cs->status != nfserr_replay_cache) {
3764 nfsd4_store_cache_entry(resp); 3766 nfsd4_store_cache_entry(resp);
3765 cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 3767 cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
3766 } 3768 }
3767 /* Renew the clientid on success and on replay */ 3769 /* Renew the clientid on success and on replay */
3768 put_client_renew(cs->session->se_client); 3770 spin_lock(&nn->client_lock);
3769 nfsd4_put_session(cs->session); 3771 nfsd4_put_session(cs->session);
3772 spin_unlock(&nn->client_lock);
3773 put_client_renew(clp);
3770 } 3774 }
3771 return 1; 3775 return 1;
3772} 3776}