diff options
| author | Arnaldo Carvalho de Melo <acme@ghostprotocols.net> | 2005-08-09 23:08:09 -0400 |
|---|---|---|
| committer | David S. Miller <davem@sunset.davemloft.net> | 2005-08-29 18:41:49 -0400 |
| commit | f3f05f7046e7c85b04af390d95a82a27160dd5d0 (patch) | |
| tree | 9a4a552c030ea8b2428ceee75311d73a6b339255 /net/ipv4/tcp_ipv4.c | |
| parent | 6e04e02165a7209a71db553b7bc48d68421e5ebf (diff) | |
[INET]: Generalise the tcp_listen_ lock routines
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 70 |
1 files changed, 9 insertions, 61 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f5373f9f00ac..5f9ad95304ca 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
| @@ -228,62 +228,11 @@ fail: | |||
| 228 | return ret; | 228 | return ret; |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it can be very bad on SMP. | ||
| 232 | * Look, when several writers sleep and reader wakes them up, all but one | ||
| 233 | * immediately hit write lock and grab all the cpus. Exclusive sleep solves | ||
| 234 | * this, _but_ remember, it adds useless work on UP machines (wake up each | ||
| 235 | * exclusive lock release). It should be ifdefed really. | ||
| 236 | */ | ||
| 237 | |||
| 238 | void tcp_listen_wlock(void) | ||
| 239 | { | ||
| 240 | write_lock(&tcp_hashinfo.lhash_lock); | ||
| 241 | |||
| 242 | if (atomic_read(&tcp_hashinfo.lhash_users)) { | ||
| 243 | DEFINE_WAIT(wait); | ||
| 244 | |||
| 245 | for (;;) { | ||
| 246 | prepare_to_wait_exclusive(&tcp_hashinfo.lhash_wait, | ||
| 247 | &wait, TASK_UNINTERRUPTIBLE); | ||
| 248 | if (!atomic_read(&tcp_hashinfo.lhash_users)) | ||
| 249 | break; | ||
| 250 | write_unlock_bh(&tcp_hashinfo.lhash_lock); | ||
| 251 | schedule(); | ||
| 252 | write_lock_bh(&tcp_hashinfo.lhash_lock); | ||
| 253 | } | ||
| 254 | |||
| 255 | finish_wait(&tcp_hashinfo.lhash_wait, &wait); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | static __inline__ void __tcp_v4_hash(struct sock *sk, const int listen_possible) | ||
| 260 | { | ||
| 261 | struct hlist_head *list; | ||
| 262 | rwlock_t *lock; | ||
| 263 | |||
| 264 | BUG_TRAP(sk_unhashed(sk)); | ||
| 265 | if (listen_possible && sk->sk_state == TCP_LISTEN) { | ||
| 266 | list = &tcp_hashinfo.listening_hash[inet_sk_listen_hashfn(sk)]; | ||
| 267 | lock = &tcp_hashinfo.lhash_lock; | ||
| 268 | tcp_listen_wlock(); | ||
| 269 | } else { | ||
| 270 | sk->sk_hashent = inet_sk_ehashfn(sk, tcp_hashinfo.ehash_size); | ||
| 271 | list = &tcp_hashinfo.ehash[sk->sk_hashent].chain; | ||
| 272 | lock = &tcp_hashinfo.ehash[sk->sk_hashent].lock; | ||
| 273 | write_lock(lock); | ||
| 274 | } | ||
| 275 | __sk_add_node(sk, list); | ||
| 276 | sock_prot_inc_use(sk->sk_prot); | ||
| 277 | write_unlock(lock); | ||
| 278 | if (listen_possible && sk->sk_state == TCP_LISTEN) | ||
| 279 | wake_up(&tcp_hashinfo.lhash_wait); | ||
| 280 | } | ||
| 281 | |||
| 282 | static void tcp_v4_hash(struct sock *sk) | 231 | static void tcp_v4_hash(struct sock *sk) |
| 283 | { | 232 | { |
| 284 | if (sk->sk_state != TCP_CLOSE) { | 233 | if (sk->sk_state != TCP_CLOSE) { |
| 285 | local_bh_disable(); | 234 | local_bh_disable(); |
| 286 | __tcp_v4_hash(sk, 1); | 235 | __inet_hash(&tcp_hashinfo, sk, 1); |
| 287 | local_bh_enable(); | 236 | local_bh_enable(); |
| 288 | } | 237 | } |
| 289 | } | 238 | } |
| @@ -297,7 +246,7 @@ void tcp_unhash(struct sock *sk) | |||
| 297 | 246 | ||
| 298 | if (sk->sk_state == TCP_LISTEN) { | 247 | if (sk->sk_state == TCP_LISTEN) { |
| 299 | local_bh_disable(); | 248 | local_bh_disable(); |
| 300 | tcp_listen_wlock(); | 249 | inet_listen_wlock(&tcp_hashinfo); |
| 301 | lock = &tcp_hashinfo.lhash_lock; | 250 | lock = &tcp_hashinfo.lhash_lock; |
| 302 | } else { | 251 | } else { |
| 303 | struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[sk->sk_hashent]; | 252 | struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[sk->sk_hashent]; |
| @@ -624,7 +573,7 @@ ok: | |||
| 624 | inet_bind_hash(sk, tb, port); | 573 | inet_bind_hash(sk, tb, port); |
| 625 | if (sk_unhashed(sk)) { | 574 | if (sk_unhashed(sk)) { |
| 626 | inet_sk(sk)->sport = htons(port); | 575 | inet_sk(sk)->sport = htons(port); |
| 627 | __tcp_v4_hash(sk, 0); | 576 | __inet_hash(&tcp_hashinfo, sk, 0); |
| 628 | } | 577 | } |
| 629 | spin_unlock(&head->lock); | 578 | spin_unlock(&head->lock); |
| 630 | 579 | ||
| @@ -641,7 +590,7 @@ ok: | |||
| 641 | tb = inet_sk(sk)->bind_hash; | 590 | tb = inet_sk(sk)->bind_hash; |
| 642 | spin_lock_bh(&head->lock); | 591 | spin_lock_bh(&head->lock); |
| 643 | if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { | 592 | if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { |
| 644 | __tcp_v4_hash(sk, 0); | 593 | __inet_hash(&tcp_hashinfo, sk, 0); |
| 645 | spin_unlock_bh(&head->lock); | 594 | spin_unlock_bh(&head->lock); |
| 646 | return 0; | 595 | return 0; |
| 647 | } else { | 596 | } else { |
| @@ -1479,7 +1428,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1479 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); | 1428 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); |
| 1480 | tcp_initialize_rcv_mss(newsk); | 1429 | tcp_initialize_rcv_mss(newsk); |
| 1481 | 1430 | ||
| 1482 | __tcp_v4_hash(newsk, 0); | 1431 | __inet_hash(&tcp_hashinfo, newsk, 0); |
| 1483 | __inet_inherit_port(&tcp_hashinfo, sk, newsk); | 1432 | __inet_inherit_port(&tcp_hashinfo, sk, newsk); |
| 1484 | 1433 | ||
| 1485 | return newsk; | 1434 | return newsk; |
| @@ -2102,12 +2051,12 @@ static void *tcp_get_idx(struct seq_file *seq, loff_t pos) | |||
| 2102 | void *rc; | 2051 | void *rc; |
| 2103 | struct tcp_iter_state* st = seq->private; | 2052 | struct tcp_iter_state* st = seq->private; |
| 2104 | 2053 | ||
| 2105 | tcp_listen_lock(); | 2054 | inet_listen_lock(&tcp_hashinfo); |
| 2106 | st->state = TCP_SEQ_STATE_LISTENING; | 2055 | st->state = TCP_SEQ_STATE_LISTENING; |
| 2107 | rc = listening_get_idx(seq, &pos); | 2056 | rc = listening_get_idx(seq, &pos); |
| 2108 | 2057 | ||
| 2109 | if (!rc) { | 2058 | if (!rc) { |
| 2110 | tcp_listen_unlock(); | 2059 | inet_listen_unlock(&tcp_hashinfo); |
| 2111 | local_bh_disable(); | 2060 | local_bh_disable(); |
| 2112 | st->state = TCP_SEQ_STATE_ESTABLISHED; | 2061 | st->state = TCP_SEQ_STATE_ESTABLISHED; |
| 2113 | rc = established_get_idx(seq, pos); | 2062 | rc = established_get_idx(seq, pos); |
| @@ -2140,7 +2089,7 @@ static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 2140 | case TCP_SEQ_STATE_LISTENING: | 2089 | case TCP_SEQ_STATE_LISTENING: |
| 2141 | rc = listening_get_next(seq, v); | 2090 | rc = listening_get_next(seq, v); |
| 2142 | if (!rc) { | 2091 | if (!rc) { |
| 2143 | tcp_listen_unlock(); | 2092 | inet_listen_unlock(&tcp_hashinfo); |
| 2144 | local_bh_disable(); | 2093 | local_bh_disable(); |
| 2145 | st->state = TCP_SEQ_STATE_ESTABLISHED; | 2094 | st->state = TCP_SEQ_STATE_ESTABLISHED; |
| 2146 | rc = established_get_first(seq); | 2095 | rc = established_get_first(seq); |
| @@ -2168,7 +2117,7 @@ static void tcp_seq_stop(struct seq_file *seq, void *v) | |||
| 2168 | } | 2117 | } |
| 2169 | case TCP_SEQ_STATE_LISTENING: | 2118 | case TCP_SEQ_STATE_LISTENING: |
| 2170 | if (v != SEQ_START_TOKEN) | 2119 | if (v != SEQ_START_TOKEN) |
| 2171 | tcp_listen_unlock(); | 2120 | inet_listen_unlock(&tcp_hashinfo); |
| 2172 | break; | 2121 | break; |
| 2173 | case TCP_SEQ_STATE_TIME_WAIT: | 2122 | case TCP_SEQ_STATE_TIME_WAIT: |
| 2174 | case TCP_SEQ_STATE_ESTABLISHED: | 2123 | case TCP_SEQ_STATE_ESTABLISHED: |
| @@ -2431,7 +2380,6 @@ void __init tcp_v4_init(struct net_proto_family *ops) | |||
| 2431 | EXPORT_SYMBOL(ipv4_specific); | 2380 | EXPORT_SYMBOL(ipv4_specific); |
| 2432 | EXPORT_SYMBOL(inet_bind_bucket_create); | 2381 | EXPORT_SYMBOL(inet_bind_bucket_create); |
| 2433 | EXPORT_SYMBOL(tcp_hashinfo); | 2382 | EXPORT_SYMBOL(tcp_hashinfo); |
| 2434 | EXPORT_SYMBOL(tcp_listen_wlock); | ||
| 2435 | EXPORT_SYMBOL(tcp_prot); | 2383 | EXPORT_SYMBOL(tcp_prot); |
| 2436 | EXPORT_SYMBOL(tcp_unhash); | 2384 | EXPORT_SYMBOL(tcp_unhash); |
| 2437 | EXPORT_SYMBOL(tcp_v4_conn_request); | 2385 | EXPORT_SYMBOL(tcp_v4_conn_request); |
