xen-netfront: use __pskb_pull_tail to ensure linear area is big enough on RX
I'm slightly concerned by the "only in exceptional circumstances" comment on __pskb_pull_tail but the structure of an skb just created by netfront shouldn't hit any of the especially slow cases. This approach still does slightly more work than the old way, since if we pull up the entire first frag we now have to shuffle everything down where before we just received into the right place in the first place. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Jeremy Fitzhardinge <jeremy@goop.org> Cc: Mel Gorman <mgorman@suse.de> Cc: xen-devel@lists.xensource.com Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Tested-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
072a9c4860
commit
3683243b2c
|
@ -57,8 +57,7 @@
|
|||
static const struct ethtool_ops xennet_ethtool_ops;
|
||||
|
||||
struct netfront_cb {
|
||||
struct page *page;
|
||||
unsigned offset;
|
||||
int pull_to;
|
||||
};
|
||||
|
||||
#define NETFRONT_SKB_CB(skb) ((struct netfront_cb *)((skb)->cb))
|
||||
|
@ -867,15 +866,9 @@ static int handle_incoming_queue(struct net_device *dev,
|
|||
struct sk_buff *skb;
|
||||
|
||||
while ((skb = __skb_dequeue(rxq)) != NULL) {
|
||||
struct page *page = NETFRONT_SKB_CB(skb)->page;
|
||||
void *vaddr = page_address(page);
|
||||
unsigned offset = NETFRONT_SKB_CB(skb)->offset;
|
||||
int pull_to = NETFRONT_SKB_CB(skb)->pull_to;
|
||||
|
||||
memcpy(skb->data, vaddr + offset,
|
||||
skb_headlen(skb));
|
||||
|
||||
if (page != skb_frag_page(&skb_shinfo(skb)->frags[0]))
|
||||
__free_page(page);
|
||||
__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);
|
||||
|
@ -913,7 +906,6 @@ static int xennet_poll(struct napi_struct *napi, int budget)
|
|||
struct sk_buff_head errq;
|
||||
struct sk_buff_head tmpq;
|
||||
unsigned long flags;
|
||||
unsigned int len;
|
||||
int err;
|
||||
|
||||
spin_lock(&np->rx_lock);
|
||||
|
@ -955,24 +947,13 @@ err:
|
|||
}
|
||||
}
|
||||
|
||||
NETFRONT_SKB_CB(skb)->page =
|
||||
skb_frag_page(&skb_shinfo(skb)->frags[0]);
|
||||
NETFRONT_SKB_CB(skb)->offset = rx->offset;
|
||||
NETFRONT_SKB_CB(skb)->pull_to = rx->status;
|
||||
if (NETFRONT_SKB_CB(skb)->pull_to > RX_COPY_THRESHOLD)
|
||||
NETFRONT_SKB_CB(skb)->pull_to = RX_COPY_THRESHOLD;
|
||||
|
||||
len = rx->status;
|
||||
if (len > RX_COPY_THRESHOLD)
|
||||
len = RX_COPY_THRESHOLD;
|
||||
skb_put(skb, len);
|
||||
|
||||
if (rx->status > len) {
|
||||
skb_shinfo(skb)->frags[0].page_offset =
|
||||
rx->offset + len;
|
||||
skb_frag_size_set(&skb_shinfo(skb)->frags[0], rx->status - len);
|
||||
skb->data_len = rx->status - len;
|
||||
} else {
|
||||
__skb_fill_page_desc(skb, 0, NULL, 0, 0);
|
||||
skb_shinfo(skb)->nr_frags = 0;
|
||||
}
|
||||
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;
|
||||
|
||||
i = xennet_fill_frags(np, skb, &tmpq);
|
||||
|
||||
|
@ -999,7 +980,7 @@ err:
|
|||
* receive throughout using the standard receive
|
||||
* buffer size was cut by 25%(!!!).
|
||||
*/
|
||||
skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
|
||||
skb->truesize += skb->data_len - RX_COPY_THRESHOLD;
|
||||
skb->len += skb->data_len;
|
||||
|
||||
if (rx->flags & XEN_NETRXF_csum_blank)
|
||||
|
|
Loading…
Reference in New Issue