tcp: fix for splice receive when used with software LRO
If an skb has nr_frags set to zero but its frag_list is not empty (as it can happen if software LRO is enabled), and a previous tcp_read_sock has consumed the linear part of the skb, then __skb_splice_bits: (a) incorrectly reports an error and (b) forgets to update the offset to account for the linear part Any of the two problems will cause the subsequent __skb_splice_bits call (the one that handles the frag_list skbs) to either skip data, or, if the unadjusted offset is greater then the size of the next skb in the frag_list, make tcp_splice_read loop forever. Signed-off-by: Octavian Purdila <opurdila@ixiacom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
57413ebc4e
commit
db43a282d3
@ -1292,12 +1292,14 @@ static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,
|
||||
{
|
||||
unsigned int nr_pages = spd->nr_pages;
|
||||
unsigned int poff, plen, len, toff, tlen;
|
||||
int headlen, seg;
|
||||
int headlen, seg, error = 0;
|
||||
|
||||
toff = *offset;
|
||||
tlen = *total_len;
|
||||
if (!tlen)
|
||||
if (!tlen) {
|
||||
error = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* if the offset is greater than the linear part, go directly to
|
||||
@ -1339,7 +1341,8 @@ static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,
|
||||
* just jump directly to update and return, no point
|
||||
* in going over fragments when the output is full.
|
||||
*/
|
||||
if (spd_fill_page(spd, virt_to_page(p), plen, poff, skb))
|
||||
error = spd_fill_page(spd, virt_to_page(p), plen, poff, skb);
|
||||
if (error)
|
||||
goto done;
|
||||
|
||||
tlen -= plen;
|
||||
@ -1369,7 +1372,8 @@ map_frag:
|
||||
if (!plen)
|
||||
break;
|
||||
|
||||
if (spd_fill_page(spd, f->page, plen, poff, skb))
|
||||
error = spd_fill_page(spd, f->page, plen, poff, skb);
|
||||
if (error)
|
||||
break;
|
||||
|
||||
tlen -= plen;
|
||||
@ -1382,7 +1386,10 @@ done:
|
||||
return 0;
|
||||
}
|
||||
err:
|
||||
return 1;
|
||||
/* update the offset to reflect the linear part skip, if any */
|
||||
if (!error)
|
||||
*offset = toff;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user