aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-01-05 16:31:18 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-20 23:19:35 -0500
commit82bda6195615891181115f579a480aa5001ce7e9 (patch)
tree6eab0263d72c665460d64243afeb64905106b8fd /net
parentb74aa930ef49a3c0d8e4c1987f89decac768fb2c (diff)
net: splice: avoid high order page splitting
splice() can handle pages of any order, but network code tries hard to split them in PAGE_SIZE units. Not quite successfully anyway, as __splice_segment() assumed poff < PAGE_SIZE. This is true for the skb->data part, not necessarily for the fragments. This patch removes this logic to give the pages as they are in the skb. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Willy Tarreau <w@1wt.eu> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/skbuff.c38
1 files changed, 9 insertions, 29 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 3ab989b0de42..f5dfdf7727c4 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1706,20 +1706,6 @@ static bool spd_fill_page(struct splice_pipe_desc *spd,
1706 return false; 1706 return false;
1707} 1707}
1708 1708
1709static inline void __segment_seek(struct page **page, unsigned int *poff,
1710 unsigned int *plen, unsigned int off)
1711{
1712 unsigned long n;
1713
1714 *poff += off;
1715 n = *poff / PAGE_SIZE;
1716 if (n)
1717 *page = nth_page(*page, n);
1718
1719 *poff = *poff % PAGE_SIZE;
1720 *plen -= off;
1721}
1722
1723static bool __splice_segment(struct page *page, unsigned int poff, 1709static bool __splice_segment(struct page *page, unsigned int poff,
1724 unsigned int plen, unsigned int *off, 1710 unsigned int plen, unsigned int *off,
1725 unsigned int *len, struct sk_buff *skb, 1711 unsigned int *len, struct sk_buff *skb,
@@ -1727,6 +1713,8 @@ static bool __splice_segment(struct page *page, unsigned int poff,
1727 struct sock *sk, 1713 struct sock *sk,
1728 struct pipe_inode_info *pipe) 1714 struct pipe_inode_info *pipe)
1729{ 1715{
1716 unsigned int flen;
1717
1730 if (!*len) 1718 if (!*len)
1731 return true; 1719 return true;
1732 1720
@@ -1737,24 +1725,16 @@ static bool __splice_segment(struct page *page, unsigned int poff,
1737 } 1725 }
1738 1726
1739 /* ignore any bits we already processed */ 1727 /* ignore any bits we already processed */
1740 if (*off) { 1728 poff += *off;
1741 __segment_seek(&page, &poff, &plen, *off); 1729 plen -= *off;
1742 *off = 0; 1730 *off = 0;
1743 }
1744
1745 do {
1746 unsigned int flen = min(*len, plen);
1747 1731
1748 /* the linear region may spread across several pages */ 1732 flen = min(*len, plen);
1749 flen = min_t(unsigned int, flen, PAGE_SIZE - poff);
1750 1733
1751 if (spd_fill_page(spd, pipe, page, &flen, poff, skb, linear, sk)) 1734 if (spd_fill_page(spd, pipe, page, &flen, poff, skb, linear, sk))
1752 return true; 1735 return true;
1753
1754 __segment_seek(&page, &poff, &plen, flen);
1755 *len -= flen;
1756 1736
1757 } while (*len && plen); 1737 *len -= flen;
1758 1738
1759 return false; 1739 return false;
1760} 1740}