diff options
author | David S. Miller <davem@davemloft.net> | 2019-09-17 17:51:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-09-17 17:51:10 -0400 |
commit | 1bab8d4c488be22d57f9dd09968c90a0ddc413bf (patch) | |
tree | 81318cd13170a3b6b72489f63e92adb0eaf49693 | |
parent | 990925fad5c227269c3fcb76c7c46811b1e86c73 (diff) | |
parent | 00b368502d18f790ab715e055869fd4bb7484a9b (diff) |
Merge ra.kernel.org:/pub/scm/linux/kernel/git/netdev/net
Pull in bug fixes from 'net' tree for the merge window.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | MAINTAINERS | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/amazon/ena/ena_netdev.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 12 | ||||
-rw-r--r-- | drivers/net/xen-netfront.c | 2 | ||||
-rw-r--r-- | include/net/pkt_sched.h | 7 | ||||
-rw-r--r-- | include/net/sock_reuseport.h | 20 | ||||
-rw-r--r-- | net/core/dev.c | 16 | ||||
-rw-r--r-- | net/core/sock_reuseport.c | 15 | ||||
-rw-r--r-- | net/dsa/dsa2.c | 2 | ||||
-rw-r--r-- | net/ipv4/datagram.c | 2 | ||||
-rw-r--r-- | net/ipv4/udp.c | 5 | ||||
-rw-r--r-- | net/ipv6/datagram.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_gre.c | 2 | ||||
-rw-r--r-- | net/ipv6/udp.c | 5 | ||||
-rw-r--r-- | net/rds/ib_stats.c | 2 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 3 |
16 files changed, 83 insertions, 23 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 32f4f05fb3da..dd39fc578607 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -649,6 +649,12 @@ M: Lino Sanfilippo <LinoSanfilippo@gmx.de> | |||
649 | S: Maintained | 649 | S: Maintained |
650 | F: drivers/net/ethernet/alacritech/* | 650 | F: drivers/net/ethernet/alacritech/* |
651 | 651 | ||
652 | FORCEDETH GIGABIT ETHERNET DRIVER | ||
653 | M: Rain River <rain.1986.08.12@gmail.com> | ||
654 | L: netdev@vger.kernel.org | ||
655 | S: Maintained | ||
656 | F: drivers/net/ethernet/nvidia/* | ||
657 | |||
652 | ALCATEL SPEEDTOUCH USB DRIVER | 658 | ALCATEL SPEEDTOUCH USB DRIVER |
653 | M: Duncan Sands <duncan.sands@free.fr> | 659 | M: Duncan Sands <duncan.sands@free.fr> |
654 | L: linux-usb@vger.kernel.org | 660 | L: linux-usb@vger.kernel.org |
@@ -17673,7 +17679,7 @@ F: Documentation/ABI/testing/sysfs-hypervisor-xen | |||
17673 | 17679 | ||
17674 | XEN NETWORK BACKEND DRIVER | 17680 | XEN NETWORK BACKEND DRIVER |
17675 | M: Wei Liu <wei.liu@kernel.org> | 17681 | M: Wei Liu <wei.liu@kernel.org> |
17676 | M: Paul Durrant <paul.durrant@citrix.com> | 17682 | M: Paul Durrant <paul@xen.org> |
17677 | L: xen-devel@lists.xenproject.org (moderated for non-subscribers) | 17683 | L: xen-devel@lists.xenproject.org (moderated for non-subscribers) |
17678 | L: netdev@vger.kernel.org | 17684 | L: netdev@vger.kernel.org |
17679 | S: Supported | 17685 | S: Supported |
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index e4bf7a4af87a..c487d2a7d6dd 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c | |||
@@ -824,7 +824,8 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget) | |||
824 | above_thresh = | 824 | above_thresh = |
825 | ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq, | 825 | ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq, |
826 | ENA_TX_WAKEUP_THRESH); | 826 | ENA_TX_WAKEUP_THRESH); |
827 | if (netif_tx_queue_stopped(txq) && above_thresh) { | 827 | if (netif_tx_queue_stopped(txq) && above_thresh && |
828 | test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags)) { | ||
828 | netif_tx_wake_queue(txq); | 829 | netif_tx_wake_queue(txq); |
829 | u64_stats_update_begin(&tx_ring->syncp); | 830 | u64_stats_update_begin(&tx_ring->syncp); |
830 | tx_ring->tx_stats.queue_wakeup++; | 831 | tx_ring->tx_stats.queue_wakeup++; |
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index c61d702fe83a..a6cb2aa60e64 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | |||
@@ -4713,10 +4713,12 @@ int stmmac_suspend(struct device *dev) | |||
4713 | if (!ndev || !netif_running(ndev)) | 4713 | if (!ndev || !netif_running(ndev)) |
4714 | return 0; | 4714 | return 0; |
4715 | 4715 | ||
4716 | phylink_stop(priv->phylink); | ||
4717 | |||
4718 | mutex_lock(&priv->lock); | 4716 | mutex_lock(&priv->lock); |
4719 | 4717 | ||
4718 | rtnl_lock(); | ||
4719 | phylink_stop(priv->phylink); | ||
4720 | rtnl_unlock(); | ||
4721 | |||
4720 | netif_device_detach(ndev); | 4722 | netif_device_detach(ndev); |
4721 | stmmac_stop_all_queues(priv); | 4723 | stmmac_stop_all_queues(priv); |
4722 | 4724 | ||
@@ -4820,9 +4822,11 @@ int stmmac_resume(struct device *dev) | |||
4820 | 4822 | ||
4821 | stmmac_start_all_queues(priv); | 4823 | stmmac_start_all_queues(priv); |
4822 | 4824 | ||
4823 | mutex_unlock(&priv->lock); | 4825 | rtnl_lock(); |
4824 | |||
4825 | phylink_start(priv->phylink); | 4826 | phylink_start(priv->phylink); |
4827 | rtnl_unlock(); | ||
4828 | |||
4829 | mutex_unlock(&priv->lock); | ||
4826 | 4830 | ||
4827 | return 0; | 4831 | return 0; |
4828 | } | 4832 | } |
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index b930d5f95222..e14ec75b61d6 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c | |||
@@ -906,7 +906,7 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue, | |||
906 | __pskb_pull_tail(skb, pull_to - skb_headlen(skb)); | 906 | __pskb_pull_tail(skb, pull_to - skb_headlen(skb)); |
907 | } | 907 | } |
908 | if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) { | 908 | if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) { |
909 | queue->rx.rsp_cons = ++cons; | 909 | queue->rx.rsp_cons = ++cons + skb_queue_len(list); |
910 | kfree_skb(nskb); | 910 | kfree_skb(nskb); |
911 | return ~0U; | 911 | return ~0U; |
912 | } | 912 | } |
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index d1632979622e..6a70845bd9ab 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h | |||
@@ -118,7 +118,12 @@ void __qdisc_run(struct Qdisc *q); | |||
118 | static inline void qdisc_run(struct Qdisc *q) | 118 | static inline void qdisc_run(struct Qdisc *q) |
119 | { | 119 | { |
120 | if (qdisc_run_begin(q)) { | 120 | if (qdisc_run_begin(q)) { |
121 | __qdisc_run(q); | 121 | /* NOLOCK qdisc must check 'state' under the qdisc seqlock |
122 | * to avoid racing with dev_qdisc_reset() | ||
123 | */ | ||
124 | if (!(q->flags & TCQ_F_NOLOCK) || | ||
125 | likely(!test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) | ||
126 | __qdisc_run(q); | ||
122 | qdisc_run_end(q); | 127 | qdisc_run_end(q); |
123 | } | 128 | } |
124 | } | 129 | } |
diff --git a/include/net/sock_reuseport.h b/include/net/sock_reuseport.h index d9112de85261..43f4a818d88f 100644 --- a/include/net/sock_reuseport.h +++ b/include/net/sock_reuseport.h | |||
@@ -21,7 +21,8 @@ struct sock_reuseport { | |||
21 | unsigned int synq_overflow_ts; | 21 | unsigned int synq_overflow_ts; |
22 | /* ID stays the same even after the size of socks[] grows. */ | 22 | /* ID stays the same even after the size of socks[] grows. */ |
23 | unsigned int reuseport_id; | 23 | unsigned int reuseport_id; |
24 | bool bind_inany; | 24 | unsigned int bind_inany:1; |
25 | unsigned int has_conns:1; | ||
25 | struct bpf_prog __rcu *prog; /* optional BPF sock selector */ | 26 | struct bpf_prog __rcu *prog; /* optional BPF sock selector */ |
26 | struct sock *socks[0]; /* array of sock pointers */ | 27 | struct sock *socks[0]; /* array of sock pointers */ |
27 | }; | 28 | }; |
@@ -37,6 +38,23 @@ extern struct sock *reuseport_select_sock(struct sock *sk, | |||
37 | extern int reuseport_attach_prog(struct sock *sk, struct bpf_prog *prog); | 38 | extern int reuseport_attach_prog(struct sock *sk, struct bpf_prog *prog); |
38 | extern int reuseport_detach_prog(struct sock *sk); | 39 | extern int reuseport_detach_prog(struct sock *sk); |
39 | 40 | ||
41 | static inline bool reuseport_has_conns(struct sock *sk, bool set) | ||
42 | { | ||
43 | struct sock_reuseport *reuse; | ||
44 | bool ret = false; | ||
45 | |||
46 | rcu_read_lock(); | ||
47 | reuse = rcu_dereference(sk->sk_reuseport_cb); | ||
48 | if (reuse) { | ||
49 | if (set) | ||
50 | reuse->has_conns = 1; | ||
51 | ret = reuse->has_conns; | ||
52 | } | ||
53 | rcu_read_unlock(); | ||
54 | |||
55 | return ret; | ||
56 | } | ||
57 | |||
40 | int reuseport_get_id(struct sock_reuseport *reuse); | 58 | int reuseport_get_id(struct sock_reuseport *reuse); |
41 | 59 | ||
42 | #endif /* _SOCK_REUSEPORT_H */ | 60 | #endif /* _SOCK_REUSEPORT_H */ |
diff --git a/net/core/dev.c b/net/core/dev.c index a9775d676285..71b18e80389f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -3467,18 +3467,22 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, | |||
3467 | qdisc_calculate_pkt_len(skb, q); | 3467 | qdisc_calculate_pkt_len(skb, q); |
3468 | 3468 | ||
3469 | if (q->flags & TCQ_F_NOLOCK) { | 3469 | if (q->flags & TCQ_F_NOLOCK) { |
3470 | if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) { | 3470 | if ((q->flags & TCQ_F_CAN_BYPASS) && q->empty && |
3471 | __qdisc_drop(skb, &to_free); | 3471 | qdisc_run_begin(q)) { |
3472 | rc = NET_XMIT_DROP; | 3472 | if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, |
3473 | } else if ((q->flags & TCQ_F_CAN_BYPASS) && q->empty && | 3473 | &q->state))) { |
3474 | qdisc_run_begin(q)) { | 3474 | __qdisc_drop(skb, &to_free); |
3475 | rc = NET_XMIT_DROP; | ||
3476 | goto end_run; | ||
3477 | } | ||
3475 | qdisc_bstats_cpu_update(q, skb); | 3478 | qdisc_bstats_cpu_update(q, skb); |
3476 | 3479 | ||
3480 | rc = NET_XMIT_SUCCESS; | ||
3477 | if (sch_direct_xmit(skb, q, dev, txq, NULL, true)) | 3481 | if (sch_direct_xmit(skb, q, dev, txq, NULL, true)) |
3478 | __qdisc_run(q); | 3482 | __qdisc_run(q); |
3479 | 3483 | ||
3484 | end_run: | ||
3480 | qdisc_run_end(q); | 3485 | qdisc_run_end(q); |
3481 | rc = NET_XMIT_SUCCESS; | ||
3482 | } else { | 3486 | } else { |
3483 | rc = q->enqueue(skb, q, &to_free) & NET_XMIT_MASK; | 3487 | rc = q->enqueue(skb, q, &to_free) & NET_XMIT_MASK; |
3484 | qdisc_run(q); | 3488 | qdisc_run(q); |
diff --git a/net/core/sock_reuseport.c b/net/core/sock_reuseport.c index 9408f9264d05..f3ceec93f392 100644 --- a/net/core/sock_reuseport.c +++ b/net/core/sock_reuseport.c | |||
@@ -295,8 +295,19 @@ struct sock *reuseport_select_sock(struct sock *sk, | |||
295 | 295 | ||
296 | select_by_hash: | 296 | select_by_hash: |
297 | /* no bpf or invalid bpf result: fall back to hash usage */ | 297 | /* no bpf or invalid bpf result: fall back to hash usage */ |
298 | if (!sk2) | 298 | if (!sk2) { |
299 | sk2 = reuse->socks[reciprocal_scale(hash, socks)]; | 299 | int i, j; |
300 | |||
301 | i = j = reciprocal_scale(hash, socks); | ||
302 | while (reuse->socks[i]->sk_state == TCP_ESTABLISHED) { | ||
303 | i++; | ||
304 | if (i >= reuse->num_socks) | ||
305 | i = 0; | ||
306 | if (i == j) | ||
307 | goto out; | ||
308 | } | ||
309 | sk2 = reuse->socks[i]; | ||
310 | } | ||
300 | } | 311 | } |
301 | 312 | ||
302 | out: | 313 | out: |
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index b501c90aabe4..73002022c9d8 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c | |||
@@ -644,6 +644,8 @@ static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master) | |||
644 | tag_protocol = ds->ops->get_tag_protocol(ds, dp->index); | 644 | tag_protocol = ds->ops->get_tag_protocol(ds, dp->index); |
645 | tag_ops = dsa_tag_driver_get(tag_protocol); | 645 | tag_ops = dsa_tag_driver_get(tag_protocol); |
646 | if (IS_ERR(tag_ops)) { | 646 | if (IS_ERR(tag_ops)) { |
647 | if (PTR_ERR(tag_ops) == -ENOPROTOOPT) | ||
648 | return -EPROBE_DEFER; | ||
647 | dev_warn(ds->dev, "No tagger for this switch\n"); | 649 | dev_warn(ds->dev, "No tagger for this switch\n"); |
648 | return PTR_ERR(tag_ops); | 650 | return PTR_ERR(tag_ops); |
649 | } | 651 | } |
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index 7bd29e694603..9a0fe0c2fa02 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <net/sock.h> | 15 | #include <net/sock.h> |
16 | #include <net/route.h> | 16 | #include <net/route.h> |
17 | #include <net/tcp_states.h> | 17 | #include <net/tcp_states.h> |
18 | #include <net/sock_reuseport.h> | ||
18 | 19 | ||
19 | int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | 20 | int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) |
20 | { | 21 | { |
@@ -69,6 +70,7 @@ int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len | |||
69 | } | 70 | } |
70 | inet->inet_daddr = fl4->daddr; | 71 | inet->inet_daddr = fl4->daddr; |
71 | inet->inet_dport = usin->sin_port; | 72 | inet->inet_dport = usin->sin_port; |
73 | reuseport_has_conns(sk, true); | ||
72 | sk->sk_state = TCP_ESTABLISHED; | 74 | sk->sk_state = TCP_ESTABLISHED; |
73 | sk_set_txhash(sk); | 75 | sk_set_txhash(sk); |
74 | inet->inet_id = jiffies; | 76 | inet->inet_id = jiffies; |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index fbcd9be3a470..cf755156a684 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -423,12 +423,13 @@ static struct sock *udp4_lib_lookup2(struct net *net, | |||
423 | score = compute_score(sk, net, saddr, sport, | 423 | score = compute_score(sk, net, saddr, sport, |
424 | daddr, hnum, dif, sdif); | 424 | daddr, hnum, dif, sdif); |
425 | if (score > badness) { | 425 | if (score > badness) { |
426 | if (sk->sk_reuseport) { | 426 | if (sk->sk_reuseport && |
427 | sk->sk_state != TCP_ESTABLISHED) { | ||
427 | hash = udp_ehashfn(net, daddr, hnum, | 428 | hash = udp_ehashfn(net, daddr, hnum, |
428 | saddr, sport); | 429 | saddr, sport); |
429 | result = reuseport_select_sock(sk, hash, skb, | 430 | result = reuseport_select_sock(sk, hash, skb, |
430 | sizeof(struct udphdr)); | 431 | sizeof(struct udphdr)); |
431 | if (result) | 432 | if (result && !reuseport_has_conns(sk, false)) |
432 | return result; | 433 | return result; |
433 | } | 434 | } |
434 | badness = score; | 435 | badness = score; |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 9ab897ded4df..96f939248d2f 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <net/ip6_route.h> | 27 | #include <net/ip6_route.h> |
28 | #include <net/tcp_states.h> | 28 | #include <net/tcp_states.h> |
29 | #include <net/dsfield.h> | 29 | #include <net/dsfield.h> |
30 | #include <net/sock_reuseport.h> | ||
30 | 31 | ||
31 | #include <linux/errqueue.h> | 32 | #include <linux/errqueue.h> |
32 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
@@ -254,6 +255,7 @@ ipv4_connected: | |||
254 | goto out; | 255 | goto out; |
255 | } | 256 | } |
256 | 257 | ||
258 | reuseport_has_conns(sk, true); | ||
257 | sk->sk_state = TCP_ESTABLISHED; | 259 | sk->sk_state = TCP_ESTABLISHED; |
258 | sk_set_txhash(sk); | 260 | sk_set_txhash(sk); |
259 | out: | 261 | out: |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index dd2d0b963260..d5779d6a6065 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
@@ -968,7 +968,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, | |||
968 | if (unlikely(!tun_info || | 968 | if (unlikely(!tun_info || |
969 | !(tun_info->mode & IP_TUNNEL_INFO_TX) || | 969 | !(tun_info->mode & IP_TUNNEL_INFO_TX) || |
970 | ip_tunnel_info_af(tun_info) != AF_INET6)) | 970 | ip_tunnel_info_af(tun_info) != AF_INET6)) |
971 | return -EINVAL; | 971 | goto tx_err; |
972 | 972 | ||
973 | key = &tun_info->key; | 973 | key = &tun_info->key; |
974 | memset(&fl6, 0, sizeof(fl6)); | 974 | memset(&fl6, 0, sizeof(fl6)); |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 2c8beb3896d1..aae4938f3dea 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -158,13 +158,14 @@ static struct sock *udp6_lib_lookup2(struct net *net, | |||
158 | score = compute_score(sk, net, saddr, sport, | 158 | score = compute_score(sk, net, saddr, sport, |
159 | daddr, hnum, dif, sdif); | 159 | daddr, hnum, dif, sdif); |
160 | if (score > badness) { | 160 | if (score > badness) { |
161 | if (sk->sk_reuseport) { | 161 | if (sk->sk_reuseport && |
162 | sk->sk_state != TCP_ESTABLISHED) { | ||
162 | hash = udp6_ehashfn(net, daddr, hnum, | 163 | hash = udp6_ehashfn(net, daddr, hnum, |
163 | saddr, sport); | 164 | saddr, sport); |
164 | 165 | ||
165 | result = reuseport_select_sock(sk, hash, skb, | 166 | result = reuseport_select_sock(sk, hash, skb, |
166 | sizeof(struct udphdr)); | 167 | sizeof(struct udphdr)); |
167 | if (result) | 168 | if (result && !reuseport_has_conns(sk, false)) |
168 | return result; | 169 | return result; |
169 | } | 170 | } |
170 | result = sk; | 171 | result = sk; |
diff --git a/net/rds/ib_stats.c b/net/rds/ib_stats.c index 9252ad126335..ac46d8961b61 100644 --- a/net/rds/ib_stats.c +++ b/net/rds/ib_stats.c | |||
@@ -42,7 +42,7 @@ DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_ib_statistics, rds_ib_stats); | |||
42 | static const char *const rds_ib_stat_names[] = { | 42 | static const char *const rds_ib_stat_names[] = { |
43 | "ib_connect_raced", | 43 | "ib_connect_raced", |
44 | "ib_listen_closed_stale", | 44 | "ib_listen_closed_stale", |
45 | "s_ib_evt_handler_call", | 45 | "ib_evt_handler_call", |
46 | "ib_tasklet_call", | 46 | "ib_tasklet_call", |
47 | "ib_tx_cq_event", | 47 | "ib_tx_cq_event", |
48 | "ib_tx_ring_full", | 48 | "ib_tx_ring_full", |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index ac28f6a5d70e..17bd8f539bc7 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -985,6 +985,9 @@ static void qdisc_destroy(struct Qdisc *qdisc) | |||
985 | 985 | ||
986 | void qdisc_put(struct Qdisc *qdisc) | 986 | void qdisc_put(struct Qdisc *qdisc) |
987 | { | 987 | { |
988 | if (!qdisc) | ||
989 | return; | ||
990 | |||
988 | if (qdisc->flags & TCQ_F_BUILTIN || | 991 | if (qdisc->flags & TCQ_F_BUILTIN || |
989 | !refcount_dec_and_test(&qdisc->refcnt)) | 992 | !refcount_dec_and_test(&qdisc->refcnt)) |
990 | return; | 993 | return; |