Set the VIRTIO_RING_F_PUBLISH_INDICES feature and publish
the last_avail index within the ring itself.

This is important for save/restore when using vringfd
because the kernel is the one tracking last_avail, but
we need to be able to peek at that state.

Signed-off-by: Mark McLoughlin <[EMAIL PROTECTED]>
---
 qemu/hw/virtio-net.c |    4 ++--
 qemu/hw/virtio.c     |   16 ++++++++--------
 qemu/hw/virtio.h     |    7 ++++++-
 3 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/qemu/hw/virtio-net.c b/qemu/hw/virtio-net.c
index a61fdb1..6c42bf0 100644
--- a/qemu/hw/virtio-net.c
+++ b/qemu/hw/virtio-net.c
@@ -106,7 +106,7 @@ static int virtio_net_can_receive(void *opaque)
        !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
        return 0;
 
-    if (n->rx_vq->vring.avail->idx == n->rx_vq->last_avail_idx)
+    if (n->rx_vq->vring.avail->idx == vq_last_avail(n->rx_vq))
        return 0;
 
     return 1;
@@ -178,7 +178,7 @@ static void virtio_net_handle_tx(VirtIODevice *vdev, 
VirtQueue *vq)
     VirtIONet *n = to_virtio_net(vdev);
 
     if (n->tx_timer_active &&
-       (vq->vring.avail->idx - vq->last_avail_idx) == 64) {
+       (vq->vring.avail->idx - vq_last_avail(vq)) == 64) {
        vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
        qemu_del_timer(n->tx_timer);
        n->tx_timer_active = 0;
diff --git a/qemu/hw/virtio.c b/qemu/hw/virtio.c
index 3119ea9..a1ee93f 100644
--- a/qemu/hw/virtio.c
+++ b/qemu/hw/virtio.c
@@ -147,17 +147,17 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
     unsigned int position;
 
     /* Check it isn't doing very strange things with descriptor numbers. */
-    if ((uint16_t)(vq->vring.avail->idx - vq->last_avail_idx) > vq->vring.num)
+    if ((uint16_t)(vq->vring.avail->idx - vq_last_avail(vq)) > vq->vring.num)
        errx(1, "Guest moved used index from %u to %u",
-            vq->last_avail_idx, vq->vring.avail->idx);
+            vq_last_avail(vq), vq->vring.avail->idx);
 
     /* If there's nothing new since last we looked, return invalid. */
-    if (vq->vring.avail->idx == vq->last_avail_idx)
+    if (vq->vring.avail->idx == vq_last_avail(vq))
        return 0;
 
     /* Grab the next descriptor number they're advertising, and increment
      * the index we've seen. */
-    head = vq->vring.avail->ring[vq->last_avail_idx++ % vq->vring.num];
+    head = vq->vring.avail->ring[vq_last_avail(vq)++ % vq->vring.num];
 
     /* If their number is silly, that's a fatal mistake. */
     if (head >= vq->vring.num)
@@ -222,7 +222,6 @@ void virtio_reset(void *opaque)
         vdev->vq[i].vring.desc = NULL;
         vdev->vq[i].vring.avail = NULL;
         vdev->vq[i].vring.used = NULL;
-        vdev->vq[i].last_avail_idx = 0;
         vdev->vq[i].pfn = 0;
     }
 }
@@ -278,6 +277,7 @@ static uint32_t virtio_ioport_read(void *opaque, uint32_t 
addr)
     case VIRTIO_PCI_HOST_FEATURES:
        ret = vdev->get_features(vdev);
        ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+       ret |= (1 << VIRTIO_RING_F_PUBLISH_INDICES);
        break;
     case VIRTIO_PCI_GUEST_FEATURES:
        ret = vdev->features;
@@ -434,7 +434,7 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int 
queue_size,
 void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
 {
     /* Always notify when queue is empty */
-    if ((vq->inuse || vq->vring.avail->idx != vq->last_avail_idx)) &&
+    if ((vq->inuse || vq->vring.avail->idx != vq_last_avail(vq)) &&
        (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT))
        return;
 
@@ -469,7 +469,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
 
        qemu_put_be32(f, vdev->vq[i].vring.num);
        qemu_put_be32s(f, &vdev->vq[i].pfn);
-       qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
+       qemu_put_be16(f, vq_last_avail(&vdev->vq[i]));
     }
 }
 
@@ -492,7 +492,7 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f)
     for (i = 0; i < num; i++) {
        vdev->vq[i].vring.num = qemu_get_be32(f);
        qemu_get_be32s(f, &vdev->vq[i].pfn);
-       qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
+       vq_last_avail(&vdev->vq[i]) = qemu_get_be16(f);
 
        if (vdev->vq[i].pfn) {
            size_t size;
diff --git a/qemu/hw/virtio.h b/qemu/hw/virtio.h
index 1adaed3..142ecbd 100644
--- a/qemu/hw/virtio.h
+++ b/qemu/hw/virtio.h
@@ -46,6 +46,9 @@
 /* This means don't interrupt guest when buffer consumed. */
 #define VRING_AVAIL_F_NO_INTERRUPT     1
 
+/* We publish the last-seen available index at the end of the used ring */
+#define VIRTIO_RING_F_PUBLISH_INDICES  28
+
 typedef struct VirtQueue VirtQueue;
 typedef struct VirtIODevice VirtIODevice;
 
@@ -89,11 +92,13 @@ struct VirtQueue
 {
     VRing vring;
     uint32_t pfn;
-    uint16_t last_avail_idx;
     int inuse;
     void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
 };
 
+/* We publish the last-seen available index at the end of the used ring */
+#define vq_last_avail(q) (*(uint16_t *)&(q)->vring.used->ring[(q)->vring.num])
+
 #define VIRTQUEUE_MAX_SIZE 1024
 
 typedef struct VirtQueueElement
-- 
1.5.4.1

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to