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; |