Commit c579bc7e authored by Linus Torvalds's avatar Linus Torvalds

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()
parents 96ee0499 a16a1647
...@@ -10824,38 +10824,36 @@ do { \ ...@@ -10824,38 +10824,36 @@ do { \
int bnx2x_init_firmware(struct bnx2x *bp) int bnx2x_init_firmware(struct bnx2x *bp)
{ {
const char *fw_file_name;
struct bnx2x_fw_file_hdr *fw_hdr; struct bnx2x_fw_file_hdr *fw_hdr;
int rc; int rc;
if (bp->firmware)
return 0;
if (!bp->firmware) { if (CHIP_IS_E1(bp))
const char *fw_file_name; fw_file_name = FW_FILE_NAME_E1;
else if (CHIP_IS_E1H(bp))
if (CHIP_IS_E1(bp)) fw_file_name = FW_FILE_NAME_E1H;
fw_file_name = FW_FILE_NAME_E1; else if (!CHIP_IS_E1x(bp))
else if (CHIP_IS_E1H(bp)) fw_file_name = FW_FILE_NAME_E2;
fw_file_name = FW_FILE_NAME_E1H; else {
else if (!CHIP_IS_E1x(bp)) BNX2X_ERR("Unsupported chip revision\n");
fw_file_name = FW_FILE_NAME_E2; return -EINVAL;
else { }
BNX2X_ERR("Unsupported chip revision\n"); BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
return -EINVAL;
}
BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
rc = request_firmware(&bp->firmware, fw_file_name, rc = request_firmware(&bp->firmware, fw_file_name, &bp->pdev->dev);
&bp->pdev->dev); if (rc) {
if (rc) { BNX2X_ERR("Can't load firmware file %s\n",
BNX2X_ERR("Can't load firmware file %s\n", fw_file_name);
fw_file_name); goto request_firmware_exit;
goto request_firmware_exit; }
}
rc = bnx2x_check_firmware(bp); rc = bnx2x_check_firmware(bp);
if (rc) { if (rc) {
BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name); BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name);
goto request_firmware_exit; goto request_firmware_exit;
}
} }
fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data; fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data;
...@@ -10901,6 +10899,7 @@ int bnx2x_init_firmware(struct bnx2x *bp) ...@@ -10901,6 +10899,7 @@ int bnx2x_init_firmware(struct bnx2x *bp)
kfree(bp->init_data); kfree(bp->init_data);
request_firmware_exit: request_firmware_exit:
release_firmware(bp->firmware); release_firmware(bp->firmware);
bp->firmware = NULL;
return rc; return rc;
} }
......
...@@ -166,7 +166,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -166,7 +166,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
dev_kfree_skb(skb); dev_kfree_skb(skb);
net->stats.tx_dropped++; net->stats.tx_dropped++;
return NETDEV_TX_BUSY; return NETDEV_TX_OK;
} }
packet->extension = (void *)(unsigned long)packet + packet->extension = (void *)(unsigned long)packet +
...@@ -226,7 +226,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -226,7 +226,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK; return NETDEV_TX_OK;
} }
/* /*
......
...@@ -328,13 +328,13 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) ...@@ -328,13 +328,13 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
unsigned long lockflags; unsigned long lockflags;
size_t size = dev->rx_urb_size; size_t size = dev->rx_urb_size;
if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) { skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
if (!skb) {
netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
usbnet_defer_kevent (dev, EVENT_RX_MEMORY); usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
usb_free_urb (urb); usb_free_urb (urb);
return -ENOMEM; return -ENOMEM;
} }
skb_reserve (skb, NET_IP_ALIGN);
entry = (struct skb_data *) skb->cb; entry = (struct skb_data *) skb->cb;
entry->urb = urb; entry->urb = urb;
......
...@@ -367,38 +367,28 @@ netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb, ...@@ -367,38 +367,28 @@ netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb,
{ {
struct i2400m *i2400m = net_dev_to_i2400m(net_dev); struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
struct device *dev = i2400m_dev(i2400m); struct device *dev = i2400m_dev(i2400m);
int result; int result = -1;
d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
if (skb_header_cloned(skb)) {
/* if (skb_header_cloned(skb) &&
* Make tcpdump/wireshark happy -- if they are pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
* running, the skb is cloned and we will overwrite goto drop;
* the mac fields in i2400m_tx_prep_header. Expand
* seems to fix this...
*/
result = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (result) {
result = NETDEV_TX_BUSY;
goto error_expand;
}
}
if (i2400m->state == I2400M_SS_IDLE) if (i2400m->state == I2400M_SS_IDLE)
result = i2400m_net_wake_tx(i2400m, net_dev, skb); result = i2400m_net_wake_tx(i2400m, net_dev, skb);
else else
result = i2400m_net_tx(i2400m, net_dev, skb); result = i2400m_net_tx(i2400m, net_dev, skb);
if (result < 0) if (result < 0) {
drop:
net_dev->stats.tx_dropped++; net_dev->stats.tx_dropped++;
else { } else {
net_dev->stats.tx_packets++; net_dev->stats.tx_packets++;
net_dev->stats.tx_bytes += skb->len; net_dev->stats.tx_bytes += skb->len;
} }
result = NETDEV_TX_OK; dev_kfree_skb(skb);
error_expand:
kfree_skb(skb);
d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result); d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result);
return result; return NETDEV_TX_OK;
} }
......
...@@ -257,7 +257,6 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, ...@@ -257,7 +257,6 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
if (rt) { if (rt) {
dev = rt->dst.dev; dev = rt->dst.dev;
dev_hold(dev);
dst_release(&rt->dst); dst_release(&rt->dst);
} }
} else } else
......
...@@ -1077,7 +1077,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, ...@@ -1077,7 +1077,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
struct net *net = dev_net(dev); struct net *net = dev_net(dev);
if (unlikely(!idev)) if (unlikely(!idev))
return NULL; return ERR_PTR(-ENODEV);
rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0); rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0);
if (unlikely(!rt)) { if (unlikely(!rt)) {
......
...@@ -943,20 +943,21 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, ...@@ -943,20 +943,21 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
} }
} }
if (nf_conntrack_event_report(IPCT_DESTROY, ct, if (del_timer(&ct->timeout)) {
NETLINK_CB(skb).pid, if (nf_conntrack_event_report(IPCT_DESTROY, ct,
nlmsg_report(nlh)) < 0) { NETLINK_CB(skb).pid,
nlmsg_report(nlh)) < 0) {
nf_ct_delete_from_lists(ct);
/* we failed to report the event, try later */
nf_ct_insert_dying_list(ct);
nf_ct_put(ct);
return 0;
}
/* death_by_timeout would report the event again */
set_bit(IPS_DYING_BIT, &ct->status);
nf_ct_delete_from_lists(ct); nf_ct_delete_from_lists(ct);
/* we failed to report the event, try later */
nf_ct_insert_dying_list(ct);
nf_ct_put(ct); nf_ct_put(ct);
return 0;
} }
/* death_by_timeout would report the event again */
set_bit(IPS_DYING_BIT, &ct->status);
nf_ct_kill(ct);
nf_ct_put(ct); nf_ct_put(ct);
return 0; return 0;
......
...@@ -469,11 +469,15 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) ...@@ -469,11 +469,15 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
if (slot->qlen == 1) { /* The flow is new */ if (slot->qlen == 1) { /* The flow is new */
if (q->tail == NULL) { /* It is the first flow */ if (q->tail == NULL) { /* It is the first flow */
slot->next = x; slot->next = x;
q->tail = slot;
} else { } else {
slot->next = q->tail->next; slot->next = q->tail->next;
q->tail->next = x; q->tail->next = x;
} }
/* We put this flow at the end of our flow list.
* This might sound unfair for a new flow to wait after old ones,
* but we could endup servicing new flows only, and freeze old ones.
*/
q->tail = slot;
/* We could use a bigger initial quantum for new flows */ /* We could use a bigger initial quantum for new flows */
slot->allot = q->scaled_quantum; slot->allot = q->scaled_quantum;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment