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: Kuniyuki Iwashima <kuniyu@amazon.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
b82ba728cc
commit
8002d44fe8
@ -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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 @@ success:
|
|||||||
|
|
||||||
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,
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
__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)
|
|||||||
}
|
}
|
||||||
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 @@ other_parity_scan:
|
|||||||
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,
|
|||||||
|
|
||||||
__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);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user