diff options
author | Eric Dumazet <edumazet@google.com> | 2013-01-05 16:31:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-07 00:07:24 -0500 |
commit | 9ca1b22d6d228177e6f929f6818a1cd3d5e30c4a (patch) | |
tree | 0dfad0c3a33ab51ec4b5859c772a21ce0b50f466 | |
parent | 81135548e697a24ab41944c4354953a71b0b9efe (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>
-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 bc96100fe23c..b03fc0c6a952 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -1707,20 +1707,6 @@ static bool spd_fill_page(struct splice_pipe_desc *spd, | |||
1707 | return false; | 1707 | return false; |
1708 | } | 1708 | } |
1709 | 1709 | ||
1710 | static inline void __segment_seek(struct page **page, unsigned int *poff, | ||
1711 | unsigned int *plen, unsigned int off) | ||
1712 | { | ||
1713 | unsigned long n; | ||
1714 | |||
1715 | *poff += off; | ||
1716 | n = *poff / PAGE_SIZE; | ||
1717 | if (n) | ||
1718 | *page = nth_page(*page, n); | ||
1719 | |||
1720 | *poff = *poff % PAGE_SIZE; | ||
1721 | *plen -= off; | ||
1722 | } | ||
1723 | |||
1724 | static bool __splice_segment(struct page *page, unsigned int poff, | 1710 | static bool __splice_segment(struct page *page, unsigned int poff, |
1725 | unsigned int plen, unsigned int *off, | 1711 | unsigned int plen, unsigned int *off, |
1726 | unsigned int *len, struct sk_buff *skb, | 1712 | unsigned int *len, struct sk_buff *skb, |
@@ -1728,6 +1714,8 @@ static bool __splice_segment(struct page *page, unsigned int poff, | |||
1728 | struct sock *sk, | 1714 | struct sock *sk, |
1729 | struct pipe_inode_info *pipe) | 1715 | struct pipe_inode_info *pipe) |
1730 | { | 1716 | { |
1717 | unsigned int flen; | ||
1718 | |||
1731 | if (!*len) | 1719 | if (!*len) |
1732 | return true; | 1720 | return true; |
1733 | 1721 | ||
@@ -1738,24 +1726,16 @@ static bool __splice_segment(struct page *page, unsigned int poff, | |||
1738 | } | 1726 | } |
1739 | 1727 | ||
1740 | /* ignore any bits we already processed */ | 1728 | /* ignore any bits we already processed */ |
1741 | if (*off) { | 1729 | poff += *off; |
1742 | __segment_seek(&page, &poff, &plen, *off); | 1730 | plen -= *off; |
1743 | *off = 0; | 1731 | *off = 0; |
1744 | } | ||
1745 | |||
1746 | do { | ||
1747 | unsigned int flen = min(*len, plen); | ||
1748 | 1732 | ||
1749 | /* the linear region may spread across several pages */ | 1733 | flen = min(*len, plen); |
1750 | flen = min_t(unsigned int, flen, PAGE_SIZE - poff); | ||
1751 | 1734 | ||
1752 | if (spd_fill_page(spd, pipe, page, &flen, poff, skb, linear, sk)) | 1735 | if (spd_fill_page(spd, pipe, page, &flen, poff, skb, linear, sk)) |
1753 | return true; | 1736 | return true; |
1754 | |||
1755 | __segment_seek(&page, &poff, &plen, flen); | ||
1756 | *len -= flen; | ||
1757 | 1737 | ||
1758 | } while (*len && plen); | 1738 | *len -= flen; |
1759 | 1739 | ||
1760 | return false; | 1740 | return false; |
1761 | } | 1741 | } |