aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-17 22:22:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-17 22:22:24 -0400
commitc579bc7e316e7e3f3b56df5e17f623325caa9783 (patch)
treefd057d71e237552436fb98f4bfb435b5c8e45787
parent96ee0499c59810736dc2e56784d061dc6a1d98e8 (diff)
parenta16a1647fa6b6783c2e91623e72e86f0c2adac5e (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking changes from David Miller: "1) icmp6_dst_alloc() returns NULL instead of ERR_PTR() leading to crashes, particularly during shutdown. Reported by Dave Jones and fixed by Eric Dumazet. 2) hyperv and wimax/i2400m return NETDEV_TX_BUSY when they have already freed the SKB, which causes crashes as to the caller this means requeue the packet. Fixes from Eric Dumazet. 3) usbnet driver doesn't allocate the right amount of headroom on fresh RX SKBs, fix from Eric Dumazet. 4) Fix regression in ip6_mc_find_dev_rcu(), as an RCU lookup it abolutely should not take a reference to 'dev', this leads to leaks. Fix from RonQing Li. 5) Fix netfilter ctnetlink race between delete and timeout expiration. From Pablo Neira Ayuso. 6) Revert SFQ change which causes regressions, specifically queueing to tail can lead to unavoidable flow starvation. From Eric Dumazet. 7) Fix a memory leak and a crash on corrupt firmware files in bnx2x, from Michal Schmidt." * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: netfilter: ctnetlink: fix race between delete and timeout expiration ipv6: Don't dev_hold(dev) in ip6_mc_find_dev_rcu. wimax/i2400m: fix erroneous NETDEV_TX_BUSY use net/hyperv: fix erroneous NETDEV_TX_BUSY use net/usbnet: reserve headroom on rx skbs bnx2x: fix memory leak in bnx2x_init_firmware() bnx2x: fix a crash on corrupt firmware file sch_sfq: revert dont put new flow at the end of flows ipv6: fix icmp6_dst_alloc()
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c51
-rw-r--r--drivers/net/hyperv/netvsc_drv.c4
-rw-r--r--drivers/net/usb/usbnet.c4
-rw-r--r--drivers/net/wimax/i2400m/netdev.c30
-rw-r--r--net/ipv6/mcast.c1
-rw-r--r--net/ipv6/route.c2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c23
-rw-r--r--net/sched/sch_sfq.c6
8 files changed, 57 insertions, 64 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 254521319150..b69f8762b339 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -10824,38 +10824,36 @@ do { \
10824 10824
10825int bnx2x_init_firmware(struct bnx2x *bp) 10825int bnx2x_init_firmware(struct bnx2x *bp)
10826{ 10826{
10827 const char *fw_file_name;
10827 struct bnx2x_fw_file_hdr *fw_hdr; 10828 struct bnx2x_fw_file_hdr *fw_hdr;
10828 int rc; 10829 int rc;
10829 10830
10831 if (bp->firmware)
10832 return 0;
10830 10833
10831 if (!bp->firmware) { 10834 if (CHIP_IS_E1(bp))
10832 const char *fw_file_name; 10835 fw_file_name = FW_FILE_NAME_E1;
10833 10836 else if (CHIP_IS_E1H(bp))
10834 if (CHIP_IS_E1(bp)) 10837 fw_file_name = FW_FILE_NAME_E1H;
10835 fw_file_name = FW_FILE_NAME_E1; 10838 else if (!CHIP_IS_E1x(bp))
10836 else if (CHIP_IS_E1H(bp)) 10839 fw_file_name = FW_FILE_NAME_E2;
10837 fw_file_name = FW_FILE_NAME_E1H; 10840 else {
10838 else if (!CHIP_IS_E1x(bp)) 10841 BNX2X_ERR("Unsupported chip revision\n");
10839 fw_file_name = FW_FILE_NAME_E2; 10842 return -EINVAL;
10840 else { 10843 }
10841 BNX2X_ERR("Unsupported chip revision\n"); 10844 BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
10842 return -EINVAL;
10843 }
10844 BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
10845 10845
10846 rc = request_firmware(&bp->firmware, fw_file_name, 10846 rc = request_firmware(&bp->firmware, fw_file_name, &bp->pdev->dev);
10847 &bp->pdev->dev); 10847 if (rc) {
10848 if (rc) { 10848 BNX2X_ERR("Can't load firmware file %s\n",
10849 BNX2X_ERR("Can't load firmware file %s\n", 10849 fw_file_name);
10850 fw_file_name); 10850 goto request_firmware_exit;
10851 goto request_firmware_exit; 10851 }
10852 }
10853 10852
10854 rc = bnx2x_check_firmware(bp); 10853 rc = bnx2x_check_firmware(bp);
10855 if (rc) { 10854 if (rc) {
10856 BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name); 10855 BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name);
10857 goto request_firmware_exit; 10856 goto request_firmware_exit;
10858 }
10859 } 10857 }
10860 10858
10861 fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data; 10859 fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data;
@@ -10901,6 +10899,7 @@ init_ops_alloc_err:
10901 kfree(bp->init_data); 10899 kfree(bp->init_data);
10902request_firmware_exit: 10900request_firmware_exit:
10903 release_firmware(bp->firmware); 10901 release_firmware(bp->firmware);
10902 bp->firmware = NULL;
10904 10903
10905 return rc; 10904 return rc;
10906} 10905}
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index bf01841bda5b..610860f28968 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -166,7 +166,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
166 166
167 dev_kfree_skb(skb); 167 dev_kfree_skb(skb);
168 net->stats.tx_dropped++; 168 net->stats.tx_dropped++;
169 return NETDEV_TX_BUSY; 169 return NETDEV_TX_OK;
170 } 170 }
171 171
172 packet->extension = (void *)(unsigned long)packet + 172 packet->extension = (void *)(unsigned long)packet +
@@ -226,7 +226,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
226 dev_kfree_skb_any(skb); 226 dev_kfree_skb_any(skb);
227 } 227 }
228 228
229 return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK; 229 return NETDEV_TX_OK;
230} 230}
231 231
232/* 232/*
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 81b96e303757..59681f01a54e 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -328,13 +328,13 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
328 unsigned long lockflags; 328 unsigned long lockflags;
329 size_t size = dev->rx_urb_size; 329 size_t size = dev->rx_urb_size;
330 330
331 if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) { 331 skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
332 if (!skb) {
332 netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); 333 netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
333 usbnet_defer_kevent (dev, EVENT_RX_MEMORY); 334 usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
334 usb_free_urb (urb); 335 usb_free_urb (urb);
335 return -ENOMEM; 336 return -ENOMEM;
336 } 337 }
337 skb_reserve (skb, NET_IP_ALIGN);
338 338
339 entry = (struct skb_data *) skb->cb; 339 entry = (struct skb_data *) skb->cb;
340 entry->urb = urb; 340 entry->urb = urb;
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index 64a110604ad3..63e4b709efa9 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -367,38 +367,28 @@ netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb,
367{ 367{
368 struct i2400m *i2400m = net_dev_to_i2400m(net_dev); 368 struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
369 struct device *dev = i2400m_dev(i2400m); 369 struct device *dev = i2400m_dev(i2400m);
370 int result; 370 int result = -1;
371 371
372 d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); 372 d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
373 if (skb_header_cloned(skb)) { 373
374 /* 374 if (skb_header_cloned(skb) &&
375 * Make tcpdump/wireshark happy -- if they are 375 pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
376 * running, the skb is cloned and we will overwrite 376 goto drop;
377 * the mac fields in i2400m_tx_prep_header. Expand
378 * seems to fix this...
379 */
380 result = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
381 if (result) {
382 result = NETDEV_TX_BUSY;
383 goto error_expand;
384 }
385 }
386 377
387 if (i2400m->state == I2400M_SS_IDLE) 378 if (i2400m->state == I2400M_SS_IDLE)
388 result = i2400m_net_wake_tx(i2400m, net_dev, skb); 379 result = i2400m_net_wake_tx(i2400m, net_dev, skb);
389 else 380 else
390 result = i2400m_net_tx(i2400m, net_dev, skb); 381 result = i2400m_net_tx(i2400m, net_dev, skb);
391 if (result < 0) 382 if (result < 0) {
383drop:
392 net_dev->stats.tx_dropped++; 384 net_dev->stats.tx_dropped++;
393 else { 385 } else {
394 net_dev->stats.tx_packets++; 386 net_dev->stats.tx_packets++;
395 net_dev->stats.tx_bytes += skb->len; 387 net_dev->stats.tx_bytes += skb->len;
396 } 388 }
397 result = NETDEV_TX_OK; 389 dev_kfree_skb(skb);
398error_expand:
399 kfree_skb(skb);
400 d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result); 390 d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result);
401 return result; 391 return NETDEV_TX_OK;
402} 392}
403 393
404 394
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index b853f06cc148..16c33e308121 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -257,7 +257,6 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
257 257
258 if (rt) { 258 if (rt) {
259 dev = rt->dst.dev; 259 dev = rt->dst.dev;
260 dev_hold(dev);
261 dst_release(&rt->dst); 260 dst_release(&rt->dst);
262 } 261 }
263 } else 262 } else
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 8c2e3ab58f2a..22b766407de1 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1077,7 +1077,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
1077 struct net *net = dev_net(dev); 1077 struct net *net = dev_net(dev);
1078 1078
1079 if (unlikely(!idev)) 1079 if (unlikely(!idev))
1080 return NULL; 1080 return ERR_PTR(-ENODEV);
1081 1081
1082 rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0); 1082 rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0);
1083 if (unlikely(!rt)) { 1083 if (unlikely(!rt)) {
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 10687692831e..b49da6c925b3 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -943,20 +943,21 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
943 } 943 }
944 } 944 }
945 945
946 if (nf_conntrack_event_report(IPCT_DESTROY, ct, 946 if (del_timer(&ct->timeout)) {
947 NETLINK_CB(skb).pid, 947 if (nf_conntrack_event_report(IPCT_DESTROY, ct,
948 nlmsg_report(nlh)) < 0) { 948 NETLINK_CB(skb).pid,
949 nlmsg_report(nlh)) < 0) {
950 nf_ct_delete_from_lists(ct);
951 /* we failed to report the event, try later */
952 nf_ct_insert_dying_list(ct);
953 nf_ct_put(ct);
954 return 0;
955 }
956 /* death_by_timeout would report the event again */
957 set_bit(IPS_DYING_BIT, &ct->status);
949 nf_ct_delete_from_lists(ct); 958 nf_ct_delete_from_lists(ct);
950 /* we failed to report the event, try later */
951 nf_ct_insert_dying_list(ct);
952 nf_ct_put(ct); 959 nf_ct_put(ct);
953 return 0;
954 } 960 }
955
956 /* death_by_timeout would report the event again */
957 set_bit(IPS_DYING_BIT, &ct->status);
958
959 nf_ct_kill(ct);
960 nf_ct_put(ct); 961 nf_ct_put(ct);
961 962
962 return 0; 963 return 0;
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 60d47180f043..02a21abea65e 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -469,11 +469,15 @@ enqueue:
469 if (slot->qlen == 1) { /* The flow is new */ 469 if (slot->qlen == 1) { /* The flow is new */
470 if (q->tail == NULL) { /* It is the first flow */ 470 if (q->tail == NULL) { /* It is the first flow */
471 slot->next = x; 471 slot->next = x;
472 q->tail = slot;
473 } else { 472 } else {
474 slot->next = q->tail->next; 473 slot->next = q->tail->next;
475 q->tail->next = x; 474 q->tail->next = x;
476 } 475 }
476 /* We put this flow at the end of our flow list.
477 * This might sound unfair for a new flow to wait after old ones,
478 * but we could endup servicing new flows only, and freeze old ones.
479 */
480 q->tail = slot;
477 /* We could use a bigger initial quantum for new flows */ 481 /* We could use a bigger initial quantum for new flows */
478 slot->allot = q->scaled_quantum; 482 slot->allot = q->scaled_quantum;
479 } 483 }