diff options
| -rw-r--r-- | drivers/block/aoe/aoenet.c | 3 | ||||
| -rw-r--r-- | drivers/net/mv643xx_eth.c | 2 | ||||
| -rw-r--r-- | drivers/net/via-velocity.c | 10 | ||||
| -rw-r--r-- | include/linux/skbuff.h | 24 | ||||
| -rw-r--r-- | net/core/dev.c | 63 | ||||
| -rw-r--r-- | net/decnet/dn_nsp_in.c | 3 | ||||
| -rw-r--r-- | net/decnet/dn_route.c | 3 | ||||
| -rw-r--r-- | net/ipv4/ipcomp.c | 11 | ||||
| -rw-r--r-- | net/ipv6/ipcomp6.c | 11 |
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 | ||
| 1172 | static 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 | */ |
| 1180 | extern int __skb_linearize(struct sk_buff *skb, gfp_t gfp); | 1184 | static inline int skb_linearize(struct sk_buff *skb) |
| 1181 | static 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 | */ | ||
| 1196 | static 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 */ | ||
| 1226 | int __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); | |||
| 3473 | EXPORT_SYMBOL(__dev_get_by_index); | 3415 | EXPORT_SYMBOL(__dev_get_by_index); |
| 3474 | EXPORT_SYMBOL(__dev_get_by_name); | 3416 | EXPORT_SYMBOL(__dev_get_by_name); |
| 3475 | EXPORT_SYMBOL(__dev_remove_pack); | 3417 | EXPORT_SYMBOL(__dev_remove_pack); |
| 3476 | EXPORT_SYMBOL(__skb_linearize); | ||
| 3477 | EXPORT_SYMBOL(dev_valid_name); | 3418 | EXPORT_SYMBOL(dev_valid_name); |
| 3478 | EXPORT_SYMBOL(dev_add_pack); | 3419 | EXPORT_SYMBOL(dev_add_pack); |
| 3479 | EXPORT_SYMBOL(dev_alloc_name); | 3420 | EXPORT_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 | ||
| 81 | static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb) | 81 | static 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 | ||
| 66 | static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) | 66 | static 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; |
