Commit 093b9c71b6e450e375f4646ba86faed0195ec7df

Authored by Jan Beulich
Committed by David S. Miller
1 parent fe5c3561e6

xen-netfront: pull on receive skb may need to happen earlier

Due to commit 3683243b ("xen-netfront: use __pskb_pull_tail to ensure
linear area is big enough on RX") xennet_fill_frags() may end up
filling MAX_SKB_FRAGS + 1 fragments in a receive skb, and only reduce
the fragment count subsequently via __pskb_pull_tail(). That's a
result of xennet_get_responses() allowing a maximum of one more slot to
be consumed (and intermediately transformed into a fragment) if the
head slot has a size less than or equal to RX_COPY_THRESHOLD.

Hence we need to adjust xennet_fill_frags() to pull earlier if we
reached the maximum fragment count - due to the described behavior of
xennet_get_responses() this guarantees that at least the first fragment
will get completely consumed, and hence the fragment count reduced.

In order to not needlessly call __pskb_pull_tail() twice, make the
original call conditional upon the pull target not having been reached
yet, and defer the newly added one as much as possible (an alternative
would have been to always call the function right before the call to
xennet_fill_frags(), but that would imply more frequent cases of
needing to call it twice).

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Cc: Ian Campbell <ian.campbell@citrix.com>
Cc: stable@vger.kernel.org (3.6 onwards)
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 13 additions and 18 deletions Side-by-side Diff

drivers/net/xen-netfront.c
... ... @@ -286,8 +286,7 @@
286 286 break;
287 287 }
288 288  
289   - __skb_fill_page_desc(skb, 0, page, 0, 0);
290   - skb_shinfo(skb)->nr_frags = 1;
  289 + skb_add_rx_frag(skb, 0, page, 0, 0, PAGE_SIZE);
291 290 __skb_queue_tail(&np->rx_batch, skb);
292 291 }
293 292  
... ... @@ -831,7 +830,6 @@
831 830 struct sk_buff_head *list)
832 831 {
833 832 struct skb_shared_info *shinfo = skb_shinfo(skb);
834   - int nr_frags = shinfo->nr_frags;
835 833 RING_IDX cons = np->rx.rsp_cons;
836 834 struct sk_buff *nskb;
837 835  
838 836  
839 837  
840 838  
841 839  
... ... @@ -840,19 +838,21 @@
840 838 RING_GET_RESPONSE(&np->rx, ++cons);
841 839 skb_frag_t *nfrag = &skb_shinfo(nskb)->frags[0];
842 840  
843   - __skb_fill_page_desc(skb, nr_frags,
844   - skb_frag_page(nfrag),
845   - rx->offset, rx->status);
  841 + if (shinfo->nr_frags == MAX_SKB_FRAGS) {
  842 + unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to;
846 843  
847   - skb->data_len += rx->status;
  844 + BUG_ON(pull_to <= skb_headlen(skb));
  845 + __pskb_pull_tail(skb, pull_to - skb_headlen(skb));
  846 + }
  847 + BUG_ON(shinfo->nr_frags >= MAX_SKB_FRAGS);
848 848  
  849 + skb_add_rx_frag(skb, shinfo->nr_frags, skb_frag_page(nfrag),
  850 + rx->offset, rx->status, PAGE_SIZE);
  851 +
849 852 skb_shinfo(nskb)->nr_frags = 0;
850 853 kfree_skb(nskb);
851   -
852   - nr_frags++;
853 854 }
854 855  
855   - shinfo->nr_frags = nr_frags;
856 856 return cons;
857 857 }
858 858  
... ... @@ -933,7 +933,8 @@
933 933 while ((skb = __skb_dequeue(rxq)) != NULL) {
934 934 int pull_to = NETFRONT_SKB_CB(skb)->pull_to;
935 935  
936   - __pskb_pull_tail(skb, pull_to - skb_headlen(skb));
  936 + if (pull_to > skb_headlen(skb))
  937 + __pskb_pull_tail(skb, pull_to - skb_headlen(skb));
937 938  
938 939 /* Ethernet work: Delayed to here as it peeks the header. */
939 940 skb->protocol = eth_type_trans(skb, dev);
940 941  
... ... @@ -1019,15 +1020,9 @@
1019 1020 skb_shinfo(skb)->frags[0].page_offset = rx->offset;
1020 1021 skb_frag_size_set(&skb_shinfo(skb)->frags[0], rx->status);
1021 1022 skb->data_len = rx->status;
  1023 + skb->len += rx->status;
1022 1024  
1023 1025 i = xennet_fill_frags(np, skb, &tmpq);
1024   -
1025   - /*
1026   - * Truesize is the actual allocation size, even if the
1027   - * allocation is only partially used.
1028   - */
1029   - skb->truesize += PAGE_SIZE * skb_shinfo(skb)->nr_frags;
1030   - skb->len += skb->data_len;
1031 1026  
1032 1027 if (rx->flags & XEN_NETRXF_csum_blank)
1033 1028 skb->ip_summed = CHECKSUM_PARTIAL;