|
@@ -2012,10 +2012,30 @@ bool __i40evf_chk_linearize(struct sk_buff *skb)
|
|
/* Walk through fragments adding latest fragment, testing it, and
|
|
/* Walk through fragments adding latest fragment, testing it, and
|
|
* then removing stale fragments from the sum.
|
|
* then removing stale fragments from the sum.
|
|
*/
|
|
*/
|
|
- stale = &skb_shinfo(skb)->frags[0];
|
|
|
|
- for (;;) {
|
|
|
|
|
|
+ for (stale = &skb_shinfo(skb)->frags[0];; stale++) {
|
|
|
|
+ int stale_size = skb_frag_size(stale);
|
|
|
|
+
|
|
sum += skb_frag_size(frag++);
|
|
sum += skb_frag_size(frag++);
|
|
|
|
|
|
|
|
+ /* The stale fragment may present us with a smaller
|
|
|
|
+ * descriptor than the actual fragment size. To account
|
|
|
|
+ * for that we need to remove all the data on the front and
|
|
|
|
+ * figure out what the remainder would be in the last
|
|
|
|
+ * descriptor associated with the fragment.
|
|
|
|
+ */
|
|
|
|
+ if (stale_size > I40E_MAX_DATA_PER_TXD) {
|
|
|
|
+ int align_pad = -(stale->page_offset) &
|
|
|
|
+ (I40E_MAX_READ_REQ_SIZE - 1);
|
|
|
|
+
|
|
|
|
+ sum -= align_pad;
|
|
|
|
+ stale_size -= align_pad;
|
|
|
|
+
|
|
|
|
+ do {
|
|
|
|
+ sum -= I40E_MAX_DATA_PER_TXD_ALIGNED;
|
|
|
|
+ stale_size -= I40E_MAX_DATA_PER_TXD_ALIGNED;
|
|
|
|
+ } while (stale_size > I40E_MAX_DATA_PER_TXD);
|
|
|
|
+ }
|
|
|
|
+
|
|
/* if sum is negative we failed to make sufficient progress */
|
|
/* if sum is negative we failed to make sufficient progress */
|
|
if (sum < 0)
|
|
if (sum < 0)
|
|
return true;
|
|
return true;
|
|
@@ -2023,7 +2043,7 @@ bool __i40evf_chk_linearize(struct sk_buff *skb)
|
|
if (!nr_frags--)
|
|
if (!nr_frags--)
|
|
break;
|
|
break;
|
|
|
|
|
|
- sum -= skb_frag_size(stale++);
|
|
|
|
|
|
+ sum -= stale_size;
|
|
}
|
|
}
|
|
|
|
|
|
return false;
|
|
return false;
|