From 753d525a08f2e18d50da9a909d48ecb7596683b3 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:48:04 +0300 Subject: [PATCH 01/16] net: Convert inet6_net_ops init method initializes sysctl defaults, allocates percpu arrays and creates /proc entries. exit method reverts the above. There are no pernet_operations, which are interested in the above entities of foreign net namespace, so inet6_net_ops are able to be marked as async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index c1e292db04db6..dbbe04018813b 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -857,6 +857,7 @@ static void __net_exit inet6_net_exit(struct net *net) static struct pernet_operations inet6_net_ops = { .init = inet6_net_init, .exit = inet6_net_exit, + .async = true, }; static const struct ipv6_stub ipv6_stub_impl = { From 9c537ca1554e5d7db69a3b606801a2101e02edda Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:48:14 +0300 Subject: [PATCH 02/16] net: Convert cfg80211_pernet_ops This patch finishes converting pernet_operations registered in net/wireless directory. These pernet_operations have only exit method, which moves devices to init_net. This action is not pernet_operations-specific, and function cfg80211_switch_netns() may be called all time during the system life. All necessary protection against concurrent cfg80211_pernet_exit() is made by rtnl_lock(). So, cfg80211_pernet_ops is able to be marked as async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/wireless/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/wireless/core.c b/net/wireless/core.c index a6f3cac8c640e..670aa229168af 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1340,6 +1340,7 @@ static void __net_exit cfg80211_pernet_exit(struct net *net) static struct pernet_operations cfg80211_pernet_ops = { .exit = cfg80211_pernet_exit, + .async = true, }; static int __init cfg80211_init(void) From b01a59a4884ed2d95b8db4741e552a689c18989b Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:48:37 +0300 Subject: [PATCH 03/16] net: Convert ip6mr_net_ops These pernet_operations create and destroy /proc entries, populate and depopulate net::rules_ops and multiroute table. All the structures are pernet, and they are not touched by foreign net pernet_operations. So, it's possible to mark them async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/ip6mr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 9f6cace9c817e..295eb5ecaee57 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1397,6 +1397,7 @@ static void __net_exit ip6mr_net_exit(struct net *net) static struct pernet_operations ip6mr_net_ops = { .init = ip6mr_net_init, .exit = ip6mr_net_exit, + .async = true, }; int __init ip6_mr_init(void) From 1a2e93329dd413585798c122aac0607093b2d379 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:48:57 +0300 Subject: [PATCH 04/16] net: Convert icmpv6_sk_ops, ndisc_net_ops and igmp6_net_ops These pernet_operations create and destroy net::ipv6.icmp_sk socket, used to send ICMP or error reply. Nobody can dereference the socket to handle a packet before net is initialized, as there is no routing; nobody can do that in parallel with exit, as all of devices are moved to init_net or destroyed and there are no packets it-flight. So, it's possible to mark these pernet_operations as async. The same for ndisc_net_ops and for igmp6_net_ops. The last one also creates and destroys /proc entries. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/icmp.c | 1 + net/ipv6/mcast.c | 1 + net/ipv6/ndisc.c | 1 + 3 files changed, 3 insertions(+) diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 6ae5dd3f4d0de..4fa4f1b150a4d 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -997,6 +997,7 @@ static void __net_exit icmpv6_sk_exit(struct net *net) static struct pernet_operations icmpv6_sk_ops = { .init = icmpv6_sk_init, .exit = icmpv6_sk_exit, + .async = true, }; int __init icmpv6_init(void) diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 9b9d2ff01b355..d9bb933dd5c42 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2997,6 +2997,7 @@ static void __net_exit igmp6_net_exit(struct net *net) static struct pernet_operations igmp6_net_ops = { .init = igmp6_net_init, .exit = igmp6_net_exit, + .async = true, }; int __init igmp6_init(void) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f61a5b613b52b..0a19ce3a6f7ff 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1882,6 +1882,7 @@ static void __net_exit ndisc_net_exit(struct net *net) static struct pernet_operations ndisc_net_ops = { .init = ndisc_net_init, .exit = ndisc_net_exit, + .async = true, }; int __init ndisc_init(void) From 509114112d0b71997dbe58d4f2976eeddf8eacc4 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:49:10 +0300 Subject: [PATCH 05/16] net: Convert raw6_net_ops, udplite6_net_ops, ipv6_proc_ops, if6_proc_net_ops and ip6_route_net_late_ops These pernet_operations create and destroy /proc entries and safely may be converted and safely may be mark as async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 1 + net/ipv6/proc.c | 1 + net/ipv6/raw.c | 1 + net/ipv6/route.c | 2 ++ 4 files changed, 5 insertions(+) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 8c17f8d8d5d92..4facfe0b18882 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4257,6 +4257,7 @@ static void __net_exit if6_proc_net_exit(struct net *net) static struct pernet_operations if6_proc_net_ops = { .init = if6_proc_net_init, .exit = if6_proc_net_exit, + .async = true, }; int __init if6_proc_init(void) diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index b67814242f78c..b8858c546f41b 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -343,6 +343,7 @@ static void __net_exit ipv6_proc_exit_net(struct net *net) static struct pernet_operations ipv6_proc_ops = { .init = ipv6_proc_init_net, .exit = ipv6_proc_exit_net, + .async = true, }; int __init ipv6_misc_proc_init(void) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 4c25339b19843..10a4ac4933b7e 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1332,6 +1332,7 @@ static void __net_exit raw6_exit_net(struct net *net) static struct pernet_operations raw6_net_ops = { .init = raw6_init_net, .exit = raw6_exit_net, + .async = true, }; int __init raw6_proc_init(void) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f0baae26db8f6..1be84ef23f431 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -4972,6 +4972,7 @@ static void __net_exit ip6_route_net_exit_late(struct net *net) static struct pernet_operations ip6_route_net_ops = { .init = ip6_route_net_init, .exit = ip6_route_net_exit, + .async = true, }; static int __net_init ipv6_inetpeer_init(struct net *net) @@ -5002,6 +5003,7 @@ static struct pernet_operations ipv6_inetpeer_ops = { static struct pernet_operations ip6_route_net_late_ops = { .init = ip6_route_net_init_late, .exit = ip6_route_net_exit_late, + .async = true, }; static struct notifier_block ip6_route_dev_notifier = { From 85ca51b2a23969dccb5abff31eb54560db8195ca Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:49:20 +0300 Subject: [PATCH 06/16] net: Convert ipv6_inetpeer_ops net->ipv6.peers is dereferenced in three places via inet_getpeer_v6(), and it's used to handle skb. All the users of inet_getpeer_v6() do not look like be able to be called from foreign net pernet_operations, so we may mark them as async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/route.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 1be84ef23f431..aa709b644945b 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -4998,6 +4998,7 @@ static void __net_exit ipv6_inetpeer_exit(struct net *net) static struct pernet_operations ipv6_inetpeer_ops = { .init = ipv6_inetpeer_init, .exit = ipv6_inetpeer_exit, + .async = true, }; static struct pernet_operations ip6_route_net_late_ops = { From 7b7dd180b85b9c39c426cfaade73f7d0409c7f85 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:49:31 +0300 Subject: [PATCH 07/16] net: Convert fib6_rules_net_ops These pernet_operations register and unregister net::ipv6.fib6_rules_ops, which are used for routing. It looks like there are no pernet_operations, which send ipv6 packages to another net, so we are able to mark them as async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/fib6_rules.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index b240f24a6e523..95a2c9e8699a7 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -368,6 +368,7 @@ static void __net_exit fib6_rules_net_exit(struct net *net) static struct pernet_operations fib6_rules_net_ops = { .init = fib6_rules_net_init, .exit = fib6_rules_net_exit, + .async = true, }; int __init fib6_rules_init(void) From fef65a2c6c3417fcf2fb0bebd8c27355d1b14a12 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:49:40 +0300 Subject: [PATCH 08/16] net: Convert tcpv6_net_ops These pernet_operations create and destroy net::ipv6.tcp_sk socket, which is used in tcp_v6_send_response() only. It looks like foreign pernet_operations don't want to set ipv6 connection inside destroyed net, so this socket may be created in destroyed in parallel with anything else. inet_twsk_purge() is also safe for that, as described in patch for tcp_sk_ops. So, it's possible to mark them as async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/tcp_ipv6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 883df0ad5bfe9..5425d7b100ee1 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2007,6 +2007,7 @@ static struct pernet_operations tcpv6_net_ops = { .init = tcpv6_net_init, .exit = tcpv6_net_exit, .exit_batch = tcpv6_net_exit_batch, + .async = true, }; int __init tcpv6_init(void) From 58708caef56b04da2c91d6aaba49c783f22055c2 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:49:49 +0300 Subject: [PATCH 09/16] net: Convert ipv6_sysctl_net_ops These pernet_operations create and destroy sysctl tables. They are not touched by another net pernet_operations. So, it's possible to execute them in parallel with others. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/sysctl_net_ipv6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index a789a8ac6a645..262f791f1b9b9 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -251,6 +251,7 @@ static void __net_exit ipv6_sysctl_net_exit(struct net *net) static struct pernet_operations ipv6_sysctl_net_ops = { .init = ipv6_sysctl_net_init, .exit = ipv6_sysctl_net_exit, + .async = true, }; static struct ctl_table_header *ip6_header; From ac34cb6c0c4d327d69e588d7a42bbc6428e2fdfd Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:49:59 +0300 Subject: [PATCH 10/16] net: Convert ping_v6_net_ops These pernet_operations only register and unregister /proc entries, so it's possible to mark them async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/ping.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index d12c55dad7d14..318c6e9142345 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -240,6 +240,7 @@ static void __net_init ping_v6_proc_exit_net(struct net *net) static struct pernet_operations ping_v6_net_ops = { .init = ping_v6_proc_init_net, .exit = ping_v6_proc_exit_net, + .async = true, }; #endif From a7852a76f414f69631ed3adc4b001c633829306d Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:50:09 +0300 Subject: [PATCH 11/16] net: Convert ip6_flowlabel_net_ops These pernet_operations create and destroy /proc entries. ip6_fl_purge() makes almost the same actions as timer ip6_fl_gc_timer does, and as it can be executed in parallel with ip6_fl_purge(), two parallel ip6_fl_purge() may be executed. So, we can mark it async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/ip6_flowlabel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 3dab664ff5034..6ddf522828945 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -873,6 +873,7 @@ static void __net_exit ip6_flowlabel_net_exit(struct net *net) static struct pernet_operations ip6_flowlabel_net_ops = { .init = ip6_flowlabel_proc_init, .exit = ip6_flowlabel_net_exit, + .async = true, }; int ip6_flowlabel_init(void) From b489141369f78ead6ed540cff29ac1974852cd7f Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:50:18 +0300 Subject: [PATCH 12/16] net: Convert xfrm6_net_ops These pernet_operations create sysctl tables and initialize net::xfrm.xfrm6_dst_ops used for routing. It doesn't look like another pernet_operations send ipv6 packets to foreign net namespaces, so it should be safe to mark the pernet_operations as async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/xfrm6_policy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 09fb44ee3b45d..88cd0c90fa81a 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -395,6 +395,7 @@ static void __net_exit xfrm6_net_exit(struct net *net) static struct pernet_operations xfrm6_net_ops = { .init = xfrm6_net_init, .exit = xfrm6_net_exit, + .async = true, }; int __init xfrm6_init(void) From d16784d9fb2a91e96374df7cb689f52cef55371b Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:50:28 +0300 Subject: [PATCH 13/16] net: Convert fib6_net_ops, ipv6_addr_label_ops and ip6_segments_ops These pernet_operations register and unregister tables and lists for packets forwarding. All of the entities are per-net. Init methods makes simple initializations, and since net is not visible for foreigners at the time it is working, it can't race with anything. Exit method is executed when there are only local devices, and there mustn't be packets in-flight. Also, it looks like no one pernet_operations want to send ipv6 packets to foreign net. The same reasons are for ipv6_addr_label_ops and ip6_segments_ops. So, we are able to mark all them as async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/addrlabel.c | 1 + net/ipv6/ip6_fib.c | 1 + net/ipv6/seg6.c | 1 + 3 files changed, 3 insertions(+) diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 1d6ced37ad718..ba2e636333703 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c @@ -344,6 +344,7 @@ static void __net_exit ip6addrlbl_net_exit(struct net *net) static struct pernet_operations ipv6_addr_label_ops = { .init = ip6addrlbl_net_init, .exit = ip6addrlbl_net_exit, + .async = true, }; int __init ipv6_addr_label_init(void) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 92b8d8c75eed6..cab95cf3b39fc 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -2160,6 +2160,7 @@ static void fib6_net_exit(struct net *net) static struct pernet_operations fib6_net_ops = { .init = fib6_net_init, .exit = fib6_net_exit, + .async = true, }; int __init fib6_init(void) diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c index 7f5621d095719..c3f13c3bd8a9d 100644 --- a/net/ipv6/seg6.c +++ b/net/ipv6/seg6.c @@ -395,6 +395,7 @@ static void __net_exit seg6_net_exit(struct net *net) static struct pernet_operations ip6_segments_ops = { .init = seg6_net_init, .exit = seg6_net_exit, + .async = true, }; static const struct genl_ops seg6_genl_ops[] = { From 5fc094f5b8c9b8e5012b7ccf303be3b123563a58 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:50:37 +0300 Subject: [PATCH 14/16] net: Convert ip6_frags_ops Exit methods calls inet_frags_exit_net() with global ip6_frags as argument. So, after we make the pernet_operations async, a pair of exit methods may be called to iterate this hash table. Since there is inet_frag_worker(), which already may work in parallel with inet_frags_exit_net(), and it can make the same cleanup, that inet_frags_exit_net() does, it's safe. So we may mark these pernet_operations as async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/reassembly.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index afbc000ad4f29..b5da69c83123b 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -733,6 +733,7 @@ static void __net_exit ipv6_frags_exit_net(struct net *net) static struct pernet_operations ip6_frags_ops = { .init = ipv6_frags_init_net, .exit = ipv6_frags_exit_net, + .async = true, }; int __init ipv6_frag_init(void) From 4d6b80762b9384db3281f792a71746b388f395be Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:50:45 +0300 Subject: [PATCH 15/16] net: Convert ip_tables_net_ops, udplite6_net_ops and xt_net_ops ip_tables_net_ops and udplite6_net_ops create and destroy /proc entries. xt_net_ops does nothing. So, we are able to mark them async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_tables.c | 1 + net/ipv6/udplite.c | 1 + net/netfilter/x_tables.c | 1 + 3 files changed, 3 insertions(+) diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 9a71f31495070..39a7cf9160e60 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1911,6 +1911,7 @@ static void __net_exit ip_tables_net_exit(struct net *net) static struct pernet_operations ip_tables_net_ops = { .init = ip_tables_net_init, .exit = ip_tables_net_exit, + .async = true, }; static int __init ip_tables_init(void) diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 14ae32bb1f3da..f3839780dc310 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -123,6 +123,7 @@ static void __net_exit udplite6_proc_exit_net(struct net *net) static struct pernet_operations udplite6_net_ops = { .init = udplite6_proc_init_net, .exit = udplite6_proc_exit_net, + .async = true, }; int __init udplite6_proc_init(void) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 2f685ee1f9c87..a6a435d7c8f4b 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1765,6 +1765,7 @@ static void __net_exit xt_net_exit(struct net *net) static struct pernet_operations xt_net_ops = { .init = xt_net_init, .exit = xt_net_exit, + .async = true, }; static int __init xt_init(void) From da349fad8045cc44cd9b1752b0e2d943df62cabf Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:50:54 +0300 Subject: [PATCH 16/16] net: Convert iptable_filter_net_ops These pernet_operations register and unregister net::ipv4.iptable_filter table. Since there are no packets in-flight at the time of exit method is working, iptables rules should not be touched. Also, pernet_operations should not send ipv4 packets each other. So, it's safe to mark them async. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv4/netfilter/iptable_filter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 9ac92ea7b93c2..c1c136a939111 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -87,6 +87,7 @@ static void __net_exit iptable_filter_net_exit(struct net *net) static struct pernet_operations iptable_filter_net_ops = { .init = iptable_filter_net_init, .exit = iptable_filter_net_exit, + .async = true, }; static int __init iptable_filter_init(void)