diff options
author | Eric Dumazet <dada1@cosmosbay.com> | 2008-11-20 03:40:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-20 03:40:07 -0500 |
commit | 5caea4ea7088e80ac5410d04660346094608b909 (patch) | |
tree | fad95133683c002d24ff5de7fb756dad806b41ed /net/ipv6 | |
parent | d8b83c57a7e497cba9b5cb156e63176323035785 (diff) |
net: listening_hash get a spinlock per bucket
This patch prepares RCU migration of listening_hash table for
TCP/DCCP protocols.
listening_hash table being small (32 slots per protocol), we add
a spinlock for each slot, instead of a single rwlock for whole table.
This should reduce hold time of readers, and writers concurrency.
Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/inet6_hashtables.c | 23 |
1 files changed, 12 insertions, 11 deletions
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index c1b4d401fd95..21544b9be259 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
@@ -25,30 +25,30 @@ | |||
25 | void __inet6_hash(struct sock *sk) | 25 | void __inet6_hash(struct sock *sk) |
26 | { | 26 | { |
27 | struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; | 27 | struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; |
28 | rwlock_t *lock; | ||
29 | 28 | ||
30 | WARN_ON(!sk_unhashed(sk)); | 29 | WARN_ON(!sk_unhashed(sk)); |
31 | 30 | ||
32 | if (sk->sk_state == TCP_LISTEN) { | 31 | if (sk->sk_state == TCP_LISTEN) { |
33 | struct hlist_head *list; | 32 | struct inet_listen_hashbucket *ilb; |
34 | 33 | ||
35 | list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; | 34 | ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; |
36 | lock = &hashinfo->lhash_lock; | 35 | spin_lock(&ilb->lock); |
37 | inet_listen_wlock(hashinfo); | 36 | __sk_add_node(sk, &ilb->head); |
38 | __sk_add_node(sk, list); | 37 | spin_unlock(&ilb->lock); |
39 | } else { | 38 | } else { |
40 | unsigned int hash; | 39 | unsigned int hash; |
41 | struct hlist_nulls_head *list; | 40 | struct hlist_nulls_head *list; |
41 | rwlock_t *lock; | ||
42 | 42 | ||
43 | sk->sk_hash = hash = inet6_sk_ehashfn(sk); | 43 | sk->sk_hash = hash = inet6_sk_ehashfn(sk); |
44 | list = &inet_ehash_bucket(hashinfo, hash)->chain; | 44 | list = &inet_ehash_bucket(hashinfo, hash)->chain; |
45 | lock = inet_ehash_lockp(hashinfo, hash); | 45 | lock = inet_ehash_lockp(hashinfo, hash); |
46 | write_lock(lock); | 46 | write_lock(lock); |
47 | __sk_nulls_add_node_rcu(sk, list); | 47 | __sk_nulls_add_node_rcu(sk, list); |
48 | write_unlock(lock); | ||
48 | } | 49 | } |
49 | 50 | ||
50 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); | 51 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); |
51 | write_unlock(lock); | ||
52 | } | 52 | } |
53 | EXPORT_SYMBOL(__inet6_hash); | 53 | EXPORT_SYMBOL(__inet6_hash); |
54 | 54 | ||
@@ -126,10 +126,11 @@ struct sock *inet6_lookup_listener(struct net *net, | |||
126 | const struct hlist_node *node; | 126 | const struct hlist_node *node; |
127 | struct sock *result = NULL; | 127 | struct sock *result = NULL; |
128 | int score, hiscore = 0; | 128 | int score, hiscore = 0; |
129 | struct inet_listen_hashbucket *ilb; | ||
129 | 130 | ||
130 | read_lock(&hashinfo->lhash_lock); | 131 | ilb = &hashinfo->listening_hash[inet_lhashfn(net, hnum)]; |
131 | sk_for_each(sk, node, | 132 | spin_lock(&ilb->lock); |
132 | &hashinfo->listening_hash[inet_lhashfn(net, hnum)]) { | 133 | sk_for_each(sk, node, &ilb->head) { |
133 | if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum && | 134 | if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum && |
134 | sk->sk_family == PF_INET6) { | 135 | sk->sk_family == PF_INET6) { |
135 | const struct ipv6_pinfo *np = inet6_sk(sk); | 136 | const struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -157,7 +158,7 @@ struct sock *inet6_lookup_listener(struct net *net, | |||
157 | } | 158 | } |
158 | if (result) | 159 | if (result) |
159 | sock_hold(result); | 160 | sock_hold(result); |
160 | read_unlock(&hashinfo->lhash_lock); | 161 | spin_unlock(&ilb->lock); |
161 | return result; | 162 | return result; |
162 | } | 163 | } |
163 | 164 | ||