diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-16 14:28:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-16 14:28:59 -0400 |
commit | 48bddb143befb1dd93c0e5a66af62cfd60c86b04 (patch) | |
tree | 8d71225922209f780d0e0a1f27beaac3e836972b /net | |
parent | c8503720fd0b952ff25bcc49b6eb9c492e22f3c6 (diff) | |
parent | 8e29f97979c300406c21994986bdfcdb67fe4ff7 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking fixes from David Miller:
1) Fix hotplug deadlock in hv_netvsc, from Stephen Hemminger.
2) Fix double-free in rmnet driver, from Dan Carpenter.
3) INET connection socket layer can double put request sockets, fix
from Eric Dumazet.
4) Don't match collect metadata-mode tunnels if the device is down,
from Haishuang Yan.
5) Do not perform TSO6/GSO on ipv6 packets with extensions headers in
be2net driver, from Suresh Reddy.
6) Fix scaling error in gen_estimator, from Eric Dumazet.
7) Fix 64-bit statistics deadlock in systemport driver, from Florian
Fainelli.
8) Fix use-after-free in sctp_sock_dump, from Xin Long.
9) Reject invalid BPF_END instructions in verifier, from Edward Cree.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (43 commits)
mlxsw: spectrum_router: Only handle IPv4 and IPv6 events
Documentation: link in networking docs
tcp: fix data delivery rate
bpf/verifier: reject BPF_ALU64|BPF_END
sctp: do not mark sk dumped when inet_sctp_diag_fill returns err
sctp: fix an use-after-free issue in sctp_sock_dump
netvsc: increase default receive buffer size
tcp: update skb->skb_mstamp more carefully
net: ipv4: fix l3slave check for index returned in IP_PKTINFO
net: smsc911x: Quieten netif during suspend
net: systemport: Fix 64-bit stats deadlock
net: vrf: avoid gcc-4.6 warning
qed: remove unnecessary call to memset
tg3: clean up redundant initialization of tnapi
tls: make tls_sw_free_resources static
sctp: potential read out of bounds in sctp_ulpevent_type_enabled()
MAINTAINERS: review Renesas DT bindings as well
net_sched: gen_estimator: fix scaling error in bytes/packets samples
nfp: wait for the NSP resource to appear on boot
nfp: wait for board state before talking to the NSP
...
Diffstat (limited to 'net')
-rw-r--r-- | net/core/filter.c | 38 | ||||
-rw-r--r-- | net/core/gen_estimator.c | 4 | ||||
-rw-r--r-- | net/ipv4/inet_connection_sock.c | 2 | ||||
-rw-r--r-- | net/ipv4/ip_sockglue.c | 8 | ||||
-rw-r--r-- | net/ipv4/ip_tunnel.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 24 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 2 | ||||
-rw-r--r-- | net/ipv6/seg6_local.c | 4 | ||||
-rw-r--r-- | net/openvswitch/datapath.c | 3 | ||||
-rw-r--r-- | net/sched/act_api.c | 23 | ||||
-rw-r--r-- | net/sched/cls_api.c | 63 | ||||
-rw-r--r-- | net/sched/cls_rsvp.h | 2 | ||||
-rw-r--r-- | net/sctp/sctp_diag.c | 33 | ||||
-rw-r--r-- | net/sctp/socket.c | 40 | ||||
-rw-r--r-- | net/tls/tls_sw.c | 2 |
15 files changed, 141 insertions, 109 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index 3a50a9b021e2..24dd33dd9f04 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -2506,21 +2506,19 @@ static int xdp_do_redirect_map(struct net_device *dev, struct xdp_buff *xdp, | |||
2506 | struct redirect_info *ri = this_cpu_ptr(&redirect_info); | 2506 | struct redirect_info *ri = this_cpu_ptr(&redirect_info); |
2507 | const struct bpf_prog *map_owner = ri->map_owner; | 2507 | const struct bpf_prog *map_owner = ri->map_owner; |
2508 | struct bpf_map *map = ri->map; | 2508 | struct bpf_map *map = ri->map; |
2509 | struct net_device *fwd = NULL; | ||
2509 | u32 index = ri->ifindex; | 2510 | u32 index = ri->ifindex; |
2510 | struct net_device *fwd; | ||
2511 | int err; | 2511 | int err; |
2512 | 2512 | ||
2513 | ri->ifindex = 0; | 2513 | ri->ifindex = 0; |
2514 | ri->map = NULL; | 2514 | ri->map = NULL; |
2515 | ri->map_owner = NULL; | 2515 | ri->map_owner = NULL; |
2516 | 2516 | ||
2517 | /* This is really only caused by a deliberately crappy | 2517 | if (unlikely(map_owner != xdp_prog)) { |
2518 | * BPF program, normally we would never hit that case, | 2518 | err = -EFAULT; |
2519 | * so no need to inform someone via tracepoints either, | 2519 | map = NULL; |
2520 | * just bail out. | 2520 | goto err; |
2521 | */ | 2521 | } |
2522 | if (unlikely(map_owner != xdp_prog)) | ||
2523 | return -EINVAL; | ||
2524 | 2522 | ||
2525 | fwd = __dev_map_lookup_elem(map, index); | 2523 | fwd = __dev_map_lookup_elem(map, index); |
2526 | if (!fwd) { | 2524 | if (!fwd) { |
@@ -2576,13 +2574,27 @@ int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb, | |||
2576 | struct bpf_prog *xdp_prog) | 2574 | struct bpf_prog *xdp_prog) |
2577 | { | 2575 | { |
2578 | struct redirect_info *ri = this_cpu_ptr(&redirect_info); | 2576 | struct redirect_info *ri = this_cpu_ptr(&redirect_info); |
2577 | const struct bpf_prog *map_owner = ri->map_owner; | ||
2578 | struct bpf_map *map = ri->map; | ||
2579 | struct net_device *fwd = NULL; | ||
2579 | u32 index = ri->ifindex; | 2580 | u32 index = ri->ifindex; |
2580 | struct net_device *fwd; | ||
2581 | unsigned int len; | 2581 | unsigned int len; |
2582 | int err = 0; | 2582 | int err = 0; |
2583 | 2583 | ||
2584 | fwd = dev_get_by_index_rcu(dev_net(dev), index); | ||
2585 | ri->ifindex = 0; | 2584 | ri->ifindex = 0; |
2585 | ri->map = NULL; | ||
2586 | ri->map_owner = NULL; | ||
2587 | |||
2588 | if (map) { | ||
2589 | if (unlikely(map_owner != xdp_prog)) { | ||
2590 | err = -EFAULT; | ||
2591 | map = NULL; | ||
2592 | goto err; | ||
2593 | } | ||
2594 | fwd = __dev_map_lookup_elem(map, index); | ||
2595 | } else { | ||
2596 | fwd = dev_get_by_index_rcu(dev_net(dev), index); | ||
2597 | } | ||
2586 | if (unlikely(!fwd)) { | 2598 | if (unlikely(!fwd)) { |
2587 | err = -EINVAL; | 2599 | err = -EINVAL; |
2588 | goto err; | 2600 | goto err; |
@@ -2600,10 +2612,12 @@ int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb, | |||
2600 | } | 2612 | } |
2601 | 2613 | ||
2602 | skb->dev = fwd; | 2614 | skb->dev = fwd; |
2603 | _trace_xdp_redirect(dev, xdp_prog, index); | 2615 | map ? _trace_xdp_redirect_map(dev, xdp_prog, fwd, map, index) |
2616 | : _trace_xdp_redirect(dev, xdp_prog, index); | ||
2604 | return 0; | 2617 | return 0; |
2605 | err: | 2618 | err: |
2606 | _trace_xdp_redirect_err(dev, xdp_prog, index, err); | 2619 | map ? _trace_xdp_redirect_map_err(dev, xdp_prog, fwd, map, index, err) |
2620 | : _trace_xdp_redirect_err(dev, xdp_prog, index, err); | ||
2607 | return err; | 2621 | return err; |
2608 | } | 2622 | } |
2609 | EXPORT_SYMBOL_GPL(xdp_do_generic_redirect); | 2623 | EXPORT_SYMBOL_GPL(xdp_do_generic_redirect); |
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index 0385dece1f6f..7c1ffd6f9501 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c | |||
@@ -83,10 +83,10 @@ static void est_timer(unsigned long arg) | |||
83 | u64 rate, brate; | 83 | u64 rate, brate; |
84 | 84 | ||
85 | est_fetch_counters(est, &b); | 85 | est_fetch_counters(est, &b); |
86 | brate = (b.bytes - est->last_bytes) << (8 - est->ewma_log); | 86 | brate = (b.bytes - est->last_bytes) << (10 - est->ewma_log - est->intvl_log); |
87 | brate -= (est->avbps >> est->ewma_log); | 87 | brate -= (est->avbps >> est->ewma_log); |
88 | 88 | ||
89 | rate = (u64)(b.packets - est->last_packets) << (8 - est->ewma_log); | 89 | rate = (u64)(b.packets - est->last_packets) << (10 - est->ewma_log - est->intvl_log); |
90 | rate -= (est->avpps >> est->ewma_log); | 90 | rate -= (est->avpps >> est->ewma_log); |
91 | 91 | ||
92 | write_seqcount_begin(&est->seq); | 92 | write_seqcount_begin(&est->seq); |
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 4089c013cb03..b9c64b40a83a 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -916,7 +916,6 @@ static void inet_child_forget(struct sock *sk, struct request_sock *req, | |||
916 | tcp_sk(child)->fastopen_rsk = NULL; | 916 | tcp_sk(child)->fastopen_rsk = NULL; |
917 | } | 917 | } |
918 | inet_csk_destroy_sock(child); | 918 | inet_csk_destroy_sock(child); |
919 | reqsk_put(req); | ||
920 | } | 919 | } |
921 | 920 | ||
922 | struct sock *inet_csk_reqsk_queue_add(struct sock *sk, | 921 | struct sock *inet_csk_reqsk_queue_add(struct sock *sk, |
@@ -987,6 +986,7 @@ void inet_csk_listen_stop(struct sock *sk) | |||
987 | sock_hold(child); | 986 | sock_hold(child); |
988 | 987 | ||
989 | inet_child_forget(sk, req, child); | 988 | inet_child_forget(sk, req, child); |
989 | reqsk_put(req); | ||
990 | bh_unlock_sock(child); | 990 | bh_unlock_sock(child); |
991 | local_bh_enable(); | 991 | local_bh_enable(); |
992 | sock_put(child); | 992 | sock_put(child); |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index e558e4f9597b..a599aa83fdad 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -1207,7 +1207,6 @@ e_inval: | |||
1207 | void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) | 1207 | void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) |
1208 | { | 1208 | { |
1209 | struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb); | 1209 | struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb); |
1210 | bool l3slave = ipv4_l3mdev_skb(IPCB(skb)->flags); | ||
1211 | bool prepare = (inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) || | 1210 | bool prepare = (inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) || |
1212 | ipv6_sk_rxinfo(sk); | 1211 | ipv6_sk_rxinfo(sk); |
1213 | 1212 | ||
@@ -1221,8 +1220,13 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) | |||
1221 | * (e.g., process binds socket to eth0 for Tx which is | 1220 | * (e.g., process binds socket to eth0 for Tx which is |
1222 | * redirected to loopback in the rtable/dst). | 1221 | * redirected to loopback in the rtable/dst). |
1223 | */ | 1222 | */ |
1224 | if (pktinfo->ipi_ifindex == LOOPBACK_IFINDEX || l3slave) | 1223 | struct rtable *rt = skb_rtable(skb); |
1224 | bool l3slave = ipv4_l3mdev_skb(IPCB(skb)->flags); | ||
1225 | |||
1226 | if (pktinfo->ipi_ifindex == LOOPBACK_IFINDEX) | ||
1225 | pktinfo->ipi_ifindex = inet_iif(skb); | 1227 | pktinfo->ipi_ifindex = inet_iif(skb); |
1228 | else if (l3slave && rt && rt->rt_iif) | ||
1229 | pktinfo->ipi_ifindex = rt->rt_iif; | ||
1226 | 1230 | ||
1227 | pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb); | 1231 | pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb); |
1228 | } else { | 1232 | } else { |
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index e1856bfa753d..e9805ad664ac 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c | |||
@@ -176,7 +176,7 @@ skip_key_lookup: | |||
176 | return cand; | 176 | return cand; |
177 | 177 | ||
178 | t = rcu_dereference(itn->collect_md_tun); | 178 | t = rcu_dereference(itn->collect_md_tun); |
179 | if (t) | 179 | if (t && t->dev->flags & IFF_UP) |
180 | return t; | 180 | return t; |
181 | 181 | ||
182 | if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP) | 182 | if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP) |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 5b6690d05abb..1c839c99114c 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -991,6 +991,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
991 | struct tcp_skb_cb *tcb; | 991 | struct tcp_skb_cb *tcb; |
992 | struct tcp_out_options opts; | 992 | struct tcp_out_options opts; |
993 | unsigned int tcp_options_size, tcp_header_size; | 993 | unsigned int tcp_options_size, tcp_header_size; |
994 | struct sk_buff *oskb = NULL; | ||
994 | struct tcp_md5sig_key *md5; | 995 | struct tcp_md5sig_key *md5; |
995 | struct tcphdr *th; | 996 | struct tcphdr *th; |
996 | int err; | 997 | int err; |
@@ -998,12 +999,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
998 | BUG_ON(!skb || !tcp_skb_pcount(skb)); | 999 | BUG_ON(!skb || !tcp_skb_pcount(skb)); |
999 | tp = tcp_sk(sk); | 1000 | tp = tcp_sk(sk); |
1000 | 1001 | ||
1001 | skb->skb_mstamp = tp->tcp_mstamp; | ||
1002 | if (clone_it) { | 1002 | if (clone_it) { |
1003 | TCP_SKB_CB(skb)->tx.in_flight = TCP_SKB_CB(skb)->end_seq | 1003 | TCP_SKB_CB(skb)->tx.in_flight = TCP_SKB_CB(skb)->end_seq |
1004 | - tp->snd_una; | 1004 | - tp->snd_una; |
1005 | tcp_rate_skb_sent(sk, skb); | 1005 | oskb = skb; |
1006 | |||
1007 | if (unlikely(skb_cloned(skb))) | 1006 | if (unlikely(skb_cloned(skb))) |
1008 | skb = pskb_copy(skb, gfp_mask); | 1007 | skb = pskb_copy(skb, gfp_mask); |
1009 | else | 1008 | else |
@@ -1011,6 +1010,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
1011 | if (unlikely(!skb)) | 1010 | if (unlikely(!skb)) |
1012 | return -ENOBUFS; | 1011 | return -ENOBUFS; |
1013 | } | 1012 | } |
1013 | skb->skb_mstamp = tp->tcp_mstamp; | ||
1014 | 1014 | ||
1015 | inet = inet_sk(sk); | 1015 | inet = inet_sk(sk); |
1016 | tcb = TCP_SKB_CB(skb); | 1016 | tcb = TCP_SKB_CB(skb); |
@@ -1122,12 +1122,15 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
1122 | 1122 | ||
1123 | err = icsk->icsk_af_ops->queue_xmit(sk, skb, &inet->cork.fl); | 1123 | err = icsk->icsk_af_ops->queue_xmit(sk, skb, &inet->cork.fl); |
1124 | 1124 | ||
1125 | if (likely(err <= 0)) | 1125 | if (unlikely(err > 0)) { |
1126 | return err; | 1126 | tcp_enter_cwr(sk); |
1127 | 1127 | err = net_xmit_eval(err); | |
1128 | tcp_enter_cwr(sk); | 1128 | } |
1129 | 1129 | if (!err && oskb) { | |
1130 | return net_xmit_eval(err); | 1130 | oskb->skb_mstamp = tp->tcp_mstamp; |
1131 | tcp_rate_skb_sent(sk, oskb); | ||
1132 | } | ||
1133 | return err; | ||
1131 | } | 1134 | } |
1132 | 1135 | ||
1133 | /* This routine just queues the buffer for sending. | 1136 | /* This routine just queues the buffer for sending. |
@@ -2869,10 +2872,11 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) | |||
2869 | skb_headroom(skb) >= 0xFFFF)) { | 2872 | skb_headroom(skb) >= 0xFFFF)) { |
2870 | struct sk_buff *nskb; | 2873 | struct sk_buff *nskb; |
2871 | 2874 | ||
2872 | skb->skb_mstamp = tp->tcp_mstamp; | ||
2873 | nskb = __pskb_copy(skb, MAX_TCP_HEADER, GFP_ATOMIC); | 2875 | nskb = __pskb_copy(skb, MAX_TCP_HEADER, GFP_ATOMIC); |
2874 | err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) : | 2876 | err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) : |
2875 | -ENOBUFS; | 2877 | -ENOBUFS; |
2878 | if (!err) | ||
2879 | skb->skb_mstamp = tp->tcp_mstamp; | ||
2876 | } else { | 2880 | } else { |
2877 | err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); | 2881 | err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); |
2878 | } | 2882 | } |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 10a693a19323..ae73164559d5 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -171,7 +171,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_ | |||
171 | } | 171 | } |
172 | 172 | ||
173 | t = rcu_dereference(ip6n->collect_md_tun); | 173 | t = rcu_dereference(ip6n->collect_md_tun); |
174 | if (t) | 174 | if (t && t->dev->flags & IFF_UP) |
175 | return t; | 175 | return t; |
176 | 176 | ||
177 | t = rcu_dereference(ip6n->tnls_wc[0]); | 177 | t = rcu_dereference(ip6n->tnls_wc[0]); |
diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c index 7ff54db73a48..825b8e01f947 100644 --- a/net/ipv6/seg6_local.c +++ b/net/ipv6/seg6_local.c | |||
@@ -72,10 +72,6 @@ static struct ipv6_sr_hdr *get_srh(struct sk_buff *skb) | |||
72 | 72 | ||
73 | srh = (struct ipv6_sr_hdr *)(skb->data + srhoff); | 73 | srh = (struct ipv6_sr_hdr *)(skb->data + srhoff); |
74 | 74 | ||
75 | /* make sure it's a Segment Routing header (Routing Type 4) */ | ||
76 | if (srh->type != IPV6_SRCRT_TYPE_4) | ||
77 | return NULL; | ||
78 | |||
79 | len = (srh->hdrlen + 1) << 3; | 75 | len = (srh->hdrlen + 1) << 3; |
80 | 76 | ||
81 | if (!pskb_may_pull(skb, srhoff + len)) | 77 | if (!pskb_may_pull(skb, srhoff + len)) |
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 76cf273a56c7..c3aec6227c91 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -1112,7 +1112,8 @@ static int ovs_nla_init_match_and_action(struct net *net, | |||
1112 | if (!a[OVS_FLOW_ATTR_KEY]) { | 1112 | if (!a[OVS_FLOW_ATTR_KEY]) { |
1113 | OVS_NLERR(log, | 1113 | OVS_NLERR(log, |
1114 | "Flow key attribute not present in set flow."); | 1114 | "Flow key attribute not present in set flow."); |
1115 | return -EINVAL; | 1115 | error = -EINVAL; |
1116 | goto error; | ||
1116 | } | 1117 | } |
1117 | 1118 | ||
1118 | *acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], key, | 1119 | *acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], key, |
diff --git a/net/sched/act_api.c b/net/sched/act_api.c index a306974e2fb4..da6fa82c98a8 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c | |||
@@ -53,10 +53,13 @@ static void tcf_action_goto_chain_exec(const struct tc_action *a, | |||
53 | res->goto_tp = rcu_dereference_bh(chain->filter_chain); | 53 | res->goto_tp = rcu_dereference_bh(chain->filter_chain); |
54 | } | 54 | } |
55 | 55 | ||
56 | static void free_tcf(struct rcu_head *head) | 56 | /* XXX: For standalone actions, we don't need a RCU grace period either, because |
57 | * actions are always connected to filters and filters are already destroyed in | ||
58 | * RCU callbacks, so after a RCU grace period actions are already disconnected | ||
59 | * from filters. Readers later can not find us. | ||
60 | */ | ||
61 | static void free_tcf(struct tc_action *p) | ||
57 | { | 62 | { |
58 | struct tc_action *p = container_of(head, struct tc_action, tcfa_rcu); | ||
59 | |||
60 | free_percpu(p->cpu_bstats); | 63 | free_percpu(p->cpu_bstats); |
61 | free_percpu(p->cpu_qstats); | 64 | free_percpu(p->cpu_qstats); |
62 | 65 | ||
@@ -76,11 +79,7 @@ static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p) | |||
76 | idr_remove_ext(&idrinfo->action_idr, p->tcfa_index); | 79 | idr_remove_ext(&idrinfo->action_idr, p->tcfa_index); |
77 | spin_unlock_bh(&idrinfo->lock); | 80 | spin_unlock_bh(&idrinfo->lock); |
78 | gen_kill_estimator(&p->tcfa_rate_est); | 81 | gen_kill_estimator(&p->tcfa_rate_est); |
79 | /* | 82 | free_tcf(p); |
80 | * gen_estimator est_timer() might access p->tcfa_lock | ||
81 | * or bstats, wait a RCU grace period before freeing p | ||
82 | */ | ||
83 | call_rcu(&p->tcfa_rcu, free_tcf); | ||
84 | } | 83 | } |
85 | 84 | ||
86 | int __tcf_idr_release(struct tc_action *p, bool bind, bool strict) | 85 | int __tcf_idr_release(struct tc_action *p, bool bind, bool strict) |
@@ -181,7 +180,7 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb, | |||
181 | idr_for_each_entry_ext(idr, p, id) { | 180 | idr_for_each_entry_ext(idr, p, id) { |
182 | ret = __tcf_idr_release(p, false, true); | 181 | ret = __tcf_idr_release(p, false, true); |
183 | if (ret == ACT_P_DELETED) { | 182 | if (ret == ACT_P_DELETED) { |
184 | module_put(p->ops->owner); | 183 | module_put(ops->owner); |
185 | n_i++; | 184 | n_i++; |
186 | } else if (ret < 0) { | 185 | } else if (ret < 0) { |
187 | goto nla_put_failure; | 186 | goto nla_put_failure; |
@@ -259,7 +258,7 @@ void tcf_idr_cleanup(struct tc_action *a, struct nlattr *est) | |||
259 | { | 258 | { |
260 | if (est) | 259 | if (est) |
261 | gen_kill_estimator(&a->tcfa_rate_est); | 260 | gen_kill_estimator(&a->tcfa_rate_est); |
262 | call_rcu(&a->tcfa_rcu, free_tcf); | 261 | free_tcf(a); |
263 | } | 262 | } |
264 | EXPORT_SYMBOL(tcf_idr_cleanup); | 263 | EXPORT_SYMBOL(tcf_idr_cleanup); |
265 | 264 | ||
@@ -515,13 +514,15 @@ EXPORT_SYMBOL(tcf_action_exec); | |||
515 | 514 | ||
516 | int tcf_action_destroy(struct list_head *actions, int bind) | 515 | int tcf_action_destroy(struct list_head *actions, int bind) |
517 | { | 516 | { |
517 | const struct tc_action_ops *ops; | ||
518 | struct tc_action *a, *tmp; | 518 | struct tc_action *a, *tmp; |
519 | int ret = 0; | 519 | int ret = 0; |
520 | 520 | ||
521 | list_for_each_entry_safe(a, tmp, actions, list) { | 521 | list_for_each_entry_safe(a, tmp, actions, list) { |
522 | ops = a->ops; | ||
522 | ret = __tcf_idr_release(a, bind, true); | 523 | ret = __tcf_idr_release(a, bind, true); |
523 | if (ret == ACT_P_DELETED) | 524 | if (ret == ACT_P_DELETED) |
524 | module_put(a->ops->owner); | 525 | module_put(ops->owner); |
525 | else if (ret < 0) | 526 | else if (ret < 0) |
526 | return ret; | 527 | return ret; |
527 | } | 528 | } |
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index c743f03cfebd..0b2219adf520 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c | |||
@@ -182,7 +182,7 @@ static struct tcf_chain *tcf_chain_create(struct tcf_block *block, | |||
182 | list_add_tail(&chain->list, &block->chain_list); | 182 | list_add_tail(&chain->list, &block->chain_list); |
183 | chain->block = block; | 183 | chain->block = block; |
184 | chain->index = chain_index; | 184 | chain->index = chain_index; |
185 | chain->refcnt = 0; | 185 | chain->refcnt = 1; |
186 | return chain; | 186 | return chain; |
187 | } | 187 | } |
188 | 188 | ||
@@ -194,21 +194,20 @@ static void tcf_chain_flush(struct tcf_chain *chain) | |||
194 | RCU_INIT_POINTER(*chain->p_filter_chain, NULL); | 194 | RCU_INIT_POINTER(*chain->p_filter_chain, NULL); |
195 | while ((tp = rtnl_dereference(chain->filter_chain)) != NULL) { | 195 | while ((tp = rtnl_dereference(chain->filter_chain)) != NULL) { |
196 | RCU_INIT_POINTER(chain->filter_chain, tp->next); | 196 | RCU_INIT_POINTER(chain->filter_chain, tp->next); |
197 | tcf_chain_put(chain); | ||
197 | tcf_proto_destroy(tp); | 198 | tcf_proto_destroy(tp); |
198 | } | 199 | } |
199 | } | 200 | } |
200 | 201 | ||
201 | static void tcf_chain_destroy(struct tcf_chain *chain) | 202 | static void tcf_chain_destroy(struct tcf_chain *chain) |
202 | { | 203 | { |
203 | /* May be already removed from the list by the previous call. */ | 204 | list_del(&chain->list); |
204 | if (!list_empty(&chain->list)) | 205 | kfree(chain); |
205 | list_del_init(&chain->list); | 206 | } |
206 | 207 | ||
207 | /* There might still be a reference held when we got here from | 208 | static void tcf_chain_hold(struct tcf_chain *chain) |
208 | * tcf_block_put. Wait for the user to drop reference before free. | 209 | { |
209 | */ | 210 | ++chain->refcnt; |
210 | if (!chain->refcnt) | ||
211 | kfree(chain); | ||
212 | } | 211 | } |
213 | 212 | ||
214 | struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, | 213 | struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, |
@@ -217,24 +216,19 @@ struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, | |||
217 | struct tcf_chain *chain; | 216 | struct tcf_chain *chain; |
218 | 217 | ||
219 | list_for_each_entry(chain, &block->chain_list, list) { | 218 | list_for_each_entry(chain, &block->chain_list, list) { |
220 | if (chain->index == chain_index) | 219 | if (chain->index == chain_index) { |
221 | goto incref; | 220 | tcf_chain_hold(chain); |
221 | return chain; | ||
222 | } | ||
222 | } | 223 | } |
223 | chain = create ? tcf_chain_create(block, chain_index) : NULL; | ||
224 | 224 | ||
225 | incref: | 225 | return create ? tcf_chain_create(block, chain_index) : NULL; |
226 | if (chain) | ||
227 | chain->refcnt++; | ||
228 | return chain; | ||
229 | } | 226 | } |
230 | EXPORT_SYMBOL(tcf_chain_get); | 227 | EXPORT_SYMBOL(tcf_chain_get); |
231 | 228 | ||
232 | void tcf_chain_put(struct tcf_chain *chain) | 229 | void tcf_chain_put(struct tcf_chain *chain) |
233 | { | 230 | { |
234 | /* Destroy unused chain, with exception of chain 0, which is the | 231 | if (--chain->refcnt == 0) |
235 | * default one and has to be always present. | ||
236 | */ | ||
237 | if (--chain->refcnt == 0 && !chain->filter_chain && chain->index != 0) | ||
238 | tcf_chain_destroy(chain); | 232 | tcf_chain_destroy(chain); |
239 | } | 233 | } |
240 | EXPORT_SYMBOL(tcf_chain_put); | 234 | EXPORT_SYMBOL(tcf_chain_put); |
@@ -279,10 +273,31 @@ void tcf_block_put(struct tcf_block *block) | |||
279 | if (!block) | 273 | if (!block) |
280 | return; | 274 | return; |
281 | 275 | ||
282 | list_for_each_entry_safe(chain, tmp, &block->chain_list, list) { | 276 | /* XXX: Standalone actions are not allowed to jump to any chain, and |
277 | * bound actions should be all removed after flushing. However, | ||
278 | * filters are destroyed in RCU callbacks, we have to hold the chains | ||
279 | * first, otherwise we would always race with RCU callbacks on this list | ||
280 | * without proper locking. | ||
281 | */ | ||
282 | |||
283 | /* Wait for existing RCU callbacks to cool down. */ | ||
284 | rcu_barrier(); | ||
285 | |||
286 | /* Hold a refcnt for all chains, except 0, in case they are gone. */ | ||
287 | list_for_each_entry(chain, &block->chain_list, list) | ||
288 | if (chain->index) | ||
289 | tcf_chain_hold(chain); | ||
290 | |||
291 | /* No race on the list, because no chain could be destroyed. */ | ||
292 | list_for_each_entry(chain, &block->chain_list, list) | ||
283 | tcf_chain_flush(chain); | 293 | tcf_chain_flush(chain); |
284 | tcf_chain_destroy(chain); | 294 | |
285 | } | 295 | /* Wait for RCU callbacks to release the reference count. */ |
296 | rcu_barrier(); | ||
297 | |||
298 | /* At this point, all the chains should have refcnt == 1. */ | ||
299 | list_for_each_entry_safe(chain, tmp, &block->chain_list, list) | ||
300 | tcf_chain_put(chain); | ||
286 | kfree(block); | 301 | kfree(block); |
287 | } | 302 | } |
288 | EXPORT_SYMBOL(tcf_block_put); | 303 | EXPORT_SYMBOL(tcf_block_put); |
@@ -360,6 +375,7 @@ static void tcf_chain_tp_insert(struct tcf_chain *chain, | |||
360 | rcu_assign_pointer(*chain->p_filter_chain, tp); | 375 | rcu_assign_pointer(*chain->p_filter_chain, tp); |
361 | RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain_info)); | 376 | RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain_info)); |
362 | rcu_assign_pointer(*chain_info->pprev, tp); | 377 | rcu_assign_pointer(*chain_info->pprev, tp); |
378 | tcf_chain_hold(chain); | ||
363 | } | 379 | } |
364 | 380 | ||
365 | static void tcf_chain_tp_remove(struct tcf_chain *chain, | 381 | static void tcf_chain_tp_remove(struct tcf_chain *chain, |
@@ -371,6 +387,7 @@ static void tcf_chain_tp_remove(struct tcf_chain *chain, | |||
371 | if (chain->p_filter_chain && tp == chain->filter_chain) | 387 | if (chain->p_filter_chain && tp == chain->filter_chain) |
372 | RCU_INIT_POINTER(*chain->p_filter_chain, next); | 388 | RCU_INIT_POINTER(*chain->p_filter_chain, next); |
373 | RCU_INIT_POINTER(*chain_info->pprev, next); | 389 | RCU_INIT_POINTER(*chain_info->pprev, next); |
390 | tcf_chain_put(chain); | ||
374 | } | 391 | } |
375 | 392 | ||
376 | static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain, | 393 | static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain, |
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index 98c05db85bcb..b1f6ed48bc72 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h | |||
@@ -389,7 +389,7 @@ static unsigned int gen_handle(struct tcf_proto *tp, unsigned salt) | |||
389 | if ((data->hgenerator += 0x10000) == 0) | 389 | if ((data->hgenerator += 0x10000) == 0) |
390 | data->hgenerator = 0x10000; | 390 | data->hgenerator = 0x10000; |
391 | h = data->hgenerator|salt; | 391 | h = data->hgenerator|salt; |
392 | if (rsvp_get(tp, h) == 0) | 392 | if (!rsvp_get(tp, h)) |
393 | return h; | 393 | return h; |
394 | } | 394 | } |
395 | return 0; | 395 | return 0; |
diff --git a/net/sctp/sctp_diag.c b/net/sctp/sctp_diag.c index e99518e79b52..22ed01a76b19 100644 --- a/net/sctp/sctp_diag.c +++ b/net/sctp/sctp_diag.c | |||
@@ -279,9 +279,11 @@ out: | |||
279 | return err; | 279 | return err; |
280 | } | 280 | } |
281 | 281 | ||
282 | static int sctp_sock_dump(struct sock *sk, void *p) | 282 | static int sctp_sock_dump(struct sctp_transport *tsp, void *p) |
283 | { | 283 | { |
284 | struct sctp_endpoint *ep = tsp->asoc->ep; | ||
284 | struct sctp_comm_param *commp = p; | 285 | struct sctp_comm_param *commp = p; |
286 | struct sock *sk = ep->base.sk; | ||
285 | struct sk_buff *skb = commp->skb; | 287 | struct sk_buff *skb = commp->skb; |
286 | struct netlink_callback *cb = commp->cb; | 288 | struct netlink_callback *cb = commp->cb; |
287 | const struct inet_diag_req_v2 *r = commp->r; | 289 | const struct inet_diag_req_v2 *r = commp->r; |
@@ -289,9 +291,7 @@ static int sctp_sock_dump(struct sock *sk, void *p) | |||
289 | int err = 0; | 291 | int err = 0; |
290 | 292 | ||
291 | lock_sock(sk); | 293 | lock_sock(sk); |
292 | if (!sctp_sk(sk)->ep) | 294 | list_for_each_entry(assoc, &ep->asocs, asocs) { |
293 | goto release; | ||
294 | list_for_each_entry(assoc, &sctp_sk(sk)->ep->asocs, asocs) { | ||
295 | if (cb->args[4] < cb->args[1]) | 295 | if (cb->args[4] < cb->args[1]) |
296 | goto next; | 296 | goto next; |
297 | 297 | ||
@@ -309,7 +309,6 @@ static int sctp_sock_dump(struct sock *sk, void *p) | |||
309 | cb->nlh->nlmsg_seq, | 309 | cb->nlh->nlmsg_seq, |
310 | NLM_F_MULTI, cb->nlh, | 310 | NLM_F_MULTI, cb->nlh, |
311 | commp->net_admin) < 0) { | 311 | commp->net_admin) < 0) { |
312 | cb->args[3] = 1; | ||
313 | err = 1; | 312 | err = 1; |
314 | goto release; | 313 | goto release; |
315 | } | 314 | } |
@@ -327,40 +326,30 @@ next: | |||
327 | cb->args[4]++; | 326 | cb->args[4]++; |
328 | } | 327 | } |
329 | cb->args[1] = 0; | 328 | cb->args[1] = 0; |
330 | cb->args[2]++; | ||
331 | cb->args[3] = 0; | 329 | cb->args[3] = 0; |
332 | cb->args[4] = 0; | 330 | cb->args[4] = 0; |
333 | release: | 331 | release: |
334 | release_sock(sk); | 332 | release_sock(sk); |
335 | sock_put(sk); | ||
336 | return err; | 333 | return err; |
337 | } | 334 | } |
338 | 335 | ||
339 | static int sctp_get_sock(struct sctp_transport *tsp, void *p) | 336 | static int sctp_sock_filter(struct sctp_transport *tsp, void *p) |
340 | { | 337 | { |
341 | struct sctp_endpoint *ep = tsp->asoc->ep; | 338 | struct sctp_endpoint *ep = tsp->asoc->ep; |
342 | struct sctp_comm_param *commp = p; | 339 | struct sctp_comm_param *commp = p; |
343 | struct sock *sk = ep->base.sk; | 340 | struct sock *sk = ep->base.sk; |
344 | struct netlink_callback *cb = commp->cb; | ||
345 | const struct inet_diag_req_v2 *r = commp->r; | 341 | const struct inet_diag_req_v2 *r = commp->r; |
346 | struct sctp_association *assoc = | 342 | struct sctp_association *assoc = |
347 | list_entry(ep->asocs.next, struct sctp_association, asocs); | 343 | list_entry(ep->asocs.next, struct sctp_association, asocs); |
348 | 344 | ||
349 | /* find the ep only once through the transports by this condition */ | 345 | /* find the ep only once through the transports by this condition */ |
350 | if (tsp->asoc != assoc) | 346 | if (tsp->asoc != assoc) |
351 | goto out; | 347 | return 0; |
352 | 348 | ||
353 | if (r->sdiag_family != AF_UNSPEC && sk->sk_family != r->sdiag_family) | 349 | if (r->sdiag_family != AF_UNSPEC && sk->sk_family != r->sdiag_family) |
354 | goto out; | 350 | return 0; |
355 | |||
356 | sock_hold(sk); | ||
357 | cb->args[5] = (long)sk; | ||
358 | 351 | ||
359 | return 1; | 352 | return 1; |
360 | |||
361 | out: | ||
362 | cb->args[2]++; | ||
363 | return 0; | ||
364 | } | 353 | } |
365 | 354 | ||
366 | static int sctp_ep_dump(struct sctp_endpoint *ep, void *p) | 355 | static int sctp_ep_dump(struct sctp_endpoint *ep, void *p) |
@@ -503,12 +492,8 @@ skip: | |||
503 | if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE))) | 492 | if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE))) |
504 | goto done; | 493 | goto done; |
505 | 494 | ||
506 | next: | 495 | sctp_for_each_transport(sctp_sock_filter, sctp_sock_dump, |
507 | cb->args[5] = 0; | 496 | net, (int *)&cb->args[2], &commp); |
508 | sctp_for_each_transport(sctp_get_sock, net, cb->args[2], &commp); | ||
509 | |||
510 | if (cb->args[5] && !sctp_sock_dump((struct sock *)cb->args[5], &commp)) | ||
511 | goto next; | ||
512 | 497 | ||
513 | done: | 498 | done: |
514 | cb->args[1] = cb->args[4]; | 499 | cb->args[1] = cb->args[4]; |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 1b00a1e09b93..d4730ada7f32 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -4658,29 +4658,39 @@ int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *), | |||
4658 | EXPORT_SYMBOL_GPL(sctp_transport_lookup_process); | 4658 | EXPORT_SYMBOL_GPL(sctp_transport_lookup_process); |
4659 | 4659 | ||
4660 | int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *), | 4660 | int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *), |
4661 | struct net *net, int pos, void *p) { | 4661 | int (*cb_done)(struct sctp_transport *, void *), |
4662 | struct net *net, int *pos, void *p) { | ||
4662 | struct rhashtable_iter hti; | 4663 | struct rhashtable_iter hti; |
4663 | void *obj; | 4664 | struct sctp_transport *tsp; |
4664 | int err; | 4665 | int ret; |
4665 | |||
4666 | err = sctp_transport_walk_start(&hti); | ||
4667 | if (err) | ||
4668 | return err; | ||
4669 | 4666 | ||
4670 | obj = sctp_transport_get_idx(net, &hti, pos + 1); | 4667 | again: |
4671 | for (; !IS_ERR_OR_NULL(obj); obj = sctp_transport_get_next(net, &hti)) { | 4668 | ret = sctp_transport_walk_start(&hti); |
4672 | struct sctp_transport *transport = obj; | 4669 | if (ret) |
4670 | return ret; | ||
4673 | 4671 | ||
4674 | if (!sctp_transport_hold(transport)) | 4672 | tsp = sctp_transport_get_idx(net, &hti, *pos + 1); |
4673 | for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) { | ||
4674 | if (!sctp_transport_hold(tsp)) | ||
4675 | continue; | 4675 | continue; |
4676 | err = cb(transport, p); | 4676 | ret = cb(tsp, p); |
4677 | sctp_transport_put(transport); | 4677 | if (ret) |
4678 | if (err) | ||
4679 | break; | 4678 | break; |
4679 | (*pos)++; | ||
4680 | sctp_transport_put(tsp); | ||
4680 | } | 4681 | } |
4681 | sctp_transport_walk_stop(&hti); | 4682 | sctp_transport_walk_stop(&hti); |
4682 | 4683 | ||
4683 | return err; | 4684 | if (ret) { |
4685 | if (cb_done && !cb_done(tsp, p)) { | ||
4686 | (*pos)++; | ||
4687 | sctp_transport_put(tsp); | ||
4688 | goto again; | ||
4689 | } | ||
4690 | sctp_transport_put(tsp); | ||
4691 | } | ||
4692 | |||
4693 | return ret; | ||
4684 | } | 4694 | } |
4685 | EXPORT_SYMBOL_GPL(sctp_for_each_transport); | 4695 | EXPORT_SYMBOL_GPL(sctp_for_each_transport); |
4686 | 4696 | ||
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index fa596fa71ba7..7d80040a37b6 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c | |||
@@ -639,7 +639,7 @@ sendpage_end: | |||
639 | return ret; | 639 | return ret; |
640 | } | 640 | } |
641 | 641 | ||
642 | void tls_sw_free_resources(struct sock *sk) | 642 | static void tls_sw_free_resources(struct sock *sk) |
643 | { | 643 | { |
644 | struct tls_context *tls_ctx = tls_get_ctx(sk); | 644 | struct tls_context *tls_ctx = tls_get_ctx(sk); |
645 | struct tls_sw_context *ctx = tls_sw_ctx(tls_ctx); | 645 | struct tls_sw_context *ctx = tls_sw_ctx(tls_ctx); |