---
 Documentation/lguest/lguest.c |    8 ++++++--
 drivers/char/vring.c          |   14 ++++++++++++++
 drivers/net/tun.c             |    8 ++++++++
 drivers/net/virtio_net.c      |    4 ++++
 drivers/virtio/virtio_ring.c  |   10 +++++++++-
 include/linux/vring.h         |    3 +++
 6 files changed, 44 insertions(+), 3 deletions(-)

diff -r e00ed7de87c1 Documentation/lguest/lguest.c
--- a/Documentation/lguest/lguest.c	Tue Jun 17 11:49:24 2008 +1000
+++ b/Documentation/lguest/lguest.c	Tue Jun 17 15:09:04 2008 +1000
@@ -874,8 +874,12 @@ static bool handle_console_input(int fd,
 				/* Just in case Waker is blocked in BREAK, send
 				 * unbreak now. */
 				write(fd, args, sizeof(args));
-				printf("xmit_notifies = %u, recv_notifies = %u, xmit_kicks = %u, recv_kicks = %u\n",
-				       num_xmit_notifies, num_recv_notifies, num_xmit_kicks, num_recv_kicks);
+				{
+					char buf[200];
+					sprintf(buf, "%u: xmit_notifies = %u, recv_notifies = %u, xmit_kicks = %u, recv_kicks = %u\n",
+						getpid(), num_xmit_notifies, num_recv_notifies, num_xmit_kicks, num_recv_kicks);
+					write(STDOUT_FILENO, buf, strlen(buf));
+				}
 				exit(2);
 			}
 			abort->count = 0;
diff -r e00ed7de87c1 drivers/char/vring.c
--- a/drivers/char/vring.c	Tue Jun 17 11:49:24 2008 +1000
+++ b/drivers/char/vring.c	Tue Jun 17 15:09:04 2008 +1000
@@ -222,6 +222,20 @@ bool vring_has_buffer(struct vring_info 
 }
 EXPORT_SYMBOL_GPL(vring_has_buffer);
 
+void vring_set_notify(struct vring_info *vr, bool on)
+{
+#if 1
+	if (on)
+		vr->ring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
+	else {
+		vr->ring.used->flags |= VRING_USED_F_NO_NOTIFY;
+		/* Make sure this is reset before caller checks for more. */
+		mb();
+	}
+#endif
+}
+EXPORT_SYMBOL_GPL(vring_set_notify);
+
 /**
  * vring_get_buffer - get a buffer from the vring
  * @vr: the vring
diff -r e00ed7de87c1 drivers/net/tun.c
--- a/drivers/net/tun.c	Tue Jun 17 11:49:24 2008 +1000
+++ b/drivers/net/tun.c	Tue Jun 17 15:09:04 2008 +1000
@@ -470,6 +470,7 @@ static int pull_recv_skbs(void *_tun)
 	int err = 0, num_copied = 0;
 	struct sk_buff *skb;
 
+	vring_set_notify(tun->inring, false);
 	while ((skb = skb_dequeue(&tun->readq)) != NULL) {
 		struct iovec iov[2+MAX_SKB_FRAGS];
 		struct virtio_net_hdr gso = { 0 }; /* no info leak */
@@ -482,7 +483,11 @@ static int pull_recv_skbs(void *_tun)
 		id = vring_get_buffer(tun->inring, iov, ARRAY_SIZE(iov), &len,
 				      NULL, 0, NULL);
 		if (id <= 0) {
+			printk("Re-enabling notifications at %lu\n",
+			       tun->dev->stats.tx_packets);
 			tun->dev->stats.tx_aborted_errors++;
+			/* Now we want to know when they add new buffers. */
+			vring_set_notify(tun->inring, true);
 			err = id;
 			break;
 		}
@@ -701,6 +706,9 @@ static int set_recv_vring(struct tun_str
 		tun->inring = NULL;
 		goto put;
 	}
+
+	/* We don't normally care when they add buffers to this. */
+	vring_set_notify(tun->inring, false);
 	return 0;
 
 put:
diff -r e00ed7de87c1 drivers/net/virtio_net.c
--- a/drivers/net/virtio_net.c	Tue Jun 17 11:49:24 2008 +1000
+++ b/drivers/net/virtio_net.c	Tue Jun 17 15:09:04 2008 +1000
@@ -550,6 +550,10 @@ static int virtnet_probe(struct virtio_d
 		err = PTR_ERR(vi->rvq);
 		goto free;
 	}
+	{
+		extern struct virtqueue *debug_vq;
+		debug_vq = vi->rvq;
+	}
 
 	vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done);
 	if (IS_ERR(vi->svq)) {
diff -r e00ed7de87c1 drivers/virtio/virtio_ring.c
--- a/drivers/virtio/virtio_ring.c	Tue Jun 17 11:49:24 2008 +1000
+++ b/drivers/virtio/virtio_ring.c	Tue Jun 17 15:09:04 2008 +1000
@@ -65,6 +65,9 @@ struct vring_virtqueue
 	void *data[];
 };
 
+struct virtqueue *debug_vq;
+EXPORT_SYMBOL(debug_vq);
+
 #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)
 
 static int vring_add_buf(struct virtqueue *_vq,
@@ -86,6 +89,8 @@ static int vring_add_buf(struct virtqueu
 		pr_debug("Can't add buf len %i - avail = %i\n",
 			 out + in, vq->num_free);
 		/* We notify *even if* VRING_USED_F_NO_NOTIFY is set here. */
+		if (_vq == debug_vq)
+			printk("Kicking FULL xmit ring\n");
 		vq->notify(&vq->vq);
 		END_USE(vq);
 		return -ENOSPC;
@@ -142,9 +147,12 @@ static void vring_kick(struct virtqueue 
 	/* Need to update avail index before checking if we should notify */
 	mb();
 
-	if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
+	if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY)) {
+		if (_vq == debug_vq)
+			printk("Kicking xmit ring\n");
 		/* Prod other side to tell it about changes. */
 		vq->notify(&vq->vq);
+	}
 
 	END_USE(vq);
 }
diff -r e00ed7de87c1 include/linux/vring.h
--- a/include/linux/vring.h	Tue Jun 17 11:49:24 2008 +1000
+++ b/include/linux/vring.h	Tue Jun 17 15:09:04 2008 +1000
@@ -64,6 +64,9 @@ bool vring_has_buffer(struct vring_info 
 
 int vring_used_buffer(struct vring_info *vr, int id, u32 len);
 
+/* Toggle whether you want to be notified about new buffers. */
+void vring_set_notify(struct vring_info *vr, bool on);
+
 void vring_wake(struct vring_info *vr);
 #endif /* __KERNEL__ */
 
