o tcp: convert struct tcp_bind_bucket to hlist

parent b3e3e604
......@@ -84,16 +84,27 @@ struct tcp_ehash_bucket {
struct tcp_bind_bucket {
unsigned short port;
signed short fastreuse;
struct tcp_bind_bucket *next;
struct tcp_bind_bucket **pprev;
struct hlist_node node;
struct hlist_head owners;
};
#define tb_for_each(tb, node, head) hlist_for_each_entry(tb, node, head, node)
struct tcp_bind_hashbucket {
spinlock_t lock;
struct tcp_bind_bucket *chain;
struct hlist_head chain;
};
static inline struct tcp_bind_bucket *__tb_head(struct tcp_bind_hashbucket *head)
{
return hlist_entry(head->chain.first, struct tcp_bind_bucket, node);
}
static inline struct tcp_bind_bucket *tb_head(struct tcp_bind_hashbucket *head)
{
return hlist_empty(&head->chain) ? NULL : __tb_head(head);
}
extern struct tcp_hashinfo {
/* This is for sockets with full identity only. Sockets here will
* always be without wildcards and will have the following invariant:
......
......@@ -2641,7 +2641,7 @@ void __init tcp_init(void)
panic("Failed to allocate TCP bind hash table\n");
for (i = 0; i < tcp_bhash_size; i++) {
tcp_bhash[i].lock = SPIN_LOCK_UNLOCKED;
tcp_bhash[i].chain = NULL;
INIT_HLIST_HEAD(&tcp_bhash[i].chain);
}
/* Try to be a bit smarter and adjust defaults depending
......
......@@ -134,10 +134,7 @@ struct tcp_bind_bucket *tcp_bucket_create(struct tcp_bind_hashbucket *head,
tb->port = snum;
tb->fastreuse = 0;
INIT_HLIST_HEAD(&tb->owners);
if ((tb->next = head->chain) != NULL)
tb->next->pprev = &tb->next;
head->chain = tb;
tb->pprev = &head->chain;
hlist_add_head(&tb->node, &head->chain);
}
return tb;
}
......@@ -146,9 +143,7 @@ struct tcp_bind_bucket *tcp_bucket_create(struct tcp_bind_hashbucket *head,
void tcp_bucket_destroy(struct tcp_bind_bucket *tb)
{
if (hlist_empty(&tb->owners)) {
if (tb->next)
tb->next->pprev = tb->pprev;
*(tb->pprev) = tb->next;
__hlist_del(&tb->node);
kmem_cache_free(tcp_bucket_cachep, tb);
}
}
......@@ -211,6 +206,7 @@ static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
{
struct tcp_bind_hashbucket *head;
struct hlist_node *node;
struct tcp_bind_bucket *tb;
int ret;
......@@ -229,7 +225,7 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
rover = low;
head = &tcp_bhash[tcp_bhashfn(rover)];
spin_lock(&head->lock);
for (tb = head->chain; tb; tb = tb->next)
tb_for_each(tb, node, &head->chain)
if (tb->port == rover)
goto next;
break;
......@@ -248,15 +244,17 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
* non-NULL and we hold it's mutex.
*/
snum = rover;
tb = NULL;
} else {
head = &tcp_bhash[tcp_bhashfn(snum)];
spin_lock(&head->lock);
for (tb = head->chain; tb; tb = tb->next)
tb_for_each(tb, node, &head->chain)
if (tb->port == snum)
break;
goto tb_found;
}
if (tb && !hlist_empty(&tb->owners)) {
tb = NULL;
goto tb_not_found;
tb_found:
if (!hlist_empty(&tb->owners)) {
if (sk->sk_reuse > 1)
goto success;
if (tb->fastreuse > 0 &&
......@@ -268,6 +266,7 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
goto fail_unlock;
}
}
tb_not_found:
ret = 1;
if (!tb && (tb = tcp_bucket_create(head, snum)) == NULL)
goto fail_unlock;
......@@ -646,6 +645,7 @@ static int tcp_v4_hash_connect(struct sock *sk)
int low = sysctl_local_port_range[0];
int high = sysctl_local_port_range[1];
int remaining = (high - low) + 1;
struct hlist_node *node;
struct tcp_tw_bucket *tw = NULL;
local_bh_disable();
......@@ -677,7 +677,7 @@ static int tcp_v4_hash_connect(struct sock *sk)
* because the established check is already
* unique enough.
*/
for (tb = head->chain; tb; tb = tb->next) {
tb_for_each(tb, node, &head->chain) {
if (tb->port == rover) {
BUG_TRAP(!hlist_empty(&tb->owners));
if (tb->fastreuse >= 0)
......
......@@ -157,6 +157,7 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
{
struct tcp_bind_hashbucket *head;
struct tcp_bind_bucket *tb;
struct hlist_node *node;
int ret;
local_bh_disable();
......@@ -173,7 +174,7 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
rover = low;
head = &tcp_bhash[tcp_bhashfn(rover)];
spin_lock(&head->lock);
for (tb = head->chain; tb; tb = tb->next)
tb_for_each(tb, node, &head->chain)
if (tb->port == rover)
goto next;
break;
......@@ -190,14 +191,16 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
/* OK, here is the one we will use. */
snum = rover;
tb = NULL;
} else {
head = &tcp_bhash[tcp_bhashfn(snum)];
spin_lock(&head->lock);
for (tb = head->chain; tb != NULL; tb = tb->next)
tb_for_each(tb, node, &head->chain)
if (tb->port == snum)
break;
goto tb_found;
}
tb = NULL;
goto tb_not_found;
tb_found:
if (tb && !hlist_empty(&tb->owners)) {
if (tb->fastreuse > 0 && sk->sk_reuse &&
sk->sk_state != TCP_LISTEN) {
......@@ -208,9 +211,9 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
goto fail_unlock;
}
}
tb_not_found:
ret = 1;
if (tb == NULL &&
(tb = tcp_bucket_create(head, snum)) == NULL)
if (!tb && (tb = tcp_bucket_create(head, snum)) == NULL)
goto fail_unlock;
if (hlist_empty(&tb->owners)) {
if (sk->sk_reuse && sk->sk_state != TCP_LISTEN)
......@@ -550,7 +553,7 @@ static int tcp_v6_hash_connect(struct sock *sk)
}
head = &tcp_bhash[tcp_bhashfn(inet_sk(sk)->num)];
tb = head->chain;
tb = tb_head(head);
spin_lock_bh(&head->lock);
......
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