diff options
author | Stanislav Kinsbursky <skinsbursky@parallels.com> | 2012-11-26 07:21:58 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2012-11-28 10:13:50 -0500 |
commit | c9a4962881929df7f1ef6e63e1b9da304faca4dd (patch) | |
tree | 2ab9a198beb2eac07c6d324cedee7d1fb1be42eb /fs/nfsd/nfs4state.c | |
parent | ec28e02ca5f2a4287c19c585f8be2d9b3ba123ea (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.c | 73 |
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 */ | ||
392 | static DEFINE_SPINLOCK(client_lock); | ||
393 | |||
394 | static unsigned int clientid_hashval(u32 id) | 391 | static 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) | |||
872 | static void free_session(struct kref *kref) | 869 | static 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 | ||
882 | void nfsd4_put_session(struct nfsd4_session *ses) | 882 | void 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 | ||
889 | static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) | 891 | static 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) | |||
1005 | static inline void | 1007 | static inline void |
1006 | renew_client(struct nfs4_client *clp) | 1008 | renew_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) | |||
1045 | static inline void | 1049 | static inline void |
1046 | free_client(struct nfs4_client *clp) | 1050 | free_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 | |||
1062 | release_session_client(struct nfsd4_session *session) | 1068 | release_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 | ||
1129 | static void expire_client(struct nfs4_client *clp) | 1136 | static 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; |
1964 | out: | 1975 | out: |
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 | ||