diff options
author | John Fastabend <john.r.fastabend@intel.com> | 2010-06-16 10:18:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-23 15:58:41 -0400 |
commit | 6afff0caa721211e8c04bdc7627ee3bff95bcb95 (patch) | |
tree | ec0b2f5b2e15f847ffad3db9501bbd9661bf671b /net/core | |
parent | 1dc8d8c06d4002be4d1373fc06f25cd589be47e1 (diff) |
net: consolidate netif_needs_gso() checks
netif_needs_gso() is checked twice in the TX path once,
before submitting the skb to the qdisc and once after
it is dequeued from the qdisc just before calling
ndo_hard_start(). This opens a window for a user to
change the gso/tso or tx checksum settings that can
cause netif_needs_gso to be true in one check and false
in the other.
Specifically, changing TX checksum setting may cause
the warning in skb_gso_segment() to be triggered if
the checksum is calculated earlier.
This consolidates the netif_needs_gso() calls so that
the stack only checks if gso is needed in
dev_hard_start_xmit().
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev.c | 68 |
1 files changed, 32 insertions, 36 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 5902426ef585..7f390b52caab 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1895,6 +1895,22 @@ static inline void skb_orphan_try(struct sk_buff *skb) | |||
1895 | skb_orphan(skb); | 1895 | skb_orphan(skb); |
1896 | } | 1896 | } |
1897 | 1897 | ||
1898 | /* | ||
1899 | * Returns true if either: | ||
1900 | * 1. skb has frag_list and the device doesn't support FRAGLIST, or | ||
1901 | * 2. skb is fragmented and the device does not support SG, or if | ||
1902 | * at least one of fragments is in highmem and device does not | ||
1903 | * support DMA from it. | ||
1904 | */ | ||
1905 | static inline int skb_needs_linearize(struct sk_buff *skb, | ||
1906 | struct net_device *dev) | ||
1907 | { | ||
1908 | return skb_is_nonlinear(skb) && | ||
1909 | ((skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) || | ||
1910 | (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) || | ||
1911 | illegal_highdma(dev, skb)))); | ||
1912 | } | ||
1913 | |||
1898 | int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, | 1914 | int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, |
1899 | struct netdev_queue *txq) | 1915 | struct netdev_queue *txq) |
1900 | { | 1916 | { |
@@ -1919,6 +1935,22 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, | |||
1919 | goto out_kfree_skb; | 1935 | goto out_kfree_skb; |
1920 | if (skb->next) | 1936 | if (skb->next) |
1921 | goto gso; | 1937 | goto gso; |
1938 | } else { | ||
1939 | if (skb_needs_linearize(skb, dev) && | ||
1940 | __skb_linearize(skb)) | ||
1941 | goto out_kfree_skb; | ||
1942 | |||
1943 | /* If packet is not checksummed and device does not | ||
1944 | * support checksumming for this protocol, complete | ||
1945 | * checksumming here. | ||
1946 | */ | ||
1947 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
1948 | skb_set_transport_header(skb, skb->csum_start - | ||
1949 | skb_headroom(skb)); | ||
1950 | if (!dev_can_checksum(dev, skb) && | ||
1951 | skb_checksum_help(skb)) | ||
1952 | goto out_kfree_skb; | ||
1953 | } | ||
1922 | } | 1954 | } |
1923 | 1955 | ||
1924 | rc = ops->ndo_start_xmit(skb, dev); | 1956 | rc = ops->ndo_start_xmit(skb, dev); |
@@ -2089,22 +2121,6 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, | |||
2089 | return rc; | 2121 | return rc; |
2090 | } | 2122 | } |
2091 | 2123 | ||
2092 | /* | ||
2093 | * Returns true if either: | ||
2094 | * 1. skb has frag_list and the device doesn't support FRAGLIST, or | ||
2095 | * 2. skb is fragmented and the device does not support SG, or if | ||
2096 | * at least one of fragments is in highmem and device does not | ||
2097 | * support DMA from it. | ||
2098 | */ | ||
2099 | static inline int skb_needs_linearize(struct sk_buff *skb, | ||
2100 | struct net_device *dev) | ||
2101 | { | ||
2102 | return skb_is_nonlinear(skb) && | ||
2103 | ((skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) || | ||
2104 | (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) || | ||
2105 | illegal_highdma(dev, skb)))); | ||
2106 | } | ||
2107 | |||
2108 | /** | 2124 | /** |
2109 | * dev_queue_xmit - transmit a buffer | 2125 | * dev_queue_xmit - transmit a buffer |
2110 | * @skb: buffer to transmit | 2126 | * @skb: buffer to transmit |
@@ -2137,25 +2153,6 @@ int dev_queue_xmit(struct sk_buff *skb) | |||
2137 | struct Qdisc *q; | 2153 | struct Qdisc *q; |
2138 | int rc = -ENOMEM; | 2154 | int rc = -ENOMEM; |
2139 | 2155 | ||
2140 | /* GSO will handle the following emulations directly. */ | ||
2141 | if (netif_needs_gso(dev, skb)) | ||
2142 | goto gso; | ||
2143 | |||
2144 | /* Convert a paged skb to linear, if required */ | ||
2145 | if (skb_needs_linearize(skb, dev) && __skb_linearize(skb)) | ||
2146 | goto out_kfree_skb; | ||
2147 | |||
2148 | /* If packet is not checksummed and device does not support | ||
2149 | * checksumming for this protocol, complete checksumming here. | ||
2150 | */ | ||
2151 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
2152 | skb_set_transport_header(skb, skb->csum_start - | ||
2153 | skb_headroom(skb)); | ||
2154 | if (!dev_can_checksum(dev, skb) && skb_checksum_help(skb)) | ||
2155 | goto out_kfree_skb; | ||
2156 | } | ||
2157 | |||
2158 | gso: | ||
2159 | /* Disable soft irqs for various locks below. Also | 2156 | /* Disable soft irqs for various locks below. Also |
2160 | * stops preemption for RCU. | 2157 | * stops preemption for RCU. |
2161 | */ | 2158 | */ |
@@ -2214,7 +2211,6 @@ gso: | |||
2214 | rc = -ENETDOWN; | 2211 | rc = -ENETDOWN; |
2215 | rcu_read_unlock_bh(); | 2212 | rcu_read_unlock_bh(); |
2216 | 2213 | ||
2217 | out_kfree_skb: | ||
2218 | kfree_skb(skb); | 2214 | kfree_skb(skb); |
2219 | return rc; | 2215 | return rc; |
2220 | out: | 2216 | out: |