mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-04 04:04:19 +00:00
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 <kuniyu@amazon.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
4461568aa4
commit
edc12f032a
@ -346,6 +346,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb);
|
||||
void tcp_rcv_space_adjust(struct sock *sk);
|
||||
int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);
|
||||
void tcp_twsk_destructor(struct sock *sk);
|
||||
void tcp_twsk_purge(struct list_head *net_exit_list, int family);
|
||||
ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
|
||||
struct pipe_inode_info *pipe, size_t len,
|
||||
unsigned int flags);
|
||||
|
@ -3206,7 +3206,7 @@ static void __net_exit tcp_sk_exit_batch(struct list_head *net_exit_list)
|
||||
{
|
||||
struct net *net;
|
||||
|
||||
inet_twsk_purge(&tcp_hashinfo, AF_INET);
|
||||
tcp_twsk_purge(net_exit_list, AF_INET);
|
||||
|
||||
list_for_each_entry(net, net_exit_list, exit_list) {
|
||||
WARN_ON_ONCE(!refcount_dec_and_test(&net->ipv4.tcp_death_row.tw_refcount));
|
||||
|
@ -347,6 +347,21 @@ void tcp_twsk_destructor(struct sock *sk)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tcp_twsk_destructor);
|
||||
|
||||
void tcp_twsk_purge(struct list_head *net_exit_list, int family)
|
||||
{
|
||||
struct net *net;
|
||||
|
||||
list_for_each_entry(net, net_exit_list, exit_list) {
|
||||
/* The last refcount is decremented in tcp_sk_exit_batch() */
|
||||
if (refcount_read(&net->ipv4.tcp_death_row.tw_refcount) == 1)
|
||||
continue;
|
||||
|
||||
inet_twsk_purge(&tcp_hashinfo, family);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tcp_twsk_purge);
|
||||
|
||||
/* Warning : This function is called without sk_listener being locked.
|
||||
* Be sure to read socket fields once, as their value could change under us.
|
||||
*/
|
||||
|
@ -2229,7 +2229,7 @@ static void __net_exit tcpv6_net_exit(struct net *net)
|
||||
|
||||
static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list)
|
||||
{
|
||||
inet_twsk_purge(&tcp_hashinfo, AF_INET6);
|
||||
tcp_twsk_purge(net_exit_list, AF_INET6);
|
||||
}
|
||||
|
||||
static struct pernet_operations tcpv6_net_ops = {
|
||||
|
Loading…
Reference in New Issue
Block a user