aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
authorStanislav Kinsbursky <skinsbursky@parallels.com>2012-11-26 07:21:58 -0500
committerJ. Bruce Fields <bfields@redhat.com>2012-11-28 10:13:50 -0500
commitc9a4962881929df7f1ef6e63e1b9da304faca4dd (patch)
tree2ab9a198beb2eac07c6d324cedee7d1fb1be42eb /fs/nfsd/nfs4state.c
parentec28e02ca5f2a4287c19c585f8be2d9b3ba123ea (diff)
nfsd: make client_lock per net
This lock protects the client lru list and session hash table, which are allocated per network namespace already. Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c73
1 files changed, 43 insertions, 30 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ffec73cdfaca..0e7e174de209 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -388,9 +388,6 @@ unhash_delegation(struct nfs4_delegation *dp)
388 * SETCLIENTID state 388 * SETCLIENTID state
389 */ 389 */
390 390
391/* client_lock protects the client lru list and session hash table */
392static DEFINE_SPINLOCK(client_lock);
393
394static unsigned int clientid_hashval(u32 id) 391static unsigned int clientid_hashval(u32 id)
395{ 392{
396 return id & CLIENT_HASH_MASK; 393 return id & CLIENT_HASH_MASK;
@@ -872,18 +869,23 @@ static void __free_session(struct nfsd4_session *ses)
872static void free_session(struct kref *kref) 869static void free_session(struct kref *kref)
873{ 870{
874 struct nfsd4_session *ses; 871 struct nfsd4_session *ses;
872 struct nfsd_net *nn;
875 873
876 lockdep_assert_held(&client_lock);
877 ses = container_of(kref, struct nfsd4_session, se_ref); 874 ses = container_of(kref, struct nfsd4_session, se_ref);
875 nn = net_generic(ses->se_client->net, nfsd_net_id);
876
877 lockdep_assert_held(&nn->client_lock);
878 nfsd4_del_conns(ses); 878 nfsd4_del_conns(ses);
879 __free_session(ses); 879 __free_session(ses);
880} 880}
881 881
882void nfsd4_put_session(struct nfsd4_session *ses) 882void nfsd4_put_session(struct nfsd4_session *ses)
883{ 883{
884 spin_lock(&client_lock); 884 struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id);
885
886 spin_lock(&nn->client_lock);
885 nfsd4_put_session_locked(ses); 887 nfsd4_put_session_locked(ses);
886 spin_unlock(&client_lock); 888 spin_unlock(&nn->client_lock);
887} 889}
888 890
889static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) 891static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan)
@@ -927,12 +929,12 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
927 new->se_cb_sec = cses->cb_sec; 929 new->se_cb_sec = cses->cb_sec;
928 kref_init(&new->se_ref); 930 kref_init(&new->se_ref);
929 idx = hash_sessionid(&new->se_sessionid); 931 idx = hash_sessionid(&new->se_sessionid);
930 spin_lock(&client_lock); 932 spin_lock(&nn->client_lock);
931 list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 933 list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
932 spin_lock(&clp->cl_lock); 934 spin_lock(&clp->cl_lock);
933 list_add(&new->se_perclnt, &clp->cl_sessions); 935 list_add(&new->se_perclnt, &clp->cl_sessions);
934 spin_unlock(&clp->cl_lock); 936 spin_unlock(&clp->cl_lock);
935 spin_unlock(&client_lock); 937 spin_unlock(&nn->client_lock);
936 938
937 if (cses->flags & SESSION4_BACK_CHAN) { 939 if (cses->flags & SESSION4_BACK_CHAN) {
938 struct sockaddr *sa = svc_addr(rqstp); 940 struct sockaddr *sa = svc_addr(rqstp);
@@ -1005,9 +1007,11 @@ renew_client_locked(struct nfs4_client *clp)
1005static inline void 1007static inline void
1006renew_client(struct nfs4_client *clp) 1008renew_client(struct nfs4_client *clp)
1007{ 1009{
1008 spin_lock(&client_lock); 1010 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1011
1012 spin_lock(&nn->client_lock);
1009 renew_client_locked(clp); 1013 renew_client_locked(clp);
1010 spin_unlock(&client_lock); 1014 spin_unlock(&nn->client_lock);
1011} 1015}
1012 1016
1013/* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 1017/* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
@@ -1045,7 +1049,9 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
1045static inline void 1049static inline void
1046free_client(struct nfs4_client *clp) 1050free_client(struct nfs4_client *clp)
1047{ 1051{
1048 lockdep_assert_held(&client_lock); 1052 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1053
1054 lockdep_assert_held(&nn->client_lock);
1049 while (!list_empty(&clp->cl_sessions)) { 1055 while (!list_empty(&clp->cl_sessions)) {
1050 struct nfsd4_session *ses; 1056 struct nfsd4_session *ses;
1051 ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 1057 ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
@@ -1062,15 +1068,16 @@ void
1062release_session_client(struct nfsd4_session *session) 1068release_session_client(struct nfsd4_session *session)
1063{ 1069{
1064 struct nfs4_client *clp = session->se_client; 1070 struct nfs4_client *clp = session->se_client;
1071 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1065 1072
1066 if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock)) 1073 if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock))
1067 return; 1074 return;
1068 if (is_client_expired(clp)) { 1075 if (is_client_expired(clp)) {
1069 free_client(clp); 1076 free_client(clp);
1070 session->se_client = NULL; 1077 session->se_client = NULL;
1071 } else 1078 } else
1072 renew_client_locked(clp); 1079 renew_client_locked(clp);
1073 spin_unlock(&client_lock); 1080 spin_unlock(&nn->client_lock);
1074} 1081}
1075 1082
1076/* must be called under the client_lock */ 1083/* must be called under the client_lock */
@@ -1119,11 +1126,11 @@ destroy_client(struct nfs4_client *clp)
1119 rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 1126 rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
1120 else 1127 else
1121 rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 1128 rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
1122 spin_lock(&client_lock); 1129 spin_lock(&nn->client_lock);
1123 unhash_client_locked(clp); 1130 unhash_client_locked(clp);
1124 if (atomic_read(&clp->cl_refcount) == 0) 1131 if (atomic_read(&clp->cl_refcount) == 0)
1125 free_client(clp); 1132 free_client(clp);
1126 spin_unlock(&client_lock); 1133 spin_unlock(&nn->client_lock);
1127} 1134}
1128 1135
1129static void expire_client(struct nfs4_client *clp) 1136static void expire_client(struct nfs4_client *clp)
@@ -1274,6 +1281,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
1274 struct sockaddr *sa = svc_addr(rqstp); 1281 struct sockaddr *sa = svc_addr(rqstp);
1275 int ret; 1282 int ret;
1276 struct net *net = SVC_NET(rqstp); 1283 struct net *net = SVC_NET(rqstp);
1284 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1277 1285
1278 clp = alloc_client(name); 1286 clp = alloc_client(name);
1279 if (clp == NULL) 1287 if (clp == NULL)
@@ -1282,9 +1290,9 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
1282 INIT_LIST_HEAD(&clp->cl_sessions); 1290 INIT_LIST_HEAD(&clp->cl_sessions);
1283 ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 1291 ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred);
1284 if (ret) { 1292 if (ret) {
1285 spin_lock(&client_lock); 1293 spin_lock(&nn->client_lock);
1286 free_client(clp); 1294 free_client(clp);
1287 spin_unlock(&client_lock); 1295 spin_unlock(&nn->client_lock);
1288 return NULL; 1296 return NULL;
1289 } 1297 }
1290 idr_init(&clp->cl_stateids); 1298 idr_init(&clp->cl_stateids);
@@ -1873,11 +1881,12 @@ static __be32 nfsd4_map_bcts_dir(u32 *dir)
1873__be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) 1881__be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc)
1874{ 1882{
1875 struct nfsd4_session *session = cstate->session; 1883 struct nfsd4_session *session = cstate->session;
1884 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1876 1885
1877 spin_lock(&client_lock); 1886 spin_lock(&nn->client_lock);
1878 session->se_cb_prog = bc->bc_cb_program; 1887 session->se_cb_prog = bc->bc_cb_program;
1879 session->se_cb_sec = bc->bc_cb_sec; 1888 session->se_cb_sec = bc->bc_cb_sec;
1880 spin_unlock(&client_lock); 1889 spin_unlock(&nn->client_lock);
1881 1890
1882 nfsd4_probe_callback(session->se_client); 1891 nfsd4_probe_callback(session->se_client);
1883 1892
@@ -1890,10 +1899,11 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
1890{ 1899{
1891 __be32 status; 1900 __be32 status;
1892 struct nfsd4_conn *conn; 1901 struct nfsd4_conn *conn;
1902 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1893 1903
1894 if (!nfsd4_last_compound_op(rqstp)) 1904 if (!nfsd4_last_compound_op(rqstp))
1895 return nfserr_not_only_op; 1905 return nfserr_not_only_op;
1896 spin_lock(&client_lock); 1906 spin_lock(&nn->client_lock);
1897 cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid, SVC_NET(rqstp)); 1907 cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid, SVC_NET(rqstp));
1898 /* Sorta weird: we only need the refcnt'ing because new_conn acquires 1908 /* Sorta weird: we only need the refcnt'ing because new_conn acquires
1899 * client_lock iself: */ 1909 * client_lock iself: */
@@ -1901,7 +1911,7 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
1901 nfsd4_get_session(cstate->session); 1911 nfsd4_get_session(cstate->session);
1902 atomic_inc(&cstate->session->se_client->cl_refcount); 1912 atomic_inc(&cstate->session->se_client->cl_refcount);
1903 } 1913 }
1904 spin_unlock(&client_lock); 1914 spin_unlock(&nn->client_lock);
1905 if (!cstate->session) 1915 if (!cstate->session)
1906 return nfserr_badsession; 1916 return nfserr_badsession;
1907 1917
@@ -1929,6 +1939,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
1929{ 1939{
1930 struct nfsd4_session *ses; 1940 struct nfsd4_session *ses;
1931 __be32 status = nfserr_badsession; 1941 __be32 status = nfserr_badsession;
1942 struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id);
1932 1943
1933 /* Notes: 1944 /* Notes:
1934 * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid 1945 * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid
@@ -1942,24 +1953,24 @@ nfsd4_destroy_session(struct svc_rqst *r,
1942 return nfserr_not_only_op; 1953 return nfserr_not_only_op;
1943 } 1954 }
1944 dump_sessionid(__func__, &sessionid->sessionid); 1955 dump_sessionid(__func__, &sessionid->sessionid);
1945 spin_lock(&client_lock); 1956 spin_lock(&nn->client_lock);
1946 ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r)); 1957 ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r));
1947 if (!ses) { 1958 if (!ses) {
1948 spin_unlock(&client_lock); 1959 spin_unlock(&nn->client_lock);
1949 goto out; 1960 goto out;
1950 } 1961 }
1951 1962
1952 unhash_session(ses); 1963 unhash_session(ses);
1953 spin_unlock(&client_lock); 1964 spin_unlock(&nn->client_lock);
1954 1965
1955 nfs4_lock_state(); 1966 nfs4_lock_state();
1956 nfsd4_probe_callback_sync(ses->se_client); 1967 nfsd4_probe_callback_sync(ses->se_client);
1957 nfs4_unlock_state(); 1968 nfs4_unlock_state();
1958 1969
1959 spin_lock(&client_lock); 1970 spin_lock(&nn->client_lock);
1960 nfsd4_del_conns(ses); 1971 nfsd4_del_conns(ses);
1961 nfsd4_put_session_locked(ses); 1972 nfsd4_put_session_locked(ses);
1962 spin_unlock(&client_lock); 1973 spin_unlock(&nn->client_lock);
1963 status = nfs_ok; 1974 status = nfs_ok;
1964out: 1975out:
1965 dprintk("%s returns %d\n", __func__, ntohl(status)); 1976 dprintk("%s returns %d\n", __func__, ntohl(status));
@@ -2025,6 +2036,7 @@ nfsd4_sequence(struct svc_rqst *rqstp,
2025 struct nfsd4_slot *slot; 2036 struct nfsd4_slot *slot;
2026 struct nfsd4_conn *conn; 2037 struct nfsd4_conn *conn;
2027 __be32 status; 2038 __be32 status;
2039 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2028 2040
2029 if (resp->opcnt != 1) 2041 if (resp->opcnt != 1)
2030 return nfserr_sequence_pos; 2042 return nfserr_sequence_pos;
@@ -2037,7 +2049,7 @@ nfsd4_sequence(struct svc_rqst *rqstp,
2037 if (!conn) 2049 if (!conn)
2038 return nfserr_jukebox; 2050 return nfserr_jukebox;
2039 2051
2040 spin_lock(&client_lock); 2052 spin_lock(&nn->client_lock);
2041 status = nfserr_badsession; 2053 status = nfserr_badsession;
2042 session = find_in_sessionid_hashtbl(&seq->sessionid, SVC_NET(rqstp)); 2054 session = find_in_sessionid_hashtbl(&seq->sessionid, SVC_NET(rqstp));
2043 if (!session) 2055 if (!session)
@@ -2113,7 +2125,7 @@ out:
2113 } 2125 }
2114 } 2126 }
2115 kfree(conn); 2127 kfree(conn);
2116 spin_unlock(&client_lock); 2128 spin_unlock(&nn->client_lock);
2117 dprintk("%s: return %d\n", __func__, ntohl(status)); 2129 dprintk("%s: return %d\n", __func__, ntohl(status));
2118 return status; 2130 return status;
2119} 2131}
@@ -3191,7 +3203,7 @@ nfs4_laundromat(struct nfsd_net *nn)
3191 dprintk("NFSD: laundromat service - starting\n"); 3203 dprintk("NFSD: laundromat service - starting\n");
3192 nfsd4_end_grace(nn); 3204 nfsd4_end_grace(nn);
3193 INIT_LIST_HEAD(&reaplist); 3205 INIT_LIST_HEAD(&reaplist);
3194 spin_lock(&client_lock); 3206 spin_lock(&nn->client_lock);
3195 list_for_each_safe(pos, next, &nn->client_lru) { 3207 list_for_each_safe(pos, next, &nn->client_lru) {
3196 clp = list_entry(pos, struct nfs4_client, cl_lru); 3208 clp = list_entry(pos, struct nfs4_client, cl_lru);
3197 if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { 3209 if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
@@ -3208,7 +3220,7 @@ nfs4_laundromat(struct nfsd_net *nn)
3208 unhash_client_locked(clp); 3220 unhash_client_locked(clp);
3209 list_add(&clp->cl_lru, &reaplist); 3221 list_add(&clp->cl_lru, &reaplist);
3210 } 3222 }
3211 spin_unlock(&client_lock); 3223 spin_unlock(&nn->client_lock);
3212 list_for_each_safe(pos, next, &reaplist) { 3224 list_for_each_safe(pos, next, &reaplist) {
3213 clp = list_entry(pos, struct nfs4_client, cl_lru); 3225 clp = list_entry(pos, struct nfs4_client, cl_lru);
3214 dprintk("NFSD: purging unused client (clientid %08x)\n", 3226 dprintk("NFSD: purging unused client (clientid %08x)\n",
@@ -4796,6 +4808,7 @@ static int nfs4_state_start_net(struct net *net)
4796 nn->unconf_name_tree = RB_ROOT; 4808 nn->unconf_name_tree = RB_ROOT;
4797 INIT_LIST_HEAD(&nn->client_lru); 4809 INIT_LIST_HEAD(&nn->client_lru);
4798 INIT_LIST_HEAD(&nn->close_lru); 4810 INIT_LIST_HEAD(&nn->close_lru);
4811 spin_lock_init(&nn->client_lock);
4799 4812
4800 INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 4813 INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
4801 4814