From d63951d7442982ef81df585a9c08c2b5fd49f898 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 4 Mar 2015 11:14:46 +0000 Subject: xen-netback: return correct ethtool stats Use correct pointer arithmetic to get the pointer to each stat. Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netback/interface.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/xen-netback') diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index f38227afe099..3aa8648080c8 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -340,12 +340,11 @@ static void xenvif_get_ethtool_stats(struct net_device *dev, unsigned int num_queues = vif->num_queues; int i; unsigned int queue_index; - struct xenvif_stats *vif_stats; for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++) { unsigned long accum = 0; for (queue_index = 0; queue_index < num_queues; ++queue_index) { - vif_stats = &vif->queues[queue_index].stats; + void *vif_stats = &vif->queues[queue_index].stats; accum += *(unsigned long *)(vif_stats + xenvif_stats[i].offset); } data[i] = accum; -- cgit v1.2.3 From 49d9991a18f9aae7b14abbd9c1cc87555330a769 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 4 Mar 2015 11:14:47 +0000 Subject: xen-netback: unref frags when handling a from-guest skb with a frag list Every time a VIF is destroyed up to 256 pages may be leaked if packets with more than MAX_SKB_FRAGS frags were transmitted from the guest. Even worse, if another user of ballooned pages allocated one of these ballooned pages it would not handle the unexpectedly >1 page count (e.g., gntdev would deadlock when unmapping a grant because the page count would never reach 1). When handling a from-guest skb with a frag list, unref the frags before releasing them so they are freed correctly when the VIF is destroyed. Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netback/netback.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/xen-netback') diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index c4d68d768408..f1d84fb1eba8 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1349,7 +1349,7 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s { unsigned int offset = skb_headlen(skb); skb_frag_t frags[MAX_SKB_FRAGS]; - int i; + int i, f; struct ubuf_info *uarg; struct sk_buff *nskb = skb_shinfo(skb)->frag_list; @@ -1389,6 +1389,11 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s frags[i].page_offset = 0; skb_frag_size_set(&frags[i], len); } + + /* Release all the original (foreign) frags. */ + for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) + skb_frag_unref(skb, f); + /* swap out with old one */ memcpy(skb_shinfo(skb)->frags, frags, -- cgit v1.2.3 From b0c21badf174eb00160f842398f3918d7b365853 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 4 Mar 2015 11:14:48 +0000 Subject: xen-netback: refactor xenvif_handle_frag_list() When handling a from-guest frag list, xenvif_handle_frag_list() replaces the frags before calling the destructor to clean up the original (foreign) frags. Whilst this is safe (the destructor doesn't actually use the frags), it looks odd. Reorder the function to be less confusing. Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netback/netback.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/net/xen-netback') diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index f1d84fb1eba8..cab9f5257f57 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1390,27 +1390,24 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s skb_frag_size_set(&frags[i], len); } + /* Copied all the bits from the frag list -- free it. */ + skb_frag_list_init(skb); + xenvif_skb_zerocopy_prepare(queue, nskb); + kfree_skb(nskb); + /* Release all the original (foreign) frags. */ for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) skb_frag_unref(skb, f); - - /* swap out with old one */ - memcpy(skb_shinfo(skb)->frags, - frags, - i * sizeof(skb_frag_t)); - skb_shinfo(skb)->nr_frags = i; - skb->truesize += i * PAGE_SIZE; - - /* remove traces of mapped pages and frag_list */ - skb_frag_list_init(skb); uarg = skb_shinfo(skb)->destructor_arg; /* increase inflight counter to offset decrement in callback */ atomic_inc(&queue->inflight_packets); uarg->callback(uarg, true); skb_shinfo(skb)->destructor_arg = NULL; - xenvif_skb_zerocopy_prepare(queue, nskb); - kfree_skb(nskb); + /* Fill the skb with the new (local) frags. */ + memcpy(skb_shinfo(skb)->frags, frags, i * sizeof(skb_frag_t)); + skb_shinfo(skb)->nr_frags = i; + skb->truesize += i * PAGE_SIZE; return 0; } -- cgit v1.2.3