aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-09-16 19:21:16 -0400
committerDavid S. Miller <davem@davemloft.net>2007-09-16 19:21:16 -0400
commitd9cc20484e5e48c6a5deb4387c20fd45bfbdde8c (patch)
treef0a9f05ad00b8a506abeb3b42cb3346cef7d2155
parente081e1e3ef4682802ac63b1e5e26158fb9ca9e90 (diff)
[NET] skbuff: Add skb_cow_head
This patch adds an optimised version of skb_cow that avoids the copy if the header can be modified even if the rest of the payload is cloned. This can be used in encapsulating paths where we only need to modify the header. As it is, this can be used in PPPOE and bridging. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/pppoe.c2
-rw-r--r--include/linux/skbuff.h40
-rw-r--r--net/bridge/br_netfilter.c2
3 files changed, 33 insertions, 11 deletions
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index bac36546e0bf..0d7f570b9a54 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -860,7 +860,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
860 /* Copy the data if there is no space for the header or if it's 860 /* Copy the data if there is no space for the header or if it's
861 * read-only. 861 * read-only.
862 */ 862 */
863 if (skb_cow(skb, sizeof(*ph) + dev->hard_header_len)) 863 if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len))
864 goto abort; 864 goto abort;
865 865
866 __skb_push(skb, sizeof(*ph)); 866 __skb_push(skb, sizeof(*ph));
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 93c27f71122a..a656cecd373c 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1352,6 +1352,22 @@ static inline int skb_clone_writable(struct sk_buff *skb, int len)
1352 skb_headroom(skb) + len <= skb->hdr_len; 1352 skb_headroom(skb) + len <= skb->hdr_len;
1353} 1353}
1354 1354
1355static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom,
1356 int cloned)
1357{
1358 int delta = 0;
1359
1360 if (headroom < NET_SKB_PAD)
1361 headroom = NET_SKB_PAD;
1362 if (headroom > skb_headroom(skb))
1363 delta = headroom - skb_headroom(skb);
1364
1365 if (delta || cloned)
1366 return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0,
1367 GFP_ATOMIC);
1368 return 0;
1369}
1370
1355/** 1371/**
1356 * skb_cow - copy header of skb when it is required 1372 * skb_cow - copy header of skb when it is required
1357 * @skb: buffer to cow 1373 * @skb: buffer to cow
@@ -1366,16 +1382,22 @@ static inline int skb_clone_writable(struct sk_buff *skb, int len)
1366 */ 1382 */
1367static inline int skb_cow(struct sk_buff *skb, unsigned int headroom) 1383static inline int skb_cow(struct sk_buff *skb, unsigned int headroom)
1368{ 1384{
1369 int delta = (headroom > NET_SKB_PAD ? headroom : NET_SKB_PAD) - 1385 return __skb_cow(skb, headroom, skb_cloned(skb));
1370 skb_headroom(skb); 1386}
1371
1372 if (delta < 0)
1373 delta = 0;
1374 1387
1375 if (delta || skb_cloned(skb)) 1388/**
1376 return pskb_expand_head(skb, (delta + (NET_SKB_PAD-1)) & 1389 * skb_cow_head - skb_cow but only making the head writable
1377 ~(NET_SKB_PAD-1), 0, GFP_ATOMIC); 1390 * @skb: buffer to cow
1378 return 0; 1391 * @headroom: needed headroom
1392 *
1393 * This function is identical to skb_cow except that we replace the
1394 * skb_cloned check by skb_header_cloned. It should be used when
1395 * you only need to push on some header and do not need to modify
1396 * the data.
1397 */
1398static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom)
1399{
1400 return __skb_cow(skb, headroom, skb_header_cloned(skb));
1379} 1401}
1380 1402
1381/** 1403/**
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 3ee2022928e3..fc13130035e7 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -183,7 +183,7 @@ int nf_bridge_copy_header(struct sk_buff *skb)
183 int err; 183 int err;
184 int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb); 184 int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
185 185
186 err = skb_cow(skb, header_size); 186 err = skb_cow_head(skb, header_size);
187 if (err) 187 if (err)
188 return err; 188 return err;
189 189