---
 Documentation/lguest/lguest.c |   17 ++++++++++++++++-
 drivers/net/Makefile          |    1 +
 drivers/net/tun.c             |    4 ++++
 drivers/net/virtio_net.c      |   28 +++++++++++++++++++---------
 drivers/virtio/virtio_ring.c  |    6 +++---
 5 files changed, 43 insertions(+), 13 deletions(-)

diff -r 1f3de6cbff94 Documentation/lguest/lguest.c
--- a/Documentation/lguest/lguest.c	Wed May 14 19:39:29 2008 +1000
+++ b/Documentation/lguest/lguest.c	Wed May 14 19:45:43 2008 +1000
@@ -299,6 +301,7 @@ static void *map_zeroed_pages(unsigned i
 		err(1, "Mmaping %u pages of /dev/zero", num);
 
 	verbose("Memory backing file is %s @ %p\n", memfile_path, addr);
+	memset(addr, 0, getpagesize() * num);
 	return addr;
 }
 
@@ -981,6 +984,19 @@ static void enable_fd(int fd, struct vir
 	write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
 }
 
+/* FIXME: When they add more receive buffers, we want to try pulling
+ * again: if we don't set a callback on the virtqueue then we never
+ * get notified.  So we have this dummy one.
+ *
+ * What *should* happen is that the tun driver manipulates the
+ * VRING_USED_F_NO_NOTIFY flag. */
+static void do_nothing(int fd, struct virtqueue *vq)
+{
+	/* FIXME: Wake up Waker: recvfd poll() might return 0 because lack of 
+	 * recv buffers. */
+	write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
+}
+
 /* When the Guest tells us they updated the status field, we handle it. */
 static void update_device_status(struct device *dev)
 {
@@ -1162,6 +1178,7 @@ static void add_virtqueue(struct device 
 
 	/* Initialize the vring. */
 	vring_init(&vq->vring, num_descs, p, getpagesize());
+	memset(p, 0, vring_size(num_descs, getpagesize()));
 
 	/* Append virtqueue to this device's descriptor.  We use
 	 * device_config() to get the end of the device's current virtqueues;
@@ -1467,7 +1484,7 @@ static void setup_tun_net(const char *ar
 	if (rings) {
 		/* First we create a new network device. */
 		dev = new_device("net", VIRTIO_ID_NET, netfd, NULL);
-		add_virtqueue(dev, VIRTQUEUE_NUM, NULL);
+		add_virtqueue(dev, VIRTQUEUE_NUM, do_nothing);
 		add_virtqueue(dev, VIRTQUEUE_NUM, handle_netring_output);
 	} else {
 		/* We don't need checksums calculated for packets coming in this
diff -r 1f3de6cbff94 drivers/net/Makefile
--- a/drivers/net/Makefile	Wed May 14 19:39:29 2008 +1000
+++ b/drivers/net/Makefile	Wed May 14 19:45:43 2008 +1000
@@ -255,3 +255,4 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_SFC) += sfc/
 
+CFLAGS_virtio_net.o += -O0
diff -r 1f3de6cbff94 drivers/net/tun.c
--- a/drivers/net/tun.c	Wed May 14 19:39:29 2008 +1000
+++ b/drivers/net/tun.c	Wed May 14 19:45:43 2008 +1000
@@ -476,9 +476,13 @@ static int pull_recv_skbs(void *_tun)
 		unsigned long len;
 		int id;
 
+		tun->dev->stats.tx_packets++;
+		tun->dev->stats.tx_bytes += skb->len;
+
 		id = vring_get_buffer(tun->inring, iov, ARRAY_SIZE(iov), &len,
 				      NULL, 0, NULL);
 		if (id <= 0) {
+			tun->dev->stats.tx_aborted_errors++;
 			err = id;
 			break;
 		}
diff -r 1f3de6cbff94 drivers/net/virtio_net.c
--- a/drivers/net/virtio_net.c	Wed May 14 19:39:29 2008 +1000
+++ b/drivers/net/virtio_net.c	Wed May 14 19:45:43 2008 +1000
@@ -75,14 +75,14 @@ static void skb_xmit_done(struct virtque
 	svq->vq_ops->disable_cb(svq);
 
 	/* Were we waiting for more output buffers? */
-	qstopped = netif_queue_stopped(vi->dev);
-	if (qstopped)
+//	qstopped = netif_queue_stopped(vi->dev);
+//	if (qstopped)
 		netif_wake_queue(vi->dev);
 
 	/* We might be stopped, but not have anything more to send, except for
 	 * that last_xmit_skb we failed last time.  Or we might not be stopped,
 	 * but we should be polite and free xmitted skbs. */
-	if (!qstopped || vi->last_xmit_skb)
+//	if (!qstopped || vi->last_xmit_skb)
 		tasklet_schedule(&vi->tasklet);
 }
 
@@ -336,23 +336,33 @@ again:
 	/* Free up any pending old buffers before queueing new ones. */
 	free_old_xmit_skbs(vi);
 
-	/* If we has a buffer left over from last time, send it now. */
+	/* If we have a buffer left over from last time, send it now. */
 	if (vi->last_xmit_skb) {
 		if (xmit_skb(vi, vi->last_xmit_skb) != 0) {
 			/* Drop this skb: we only queue one. */
 			vi->dev->stats.tx_dropped++;
 			kfree_skb(skb);
+			skb = NULL;
 			goto stop_queue;
 		}
 		vi->last_xmit_skb = NULL;
 	}
 
-	/* Put new one in send queue and do transmit */
-	__skb_queue_head(&vi->send, skb);
-	if (xmit_skb(vi, skb) != 0) {
-		vi->last_xmit_skb = skb;
-		goto stop_queue;
+	if (likely(skb)) {
+		/* Put new one in send queue and do transmit */
+		__skb_queue_head(&vi->send, skb);
+		if (xmit_skb(vi, skb) != 0) {
+#if 0
+			vi->last_xmit_skb = skb;
+			skb = NULL;
+			goto stop_queue;
+#else
+			__skb_unlink(skb, &vi->send);
+			return NETDEV_TX_BUSY;
+#endif
+		}
 	}
+
 done:
 	vi->svq->vq_ops->kick(vi->svq);
 	return NETDEV_TX_OK;
diff -r 1f3de6cbff94 drivers/virtio/virtio_ring.c
--- a/drivers/virtio/virtio_ring.c	Wed May 14 19:39:29 2008 +1000
+++ b/drivers/virtio/virtio_ring.c	Wed May 14 19:45:43 2008 +1000
@@ -221,7 +221,7 @@ static void vring_disable_cb(struct virt
 {
 	struct vring_virtqueue *vq = to_vvq(_vq);
 
-	vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+//	vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
 }
 
 static bool vring_enable_cb(struct virtqueue *_vq)
@@ -229,11 +229,11 @@ static bool vring_enable_cb(struct virtq
 	struct vring_virtqueue *vq = to_vvq(_vq);
 
 	START_USE(vq);
-	BUG_ON(!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT));
+//	BUG_ON(!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT));
 
 	/* We optimistically turn back on interrupts, then check if there was
 	 * more to do. */
-	vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
+//	vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
 	mb();
 	if (unlikely(more_used(vq))) {
 		END_USE(vq);
