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 | } |
