Skip to content

Commit b508429

Browse files
edumazetopsiff
authored andcommitted
tcp: use RCU in __inet{6}_check_established()
mainline inclusion from mainline-v6.15-rc1 category: performance When __inet_hash_connect() has to try many 4-tuples before finding an available one, we see a high spinlock cost from __inet_check_established() and/or __inet6_check_established(). This patch adds an RCU lookup to avoid the spinlock acquisition when the 4-tuple is found in the hash table. Note that there are still spin_lock_bh() calls in __inet_hash_connect() to protect inet_bind_hashbucket, this will be fixed later in this series. Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Jason Xing <kerneljasonxing@gmail.com> Tested-by: Jason Xing <kerneljasonxing@gmail.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com> Link: https://patch.msgid.link/20250302124237.3913746-2-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> (cherry picked from commit ae9d5b1) Signed-off-by: Wentao Guan <guanwentao@uniontech.com> Change-Id: I6cce9a2afd4062f8622cab4cad0a7d6453c4f33f
1 parent deafd84 commit b508429

2 files changed

Lines changed: 32 additions & 6 deletions

File tree

net/ipv4/inet_hashtables.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -552,11 +552,24 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
552552
unsigned int hash = inet_ehashfn(net, daddr, lport,
553553
saddr, inet->inet_dport);
554554
struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
555-
spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
556-
struct sock *sk2;
557-
const struct hlist_nulls_node *node;
558555
struct inet_timewait_sock *tw = NULL;
556+
const struct hlist_nulls_node *node;
557+
struct sock *sk2;
558+
spinlock_t *lock;
559+
560+
rcu_read_lock();
561+
sk_nulls_for_each(sk2, node, &head->chain) {
562+
if (sk2->sk_hash != hash ||
563+
!inet_match(net, sk2, acookie, ports, dif, sdif))
564+
continue;
565+
if (sk2->sk_state == TCP_TIME_WAIT)
566+
break;
567+
rcu_read_unlock();
568+
return -EADDRNOTAVAIL;
569+
}
570+
rcu_read_unlock();
559571

572+
lock = inet_ehash_lockp(hinfo, hash);
560573
spin_lock(lock);
561574

562575
sk_nulls_for_each(sk2, node, &head->chain) {

net/ipv6/inet6_hashtables.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,11 +276,24 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
276276
const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr,
277277
inet->inet_dport);
278278
struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
279-
spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
280-
struct sock *sk2;
281-
const struct hlist_nulls_node *node;
282279
struct inet_timewait_sock *tw = NULL;
280+
const struct hlist_nulls_node *node;
281+
struct sock *sk2;
282+
spinlock_t *lock;
283+
284+
rcu_read_lock();
285+
sk_nulls_for_each(sk2, node, &head->chain) {
286+
if (sk2->sk_hash != hash ||
287+
!inet6_match(net, sk2, saddr, daddr, ports, dif, sdif))
288+
continue;
289+
if (sk2->sk_state == TCP_TIME_WAIT)
290+
break;
291+
rcu_read_unlock();
292+
return -EADDRNOTAVAIL;
293+
}
294+
rcu_read_unlock();
283295

296+
lock = inet_ehash_lockp(hinfo, hash);
284297
spin_lock(lock);
285298

286299
sk_nulls_for_each(sk2, node, &head->chain) {

0 commit comments

Comments
 (0)