Skip to content

Commit

Permalink
xen-netfront: pull on receive skb may need to happen earlier
Browse files Browse the repository at this point in the history
Due to commit 3683243 ("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 <[email protected]>
Acked-by: Wei Liu <[email protected]>
Cc: Ian Campbell <[email protected]>
Cc: [email protected] (3.6 onwards)
Acked-by: Ian Campbell <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
jbeulich authored and davem330 committed Jul 17, 2013
1 parent fe5c356 commit 093b9c7
Showing 1 changed file with 13 additions and 18 deletions.
31 changes: 13 additions & 18 deletions drivers/net/xen-netfront.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,7 @@ static void xennet_alloc_rx_buffers(struct net_device *dev)
break;
}

__skb_fill_page_desc(skb, 0, page, 0, 0);
skb_shinfo(skb)->nr_frags = 1;
skb_add_rx_frag(skb, 0, page, 0, 0, PAGE_SIZE);
__skb_queue_tail(&np->rx_batch, skb);
}

Expand Down Expand Up @@ -831,7 +830,6 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np,
struct sk_buff_head *list)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
int nr_frags = shinfo->nr_frags;
RING_IDX cons = np->rx.rsp_cons;
struct sk_buff *nskb;

Expand All @@ -840,19 +838,21 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np,
RING_GET_RESPONSE(&np->rx, ++cons);
skb_frag_t *nfrag = &skb_shinfo(nskb)->frags[0];

__skb_fill_page_desc(skb, nr_frags,
skb_frag_page(nfrag),
rx->offset, rx->status);
if (shinfo->nr_frags == MAX_SKB_FRAGS) {
unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to;

skb->data_len += rx->status;
BUG_ON(pull_to <= skb_headlen(skb));
__pskb_pull_tail(skb, pull_to - skb_headlen(skb));
}
BUG_ON(shinfo->nr_frags >= MAX_SKB_FRAGS);

skb_add_rx_frag(skb, shinfo->nr_frags, skb_frag_page(nfrag),
rx->offset, rx->status, PAGE_SIZE);

skb_shinfo(nskb)->nr_frags = 0;
kfree_skb(nskb);

nr_frags++;
}

shinfo->nr_frags = nr_frags;
return cons;
}

Expand Down Expand Up @@ -933,7 +933,8 @@ static int handle_incoming_queue(struct net_device *dev,
while ((skb = __skb_dequeue(rxq)) != NULL) {
int pull_to = NETFRONT_SKB_CB(skb)->pull_to;

__pskb_pull_tail(skb, pull_to - skb_headlen(skb));
if (pull_to > skb_headlen(skb))
__pskb_pull_tail(skb, pull_to - skb_headlen(skb));

/* Ethernet work: Delayed to here as it peeks the header. */
skb->protocol = eth_type_trans(skb, dev);
Expand Down Expand Up @@ -1019,16 +1020,10 @@ static int xennet_poll(struct napi_struct *napi, int budget)
skb_shinfo(skb)->frags[0].page_offset = rx->offset;
skb_frag_size_set(&skb_shinfo(skb)->frags[0], rx->status);
skb->data_len = rx->status;
skb->len += rx->status;

i = xennet_fill_frags(np, skb, &tmpq);

/*
* Truesize is the actual allocation size, even if the
* allocation is only partially used.
*/
skb->truesize += PAGE_SIZE * skb_shinfo(skb)->nr_frags;
skb->len += skb->data_len;

if (rx->flags & XEN_NETRXF_csum_blank)
skb->ip_summed = CHECKSUM_PARTIAL;
else if (rx->flags & XEN_NETRXF_data_validated)
Expand Down

0 comments on commit 093b9c7

Please sign in to comment.