# HG changeset patch
# User Jimi Xenidis <[EMAIL PROTECTED]>
# Node ID bcd09a8690af89f3c8ac1bc92a003d2a9cddb0c6
# Parent  968ced1469e8cbf36d00f437ac084bf064f6df00
Backport the fix in current xen-unstable tree.

Signed-off-by: Tony Breeds <[EMAIL PROTECTED]>
Signed-off-by: Jimi Xenidis <[EMAIL PROTECTED]>
---

---
 drivers/net/bnx2.c             |    2 +-
 drivers/net/chelsio/sge.c      |    2 +-
 drivers/net/e1000/e1000_main.c |    2 +-
 drivers/net/forcedeth.c        |    2 +-
 drivers/net/ixgb/ixgb_main.c   |    2 +-
 drivers/net/loopback.c         |    2 +-
 drivers/net/sky2.c             |    2 +-
 drivers/net/typhoon.c          |    4 ++--
 drivers/s390/net/qeth_main.c   |    2 +-
 include/linux/netdevice.h      |   14 ++++++++------
 include/linux/skbuff.h         |    5 +++++
 include/net/protocol.h         |    1 +
 include/net/tcp.h              |    1 +
 net/bridge/br_netfilter.c      |    2 +-
 net/core/dev.c                 |   36 ++++++++++++++++++++++++++++++++----
 net/ipv4/af_inet.c             |   36 ++++++++++++++++++++++++++++++++++++
 net/ipv4/ip_output.c           |    4 ++--
 net/ipv4/tcp_ipv4.c            |   18 ++++++++++++++++++
 net/ipv4/xfrm4_output.c        |    2 +-
 net/ipv6/ip6_output.c          |    2 +-
 net/ipv6/xfrm6_output.c        |    2 +-
 21 files changed, 117 insertions(+), 26 deletions(-)

diff -r 968ced1469e8 -r bcd09a8690af drivers/net/bnx2.c
--- a/drivers/net/bnx2.c        Tue Oct 17 17:03:31 2006 -0400
+++ b/drivers/net/bnx2.c        Tue Oct 24 06:10:42 2006 -0400
@@ -1640,7 +1640,7 @@ bnx2_tx_int(struct bnx2 *bp)
                skb = tx_buf->skb;
 #ifdef BCM_TSO 
                /* partial BD completions possible with TSO packets */
