diff options
author | Mark McLoughlin <markmc@redhat.com> | 2008-11-17 01:39:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-17 01:39:18 -0500 |
commit | 0a888fd1f6320d1d9318c58de9bca3cef41546d6 (patch) | |
tree | e1ff542e6c8acba415d67a3764e4124849801805 /drivers/net/virtio_net.c | |
parent | 908cd2dabbfbbefb02f6b908a1188a62e685136a (diff) |
virtio_net: Recycle some more rx buffer pages
Each time we re-fill the recv queue with buffers, we allocate
one too many skbs and free it again when adding fails. We should
recycle the pages allocated in this case.
A previous version of this patch made trim_pages() trim trailing
unused pages from skbs with some paged data, but this actually
caused a barely measurable slowdown.
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (use netdev_priv)
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r-- | drivers/net/virtio_net.c | 22 |
1 files changed, 13 insertions, 9 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index ede0a80045b3..f5207ef21a91 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -82,6 +82,16 @@ static void give_a_page(struct virtnet_info *vi, struct page *page) | |||
82 | vi->pages = page; | 82 | vi->pages = page; |
83 | } | 83 | } |
84 | 84 | ||
85 | static void trim_pages(struct virtnet_info *vi, struct sk_buff *skb) | ||
86 | { | ||
87 | unsigned int i; | ||
88 | |||
89 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) | ||
90 | give_a_page(vi, skb_shinfo(skb)->frags[i].page); | ||
91 | skb_shinfo(skb)->nr_frags = 0; | ||
92 | skb->data_len = 0; | ||
93 | } | ||
94 | |||
85 | static struct page *get_a_page(struct virtnet_info *vi, gfp_t gfp_mask) | 95 | static struct page *get_a_page(struct virtnet_info *vi, gfp_t gfp_mask) |
86 | { | 96 | { |
87 | struct page *p = vi->pages; | 97 | struct page *p = vi->pages; |
@@ -121,15 +131,8 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, | |||
121 | } | 131 | } |
122 | len -= sizeof(struct virtio_net_hdr); | 132 | len -= sizeof(struct virtio_net_hdr); |
123 | 133 | ||
124 | if (len <= MAX_PACKET_LEN) { | 134 | if (len <= MAX_PACKET_LEN) |
125 | unsigned int i; | 135 | trim_pages(netdev_priv(dev), skb); |
126 | |||
127 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) | ||
128 | give_a_page(netdev_priv(dev), | ||
129 | skb_shinfo(skb)->frags[i].page); | ||
130 | skb->data_len = 0; | ||
131 | skb_shinfo(skb)->nr_frags = 0; | ||
132 | } | ||
133 | 136 | ||
134 | err = pskb_trim(skb, len); | 137 | err = pskb_trim(skb, len); |
135 | if (err) { | 138 | if (err) { |
@@ -233,6 +236,7 @@ static void try_fill_recv(struct virtnet_info *vi) | |||
233 | err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb); | 236 | err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb); |
234 | if (err) { | 237 | if (err) { |
235 | skb_unlink(skb, &vi->recv); | 238 | skb_unlink(skb, &vi->recv); |
239 | trim_pages(vi, skb); | ||
236 | kfree_skb(skb); | 240 | kfree_skb(skb); |
237 | break; | 241 | break; |
238 | } | 242 | } |