Commit 8002d44f authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by David S. Miller

tcp: Check hlist_empty(&tb->bhash2) instead of hlist_empty(&tb->owners).

We use hlist_empty(&tb->owners) to check if the bhash bucket has a socket.
We can check the child bhash2 buckets instead.

For this to work, the bhash2 bucket must be freed before the bhash bucket.
Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b82ba728
...@@ -474,7 +474,7 @@ void inet_csk_update_fastreuse(struct inet_bind_bucket *tb, ...@@ -474,7 +474,7 @@ void inet_csk_update_fastreuse(struct inet_bind_bucket *tb,
kuid_t uid = sock_i_uid(sk); kuid_t uid = sock_i_uid(sk);
bool reuse = sk->sk_reuse && sk->sk_state != TCP_LISTEN; bool reuse = sk->sk_reuse && sk->sk_state != TCP_LISTEN;
if (hlist_empty(&tb->owners)) { if (hlist_empty(&tb->bhash2)) {
tb->fastreuse = reuse; tb->fastreuse = reuse;
if (sk->sk_reuseport) { if (sk->sk_reuseport) {
tb->fastreuseport = FASTREUSEPORT_ANY; tb->fastreuseport = FASTREUSEPORT_ANY;
...@@ -566,7 +566,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) ...@@ -566,7 +566,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
} }
if (!found_port) { if (!found_port) {
if (!hlist_empty(&tb->owners)) { if (!hlist_empty(&tb->bhash2)) {
if (sk->sk_reuse == SK_FORCE_REUSE || if (sk->sk_reuse == SK_FORCE_REUSE ||
(tb->fastreuse > 0 && reuse) || (tb->fastreuse > 0 && reuse) ||
sk_reuseport_match(tb, sk)) sk_reuseport_match(tb, sk))
...@@ -608,11 +608,10 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) ...@@ -608,11 +608,10 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
fail_unlock: fail_unlock:
if (ret) { if (ret) {
if (bhash2_created)
inet_bind2_bucket_destroy(hinfo->bind2_bucket_cachep, tb2);
if (bhash_created) if (bhash_created)
inet_bind_bucket_destroy(hinfo->bind_bucket_cachep, tb); inet_bind_bucket_destroy(hinfo->bind_bucket_cachep, tb);
if (bhash2_created)
inet_bind2_bucket_destroy(hinfo->bind2_bucket_cachep,
tb2);
} }
if (head2_lock_acquired) if (head2_lock_acquired)
spin_unlock(&head2->lock); spin_unlock(&head2->lock);
......
...@@ -88,7 +88,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep, ...@@ -88,7 +88,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep,
*/ */
void inet_bind_bucket_destroy(struct kmem_cache *cachep, struct inet_bind_bucket *tb) void inet_bind_bucket_destroy(struct kmem_cache *cachep, struct inet_bind_bucket *tb)
{ {
if (hlist_empty(&tb->owners)) { if (hlist_empty(&tb->bhash2)) {
__hlist_del(&tb->node); __hlist_del(&tb->node);
kmem_cache_free(cachep, tb); kmem_cache_free(cachep, tb);
} }
...@@ -195,7 +195,6 @@ static void __inet_put_port(struct sock *sk) ...@@ -195,7 +195,6 @@ static void __inet_put_port(struct sock *sk)
__sk_del_bind_node(sk); __sk_del_bind_node(sk);
inet_csk(sk)->icsk_bind_hash = NULL; inet_csk(sk)->icsk_bind_hash = NULL;
inet_sk(sk)->inet_num = 0; inet_sk(sk)->inet_num = 0;
inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
spin_lock(&head2->lock); spin_lock(&head2->lock);
if (inet_csk(sk)->icsk_bind2_hash) { if (inet_csk(sk)->icsk_bind2_hash) {
...@@ -207,6 +206,7 @@ static void __inet_put_port(struct sock *sk) ...@@ -207,6 +206,7 @@ static void __inet_put_port(struct sock *sk)
} }
spin_unlock(&head2->lock); spin_unlock(&head2->lock);
inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
spin_unlock(&head->lock); spin_unlock(&head->lock);
} }
...@@ -1062,7 +1062,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, ...@@ -1062,7 +1062,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
if (tb->fastreuse >= 0 || if (tb->fastreuse >= 0 ||
tb->fastreuseport >= 0) tb->fastreuseport >= 0)
goto next_port; goto next_port;
WARN_ON(hlist_empty(&tb->owners)); WARN_ON(hlist_empty(&tb->bhash2));
if (!check_established(death_row, sk, if (!check_established(death_row, sk,
port, &tw)) port, &tw))
goto ok; goto ok;
......
...@@ -37,11 +37,11 @@ void inet_twsk_bind_unhash(struct inet_timewait_sock *tw, ...@@ -37,11 +37,11 @@ void inet_twsk_bind_unhash(struct inet_timewait_sock *tw,
__hlist_del(&tw->tw_bind_node); __hlist_del(&tw->tw_bind_node);
tw->tw_tb = NULL; tw->tw_tb = NULL;
inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
__hlist_del(&tw->tw_bind2_node); __hlist_del(&tw->tw_bind2_node);
tw->tw_tb2 = NULL; tw->tw_tb2 = NULL;
inet_bind2_bucket_destroy(hashinfo->bind2_bucket_cachep, tb2); inet_bind2_bucket_destroy(hashinfo->bind2_bucket_cachep, tb2);
inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
__sock_put((struct sock *)tw); __sock_put((struct sock *)tw);
} }
......
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