Commit 5ee31fc1 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by David S. Miller

[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: default avatarPavel Emelyanov <xemul@openvz.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 535174ef
...@@ -413,6 +413,11 @@ static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo, ...@@ -413,6 +413,11 @@ static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
return sk; return sk;
} }
extern int __inet_hash_connect(struct inet_timewait_death_row *death_row,
struct sock *sk,
int (*check_established)(struct inet_timewait_death_row *,
struct sock *, __u16, struct inet_timewait_sock **),
void (*hash)(struct inet_hashinfo *, struct sock *));
extern int inet_hash_connect(struct inet_timewait_death_row *death_row, extern int inet_hash_connect(struct inet_timewait_death_row *death_row,
struct sock *sk); struct sock *sk);
#endif /* _INET_HASHTABLES_H */ #endif /* _INET_HASHTABLES_H */
...@@ -348,11 +348,11 @@ void __inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk) ...@@ -348,11 +348,11 @@ void __inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk)
} }
EXPORT_SYMBOL_GPL(__inet_hash); EXPORT_SYMBOL_GPL(__inet_hash);
/* int __inet_hash_connect(struct inet_timewait_death_row *death_row,
* Bind a port for a connect operation and hash it. struct sock *sk,
*/ int (*check_established)(struct inet_timewait_death_row *,
int inet_hash_connect(struct inet_timewait_death_row *death_row, struct sock *, __u16, struct inet_timewait_sock **),
struct sock *sk) void (*hash)(struct inet_hashinfo *, struct sock *))
{ {
struct inet_hashinfo *hinfo = death_row->hashinfo; struct inet_hashinfo *hinfo = death_row->hashinfo;
const unsigned short snum = inet_sk(sk)->num; const unsigned short snum = inet_sk(sk)->num;
...@@ -385,9 +385,8 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row, ...@@ -385,9 +385,8 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row,
BUG_TRAP(!hlist_empty(&tb->owners)); BUG_TRAP(!hlist_empty(&tb->owners));
if (tb->fastreuse >= 0) if (tb->fastreuse >= 0)
goto next_port; goto next_port;
if (!__inet_check_established(death_row, if (!check_established(death_row, sk,
sk, port, port, &tw))
&tw))
goto ok; goto ok;
goto next_port; goto next_port;
} }
...@@ -415,7 +414,7 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row, ...@@ -415,7 +414,7 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row,
inet_bind_hash(sk, tb, port); inet_bind_hash(sk, tb, port);
if (sk_unhashed(sk)) { if (sk_unhashed(sk)) {
inet_sk(sk)->sport = htons(port); inet_sk(sk)->sport = htons(port);
__inet_hash_nolisten(hinfo, sk); hash(hinfo, sk);
} }
spin_unlock(&head->lock); spin_unlock(&head->lock);
...@@ -432,17 +431,28 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row, ...@@ -432,17 +431,28 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row,
tb = inet_csk(sk)->icsk_bind_hash; tb = inet_csk(sk)->icsk_bind_hash;
spin_lock_bh(&head->lock); spin_lock_bh(&head->lock);
if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) {
__inet_hash_nolisten(hinfo, sk); hash(hinfo, sk);
spin_unlock_bh(&head->lock); spin_unlock_bh(&head->lock);
return 0; return 0;
} else { } else {
spin_unlock(&head->lock); spin_unlock(&head->lock);
/* No definite answer... Walk to established hash table */ /* No definite answer... Walk to established hash table */
ret = __inet_check_established(death_row, sk, snum, NULL); ret = check_established(death_row, sk, snum, NULL);
out: out:
local_bh_enable(); local_bh_enable();
return ret; return ret;
} }
} }
EXPORT_SYMBOL_GPL(__inet_hash_connect);
/*
* Bind a port for a connect operation and hash it.
*/
int inet_hash_connect(struct inet_timewait_death_row *death_row,
struct sock *sk)
{
return __inet_hash_connect(death_row, sk,
__inet_check_established, __inet_hash_nolisten);
}
EXPORT_SYMBOL_GPL(inet_hash_connect); EXPORT_SYMBOL_GPL(inet_hash_connect);
...@@ -233,97 +233,8 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk) ...@@ -233,97 +233,8 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk)
int inet6_hash_connect(struct inet_timewait_death_row *death_row, int inet6_hash_connect(struct inet_timewait_death_row *death_row,
struct sock *sk) struct sock *sk)
{ {
struct inet_hashinfo *hinfo = death_row->hashinfo; return __inet_hash_connect(death_row, sk,
const unsigned short snum = inet_sk(sk)->num; __inet6_check_established, __inet6_hash);
struct inet_bind_hashbucket *head;
struct inet_bind_bucket *tb;
int ret;
if (snum == 0) {
int i, port, low, high, remaining;
static u32 hint;
const u32 offset = hint + inet6_sk_port_offset(sk);
struct hlist_node *node;
struct inet_timewait_sock *tw = NULL;
inet_get_local_port_range(&low, &high);
remaining = (high - low) + 1;
local_bh_disable();
for (i = 1; i <= remaining; i++) {
port = low + (i + offset) % remaining;
head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
spin_lock(&head->lock);
/* Does not bother with rcv_saddr checks,
* because the established check is already
* unique enough.
*/
inet_bind_bucket_for_each(tb, node, &head->chain) {
if (tb->port == port) {
BUG_TRAP(!hlist_empty(&tb->owners));
if (tb->fastreuse >= 0)
goto next_port;
if (!__inet6_check_established(death_row,
sk, port,
&tw))
goto ok;
goto next_port;
}
}
tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep,
head, port);
if (!tb) {
spin_unlock(&head->lock);
break;
}
tb->fastreuse = -1;
goto ok;
next_port:
spin_unlock(&head->lock);
}
local_bh_enable();
return -EADDRNOTAVAIL;
ok:
hint += i;
/* Head lock still held and bh's disabled */
inet_bind_hash(sk, tb, port);
if (sk_unhashed(sk)) {
inet_sk(sk)->sport = htons(port);
__inet6_hash(hinfo, sk);
}
spin_unlock(&head->lock);
if (tw) {
inet_twsk_deschedule(tw, death_row);
inet_twsk_put(tw);
}
ret = 0;
goto out;
}
head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size)];
tb = inet_csk(sk)->icsk_bind_hash;
spin_lock_bh(&head->lock);
if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) {
__inet6_hash(hinfo, sk);
spin_unlock_bh(&head->lock);
return 0;
} else {
spin_unlock(&head->lock);
/* No definite answer... Walk to established hash table */
ret = __inet6_check_established(death_row, sk, snum, NULL);
out:
local_bh_enable();
return ret;
}
} }
EXPORT_SYMBOL_GPL(inet6_hash_connect); EXPORT_SYMBOL_GPL(inet6_hash_connect);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment