aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/virtio_net.c
diff options
context:
space:
mode:
authorMark McLoughlin <markmc@redhat.com>2008-06-08 06:50:56 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-06-10 18:20:31 -0400
commit14c998f034bdc9a5bfa53bca18fbd0738cbc65e8 (patch)
tree161263012d022bddcdb7a0389f0ab367c013ce66 /drivers/net/virtio_net.c
parent2506ece0c0bbd2fc19a4827b96dc52ea47e2ce4a (diff)
virtio: virtio_net free transmit skbs in a timer
virtio_net currently only frees old transmit skbs just before queueing new ones. If the queue is full, it then enables interrupts and waits for notification that more work has been performed. However, a side-effect of this scheme is that there are always xmit skbs left dangling when no new packets are sent, against the Documentation/networking/driver.txt guideline: "... it is not allowed for your TX mitigation scheme to let TX packets "hang out" in the TX ring unreclaimed forever if no new TX packets are sent." Add a timer to ensure that any time we queue new TX skbs, we will shortly free them again. This fixes an easily reproduced hang at shutdown where iptables attempts to unload nf_conntrack and nf_conntrack waits for an skb it is tracking to be freed, but virtio_net never frees it. Signed-off-by: Mark McLoughlin <markmc@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r--drivers/net/virtio_net.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 9a3b85e55ccc..156d76fee164 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -44,6 +44,8 @@ struct virtnet_info
44 /* The skb we couldn't send because buffers were full. */ 44 /* The skb we couldn't send because buffers were full. */
45 struct sk_buff *last_xmit_skb; 45 struct sk_buff *last_xmit_skb;
46 46
47 struct timer_list xmit_free_timer;
48
47 /* Number of input buffers, and max we've ever had. */ 49 /* Number of input buffers, and max we've ever had. */
48 unsigned int num, max; 50 unsigned int num, max;
49 51
@@ -240,9 +242,23 @@ static void free_old_xmit_skbs(struct virtnet_info *vi)
240 } 242 }
241} 243}
242 244
245static void xmit_free(unsigned long data)
246{
247 struct virtnet_info *vi = (void *)data;
248
249 netif_tx_lock(vi->dev);
250
251 free_old_xmit_skbs(vi);
252
253 if (!skb_queue_empty(&vi->send))
254 mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10));
255
256 netif_tx_unlock(vi->dev);
257}
258
243static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) 259static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
244{ 260{
245 int num; 261 int num, err;
246 struct scatterlist sg[2+MAX_SKB_FRAGS]; 262 struct scatterlist sg[2+MAX_SKB_FRAGS];
247 struct virtio_net_hdr *hdr; 263 struct virtio_net_hdr *hdr;
248 const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; 264 const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
@@ -285,7 +301,11 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
285 vnet_hdr_to_sg(sg, skb); 301 vnet_hdr_to_sg(sg, skb);
286 num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; 302 num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
287 303
288 return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); 304 err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
305 if (!err)
306 mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10));
307
308 return err;
289} 309}
290 310
291static void xmit_tasklet(unsigned long data) 311static void xmit_tasklet(unsigned long data)
@@ -456,6 +476,8 @@ static int virtnet_probe(struct virtio_device *vdev)
456 476
457 tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi); 477 tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi);
458 478
479 setup_timer(&vi->xmit_free_timer, xmit_free, (unsigned long)vi);
480
459 err = register_netdev(dev); 481 err = register_netdev(dev);
460 if (err) { 482 if (err) {
461 pr_debug("virtio_net: registering device failed\n"); 483 pr_debug("virtio_net: registering device failed\n");
@@ -493,6 +515,8 @@ static void virtnet_remove(struct virtio_device *vdev)
493 /* Stop all the virtqueues. */ 515 /* Stop all the virtqueues. */
494 vdev->config->reset(vdev); 516 vdev->config->reset(vdev);
495 517
518 del_timer_sync(&vi->xmit_free_timer);
519
496 /* Free our skbs in send and recv queues, if any. */ 520 /* Free our skbs in send and recv queues, if any. */
497 while ((skb = __skb_dequeue(&vi->recv)) != NULL) { 521 while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
498 kfree_skb(skb); 522 kfree_skb(skb);