aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2009-09-24 11:59:20 -0400
committerRusty Russell <rusty@rustcorp.com.au>2009-09-23 20:29:20 -0400
commit48925e372f04f5e35fec6269127c62b2c71ab794 (patch)
tree451e84e09afc37ed6f8dc262b40bd88106883410 /drivers
parentb3f24698a7faa6e9d8a14124cfdc25353fc8ca19 (diff)
virtio_net: avoid (most) NETDEV_TX_BUSY by stopping queue early.
Now we can tell the theoretical capacity remaining in the output queue, virtio_net can waste entries by stopping the queue early. It doesn't work in the case of indirect buffers and kmalloc failure, but that's rare (we could drop the packet in that case, but other drivers return TX_BUSY for similar reasons). For the record, I think this patch reflects poorly on the linux network API. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Cc: Dinesh Subhraveti <dineshs@us.ibm.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/virtio_net.c64
1 files changed, 40 insertions, 24 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 420388a4c5e8..effe8c685f77 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -1,4 +1,4 @@
1/* A simple network driver using virtio. 1/* A network driver using virtio.
2 * 2 *
3 * Copyright 2007 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation 3 * Copyright 2007 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
4 * 4 *
@@ -73,6 +73,7 @@ struct skb_vnet_hdr {
73 struct virtio_net_hdr hdr; 73 struct virtio_net_hdr hdr;
74 struct virtio_net_hdr_mrg_rxbuf mhdr; 74 struct virtio_net_hdr_mrg_rxbuf mhdr;
75 }; 75 };
76 unsigned int num_sg;
76}; 77};
77 78
78static inline struct skb_vnet_hdr *skb_vnet_hdr(struct sk_buff *skb) 79static inline struct skb_vnet_hdr *skb_vnet_hdr(struct sk_buff *skb)
@@ -442,23 +443,24 @@ again:
442 return received; 443 return received;
443} 444}
444 445
445static void free_old_xmit_skbs(struct virtnet_info *vi) 446static unsigned int free_old_xmit_skbs(struct virtnet_info *vi)
446{ 447{
447 struct sk_buff *skb; 448 struct sk_buff *skb;
448 unsigned int len; 449 unsigned int len, tot_sgs = 0;
449 450
450 while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) { 451 while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) {
451 pr_debug("Sent skb %p\n", skb); 452 pr_debug("Sent skb %p\n", skb);
452 __skb_unlink(skb, &vi->send); 453 __skb_unlink(skb, &vi->send);
453 vi->dev->stats.tx_bytes += skb->len; 454 vi->dev->stats.tx_bytes += skb->len;
454 vi->dev->stats.tx_packets++; 455 vi->dev->stats.tx_packets++;
456 tot_sgs += skb_vnet_hdr(skb)->num_sg;
455 kfree_skb(skb); 457 kfree_skb(skb);
456 } 458 }
459 return tot_sgs;
457} 460}
458 461
459static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) 462static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
460{ 463{
461 int num;
462 struct scatterlist sg[2+MAX_SKB_FRAGS]; 464 struct scatterlist sg[2+MAX_SKB_FRAGS];
463 struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb); 465 struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
464 const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; 466 const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
@@ -502,13 +504,14 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
502 else 504 else
503 sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr)); 505 sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr));
504 506
505 num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; 507 hdr->num_sg = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
506 return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); 508 return vi->svq->vq_ops->add_buf(vi->svq, sg, hdr->num_sg, 0, skb);
507} 509}
508 510
509static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) 511static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
510{ 512{
511 struct virtnet_info *vi = netdev_priv(dev); 513 struct virtnet_info *vi = netdev_priv(dev);
514 int capacity;
512 515
513again: 516again:
514 /* Free up any pending old buffers before queueing new ones. */ 517 /* Free up any pending old buffers before queueing new ones. */
@@ -516,27 +519,40 @@ again:
516 519
517 /* Put new one in send queue and do transmit */ 520 /* Put new one in send queue and do transmit */
518 __skb_queue_head(&vi->send, skb); 521 __skb_queue_head(&vi->send, skb);
519 if (likely(xmit_skb(vi, skb) >= 0)) { 522 capacity = xmit_skb(vi, skb);
520 vi->svq->vq_ops->kick(vi->svq); 523
521 /* Don't wait up for transmitted skbs to be freed. */ 524 /* This can happen with OOM and indirect buffers. */
522 skb_orphan(skb); 525 if (unlikely(capacity < 0)) {
523 nf_reset(skb); 526 netif_stop_queue(dev);
524 return NETDEV_TX_OK; 527 dev_warn(&dev->dev, "Unexpected full queue\n");
528 if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
529 vi->svq->vq_ops->disable_cb(vi->svq);
530 netif_start_queue(dev);
531 goto again;
532 }
533 return NETDEV_TX_BUSY;
525 } 534 }
526 535
527 /* Ring too full for this packet, remove it from queue again. */ 536 vi->svq->vq_ops->kick(vi->svq);
528 pr_debug("%s: virtio not prepared to send\n", dev->name); 537 /* Don't wait up for transmitted skbs to be freed. */
529 __skb_unlink(skb, &vi->send); 538 skb_orphan(skb);
530 netif_stop_queue(dev); 539 nf_reset(skb);
531 540
532 /* Activate callback for using skbs: if this returns false it 541 /* Apparently nice girls don't return TX_BUSY; stop the queue
533 * means some were used in the meantime. */ 542 * before it gets out of hand. Naturally, this wastes entries. */
534 if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { 543 if (capacity < 2+MAX_SKB_FRAGS) {
535 vi->svq->vq_ops->disable_cb(vi->svq); 544 netif_stop_queue(dev);
536 netif_start_queue(dev); 545 if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
537 goto again; 546 /* More just got used, free them then recheck. */
547 capacity += free_old_xmit_skbs(vi);
548 if (capacity >= 2+MAX_SKB_FRAGS) {
549 netif_start_queue(dev);
550 vi->svq->vq_ops->disable_cb(vi->svq);
551 }
552 }
538 } 553 }
539 return NETDEV_TX_BUSY; 554
555 return NETDEV_TX_OK;
540} 556}
541 557
542static int virtnet_set_mac_address(struct net_device *dev, void *p) 558static int virtnet_set_mac_address(struct net_device *dev, void *p)