|
|
@@ -1192,23 +1192,16 @@ static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb)
|
|
|
skb_pull(skb, maclen);
|
|
|
|
|
|
if (port->tso && gso_size < datalen) {
|
|
|
+ if (skb_unclone(skb, GFP_ATOMIC))
|
|
|
+ goto out_dropped;
|
|
|
+
|
|
|
/* segment to TSO size */
|
|
|
skb_shinfo(skb)->gso_size = datalen;
|
|
|
skb_shinfo(skb)->gso_segs = gso_segs;
|
|
|
-
|
|
|
- segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO);
|
|
|
-
|
|
|
- /* restore gso_size & gso_segs */
|
|
|
- skb_shinfo(skb)->gso_size = gso_size;
|
|
|
- skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len - hlen,
|
|
|
- gso_size);
|
|
|
- } else
|
|
|
- segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO);
|
|
|
- if (IS_ERR(segs)) {
|
|
|
- dev->stats.tx_dropped++;
|
|
|
- dev_kfree_skb_any(skb);
|
|
|
- return NETDEV_TX_OK;
|
|
|
}
|
|
|
+ segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO);
|
|
|
+ if (IS_ERR(segs))
|
|
|
+ goto out_dropped;
|
|
|
|
|
|
skb_push(skb, maclen);
|
|
|
skb_reset_mac_header(skb);
|
|
|
@@ -1246,6 +1239,10 @@ static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb)
|
|
|
if (!(status & NETDEV_TX_MASK))
|
|
|
dev_kfree_skb_any(skb);
|
|
|
return status;
|
|
|
+out_dropped:
|
|
|
+ dev->stats.tx_dropped++;
|
|
|
+ dev_kfree_skb_any(skb);
|
|
|
+ return NETDEV_TX_OK;
|
|
|
}
|
|
|
|
|
|
static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
|