From patchwork Fri Jan 25 14:27:02 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [RFC, 2/7] net: only allow paged fragments with the same destructor to be coalesced. Date: Fri, 25 Jan 2013 04:27:02 -0000 From: Alex Bligh X-Patchwork-Id: 215751 Message-Id: <1359124027-1170-3-git-send-email-alex@alex.org.uk> To: netdev Cc: Stefano Stabellini , Ian Campbell , Alex Bligh , "Trond Myklebust" , Mel Gorman From: Ian Campbell Signed-off-by: Ian Campbell citrix.com> Cc: "David S. Miller" davemloft.net> Cc: Alexey Kuznetsov ms2.inr.ac.ru> Cc: "Pekka Savola (ipv6)" netcore.fi> Cc: James Morris namei.org> Cc: Hideaki YOSHIFUJI linux-ipv6.org> Cc: Patrick McHardy trash.net> Cc: Eric Dumazet gmail.com> Cc: "Michał Mirosław" rere.qmqm.pl> Cc: netdev vger.kernel.org Signed-off-by: Alex Bligh --- include/linux/skbuff.h | 7 +++++-- net/core/skbuff.c | 1 + net/ipv4/ip_output.c | 2 +- net/ipv4/tcp.c | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 2619a61..8a8eecd 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1970,13 +1970,16 @@ static inline int skb_add_data(struct sk_buff *skb, } static inline int skb_can_coalesce(struct sk_buff *skb, int i, - const struct page *page, int off) + const struct page *page, + const struct skb_frag_destructor *destroy, + int off) { if (i) { const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i - 1]; return page == skb_frag_page(frag) && - off == frag->page_offset + skb_frag_size(frag); + off == frag->page_offset + skb_frag_size(frag) && + frag->page.destructor == destroy; } return 0; } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 8b46cad..425cd5a 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2276,6 +2276,7 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen) */ if (!to || !skb_can_coalesce(tgt, to, skb_frag_page(fragfrom), + fragfrom->page.destructor, fragfrom->page_offset)) { merge = -1; } else { diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 0bc95f3..3252e06 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1229,7 +1229,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, i = skb_shinfo(skb)->nr_frags; if (len > size) len = size; - if (skb_can_coalesce(skb, i, page, offset)) { + if (skb_can_coalesce(skb, i, page, NULL, offset)) { skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len); } else if (i < MAX_SKB_FRAGS) { get_page(page); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 34f5db1..018de0c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -804,7 +804,7 @@ new_segment: copy = size; i = skb_shinfo(skb)->nr_frags; - can_coalesce = skb_can_coalesce(skb, i, page, offset); + can_coalesce = skb_can_coalesce(skb, i, page, NULL, offset); if (!can_coalesce && i >= MAX_SKB_FRAGS) { tcp_mark_push(tp, skb); goto new_segment; @@ -1008,7 +1008,7 @@ new_segment: struct page *page = TCP_PAGE(sk); int off = TCP_OFF(sk); - if (skb_can_coalesce(skb, i, page, off) && + if (skb_can_coalesce(skb, i, page, NULL, off) && off != PAGE_SIZE) { /* We can extend the last page * fragment. */