Skip to content

Commit edc12f0

Browse files
q2venkuba-moo
authored andcommitted
tcp: Save unnecessary inet_twsk_purge() calls.
While destroying netns, we call inet_twsk_purge() in tcp_sk_exit_batch() and tcpv6_net_exit_batch() for AF_INET and AF_INET6. These commands trigger the kernel to walk through the potentially big ehash twice even though the netns has no TIME_WAIT sockets. # ip netns add test # ip netns del test or # unshare -n /bin/true >/dev/null When tw_refcount is 1, we need not call inet_twsk_purge() at least for the net. We can save such unneeded iterations if all netns in net_exit_list have no TIME_WAIT sockets. This change eliminates the tax by the additional unshare() described in the next patch to guarantee the per-netns ehash size. Tested: # mount -t debugfs none /sys/kernel/debug/ # echo cleanup_net > /sys/kernel/debug/tracing/set_ftrace_filter # echo inet_twsk_purge >> /sys/kernel/debug/tracing/set_ftrace_filter # echo function > /sys/kernel/debug/tracing/current_tracer # cat ./add_del_unshare.sh for i in `seq 1 40` do (for j in `seq 1 100` ; do unshare -n /bin/true >/dev/null ; done) & done wait; # ./add_del_unshare.sh Before the patch: # cat /sys/kernel/debug/tracing/trace_pipe kworker/u128:0-8 [031] ...1. 174.162765: cleanup_net <-process_one_work kworker/u128:0-8 [031] ...1. 174.240796: inet_twsk_purge <-cleanup_net kworker/u128:0-8 [032] ...1. 174.244759: inet_twsk_purge <-tcp_sk_exit_batch kworker/u128:0-8 [034] ...1. 174.290861: cleanup_net <-process_one_work kworker/u128:0-8 [039] ...1. 175.245027: inet_twsk_purge <-cleanup_net kworker/u128:0-8 [046] ...1. 175.290541: inet_twsk_purge <-tcp_sk_exit_batch kworker/u128:0-8 [037] ...1. 175.321046: cleanup_net <-process_one_work kworker/u128:0-8 [024] ...1. 175.941633: inet_twsk_purge <-cleanup_net kworker/u128:0-8 [025] ...1. 176.242539: inet_twsk_purge <-tcp_sk_exit_batch After: # cat /sys/kernel/debug/tracing/trace_pipe kworker/u128:0-8 [038] ...1. 428.116174: cleanup_net <-process_one_work kworker/u128:0-8 [038] ...1. 428.262532: cleanup_net <-process_one_work kworker/u128:0-8 [030] ...1. 429.292645: cleanup_net <-process_one_work Signed-off-by: Kuniyuki Iwashima <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 4461568 commit edc12f0

File tree

4 files changed

+18
-2
lines changed

4 files changed

+18
-2
lines changed

include/net/tcp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb);
346346
void tcp_rcv_space_adjust(struct sock *sk);
347347
int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);
348348
void tcp_twsk_destructor(struct sock *sk);
349+
void tcp_twsk_purge(struct list_head *net_exit_list, int family);
349350
ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
350351
struct pipe_inode_info *pipe, size_t len,
351352
unsigned int flags);

net/ipv4/tcp_ipv4.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3206,7 +3206,7 @@ static void __net_exit tcp_sk_exit_batch(struct list_head *net_exit_list)
32063206
{
32073207
struct net *net;
32083208

3209-
inet_twsk_purge(&tcp_hashinfo, AF_INET);
3209+
tcp_twsk_purge(net_exit_list, AF_INET);
32103210

32113211
list_for_each_entry(net, net_exit_list, exit_list) {
32123212
WARN_ON_ONCE(!refcount_dec_and_test(&net->ipv4.tcp_death_row.tw_refcount));

net/ipv4/tcp_minisocks.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,21 @@ void tcp_twsk_destructor(struct sock *sk)
347347
}
348348
EXPORT_SYMBOL_GPL(tcp_twsk_destructor);
349349

350+
void tcp_twsk_purge(struct list_head *net_exit_list, int family)
351+
{
352+
struct net *net;
353+
354+
list_for_each_entry(net, net_exit_list, exit_list) {
355+
/* The last refcount is decremented in tcp_sk_exit_batch() */
356+
if (refcount_read(&net->ipv4.tcp_death_row.tw_refcount) == 1)
357+
continue;
358+
359+
inet_twsk_purge(&tcp_hashinfo, family);
360+
break;
361+
}
362+
}
363+
EXPORT_SYMBOL_GPL(tcp_twsk_purge);
364+
350365
/* Warning : This function is called without sk_listener being locked.
351366
* Be sure to read socket fields once, as their value could change under us.
352367
*/

net/ipv6/tcp_ipv6.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2229,7 +2229,7 @@ static void __net_exit tcpv6_net_exit(struct net *net)
22292229

22302230
static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list)
22312231
{
2232-
inet_twsk_purge(&tcp_hashinfo, AF_INET6);
2232+
tcp_twsk_purge(net_exit_list, AF_INET6);
22332233
}
22342234

22352235
static struct pernet_operations tcpv6_net_ops = {

0 commit comments

Comments
 (0)