On Fri, 1 Feb 2008, Ilpo Järvinen wrote: > @@ -1322,6 +1324,206 @@ static int tcp_sacktag_one(struct sk_buff *skb, > struct sock *sk, > return flag; > } > > +/* Attempts to shift up to shiftlen worth of bytes from prev to skb. > + * Returns number bytes shifted. > + * > + * TODO: in case the prev runs out of frag space, operation could be > + * made to return with a partial result (would allow tighter packing). > + */ > +static int skb_shift(struct sk_buff *prev, struct sk_buff *skb, > + unsigned int shiftlen) > +{ > + int i, to, merge; > + unsigned int todo; > + struct skb_frag_struct *from, *fragto; > + > + if (skb_cloned(skb) || skb_cloned(prev)) > + return 0; > + > + todo = shiftlen; > + i = 0; > + from = &skb_shinfo(skb)->frags[i]; > + to = skb_shinfo(prev)->nr_frags; > + > + merge = to - 1; > + if (!skb_can_coalesce(prev, merge + 1, from->page, from->page_offset)) > + merge = -1; > + if (merge >= 0) { > + i++; > + if (from->size >= shiftlen) > + goto onlymerge; > + todo -= from->size; > + } > + > + /* Skip full, not-fitting skb to avoid expensive operations */ > + if ((shiftlen == skb->len) && > + (skb_shinfo(skb)->nr_frags - merge) < (MAX_SKB_FRAGS - to))
Before somebody else notices it: s/merge/i/, a leftover from flag -> idx conversion. > + return 0; > + > + while (todo && (i < skb_shinfo(skb)->nr_frags)) { > + if (to == MAX_SKB_FRAGS) > + return 0; > + -- i.