diff options
-rw-r--r-- | fs/nfsd/nfs4state.c | 23 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 6 |
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 | ||
98 | static void free_session(struct nfsd4_session *); | 98 | static void free_session(struct nfsd4_session *); |
99 | 99 | ||
100 | void nfsd4_put_session(struct nfsd4_session *ses) | 100 | static 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 | ||
105 | static bool is_session_dead(struct nfsd4_session *ses) | 105 | void 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 | ||
110 | static __be32 mark_session_dead_locked(struct nfsd4_session *ses) | 111 | static __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; |
2108 | out_put_session: | ||
2109 | nfsd4_put_session(ses); | ||
2105 | out_client_lock: | 2110 | out_client_lock: |
2106 | spin_unlock(&nn->client_lock); | 2111 | spin_unlock(&nn->client_lock); |
2107 | out: | 2112 | out: |
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 | } |