diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/core/dev.c | 4 | ||||
| -rw-r--r-- | net/core/fib_rules.c | 2 | ||||
| -rw-r--r-- | net/core/net_namespace.c | 28 | ||||
| -rw-r--r-- | net/core/sock.c | 19 | ||||
| -rw-r--r-- | net/decnet/dn_rules.c | 2 | ||||
| -rw-r--r-- | net/dsa/dsa.c | 23 | ||||
| -rw-r--r-- | net/ipv4/fib_frontend.c | 2 | ||||
| -rw-r--r-- | net/ipv4/ipmr.c | 5 | ||||
| -rw-r--r-- | net/ipv4/tcp_input.c | 7 | ||||
| -rw-r--r-- | net/ipv6/fib6_rules.c | 2 | ||||
| -rw-r--r-- | net/ipv6/ip6_output.c | 3 | ||||
| -rw-r--r-- | net/ipv6/ip6mr.c | 4 | ||||
| -rw-r--r-- | net/l2tp/l2tp_core.c | 1 |
13 files changed, 60 insertions, 42 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 26622d614f81..3b3965288f52 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -2870,7 +2870,9 @@ static void skb_update_prio(struct sk_buff *skb) | |||
| 2870 | #define skb_update_prio(skb) | 2870 | #define skb_update_prio(skb) |
| 2871 | #endif | 2871 | #endif |
| 2872 | 2872 | ||
| 2873 | static DEFINE_PER_CPU(int, xmit_recursion); | 2873 | DEFINE_PER_CPU(int, xmit_recursion); |
| 2874 | EXPORT_SYMBOL(xmit_recursion); | ||
| 2875 | |||
| 2874 | #define RECURSION_LIMIT 10 | 2876 | #define RECURSION_LIMIT 10 |
| 2875 | 2877 | ||
| 2876 | /** | 2878 | /** |
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 68ea6950cad1..9a12668f7d62 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
| @@ -165,9 +165,9 @@ void fib_rules_unregister(struct fib_rules_ops *ops) | |||
| 165 | 165 | ||
| 166 | spin_lock(&net->rules_mod_lock); | 166 | spin_lock(&net->rules_mod_lock); |
| 167 | list_del_rcu(&ops->list); | 167 | list_del_rcu(&ops->list); |
| 168 | fib_rules_cleanup_ops(ops); | ||
| 169 | spin_unlock(&net->rules_mod_lock); | 168 | spin_unlock(&net->rules_mod_lock); |
| 170 | 169 | ||
| 170 | fib_rules_cleanup_ops(ops); | ||
| 171 | kfree_rcu(ops, rcu); | 171 | kfree_rcu(ops, rcu); |
| 172 | } | 172 | } |
| 173 | EXPORT_SYMBOL_GPL(fib_rules_unregister); | 173 | EXPORT_SYMBOL_GPL(fib_rules_unregister); |
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index ce6396a75b8b..e7345d9031df 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
| @@ -198,8 +198,10 @@ static int __peernet2id(struct net *net, struct net *peer, bool alloc) | |||
| 198 | */ | 198 | */ |
| 199 | int peernet2id(struct net *net, struct net *peer) | 199 | int peernet2id(struct net *net, struct net *peer) |
| 200 | { | 200 | { |
| 201 | int id = __peernet2id(net, peer, true); | 201 | bool alloc = atomic_read(&peer->count) == 0 ? false : true; |
| 202 | int id; | ||
| 202 | 203 | ||
| 204 | id = __peernet2id(net, peer, alloc); | ||
| 203 | return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED; | 205 | return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED; |
| 204 | } | 206 | } |
| 205 | EXPORT_SYMBOL(peernet2id); | 207 | EXPORT_SYMBOL(peernet2id); |
| @@ -338,7 +340,7 @@ static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */ | |||
| 338 | static void cleanup_net(struct work_struct *work) | 340 | static void cleanup_net(struct work_struct *work) |
| 339 | { | 341 | { |
| 340 | const struct pernet_operations *ops; | 342 | const struct pernet_operations *ops; |
| 341 | struct net *net, *tmp, *peer; | 343 | struct net *net, *tmp; |
| 342 | struct list_head net_kill_list; | 344 | struct list_head net_kill_list; |
| 343 | LIST_HEAD(net_exit_list); | 345 | LIST_HEAD(net_exit_list); |
| 344 | 346 | ||
| @@ -354,6 +356,14 @@ static void cleanup_net(struct work_struct *work) | |||
| 354 | list_for_each_entry(net, &net_kill_list, cleanup_list) { | 356 | list_for_each_entry(net, &net_kill_list, cleanup_list) { |
| 355 | list_del_rcu(&net->list); | 357 | list_del_rcu(&net->list); |
| 356 | list_add_tail(&net->exit_list, &net_exit_list); | 358 | list_add_tail(&net->exit_list, &net_exit_list); |
| 359 | for_each_net(tmp) { | ||
| 360 | int id = __peernet2id(tmp, net, false); | ||
| 361 | |||
| 362 | if (id >= 0) | ||
| 363 | idr_remove(&tmp->netns_ids, id); | ||
| 364 | } | ||
| 365 | idr_destroy(&net->netns_ids); | ||
| 366 | |||
| 357 | } | 367 | } |
| 358 | rtnl_unlock(); | 368 | rtnl_unlock(); |
| 359 | 369 | ||
| @@ -379,26 +389,12 @@ static void cleanup_net(struct work_struct *work) | |||
| 379 | */ | 389 | */ |
| 380 | rcu_barrier(); | 390 | rcu_barrier(); |
| 381 | 391 | ||
| 382 | rtnl_lock(); | ||
| 383 | /* Finally it is safe to free my network namespace structure */ | 392 | /* Finally it is safe to free my network namespace structure */ |
| 384 | list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { | 393 | list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { |
| 385 | /* Unreference net from all peers (no need to loop over | ||
| 386 | * net_exit_list because idr_destroy() will be called for each | ||
| 387 | * element of this list. | ||
| 388 | */ | ||
| 389 | for_each_net(peer) { | ||
| 390 | int id = __peernet2id(peer, net, false); | ||
| 391 | |||
| 392 | if (id >= 0) | ||
| 393 | idr_remove(&peer->netns_ids, id); | ||
| 394 | } | ||
| 395 | idr_destroy(&net->netns_ids); | ||
| 396 | |||
| 397 | list_del_init(&net->exit_list); | 394 | list_del_init(&net->exit_list); |
| 398 | put_user_ns(net->user_ns); | 395 | put_user_ns(net->user_ns); |
| 399 | net_drop_ns(net); | 396 | net_drop_ns(net); |
| 400 | } | 397 | } |
| 401 | rtnl_unlock(); | ||
| 402 | } | 398 | } |
| 403 | static DECLARE_WORK(net_cleanup_work, cleanup_net); | 399 | static DECLARE_WORK(net_cleanup_work, cleanup_net); |
| 404 | 400 | ||
diff --git a/net/core/sock.c b/net/core/sock.c index 119ae464b44a..654e38a99759 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
| @@ -653,6 +653,25 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) | |||
| 653 | sock_reset_flag(sk, bit); | 653 | sock_reset_flag(sk, bit); |
| 654 | } | 654 | } |
| 655 | 655 | ||
| 656 | bool sk_mc_loop(struct sock *sk) | ||
| 657 | { | ||
| 658 | if (dev_recursion_level()) | ||
| 659 | return false; | ||
| 660 | if (!sk) | ||
| 661 | return true; | ||
| 662 | switch (sk->sk_family) { | ||
| 663 | case AF_INET: | ||
| 664 | return inet_sk(sk)->mc_loop; | ||
| 665 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 666 | case AF_INET6: | ||
| 667 | return inet6_sk(sk)->mc_loop; | ||
| 668 | #endif | ||
| 669 | } | ||
| 670 | WARN_ON(1); | ||
| 671 | return true; | ||
| 672 | } | ||
| 673 | EXPORT_SYMBOL(sk_mc_loop); | ||
| 674 | |||
| 656 | /* | 675 | /* |
| 657 | * This is meant for all protocols to use and covers goings on | 676 | * This is meant for all protocols to use and covers goings on |
| 658 | * at the socket level. Everything here is generic. | 677 | * at the socket level. Everything here is generic. |
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index faf7cc3483fe..9d66a0f72f90 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c | |||
| @@ -248,7 +248,9 @@ void __init dn_fib_rules_init(void) | |||
| 248 | 248 | ||
| 249 | void __exit dn_fib_rules_cleanup(void) | 249 | void __exit dn_fib_rules_cleanup(void) |
| 250 | { | 250 | { |
| 251 | rtnl_lock(); | ||
| 251 | fib_rules_unregister(dn_fib_rules_ops); | 252 | fib_rules_unregister(dn_fib_rules_ops); |
| 253 | rtnl_unlock(); | ||
| 252 | rcu_barrier(); | 254 | rcu_barrier(); |
| 253 | } | 255 | } |
| 254 | 256 | ||
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 899772108ee3..5eaadabe23a1 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c | |||
| @@ -513,12 +513,10 @@ static struct net_device *dev_to_net_device(struct device *dev) | |||
| 513 | #ifdef CONFIG_OF | 513 | #ifdef CONFIG_OF |
| 514 | static int dsa_of_setup_routing_table(struct dsa_platform_data *pd, | 514 | static int dsa_of_setup_routing_table(struct dsa_platform_data *pd, |
| 515 | struct dsa_chip_data *cd, | 515 | struct dsa_chip_data *cd, |
| 516 | int chip_index, | 516 | int chip_index, int port_index, |
| 517 | struct device_node *link) | 517 | struct device_node *link) |
| 518 | { | 518 | { |
| 519 | int ret; | ||
| 520 | const __be32 *reg; | 519 | const __be32 *reg; |
| 521 | int link_port_addr; | ||
| 522 | int link_sw_addr; | 520 | int link_sw_addr; |
| 523 | struct device_node *parent_sw; | 521 | struct device_node *parent_sw; |
| 524 | int len; | 522 | int len; |
| @@ -531,6 +529,10 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd, | |||
| 531 | if (!reg || (len != sizeof(*reg) * 2)) | 529 | if (!reg || (len != sizeof(*reg) * 2)) |
| 532 | return -EINVAL; | 530 | return -EINVAL; |
| 533 | 531 | ||
| 532 | /* | ||
| 533 | * Get the destination switch number from the second field of its 'reg' | ||
| 534 | * property, i.e. for "reg = <0x19 1>" sw_addr is '1'. | ||
| 535 | */ | ||
| 534 | link_sw_addr = be32_to_cpup(reg + 1); | 536 | link_sw_addr = be32_to_cpup(reg + 1); |
| 535 | 537 | ||
| 536 | if (link_sw_addr >= pd->nr_chips) | 538 | if (link_sw_addr >= pd->nr_chips) |
| @@ -547,20 +549,9 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd, | |||
| 547 | memset(cd->rtable, -1, pd->nr_chips * sizeof(s8)); | 549 | memset(cd->rtable, -1, pd->nr_chips * sizeof(s8)); |
| 548 | } | 550 | } |
| 549 | 551 | ||
| 550 | reg = of_get_property(link, "reg", NULL); | 552 | cd->rtable[link_sw_addr] = port_index; |
| 551 | if (!reg) { | ||
| 552 | ret = -EINVAL; | ||
| 553 | goto out; | ||
| 554 | } | ||
| 555 | |||
| 556 | link_port_addr = be32_to_cpup(reg); | ||
| 557 | |||
| 558 | cd->rtable[link_sw_addr] = link_port_addr; | ||
| 559 | 553 | ||
| 560 | return 0; | 554 | return 0; |
| 561 | out: | ||
| 562 | kfree(cd->rtable); | ||
| 563 | return ret; | ||
| 564 | } | 555 | } |
| 565 | 556 | ||
| 566 | static void dsa_of_free_platform_data(struct dsa_platform_data *pd) | 557 | static void dsa_of_free_platform_data(struct dsa_platform_data *pd) |
| @@ -670,7 +661,7 @@ static int dsa_of_probe(struct device *dev) | |||
| 670 | if (!strcmp(port_name, "dsa") && link && | 661 | if (!strcmp(port_name, "dsa") && link && |
| 671 | pd->nr_chips > 1) { | 662 | pd->nr_chips > 1) { |
| 672 | ret = dsa_of_setup_routing_table(pd, cd, | 663 | ret = dsa_of_setup_routing_table(pd, cd, |
| 673 | chip_index, link); | 664 | chip_index, port_index, link); |
| 674 | if (ret) | 665 | if (ret) |
| 675 | goto out_free_chip; | 666 | goto out_free_chip; |
| 676 | } | 667 | } |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 2166d2bf1562..872494e6e6eb 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
| @@ -1175,13 +1175,11 @@ static void ip_fib_net_exit(struct net *net) | |||
| 1175 | unsigned int i; | 1175 | unsigned int i; |
| 1176 | 1176 | ||
| 1177 | rtnl_lock(); | 1177 | rtnl_lock(); |
| 1178 | |||
| 1179 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 1178 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
| 1180 | RCU_INIT_POINTER(net->ipv4.fib_local, NULL); | 1179 | RCU_INIT_POINTER(net->ipv4.fib_local, NULL); |
| 1181 | RCU_INIT_POINTER(net->ipv4.fib_main, NULL); | 1180 | RCU_INIT_POINTER(net->ipv4.fib_main, NULL); |
| 1182 | RCU_INIT_POINTER(net->ipv4.fib_default, NULL); | 1181 | RCU_INIT_POINTER(net->ipv4.fib_default, NULL); |
| 1183 | #endif | 1182 | #endif |
| 1184 | |||
| 1185 | for (i = 0; i < FIB_TABLE_HASHSZ; i++) { | 1183 | for (i = 0; i < FIB_TABLE_HASHSZ; i++) { |
| 1186 | struct hlist_head *head = &net->ipv4.fib_table_hash[i]; | 1184 | struct hlist_head *head = &net->ipv4.fib_table_hash[i]; |
| 1187 | struct hlist_node *tmp; | 1185 | struct hlist_node *tmp; |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index c204b728bbc1..5f17d0e78071 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
| @@ -276,11 +276,13 @@ static void __net_exit ipmr_rules_exit(struct net *net) | |||
| 276 | { | 276 | { |
| 277 | struct mr_table *mrt, *next; | 277 | struct mr_table *mrt, *next; |
| 278 | 278 | ||
| 279 | rtnl_lock(); | ||
| 279 | list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) { | 280 | list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) { |
| 280 | list_del(&mrt->list); | 281 | list_del(&mrt->list); |
| 281 | ipmr_free_table(mrt); | 282 | ipmr_free_table(mrt); |
| 282 | } | 283 | } |
| 283 | fib_rules_unregister(net->ipv4.mr_rules_ops); | 284 | fib_rules_unregister(net->ipv4.mr_rules_ops); |
| 285 | rtnl_unlock(); | ||
| 284 | } | 286 | } |
| 285 | #else | 287 | #else |
| 286 | #define ipmr_for_each_table(mrt, net) \ | 288 | #define ipmr_for_each_table(mrt, net) \ |
| @@ -306,7 +308,10 @@ static int __net_init ipmr_rules_init(struct net *net) | |||
| 306 | 308 | ||
| 307 | static void __net_exit ipmr_rules_exit(struct net *net) | 309 | static void __net_exit ipmr_rules_exit(struct net *net) |
| 308 | { | 310 | { |
| 311 | rtnl_lock(); | ||
| 309 | ipmr_free_table(net->ipv4.mrt); | 312 | ipmr_free_table(net->ipv4.mrt); |
| 313 | net->ipv4.mrt = NULL; | ||
| 314 | rtnl_unlock(); | ||
| 310 | } | 315 | } |
| 311 | #endif | 316 | #endif |
| 312 | 317 | ||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index df7e7fa12733..c1ce304ba8d2 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
| @@ -3105,10 +3105,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, | |||
| 3105 | if (!first_ackt.v64) | 3105 | if (!first_ackt.v64) |
| 3106 | first_ackt = last_ackt; | 3106 | first_ackt = last_ackt; |
| 3107 | 3107 | ||
| 3108 | if (!(sacked & TCPCB_SACKED_ACKED)) | 3108 | if (!(sacked & TCPCB_SACKED_ACKED)) { |
| 3109 | reord = min(pkts_acked, reord); | 3109 | reord = min(pkts_acked, reord); |
| 3110 | if (!after(scb->end_seq, tp->high_seq)) | 3110 | if (!after(scb->end_seq, tp->high_seq)) |
| 3111 | flag |= FLAG_ORIG_SACK_ACKED; | 3111 | flag |= FLAG_ORIG_SACK_ACKED; |
| 3112 | } | ||
| 3112 | } | 3113 | } |
| 3113 | 3114 | ||
| 3114 | if (sacked & TCPCB_SACKED_ACKED) | 3115 | if (sacked & TCPCB_SACKED_ACKED) |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 61fb184b818d..2367a16eae58 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
| @@ -315,7 +315,9 @@ out_fib6_rules_ops: | |||
| 315 | 315 | ||
| 316 | static void __net_exit fib6_rules_net_exit(struct net *net) | 316 | static void __net_exit fib6_rules_net_exit(struct net *net) |
| 317 | { | 317 | { |
| 318 | rtnl_lock(); | ||
| 318 | fib_rules_unregister(net->ipv6.fib6_rules_ops); | 319 | fib_rules_unregister(net->ipv6.fib6_rules_ops); |
| 320 | rtnl_unlock(); | ||
| 319 | } | 321 | } |
| 320 | 322 | ||
| 321 | static struct pernet_operations fib6_rules_net_ops = { | 323 | static struct pernet_operations fib6_rules_net_ops = { |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 84c58da10f5c..654f245aa930 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -542,7 +542,8 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 542 | { | 542 | { |
| 543 | struct sk_buff *frag; | 543 | struct sk_buff *frag; |
| 544 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); | 544 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); |
| 545 | struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; | 545 | struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? |
| 546 | inet6_sk(skb->sk) : NULL; | ||
| 546 | struct ipv6hdr *tmp_hdr; | 547 | struct ipv6hdr *tmp_hdr; |
| 547 | struct frag_hdr *fh; | 548 | struct frag_hdr *fh; |
| 548 | unsigned int mtu, hlen, left, len; | 549 | unsigned int mtu, hlen, left, len; |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 26456037bdfc..8493a22e74eb 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
| @@ -265,8 +265,8 @@ static void __net_exit ip6mr_rules_exit(struct net *net) | |||
| 265 | list_del(&mrt->list); | 265 | list_del(&mrt->list); |
| 266 | ip6mr_free_table(mrt); | 266 | ip6mr_free_table(mrt); |
| 267 | } | 267 | } |
| 268 | rtnl_unlock(); | ||
| 269 | fib_rules_unregister(net->ipv6.mr6_rules_ops); | 268 | fib_rules_unregister(net->ipv6.mr6_rules_ops); |
| 269 | rtnl_unlock(); | ||
| 270 | } | 270 | } |
| 271 | #else | 271 | #else |
| 272 | #define ip6mr_for_each_table(mrt, net) \ | 272 | #define ip6mr_for_each_table(mrt, net) \ |
| @@ -334,7 +334,7 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id) | |||
| 334 | 334 | ||
| 335 | static void ip6mr_free_table(struct mr6_table *mrt) | 335 | static void ip6mr_free_table(struct mr6_table *mrt) |
| 336 | { | 336 | { |
| 337 | del_timer(&mrt->ipmr_expire_timer); | 337 | del_timer_sync(&mrt->ipmr_expire_timer); |
| 338 | mroute_clean_tables(mrt); | 338 | mroute_clean_tables(mrt); |
| 339 | kfree(mrt); | 339 | kfree(mrt); |
| 340 | } | 340 | } |
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 895348e44c7d..a29a504492af 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
| @@ -1871,6 +1871,7 @@ static int __init l2tp_init(void) | |||
| 1871 | l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0); | 1871 | l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0); |
| 1872 | if (!l2tp_wq) { | 1872 | if (!l2tp_wq) { |
| 1873 | pr_err("alloc_workqueue failed\n"); | 1873 | pr_err("alloc_workqueue failed\n"); |
| 1874 | unregister_pernet_device(&l2tp_net_ops); | ||
| 1874 | rc = -ENOMEM; | 1875 | rc = -ENOMEM; |
| 1875 | goto out; | 1876 | goto out; |
| 1876 | } | 1877 | } |
