Re: bug in virtio network driver?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am Mittwoch, 29. August 2007 schrieb Rusty Russell:
> On Tue, 2007-08-21 at 18:02 +0200, Christian Borntraeger wrote:
> > Am Dienstag, 21. August 2007 schrieb Rusty Russell:
> > > The only reason that we don't do it in skb_xmit_done() is because
> > > kfree_skb() isn't supposed to be called from an interrupt.  But there's
> > > dev_kfree_skb_any() which can be used.
> > 
> > Ok, I now hacked something that works but I really dont like the 
> > local_irq_disable bits. I sent this patch nevertheless, but I will look 
into 
> > Arnds suggestion.
> 
> Hi Christian,
> 
> 	What's the status of this?  Should I apply this patch, or do you want
> me to wait for a ->poll patch as per Arnd's suggestion?

I looked at Arnds suggestions. It seems that even with a cleanup in the poll 
function, we have no guarantee that the outstanding skb is reclaimed because 
there might be no incoming packet. Other drivers (like spider_net) solve this 
by using an additional tx_timer.
I start to think that my latest patch is actually not that bad: lets do the 
reclaim when the host tells us its done. 

Arnd, do you have an opinion about that?

Christian

for reference:

---
 drivers/net/virtio_net.c |   47 
++++++++++++++++++++++++++---------------------
 1 file changed, 26 insertions(+), 21 deletions(-)

Index: linux-2.6.22/drivers/net/virtio_net.c
===================================================================
--- linux-2.6.22.orig/drivers/net/virtio_net.c
+++ linux-2.6.22/drivers/net/virtio_net.c
@@ -53,12 +52,31 @@ static void vnet_hdr_to_sg(struct scatte
 	sg->length = sizeof(struct virtio_net_hdr);
 }
 
+static void free_old_xmit_skbs(struct virtnet_info *vi)
+{
+	struct sk_buff *skb;
+	unsigned int len;
+
+	netif_tx_lock(vi->ndev);
+	while ((skb = vi->vq_send->ops->get_buf(vi->vq_send, &len)) != NULL) {
+		/* They cannot have written to the packet. */
+		BUG_ON(len != 0);
+		pr_debug("Sent skb %p\n", skb);
+		__skb_unlink(skb, &vi->send);
+		vi->ndev->stats.tx_bytes += skb->len;
+		vi->ndev->stats.tx_packets++;
+		dev_kfree_skb_irq(skb);
+	}
+	netif_tx_unlock(vi->ndev);
+}
+
 static bool skb_xmit_done(struct virtqueue *vq)
 {
 	struct virtnet_info *vi = vq->priv;
 
 	/* In case we were waiting for output buffers. */
 	netif_wake_queue(vi->ndev);
+	free_old_xmit_skbs(vi);
 	return true;
 }
 
@@ -214,22 +232,6 @@ again:
 	return 0;
 }
 
-static void free_old_xmit_skbs(struct virtnet_info *vi)
-{
-	struct sk_buff *skb;
-	unsigned int len;
-
-	while ((skb = vi->vq_send->ops->get_buf(vi->vq_send, &len)) != NULL) {
-		/* They cannot have written to the packet. */
-		BUG_ON(len != 0);
-		pr_debug("Sent skb %p\n", skb);
-		__skb_unlink(skb, &vi->send);
-		vi->ndev->stats.tx_bytes += skb->len;
-		vi->ndev->stats.tx_packets++;
-		kfree_skb(skb);
-	}
-}
-
 static int start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct virtnet_info *vi = netdev_priv(dev);
@@ -238,12 +240,12 @@ static int start_xmit(struct sk_buff *sk
 	struct virtio_net_hdr *hdr;
 	const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
 
+	local_irq_disable();
+	netif_tx_lock(vi->ndev);
 	pr_debug("%s: xmit %p %02x:%02x:%02x:%02x:%02x:%02x\n",
 		 dev->name, skb,
 		 dest[0], dest[1], dest[2], dest[3], dest[4], dest[5]);
 
-	free_old_xmit_skbs(vi);
-
 	/* Encode metadata header at front. */
 	hdr = skb_vnet_hdr(skb);
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -280,10 +282,13 @@ static int start_xmit(struct sk_buff *sk
 		pr_debug("%s: virtio not prepared to send\n", dev->name);
 		skb_unlink(skb, &vi->send);
 		netif_stop_queue(dev);
+		netif_tx_unlock(vi->ndev);
+		local_irq_enable();
 		return NETDEV_TX_BUSY;
 	}
 	vi->vq_send->ops->sync(vi->vq_send);
-
+	netif_tx_unlock(vi->ndev);
+	local_irq_enable();
 	return 0;
 }
 
@@ -343,7 +348,7 @@ struct net_device *virtnet_probe(struct 
 	dev->poll = virtnet_poll;
 	dev->hard_start_xmit = start_xmit;
 	dev->weight = 16;
-	dev->features = features;
+	dev->features = features | NETIF_F_LLTX;
 	SET_NETDEV_DEV(dev, device);
 
 	vi = netdev_priv(dev);
_______________________________________________
Virtualization mailing list
Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx
https://lists.linux-foundation.org/mailman/listinfo/virtualization

[Index of Archives]     [KVM Development]     [Libvirt Development]     [Libvirt Users]     [CentOS Virtualization]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux