aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2013-03-19 12:05:39 -0400
committerJ. Bruce Fields <bfields@redhat.com>2013-04-03 11:48:40 -0400
commit66b2b9b2b0e8a9034806293a436628400a44a71d (patch)
treea1a142425240c28f7b942dc665afe77752c82ae1 /fs
parent221a68766973d7a3afe40a05abd8258b5de016a0 (diff)
nfsd4: don't destroy in-use session
This changes session destruction to be similar to client destruction in that attempts to destroy a session while in use (which should be rare corner cases) result in DELAY. This simplifies things somewhat and helps meet a coming 4.2 requirement. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4state.c72
-rw-r--r--fs/nfsd/state.h4
2 files changed, 43 insertions, 33 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3b4ce41c9db8..2fd015587167 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -94,17 +94,32 @@ nfs4_lock_state(void)
94 mutex_lock(&client_mutex); 94 mutex_lock(&client_mutex);
95} 95}
96 96
97static void free_session(struct kref *); 97static void free_session(struct nfsd4_session *);
98 98
99/* Must be called under the client_lock */ 99void nfsd4_put_session(struct nfsd4_session *ses)
100static void nfsd4_put_session_locked(struct nfsd4_session *ses) 100{
101 atomic_dec(&ses->se_ref);
102}
103
104static bool is_session_dead(struct nfsd4_session *ses)
101{ 105{
102 kref_put(&ses->se_ref, free_session); 106 return ses->se_flags & NFS4_SESSION_DEAD;
107}
108
109static __be32 mark_session_dead_locked(struct nfsd4_session *ses)
110{
111 if (atomic_read(&ses->se_ref))
112 return nfserr_jukebox;
113 ses->se_flags |= NFS4_SESSION_DEAD;
114 return nfs_ok;
103} 115}
104 116
105static void nfsd4_get_session(struct nfsd4_session *ses) 117static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
106{ 118{
107 kref_get(&ses->se_ref); 119 if (is_session_dead(ses))
120 return nfserr_badsession;
121 atomic_inc(&ses->se_ref);
122 return nfs_ok;
108} 123}
109 124
110void 125void
@@ -935,28 +950,15 @@ static void __free_session(struct nfsd4_session *ses)
935 kfree(ses); 950 kfree(ses);
936} 951}
937 952
938static void free_session(struct kref *kref) 953static void free_session(struct nfsd4_session *ses)
939{ 954{
940 struct nfsd4_session *ses; 955 struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id);
941 struct nfsd_net *nn;
942
943 ses = container_of(kref, struct nfsd4_session, se_ref);
944 nn = net_generic(ses->se_client->net, nfsd_net_id);
945 956
946 lockdep_assert_held(&nn->client_lock); 957 lockdep_assert_held(&nn->client_lock);
947 nfsd4_del_conns(ses); 958 nfsd4_del_conns(ses);
948 __free_session(ses); 959 __free_session(ses);
949} 960}
950 961
951void nfsd4_put_session(struct nfsd4_session *ses)
952{
953 struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id);
954
955 spin_lock(&nn->client_lock);
956 nfsd4_put_session_locked(ses);
957 spin_unlock(&nn->client_lock);
958}
959
960static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan, 962static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan,
961 struct nfsd_net *nn) 963 struct nfsd_net *nn)
962{ 964{
@@ -997,7 +999,7 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
997 new->se_flags = cses->flags; 999 new->se_flags = cses->flags;
998 new->se_cb_prog = cses->callback_prog; 1000 new->se_cb_prog = cses->callback_prog;
999 new->se_cb_sec = cses->cb_sec; 1001 new->se_cb_sec = cses->cb_sec;
1000 kref_init(&new->se_ref); 1002 atomic_set(&new->se_ref, 0);
1001 idx = hash_sessionid(&new->se_sessionid); 1003 idx = hash_sessionid(&new->se_sessionid);
1002 spin_lock(&nn->client_lock); 1004 spin_lock(&nn->client_lock);
1003 list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 1005 list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
@@ -1095,7 +1097,8 @@ free_client(struct nfs4_client *clp)
1095 ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 1097 ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
1096 se_perclnt); 1098 se_perclnt);
1097 list_del(&ses->se_perclnt); 1099 list_del(&ses->se_perclnt);
1098 nfsd4_put_session_locked(ses); 1100 WARN_ON_ONCE(atomic_read(&ses->se_ref));
1101 free_session(ses);
1099 } 1102 }
1100 free_svc_cred(&clp->cl_cred); 1103 free_svc_cred(&clp->cl_cred);
1101 kfree(clp->cl_name.data); 1104 kfree(clp->cl_name.data);
@@ -1976,15 +1979,16 @@ nfsd4_destroy_session(struct svc_rqst *r,
1976 status = nfserr_badsession; 1979 status = nfserr_badsession;
1977 if (!ses) 1980 if (!ses)
1978 goto out_client_lock; 1981 goto out_client_lock;
1979 1982 status = mark_session_dead_locked(ses);
1983 if (status)
1984 goto out_client_lock;
1980 unhash_session(ses); 1985 unhash_session(ses);
1981 spin_unlock(&nn->client_lock); 1986 spin_unlock(&nn->client_lock);
1982 1987
1983 nfsd4_probe_callback_sync(ses->se_client); 1988 nfsd4_probe_callback_sync(ses->se_client);
1984 1989
1985 spin_lock(&nn->client_lock); 1990 spin_lock(&nn->client_lock);
1986 nfsd4_del_conns(ses); 1991 free_session(ses);
1987 nfsd4_put_session_locked(ses);
1988 status = nfs_ok; 1992 status = nfs_ok;
1989out_client_lock: 1993out_client_lock:
1990 spin_unlock(&nn->client_lock); 1994 spin_unlock(&nn->client_lock);
@@ -2075,18 +2079,21 @@ nfsd4_sequence(struct svc_rqst *rqstp,
2075 status = get_client_locked(clp); 2079 status = get_client_locked(clp);
2076 if (status) 2080 if (status)
2077 goto out_no_session; 2081 goto out_no_session;
2082 status = nfsd4_get_session_locked(session);
2083 if (status)
2084 goto out_put_client;
2078 2085
2079 status = nfserr_too_many_ops; 2086 status = nfserr_too_many_ops;
2080 if (nfsd4_session_too_many_ops(rqstp, session)) 2087 if (nfsd4_session_too_many_ops(rqstp, session))
2081 goto out_put_client; 2088 goto out_put_session;
2082 2089
2083 status = nfserr_req_too_big; 2090 status = nfserr_req_too_big;
2084 if (nfsd4_request_too_big(rqstp, session)) 2091 if (nfsd4_request_too_big(rqstp, session))
2085 goto out_put_client; 2092 goto out_put_session;
2086 2093
2087 status = nfserr_badslot; 2094 status = nfserr_badslot;
2088 if (seq->slotid >= session->se_fchannel.maxreqs) 2095 if (seq->slotid >= session->se_fchannel.maxreqs)
2089 goto out_put_client; 2096 goto out_put_session;
2090 2097
2091 slot = session->se_slots[seq->slotid]; 2098 slot = session->se_slots[seq->slotid];
2092 dprintk("%s: slotid %d\n", __func__, seq->slotid); 2099 dprintk("%s: slotid %d\n", __func__, seq->slotid);
@@ -2101,7 +2108,7 @@ nfsd4_sequence(struct svc_rqst *rqstp,
2101 if (status == nfserr_replay_cache) { 2108 if (status == nfserr_replay_cache) {
2102 status = nfserr_seq_misordered; 2109 status = nfserr_seq_misordered;
2103 if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 2110 if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
2104 goto out_put_client; 2111 goto out_put_session;
2105 cstate->slot = slot; 2112 cstate->slot = slot;
2106 cstate->session = session; 2113 cstate->session = session;
2107 /* Return the cached reply status and set cstate->status 2114 /* Return the cached reply status and set cstate->status
@@ -2111,7 +2118,7 @@ nfsd4_sequence(struct svc_rqst *rqstp,
2111 goto out; 2118 goto out;
2112 } 2119 }
2113 if (status) 2120 if (status)
2114 goto out_put_client; 2121 goto out_put_session;
2115 2122
2116 nfsd4_sequence_check_conn(conn, session); 2123 nfsd4_sequence_check_conn(conn, session);
2117 conn = NULL; 2124 conn = NULL;
@@ -2128,7 +2135,6 @@ nfsd4_sequence(struct svc_rqst *rqstp,
2128 cstate->session = session; 2135 cstate->session = session;
2129 2136
2130out: 2137out:
2131 nfsd4_get_session(cstate->session);
2132 switch (clp->cl_cb_state) { 2138 switch (clp->cl_cb_state) {
2133 case NFSD4_CB_DOWN: 2139 case NFSD4_CB_DOWN:
2134 seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 2140 seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
@@ -2143,6 +2149,8 @@ out_no_session:
2143 kfree(conn); 2149 kfree(conn);
2144 spin_unlock(&nn->client_lock); 2150 spin_unlock(&nn->client_lock);
2145 return status; 2151 return status;
2152out_put_session:
2153 nfsd4_put_session(session);
2146out_put_client: 2154out_put_client:
2147 put_client_renew_locked(clp); 2155 put_client_renew_locked(clp);
2148 goto out_no_session; 2156 goto out_no_session;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 07f8a822a6ce..f6ae4db3efdb 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -194,9 +194,11 @@ struct nfsd4_conn {
194}; 194};
195 195
196struct nfsd4_session { 196struct nfsd4_session {
197 struct kref se_ref; 197 atomic_t se_ref;
198 struct list_head se_hash; /* hash by sessionid */ 198 struct list_head se_hash; /* hash by sessionid */
199 struct list_head se_perclnt; 199 struct list_head se_perclnt;
200/* See SESSION4_PERSIST, etc. for standard flags; this is internal-only: */
201#define NFS4_SESSION_DEAD 0x010
200 u32 se_flags; 202 u32 se_flags;
201 struct nfs4_client *se_client; 203 struct nfs4_client *se_client;
202 struct nfs4_sessionid se_sessionid; 204 struct nfs4_sessionid se_sessionid;