aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-06-09 19:10:40 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-18 00:30:16 -0400
commit364c6badde0dd62a0a38e5ed67f85d87d6665780 (patch)
tree56c8ad3e3f45fafec010da4f5858825db5dbc86c
parent932ff279a43ab7257942cddff2595acd541cc49b (diff)
[NET]: Clean up skb_linearize
The linearisation operation doesn't need to be super-optimised. So we can replace __skb_linearize with __pskb_pull_tail which does the same thing but is more general. Also, most users of skb_linearize end up testing whether the skb is linear or not so it helps to make skb_linearize do just that. Some callers of skb_linearize also use it to copy cloned data, so it's useful to have a new function skb_linearize_cow to copy the data if it's either non-linear or cloned. Last but not least, I've removed the gfp argument since nobody uses it anymore. If it's ever needed we can easily add it back. Misc bugs fixed by this patch: * via-velocity error handling (also, no SG => no frags) Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/block/aoe/aoenet.c3
-rw-r--r--drivers/net/mv643xx_eth.c2
-rw-r--r--drivers/net/via-velocity.c10
-rw-r--r--include/linux/skbuff.h24
-rw-r--r--net/core/dev.c63
-rw-r--r--net/decnet/dn_nsp_in.c3
-rw-r--r--net/decnet/dn_route.c3
-rw-r--r--net/ipv4/ipcomp.c11
-rw-r--r--net/ipv6/ipcomp6.c11
9 files changed, 39 insertions, 91 deletions
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index fdff774b8ab9..c1434ed11880 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -116,8 +116,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
116 skb = skb_share_check(skb, GFP_ATOMIC); 116 skb = skb_share_check(skb, GFP_ATOMIC);
117 if (skb == NULL) 117 if (skb == NULL)
118 return 0; 118 return 0;
119 if (skb_is_nonlinear(skb)) 119 if (skb_linearize(skb))
120 if (skb_linearize(skb, GFP_ATOMIC) < 0)
121 goto exit; 120 goto exit;
122 if (!is_aoe_netif(ifp)) 121 if (!is_aoe_netif(ifp))
123 goto exit; 122 goto exit;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 411f4d809c47..625ff61c9988 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1200,7 +1200,7 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
1200 } 1200 }
1201 1201
1202 if (has_tiny_unaligned_frags(skb)) { 1202 if (has_tiny_unaligned_frags(skb)) {
1203 if ((skb_linearize(skb, GFP_ATOMIC) != 0)) { 1203 if (__skb_linearize(skb)) {
1204 stats->tx_dropped++; 1204 stats->tx_dropped++;
1205 printk(KERN_DEBUG "%s: failed to linearize tiny " 1205 printk(KERN_DEBUG "%s: failed to linearize tiny "
1206 "unaligned fragment\n", dev->name); 1206 "unaligned fragment\n", dev->name);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index ed1f837c8fda..2eb6b5f9ba0d 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -1899,6 +1899,13 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
1899 1899
1900 int pktlen = skb->len; 1900 int pktlen = skb->len;
1901 1901
1902#ifdef VELOCITY_ZERO_COPY_SUPPORT
1903 if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
1904 kfree_skb(skb);
1905 return 0;
1906 }
1907#endif
1908
1902 spin_lock_irqsave(&vptr->lock, flags); 1909 spin_lock_irqsave(&vptr->lock, flags);
1903 1910
1904 index = vptr->td_curr[qnum]; 1911 index = vptr->td_curr[qnum];
@@ -1914,8 +1921,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
1914 */ 1921 */
1915 if (pktlen < ETH_ZLEN) { 1922 if (pktlen < ETH_ZLEN) {
1916 /* Cannot occur until ZC support */ 1923 /* Cannot occur until ZC support */
1917 if(skb_linearize(skb, GFP_ATOMIC))
1918 return 0;
1919 pktlen = ETH_ZLEN; 1924 pktlen = ETH_ZLEN;
1920 memcpy(tdinfo->buf, skb->data, skb->len); 1925 memcpy(tdinfo->buf, skb->data, skb->len);
1921 memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len); 1926 memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
@@ -1933,7 +1938,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
1933 int nfrags = skb_shinfo(skb)->nr_frags; 1938 int nfrags = skb_shinfo(skb)->nr_frags;
1934 tdinfo->skb = skb; 1939 tdinfo->skb = skb;
1935 if (nfrags > 6) { 1940 if (nfrags > 6) {
1936 skb_linearize(skb, GFP_ATOMIC);
1937 memcpy(tdinfo->buf, skb->data, skb->len); 1941 memcpy(tdinfo->buf, skb->data, skb->len);
1938 tdinfo->skb_dma[0] = tdinfo->buf_dma; 1942 tdinfo->skb_dma[0] = tdinfo->buf_dma;
1939 td_ptr->tdesc0.pktsize = 1943 td_ptr->tdesc0.pktsize =
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index fe2c58e5306f..830f58fa03a2 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1169,18 +1169,34 @@ static inline int skb_can_coalesce(struct sk_buff *skb, int i,
1169 return 0; 1169 return 0;
1170} 1170}
1171 1171
1172static inline int __skb_linearize(struct sk_buff *skb)
1173{
1174 return __pskb_pull_tail(skb, skb->data_len) ? 0 : -ENOMEM;
1175}
1176
1172/** 1177/**
1173 * skb_linearize - convert paged skb to linear one 1178 * skb_linearize - convert paged skb to linear one
1174 * @skb: buffer to linarize 1179 * @skb: buffer to linarize
1175 * @gfp: allocation mode
1176 * 1180 *
1177 * If there is no free memory -ENOMEM is returned, otherwise zero 1181 * If there is no free memory -ENOMEM is returned, otherwise zero
1178 * is returned and the old skb data released. 1182 * is returned and the old skb data released.
1179 */ 1183 */
1180extern int __skb_linearize(struct sk_buff *skb, gfp_t gfp); 1184static inline int skb_linearize(struct sk_buff *skb)
1181static inline int skb_linearize(struct sk_buff *skb, gfp_t gfp) 1185{
1186 return skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0;
1187}
1188
1189/**
1190 * skb_linearize_cow - make sure skb is linear and writable
1191 * @skb: buffer to process
1192 *
1193 * If there is no free memory -ENOMEM is returned, otherwise zero
1194 * is returned and the old skb data released.
1195 */
1196static inline int skb_linearize_cow(struct sk_buff *skb)
1182{ 1197{
1183 return __skb_linearize(skb, gfp); 1198 return skb_is_nonlinear(skb) || skb_cloned(skb) ?
1199 __skb_linearize(skb) : 0;
1184} 1200}
1185 1201
1186/** 1202/**
diff --git a/net/core/dev.c b/net/core/dev.c
index 1b09f1cae46e..91361bc2b682 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1222,64 +1222,6 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
1222#define illegal_highdma(dev, skb) (0) 1222#define illegal_highdma(dev, skb) (0)
1223#endif 1223#endif
1224 1224
1225/* Keep head the same: replace data */
1226int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask)
1227{
1228 unsigned int size;
1229 u8 *data;
1230 long offset;
1231 struct skb_shared_info *ninfo;
1232 int headerlen = skb->data - skb->head;
1233 int expand = (skb->tail + skb->data_len) - skb->end;
1234
1235 if (skb_shared(skb))
1236 BUG();
1237
1238 if (expand <= 0)
1239 expand = 0;
1240
1241 size = skb->end - skb->head + expand;
1242 size = SKB_DATA_ALIGN(size);
1243 data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
1244 if (!data)
1245 return -ENOMEM;
1246
1247 /* Copy entire thing */
1248 if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len))
1249 BUG();
1250
1251 /* Set up shinfo */
1252 ninfo = (struct skb_shared_info*)(data + size);
1253 atomic_set(&ninfo->dataref, 1);
1254 ninfo->tso_size = skb_shinfo(skb)->tso_size;
1255 ninfo->tso_segs = skb_shinfo(skb)->tso_segs;
1256 ninfo->nr_frags = 0;
1257 ninfo->frag_list = NULL;
1258
1259 /* Offset between the two in bytes */
1260 offset = data - skb->head;
1261
1262 /* Free old data. */
1263 skb_release_data(skb);
1264
1265 skb->head = data;
1266 skb->end = data + size;
1267
1268 /* Set up new pointers */
1269 skb->h.raw += offset;
1270 skb->nh.raw += offset;
1271 skb->mac.raw += offset;
1272 skb->tail += offset;
1273 skb->data += offset;
1274
1275 /* We are no longer a clone, even if we were. */
1276 skb->cloned = 0;
1277
1278 skb->tail += skb->data_len;
1279 skb->data_len = 0;
1280 return 0;
1281}
1282
1283#define HARD_TX_LOCK(dev, cpu) { \ 1225#define HARD_TX_LOCK(dev, cpu) { \
1284 if ((dev->features & NETIF_F_LLTX) == 0) { \ 1226 if ((dev->features & NETIF_F_LLTX) == 0) { \
1285 netif_tx_lock(dev); \ 1227 netif_tx_lock(dev); \
@@ -1326,7 +1268,7 @@ int dev_queue_xmit(struct sk_buff *skb)
1326 1268
1327 if (skb_shinfo(skb)->frag_list && 1269 if (skb_shinfo(skb)->frag_list &&
1328 !(dev->features & NETIF_F_FRAGLIST) && 1270 !(dev->features & NETIF_F_FRAGLIST) &&
1329 __skb_linearize(skb, GFP_ATOMIC)) 1271 __skb_linearize(skb))
1330 goto out_kfree_skb; 1272 goto out_kfree_skb;
1331 1273
1332 /* Fragmented skb is linearized if device does not support SG, 1274 /* Fragmented skb is linearized if device does not support SG,
@@ -1335,7 +1277,7 @@ int dev_queue_xmit(struct sk_buff *skb)
1335 */ 1277 */
1336 if (skb_shinfo(skb)->nr_frags && 1278 if (skb_shinfo(skb)->nr_frags &&
1337 (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) && 1279 (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
1338 __skb_linearize(skb, GFP_ATOMIC)) 1280 __skb_linearize(skb))
1339 goto out_kfree_skb; 1281 goto out_kfree_skb;
1340 1282
1341 /* If packet is not checksummed and device does not support 1283 /* If packet is not checksummed and device does not support
@@ -3473,7 +3415,6 @@ subsys_initcall(net_dev_init);
3473EXPORT_SYMBOL(__dev_get_by_index); 3415EXPORT_SYMBOL(__dev_get_by_index);
3474EXPORT_SYMBOL(__dev_get_by_name); 3416EXPORT_SYMBOL(__dev_get_by_name);
3475EXPORT_SYMBOL(__dev_remove_pack); 3417EXPORT_SYMBOL(__dev_remove_pack);
3476EXPORT_SYMBOL(__skb_linearize);
3477EXPORT_SYMBOL(dev_valid_name); 3418EXPORT_SYMBOL(dev_valid_name);
3478EXPORT_SYMBOL(dev_add_pack); 3419EXPORT_SYMBOL(dev_add_pack);
3479EXPORT_SYMBOL(dev_alloc_name); 3420EXPORT_SYMBOL(dev_alloc_name);
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
index 547523b41c81..a2ba9db1c376 100644
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -801,8 +801,7 @@ got_it:
801 * We linearize everything except data segments here. 801 * We linearize everything except data segments here.
802 */ 802 */
803 if (cb->nsp_flags & ~0x60) { 803 if (cb->nsp_flags & ~0x60) {
804 if (unlikely(skb_is_nonlinear(skb)) && 804 if (unlikely(skb_linearize(skb)))
805 skb_linearize(skb, GFP_ATOMIC) != 0)
806 goto free_out; 805 goto free_out;
807 } 806 }
808 807
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index e172cf98d7fc..5abf7057af00 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -629,8 +629,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
629 padlen); 629 padlen);
630 630
631 if (flags & DN_RT_PKT_CNTL) { 631 if (flags & DN_RT_PKT_CNTL) {
632 if (unlikely(skb_is_nonlinear(skb)) && 632 if (unlikely(skb_linearize(skb)))
633 skb_linearize(skb, GFP_ATOMIC) != 0)
634 goto dump_it; 633 goto dump_it;
635 634
636 switch(flags & DN_RT_CNTL_MSK) { 635 switch(flags & DN_RT_CNTL_MSK) {
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 8e243589045f..3ed8b57a1002 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -80,15 +80,12 @@ out:
80 80
81static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb) 81static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
82{ 82{
83 int err = 0; 83 int err = -ENOMEM;
84 struct iphdr *iph; 84 struct iphdr *iph;
85 struct ip_comp_hdr *ipch; 85 struct ip_comp_hdr *ipch;
86 86
87 if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && 87 if (skb_linearize_cow(skb))
88 skb_linearize(skb, GFP_ATOMIC) != 0) {
89 err = -ENOMEM;
90 goto out; 88 goto out;
91 }
92 89
93 skb->ip_summed = CHECKSUM_NONE; 90 skb->ip_summed = CHECKSUM_NONE;
94 91
@@ -158,10 +155,8 @@ static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
158 goto out_ok; 155 goto out_ok;
159 } 156 }
160 157
161 if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && 158 if (skb_linearize_cow(skb))
162 skb_linearize(skb, GFP_ATOMIC) != 0) {
163 goto out_ok; 159 goto out_ok;
164 }
165 160
166 err = ipcomp_compress(x, skb); 161 err = ipcomp_compress(x, skb);
167 iph = skb->nh.iph; 162 iph = skb->nh.iph;
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index cec3be544b69..f28cd37feed3 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -65,7 +65,7 @@ static LIST_HEAD(ipcomp6_tfms_list);
65 65
66static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) 66static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
67{ 67{
68 int err = 0; 68 int err = -ENOMEM;
69 struct ipv6hdr *iph; 69 struct ipv6hdr *iph;
70 struct ipv6_comp_hdr *ipch; 70 struct ipv6_comp_hdr *ipch;
71 int plen, dlen; 71 int plen, dlen;
@@ -74,11 +74,8 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
74 struct crypto_tfm *tfm; 74 struct crypto_tfm *tfm;
75 int cpu; 75 int cpu;
76 76
77 if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && 77 if (skb_linearize_cow(skb))
78 skb_linearize(skb, GFP_ATOMIC) != 0) {
79 err = -ENOMEM;
80 goto out; 78 goto out;
81 }
82 79
83 skb->ip_summed = CHECKSUM_NONE; 80 skb->ip_summed = CHECKSUM_NONE;
84 81
@@ -142,10 +139,8 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb)
142 goto out_ok; 139 goto out_ok;
143 } 140 }
144 141
145 if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && 142 if (skb_linearize_cow(skb))
146 skb_linearize(skb, GFP_ATOMIC) != 0) {
147 goto out_ok; 143 goto out_ok;
148 }
149 144
150 /* compression */ 145 /* compression */
151 plen = skb->len - hdr_len; 146 plen = skb->len - hdr_len;