diff options
author | David Vrabel <david.vrabel@citrix.com> | 2015-03-04 06:14:47 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-05 14:58:17 -0500 |
commit | 49d9991a18f9aae7b14abbd9c1cc87555330a769 (patch) | |
tree | f642411098ecbf508d8303abdaacaa7e39642482 /drivers/net/xen-netback | |
parent | d63951d7442982ef81df585a9c08c2b5fd49f898 (diff) |
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 <david.vrabel@citrix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/xen-netback')
-rw-r--r-- | drivers/net/xen-netback/netback.c | 7 |
1 files changed, 6 insertions, 1 deletions
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 | |||
1349 | { | 1349 | { |
1350 | unsigned int offset = skb_headlen(skb); | 1350 | unsigned int offset = skb_headlen(skb); |
1351 | skb_frag_t frags[MAX_SKB_FRAGS]; | 1351 | skb_frag_t frags[MAX_SKB_FRAGS]; |
1352 | int i; | 1352 | int i, f; |
1353 | struct ubuf_info *uarg; | 1353 | struct ubuf_info *uarg; |
1354 | struct sk_buff *nskb = skb_shinfo(skb)->frag_list; | 1354 | struct sk_buff *nskb = skb_shinfo(skb)->frag_list; |
1355 | 1355 | ||
@@ -1389,6 +1389,11 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s | |||
1389 | frags[i].page_offset = 0; | 1389 | frags[i].page_offset = 0; |
1390 | skb_frag_size_set(&frags[i], len); | 1390 | skb_frag_size_set(&frags[i], len); |
1391 | } | 1391 | } |
1392 | |||
1393 | /* Release all the original (foreign) frags. */ | ||
1394 | for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) | ||
1395 | skb_frag_unref(skb, f); | ||
1396 | |||
1392 | /* swap out with old one */ | 1397 | /* swap out with old one */ |
1393 | memcpy(skb_shinfo(skb)->frags, | 1398 | memcpy(skb_shinfo(skb)->frags, |
1394 | frags, | 1399 | frags, |