diff options
| author | Pavel Emelyanov <xemul@openvz.org> | 2008-01-31 08:04:45 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2008-01-31 22:28:17 -0500 |
| commit | 5ee31fc1ecdcbc234c8c56dcacef87c8e09909d8 (patch) | |
| tree | 5fe73acbcf784f9ee326d7d10ae217c7b4eb13ee | |
| parent | 535174efbe0f0454f0595c31b823498c197eeb4f (diff) | |
[INET]: Consolidate inet(6)_hash_connect.
These two functions are the same except for what they call
to "check_established" and "hash" for a socket.
This saves half-a-kilo for ipv4 and ipv6.
add/remove: 1/0 grow/shrink: 1/4 up/down: 582/-1128 (-546)
function old new delta
__inet_hash_connect - 577 +577
arp_ignore 108 113 +5
static.hint 8 4 -4
rt_worker_func 376 372 -4
inet6_hash_connect 584 25 -559
inet_hash_connect 586 25 -561
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/inet_hashtables.h | 5 | ||||
| -rw-r--r-- | net/ipv4/inet_hashtables.c | 32 | ||||
| -rw-r--r-- | net/ipv6/inet6_hashtables.c | 93 |
3 files changed, 28 insertions, 102 deletions
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 761bdc01425d..a34a8f25fc57 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h | |||
| @@ -413,6 +413,11 @@ static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo, | |||
| 413 | return sk; | 413 | return sk; |
| 414 | } | 414 | } |
| 415 | 415 | ||
| 416 | extern int __inet_hash_connect(struct inet_timewait_death_row *death_row, | ||
| 417 | struct sock *sk, | ||
| 418 | int (*check_established)(struct inet_timewait_death_row *, | ||
| 419 | struct sock *, __u16, struct inet_timewait_sock **), | ||
| 420 | void (*hash)(struct inet_hashinfo *, struct sock *)); | ||
| 416 | extern int inet_hash_connect(struct inet_timewait_death_row *death_row, | 421 | extern int inet_hash_connect(struct inet_timewait_death_row *death_row, |
| 417 | struct sock *sk); | 422 | struct sock *sk); |
| 418 | #endif /* _INET_HASHTABLES_H */ | 423 | #endif /* _INET_HASHTABLES_H */ |
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 619c63c6948a..b93d40ff6ef4 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c | |||
| @@ -348,11 +348,11 @@ void __inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk) | |||
| 348 | } | 348 | } |
| 349 | EXPORT_SYMBOL_GPL(__inet_hash); | 349 | EXPORT_SYMBOL_GPL(__inet_hash); |
| 350 | 350 | ||
| 351 | /* | 351 | int __inet_hash_connect(struct inet_timewait_death_row *death_row, |
| 352 | * Bind a port for a connect operation and hash it. | 352 | struct sock *sk, |
| 353 | */ | 353 | int (*check_established)(struct inet_timewait_death_row *, |
| 354 | int inet_hash_connect(struct inet_timewait_death_row *death_row, | 354 | struct sock *, __u16, struct inet_timewait_sock **), |
| 355 | struct sock *sk) | 355 | void (*hash)(struct inet_hashinfo *, struct sock *)) |
| 356 | { | 356 | { |
| 357 | struct inet_hashinfo *hinfo = death_row->hashinfo; | 357 | struct inet_hashinfo *hinfo = death_row->hashinfo; |
| 358 | const unsigned short snum = inet_sk(sk)->num; | 358 | const unsigned short snum = inet_sk(sk)->num; |
| @@ -385,9 +385,8 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row, | |||
| 385 | BUG_TRAP(!hlist_empty(&tb->owners)); | 385 | BUG_TRAP(!hlist_empty(&tb->owners)); |
| 386 | if (tb->fastreuse >= 0) | 386 | if (tb->fastreuse >= 0) |
| 387 | goto next_port; | 387 | goto next_port; |
| 388 | if (!__inet_check_established(death_row, | 388 | if (!check_established(death_row, sk, |
| 389 | sk, port, | 389 | port, &tw)) |
| 390 | &tw)) | ||
| 391 | goto ok; | 390 | goto ok; |
| 392 | goto next_port; | 391 | goto next_port; |
| 393 | } | 392 | } |
| @@ -415,7 +414,7 @@ ok: | |||
| 415 | inet_bind_hash(sk, tb, port); | 414 | inet_bind_hash(sk, tb, port); |
| 416 | if (sk_unhashed(sk)) { | 415 | if (sk_unhashed(sk)) { |
| 417 | inet_sk(sk)->sport = htons(port); | 416 | inet_sk(sk)->sport = htons(port); |
| 418 | __inet_hash_nolisten(hinfo, sk); | 417 | hash(hinfo, sk); |
| 419 | } | 418 | } |
| 420 | spin_unlock(&head->lock); | 419 | spin_unlock(&head->lock); |
| 421 | 420 | ||
| @@ -432,17 +431,28 @@ ok: | |||
| 432 | tb = inet_csk(sk)->icsk_bind_hash; | 431 | tb = inet_csk(sk)->icsk_bind_hash; |
| 433 | spin_lock_bh(&head->lock); | 432 | spin_lock_bh(&head->lock); |
| 434 | if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { | 433 | if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { |
| 435 | __inet_hash_nolisten(hinfo, sk); | 434 | hash(hinfo, sk); |
| 436 | spin_unlock_bh(&head->lock); | 435 | spin_unlock_bh(&head->lock); |
| 437 | return 0; | 436 | return 0; |
| 438 | } else { | 437 | } else { |
| 439 | spin_unlock(&head->lock); | 438 | spin_unlock(&head->lock); |
| 440 | /* No definite answer... Walk to established hash table */ | 439 | /* No definite answer... Walk to established hash table */ |
| 441 | ret = __inet_check_established(death_row, sk, snum, NULL); | 440 | ret = check_established(death_row, sk, snum, NULL); |
| 442 | out: | 441 | out: |
| 443 | local_bh_enable(); | 442 | local_bh_enable(); |
| 444 | return ret; | 443 | return ret; |
| 445 | } | 444 | } |
| 446 | } | 445 | } |
| 446 | EXPORT_SYMBOL_GPL(__inet_hash_connect); | ||
| 447 | |||
| 448 | /* | ||
| 449 | * Bind a port for a connect operation and hash it. | ||
| 450 | */ | ||
| 451 | int inet_hash_connect(struct inet_timewait_death_row *death_row, | ||
| 452 | struct sock *sk) | ||
| 453 | { | ||
| 454 | return __inet_hash_connect(death_row, sk, | ||
| 455 | __inet_check_established, __inet_hash_nolisten); | ||
| 456 | } | ||
| 447 | 457 | ||
| 448 | EXPORT_SYMBOL_GPL(inet_hash_connect); | 458 | EXPORT_SYMBOL_GPL(inet_hash_connect); |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 06b01befc90e..ece6d0ee2da5 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
| @@ -233,97 +233,8 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk) | |||
| 233 | int inet6_hash_connect(struct inet_timewait_death_row *death_row, | 233 | int inet6_hash_connect(struct inet_timewait_death_row *death_row, |
| 234 | struct sock *sk) | 234 | struct sock *sk) |
| 235 | { | 235 | { |
| 236 | struct inet_hashinfo *hinfo = death_row->hashinfo; | 236 | return __inet_hash_connect(death_row, sk, |
| 237 | const unsigned short snum = inet_sk(sk)->num; | 237 | __inet6_check_established, __inet6_hash); |
| 238 | struct inet_bind_hashbucket *head; | ||
| 239 | struct inet_bind_bucket *tb; | ||
| 240 | int ret; | ||
| 241 | |||
| 242 | if (snum == 0) { | ||
| 243 | int i, port, low, high, remaining; | ||
| 244 | static u32 hint; | ||
| 245 | const u32 offset = hint + inet6_sk_port_offset(sk); | ||
| 246 | struct hlist_node *node; | ||
| 247 | struct inet_timewait_sock *tw = NULL; | ||
| 248 | |||
| 249 | inet_get_local_port_range(&low, &high); | ||
| 250 | remaining = (high - low) + 1; | ||
| 251 | |||
| 252 | local_bh_disable(); | ||
| 253 | for (i = 1; i <= remaining; i++) { | ||
| 254 | port = low + (i + offset) % remaining; | ||
| 255 | head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; | ||
| 256 | spin_lock(&head->lock); | ||
| 257 | |||
| 258 | /* Does not bother with rcv_saddr checks, | ||
| 259 | * because the established check is already | ||
| 260 | * unique enough. | ||
| 261 | */ | ||
| 262 | inet_bind_bucket_for_each(tb, node, &head->chain) { | ||
| 263 | if (tb->port == port) { | ||
| 264 | BUG_TRAP(!hlist_empty(&tb->owners)); | ||
| 265 | if (tb->fastreuse >= 0) | ||
| 266 | goto next_port; | ||
| 267 | if (!__inet6_check_established(death_row, | ||
| 268 | sk, port, | ||
| 269 | &tw)) | ||
| 270 | goto ok; | ||
| 271 | goto next_port; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, | ||
| 276 | head, port); | ||
| 277 | if (!tb) { | ||
| 278 | spin_unlock(&head->lock); | ||
| 279 | break; | ||
| 280 | } | ||
| 281 | tb->fastreuse = -1; | ||
| 282 | goto ok; | ||
| 283 | |||
| 284 | next_port: | ||
| 285 | spin_unlock(&head->lock); | ||
| 286 | } | ||
| 287 | local_bh_enable(); | ||
| 288 | |||
| 289 | return -EADDRNOTAVAIL; | ||
| 290 | |||
| 291 | ok: | ||
| 292 | hint += i; | ||
| 293 | |||
| 294 | /* Head lock still held and bh's disabled */ | ||
| 295 | inet_bind_hash(sk, tb, port); | ||
| 296 | if (sk_unhashed(sk)) { | ||
| 297 | inet_sk(sk)->sport = htons(port); | ||
| 298 | __inet6_hash(hinfo, sk); | ||
| 299 | } | ||
| 300 | spin_unlock(&head->lock); | ||
| 301 | |||
| 302 | if (tw) { | ||
| 303 | inet_twsk_deschedule(tw, death_row); | ||
| 304 | inet_twsk_put(tw); | ||
| 305 | } | ||
| 306 | |||
| 307 | ret = 0; | ||
| 308 | goto out; | ||
| 309 | } | ||
| 310 | |||
| 311 | head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size)]; | ||
| 312 | tb = inet_csk(sk)->icsk_bind_hash; | ||
| 313 | spin_lock_bh(&head->lock); | ||
| 314 | |||
| 315 | if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) { | ||
| 316 | __inet6_hash(hinfo, sk); | ||
| 317 | spin_unlock_bh(&head->lock); | ||
| 318 | return 0; | ||
| 319 | } else { | ||
| 320 | spin_unlock(&head->lock); | ||
| 321 | /* No definite answer... Walk to established hash table */ | ||
| 322 | ret = __inet6_check_established(death_row, sk, snum, NULL); | ||
| 323 | out: | ||
| 324 | local_bh_enable(); | ||
| 325 | return ret; | ||
| 326 | } | ||
| 327 | } | 238 | } |
| 328 | 239 | ||
| 329 | EXPORT_SYMBOL_GPL(inet6_hash_connect); | 240 | EXPORT_SYMBOL_GPL(inet6_hash_connect); |