-               if (skb_shinfo(skb)->gso_size) {
+               if (skb_is_gso(skb)) {
                        u16 last_idx, last_ring_idx;
 
                        last_idx = sw_cons +
diff -r 968ced1469e8 -r bcd09a8690af drivers/net/chelsio/sge.c
--- a/drivers/net/chelsio/sge.c Tue Oct 17 17:03:31 2006 -0400
+++ b/drivers/net/chelsio/sge.c Tue Oct 24 06:10:42 2006 -0400
@@ -1418,7 +1418,7 @@ int t1_start_xmit(struct sk_buff *skb, s
        struct cpl_tx_pkt *cpl;
 
 #ifdef NETIF_F_TSO
-       if (skb_shinfo(skb)->gso_size) {
+       if (skb_is_gso(skb)) {
                int eth_type;
                struct cpl_tx_pkt_lso *hdr;
 
diff -r 968ced1469e8 -r bcd09a8690af drivers/net/e1000/e1000_main.c
--- a/drivers/net/e1000/e1000_main.c    Tue Oct 17 17:03:31 2006 -0400
+++ b/drivers/net/e1000/e1000_main.c    Tue Oct 24 06:10:42 2006 -0400
@@ -2394,7 +2394,7 @@ e1000_tso(struct e1000_adapter *adapter,
        uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
        int err;
 
-       if (skb_shinfo(skb)->gso_size) {
+       if (skb_is_gso(skb)) {
                if (skb_header_cloned(skb)) {
                        err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
                        if (err)
diff -r 968ced1469e8 -r bcd09a8690af drivers/net/forcedeth.c
--- a/drivers/net/forcedeth.c   Tue Oct 17 17:03:31 2006 -0400
+++ b/drivers/net/forcedeth.c   Tue Oct 24 06:10:42 2006 -0400
@@ -1495,7 +1495,7 @@ static int nv_start_xmit(struct sk_buff 
        np->tx_skbuff[nr] = skb;
 
 #ifdef NETIF_F_TSO
-       if (skb_shinfo(skb)->gso_size)
+       if (skb_is_gso(skb))
                tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << 
NV_TX2_TSO_SHIFT);
        else
 #endif
diff -r 968ced1469e8 -r bcd09a8690af drivers/net/ixgb/ixgb_main.c
--- a/drivers/net/ixgb/ixgb_main.c      Tue Oct 17 17:03:31 2006 -0400
+++ b/drivers/net/ixgb/ixgb_main.c      Tue Oct 24 06:10:42 2006 -0400
@@ -1173,7 +1173,7 @@ ixgb_tso(struct ixgb_adapter *adapter, s
        uint16_t ipcse, tucse, mss;
        int err;
 
-       if(likely(skb_shinfo(skb)->gso_size)) {
+       if (likely(skb_is_gso(skb))) {
                if (skb_header_cloned(skb)) {
                        err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
                        if (err)
diff -r 968ced1469e8 -r bcd09a8690af drivers/net/loopback.c
--- a/drivers/net/loopback.c    Tue Oct 17 17:03:31 2006 -0400
+++ b/drivers/net/loopback.c    Tue Oct 24 06:10:42 2006 -0400
@@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff 
 #endif
 
 #ifdef LOOPBACK_TSO
-       if (skb_shinfo(skb)->gso_size) {
+       if (skb_is_gso(skb)) {
                BUG_ON(skb->protocol != htons(ETH_P_IP));
                BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
 
diff -r 968ced1469e8 -r bcd09a8690af drivers/net/sky2.c
--- a/drivers/net/sky2.c        Tue Oct 17 17:03:31 2006 -0400
+++ b/drivers/net/sky2.c        Tue Oct 24 06:10:42 2006 -0400
@@ -1160,7 +1160,7 @@ static unsigned tx_le_req(const struct s
        count = sizeof(dma_addr_t) / sizeof(u32);
        count += skb_shinfo(skb)->nr_frags * count;
 
-       if (skb_shinfo(skb)->gso_size)
+       if (skb_is_gso(skb))
                ++count;
 
        if (skb->ip_summed == CHECKSUM_HW)
diff -r 968ced1469e8 -r bcd09a8690af drivers/net/typhoon.c
--- a/drivers/net/typhoon.c     Tue Oct 17 17:03:31 2006 -0400
+++ b/drivers/net/typhoon.c     Tue Oct 24 06:10:42 2006 -0400
@@ -805,7 +805,7 @@ typhoon_start_tx(struct sk_buff *skb, st
         * If problems develop with TSO, check this first.
         */
        numDesc = skb_shinfo(skb)->nr_frags + 1;
-       if(skb_tso_size(skb))
+       if (skb_is_gso(skb))
                numDesc++;
 
        /* When checking for free space in the ring, we need to also
@@ -845,7 +845,7 @@ typhoon_start_tx(struct sk_buff *skb, st
                                TYPHOON_TX_PF_VLAN_TAG_SHIFT);
        }
 
-       if(skb_tso_size(skb)) {
+       if (skb_is_gso(skb)) {
                first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT;
                first_txd->numDesc++;
 
diff -r 968ced1469e8 -r bcd09a8690af drivers/s390/net/qeth_main.c
--- a/drivers/s390/net/qeth_main.c      Tue Oct 17 17:03:31 2006 -0400
+++ b/drivers/s390/net/qeth_main.c      Tue Oct 24 06:10:42 2006 -0400
@@ -4453,7 +4453,7 @@ qeth_send_packet(struct qeth_card *card,
        queue = card->qdio.out_qs
                [qeth_get_priority_queue(card, skb, ipv, cast_type)];
 
-       if (skb_shinfo(skb)->gso_size)
+       if (skb_is_gso(skb))
                large_send = card->options.large_send;
 
        /*are we able to do TSO ? If so ,prepare and send it from here */
diff -r 968ced1469e8 -r bcd09a8690af include/linux/netdevice.h
--- a/include/linux/netdevice.h Tue Oct 17 17:03:31 2006 -0400
+++ b/include/linux/netdevice.h Tue Oct 24 06:10:42 2006 -0400
@@ -547,6 +547,7 @@ struct packet_type {
                                         struct net_device *);
        struct sk_buff          *(*gso_segment)(struct sk_buff *skb,
                                                int features);
+       int                     (*gso_send_check)(struct sk_buff *skb);
        void                    *af_packet_priv;
        struct list_head        list;
 };
@@ -921,10 +922,10 @@ static inline void netif_tx_lock_bh(stru
 
 static inline int netif_tx_trylock(struct net_device *dev)
 {
-       int err = spin_trylock(&dev->_xmit_lock);
-       if (!err)
+       int ok = spin_trylock(&dev->_xmit_lock);
+       if (likely(ok))
                dev->xmit_lock_owner = smp_processor_id();
-       return err;
+       return ok;
 }
 
 static inline void netif_tx_unlock(struct net_device *dev)
@@ -993,14 +994,15 @@ extern void linkwatch_run_queue(void);
 
 static inline int skb_gso_ok(struct sk_buff *skb, int features)
 {
-       int feature = skb_shinfo(skb)->gso_size ?
-                     skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT : 0;
+       int feature = skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT;
        return (features & feature) == feature;
 }
 
 static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
 {
-       return !skb_gso_ok(skb, dev->features);
+       return skb_is_gso(skb) &&
+              (!skb_gso_ok(skb, dev->features) ||
+               unlikely(skb->ip_summed != CHECKSUM_HW));
 }
 
 #endif /* __KERNEL__ */
diff -r 968ced1469e8 -r bcd09a8690af include/linux/skbuff.h
--- a/include/linux/skbuff.h    Tue Oct 17 17:03:31 2006 -0400
+++ b/include/linux/skbuff.h    Tue Oct 24 06:10:42 2006 -0400
@@ -1459,5 +1459,10 @@ static inline void skb_init_secmark(stru
 { }
 #endif
 
+static inline int skb_is_gso(const struct sk_buff *skb)
+{
+       return skb_shinfo(skb)->gso_size;
+}
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SKBUFF_H */
diff -r 968ced1469e8 -r bcd09a8690af include/net/protocol.h
--- a/include/net/protocol.h    Tue Oct 17 17:03:31 2006 -0400
+++ b/include/net/protocol.h    Tue Oct 24 06:10:42 2006 -0400
@@ -36,6 +36,7 @@ struct net_protocol {
 struct net_protocol {
        int                     (*handler)(struct sk_buff *skb);
        void                    (*err_handler)(struct sk_buff *skb, u32 info);
+       int                     (*gso_send_check)(struct sk_buff *skb);
        struct sk_buff         *(*gso_segment)(struct sk_buff *skb,
                                               int features);
        int                     no_policy;
diff -r 968ced1469e8 -r bcd09a8690af include/net/tcp.h
--- a/include/net/tcp.h Tue Oct 17 17:03:31 2006 -0400
+++ b/include/net/tcp.h Tue Oct 24 06:10:42 2006 -0400
@@ -1086,6 +1086,7 @@ extern struct request_sock_ops tcp_reque
 
 extern int tcp_v4_destroy_sock(struct sock *sk);
 
+extern int tcp_v4_gso_send_check(struct sk_buff *skb);
 extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features);
 
 #ifdef CONFIG_PROC_FS
diff -r 968ced1469e8 -r bcd09a8690af net/bridge/br_netfilter.c
--- a/net/bridge/br_netfilter.c Tue Oct 17 17:03:31 2006 -0400
+++ b/net/bridge/br_netfilter.c Tue Oct 24 06:10:42 2006 -0400
@@ -761,7 +761,7 @@ static int br_nf_dev_queue_xmit(struct s
 {
        if (skb->protocol == htons(ETH_P_IP) &&
            skb->len > skb->dev->mtu &&
-           !skb_shinfo(skb)->gso_size)
+           !skb_is_gso(skb))
                return ip_fragment(skb, br_dev_queue_push_xmit);
        else
                return br_dev_queue_push_xmit(skb);
diff -r 968ced1469e8 -r bcd09a8690af net/core/dev.c
--- a/net/core/dev.c    Tue Oct 17 17:03:31 2006 -0400
+++ b/net/core/dev.c    Tue Oct 24 06:10:42 2006 -0400
@@ -1169,9 +1169,17 @@ int skb_checksum_help(struct sk_buff *sk
        unsigned int csum;
        int ret = 0, offset = skb->h.raw - skb->data;
 
-       if (inward) {
-               skb->ip_summed = CHECKSUM_NONE;
-               goto out;
+       if (inward)
+               goto out_set_summed;
+
+       if (unlikely(skb_shinfo(skb)->gso_size)) {
+               static int warned;
+
+               WARN_ON(!warned);
+               warned = 1;
+
+               /* Let GSO fix up the checksum. */
+               goto out_set_summed;
        }
 
        if (skb_cloned(skb)) {
@@ -1188,6 +1196,8 @@ int skb_checksum_help(struct sk_buff *sk
        BUG_ON(skb->csum + 2 > offset);
 
        *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
+
+out_set_summed:
        skb->ip_summed = CHECKSUM_NONE;
 out:   
        return ret;
@@ -1208,17 +1218,35 @@ struct sk_buff *skb_gso_segment(struct s
        struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
        struct packet_type *ptype;
        int type = skb->protocol;
+       int err;
 
        BUG_ON(skb_shinfo(skb)->frag_list);
-       BUG_ON(skb->ip_summed != CHECKSUM_HW);
 
        skb->mac.raw = skb->data;
        skb->mac_len = skb->nh.raw - skb->data;
        __skb_pull(skb, skb->mac_len);
 
+       if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
+               static int warned;
+
+               WARN_ON(!warned);
+               warned = 1;
+
+               if (skb_header_cloned(skb) &&
+                   (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+                       return ERR_PTR(err);
+       }
+
        rcu_read_lock();
        list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
                if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
+                       if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
+                               err = ptype->gso_send_check(skb);
+                               segs = ERR_PTR(err);
+                               if (err || skb_gso_ok(skb, features))
+                                       break;
+                               __skb_push(skb, skb->data - skb->nh.raw);
+                       }
                        segs = ptype->gso_segment(skb, features);
                        break;
                }
diff -r 968ced1469e8 -r bcd09a8690af net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c        Tue Oct 17 17:03:31 2006 -0400
+++ b/net/ipv4/af_inet.c        Tue Oct 24 06:10:42 2006 -0400
@@ -1097,6 +1097,40 @@ int inet_sk_rebuild_header(struct sock *
 
 EXPORT_SYMBOL(inet_sk_rebuild_header);
 
+static int inet_gso_send_check(struct sk_buff *skb)
+{
+       struct iphdr *iph;
+       struct net_protocol *ops;
+       int proto;
+       int ihl;
+       int err = -EINVAL;
+
+       if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
+               goto out;
+
+       iph = skb->nh.iph;
+       ihl = iph->ihl * 4;
+       if (ihl < sizeof(*iph))
+               goto out;
+
+       if (unlikely(!pskb_may_pull(skb, ihl)))
+               goto out;
+
+       skb->h.raw = __skb_pull(skb, ihl);
+       iph = skb->nh.iph;
+       proto = iph->protocol & (MAX_INET_PROTOS - 1);
+       err = -EPROTONOSUPPORT;
+
+       rcu_read_lock();
+       ops = rcu_dereference(inet_protos[proto]);
+       if (likely(ops && ops->gso_send_check))
+               err = ops->gso_send_check(skb);
+       rcu_read_unlock();
+
+out:
+       return err;
+}
+
 static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
@@ -1154,6 +1188,7 @@ static struct net_protocol tcp_protocol 
 static struct net_protocol tcp_protocol = {
        .handler =      tcp_v4_rcv,
        .err_handler =  tcp_v4_err,
+       .gso_send_check = tcp_v4_gso_send_check,
        .gso_segment =  tcp_tso_segment,
        .no_policy =    1,
 };
@@ -1200,6 +1235,7 @@ static struct packet_type ip_packet_type
 static struct packet_type ip_packet_type = {
        .type = __constant_htons(ETH_P_IP),
        .func = ip_rcv,
+       .gso_send_check = inet_gso_send_check,
        .gso_segment = inet_gso_segment,
 };
 
diff -r 968ced1469e8 -r bcd09a8690af net/ipv4/ip_output.c
--- a/net/ipv4/ip_output.c      Tue Oct 17 17:03:31 2006 -0400
+++ b/net/ipv4/ip_output.c      Tue Oct 24 06:10:42 2006 -0400
@@ -210,7 +210,7 @@ static inline int ip_finish_output(struc
                return dst_output(skb);
        }
 #endif
-       if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size)
+       if (skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb))
                return ip_fragment(skb, ip_finish_output2);
        else
                return ip_finish_output2(skb);
@@ -1096,7 +1096,7 @@ ssize_t   ip_append_page(struct sock *sk, 
        while (size > 0) {
                int i;
 
-               if (skb_shinfo(skb)->gso_size)
+               if (skb_is_gso(skb))
                        len = size;
                else {
 
diff -r 968ced1469e8 -r bcd09a8690af net/ipv4/tcp_ipv4.c
--- a/net/ipv4/tcp_ipv4.c       Tue Oct 17 17:03:31 2006 -0400
+++ b/net/ipv4/tcp_ipv4.c       Tue Oct 24 06:10:42 2006 -0400
@@ -494,6 +494,24 @@ void tcp_v4_send_check(struct sock *sk, 
                                                      th->doff << 2,
                                                      skb->csum));
        }
+}
+
+int tcp_v4_gso_send_check(struct sk_buff *skb)
+{
+       struct iphdr *iph;
+       struct tcphdr *th;
+
+       if (!pskb_may_pull(skb, sizeof(*th)))
+               return -EINVAL;
+
+       iph = skb->nh.iph;
+       th = skb->h.th;
+
+       th->check = 0;
+       th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0);
+       skb->csum = offsetof(struct tcphdr, check);
+       skb->ip_summed = CHECKSUM_HW;
+       return 0;
 }
 
 /*
diff -r 968ced1469e8 -r bcd09a8690af net/ipv4/xfrm4_output.c
--- a/net/ipv4/xfrm4_output.c   Tue Oct 17 17:03:31 2006 -0400
+++ b/net/ipv4/xfrm4_output.c   Tue Oct 24 06:10:42 2006 -0400
@@ -140,7 +140,7 @@ static int xfrm4_output_finish(struct sk
        }
 #endif
 
-       if (!skb_shinfo(skb)->gso_size)
+       if (!skb_is_gso(skb))
                return xfrm4_output_finish2(skb);
 
        skb->protocol = htons(ETH_P_IP);
diff -r 968ced1469e8 -r bcd09a8690af net/ipv6/ip6_output.c
--- a/net/ipv6/ip6_output.c     Tue Oct 17 17:03:31 2006 -0400
+++ b/net/ipv6/ip6_output.c     Tue Oct 24 06:10:42 2006 -0400
@@ -148,7 +148,7 @@ static int ip6_output2(struct sk_buff *s
 
 int ip6_output(struct sk_buff *skb)
 {
-       if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) ||
+       if ((skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) ||
                                dst_allfrag(skb->dst))
                return ip6_fragment(skb, ip6_output2);
        else
diff -r 968ced1469e8 -r bcd09a8690af net/ipv6/xfrm6_output.c
--- a/net/ipv6/xfrm6_output.c   Tue Oct 17 17:03:31 2006 -0400
+++ b/net/ipv6/xfrm6_output.c   Tue Oct 24 06:10:42 2006 -0400
@@ -122,7 +122,7 @@ static int xfrm6_output_finish(struct sk
 {
        struct sk_buff *segs;
 
-       if (!skb_shinfo(skb)->gso_size)
+       if (!skb_is_gso(skb))
                return xfrm6_output_finish2(skb);
 
        skb->protocol = htons(ETH_P_IP);

_______________________________________________
Xen-ppc-devel mailing list
Xen-ppc-devel@lists.xensource.com
http://lists.xensource.com/xen-ppc-devel

Reply via email to