summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorDavid L Stevens <david.stevens@oracle.com>2015-02-11 13:20:17 (GMT)
committerDavid S. Miller <davem@davemloft.net>2015-02-12 03:41:40 (GMT)
commitf7d70f74811f5a522885b2962edeccb417e950c7 (patch)
treea67252c41e854d14fdc25772e95da17d55c3851b /drivers/net
parent1d6c4cca41840c82e6967a48137f622547244630 (diff)
downloadlinux-f7d70f74811f5a522885b2962edeccb417e950c7.tar.xz
sunvnet: don't change gso data on clones
This patch unclones an skb for the case where the sunvnet driver needs to change the segmentation size so that it doesn't interfere with TCP SACK's use of them. Signed-off-by: David L Stevens <david.stevens@oracle.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c23
1 files changed, 10 insertions, 13 deletions
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index 2b10b85..22e0cad 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -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)