diff options
author | Eric Dumazet <edumazet@google.com> | 2013-01-05 16:31:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-20 23:19:35 -0500 |
commit | 82bda6195615891181115f579a480aa5001ce7e9 (patch) | |
tree | 6eab0263d72c665460d64243afeb64905106b8fd /net | |
parent | b74aa930ef49a3c0d8e4c1987f89decac768fb2c (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.c | 38 |
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 | ||
1709 | static 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 | |||
1723 | static bool __splice_segment(struct page *page, unsigned int poff, | 1709 | static 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 | } |