Commit fa9835e5 authored by Tom Herbert's avatar Tom Herbert Committed by David S. Miller

net: Walk fragments in __skb_splice_bits

Add walking of fragments in __skb_splice_bits.
Signed-off-by: default avatarTom Herbert <tom@herbertland.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f092276d
...@@ -1918,6 +1918,7 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe, ...@@ -1918,6 +1918,7 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
struct splice_pipe_desc *spd, struct sock *sk) struct splice_pipe_desc *spd, struct sock *sk)
{ {
int seg; int seg;
struct sk_buff *iter;
/* map the linear part : /* map the linear part :
* If skb->head_frag is set, this 'linear' part is backed by a * If skb->head_frag is set, this 'linear' part is backed by a
...@@ -1944,6 +1945,19 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe, ...@@ -1944,6 +1945,19 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
return true; return true;
} }
skb_walk_frags(skb, iter) {
if (*offset >= iter->len) {
*offset -= iter->len;
continue;
}
/* __skb_splice_bits() only fails if the output has no room
* left, so no point in going over the frag_list for the error
* case.
*/
if (__skb_splice_bits(iter, pipe, offset, len, spd, sk))
return true;
}
return false; return false;
} }
...@@ -1970,9 +1984,7 @@ ssize_t skb_socket_splice(struct sock *sk, ...@@ -1970,9 +1984,7 @@ ssize_t skb_socket_splice(struct sock *sk,
/* /*
* Map data from the skb to a pipe. Should handle both the linear part, * Map data from the skb to a pipe. Should handle both the linear part,
* the fragments, and the frag list. It does NOT handle frag lists within * the fragments, and the frag list.
* the frag list, if such a thing exists. We'd probably need to recurse to
* handle that cleanly.
*/ */
int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
struct pipe_inode_info *pipe, unsigned int tlen, struct pipe_inode_info *pipe, unsigned int tlen,
...@@ -1991,29 +2003,10 @@ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, ...@@ -1991,29 +2003,10 @@ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
.ops = &nosteal_pipe_buf_ops, .ops = &nosteal_pipe_buf_ops,
.spd_release = sock_spd_release, .spd_release = sock_spd_release,
}; };
struct sk_buff *frag_iter;
int ret = 0; int ret = 0;
/* __skb_splice_bits(skb, pipe, &offset, &tlen, &spd, sk);
* __skb_splice_bits() only fails if the output has no room left,
* so no point in going over the frag_list for the error case.
*/
if (__skb_splice_bits(skb, pipe, &offset, &tlen, &spd, sk))
goto done;
else if (!tlen)
goto done;
/*
* now see if we have a frag_list to map
*/
skb_walk_frags(skb, frag_iter) {
if (!tlen)
break;
if (__skb_splice_bits(frag_iter, pipe, &offset, &tlen, &spd, sk))
break;
}
done:
if (spd.nr_pages) if (spd.nr_pages)
ret = splice_cb(sk, pipe, &spd); ret = splice_cb(sk, pipe, &spd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment