diff mbox

[PATCHv2,2/3] virtio: add missing mb() on enable notification

Message ID 89f5bc9dc88a401b472508586752d8906b7505d6.1335186822.git.mst@redhat.com
State New
Headers show

Commit Message

Michael S. Tsirkin April 23, 2012, 1:19 p.m. UTC
This fixes an issue dual to the one fixed by
patch 'virtio: add missing mb() on notification'
and applies on top.

In this case, to enable vq kick to exit to host,
qemu writes out used flag then reads the
avail index. if these are reordered we get a race:

    host avail index read: ring is empty
    		guest avail index write
    		guest flag read: exit disabled
    host used flag write: enable exit

which results in a lost exit: host will never be notified about the
avail index update.  Again, happens in the field but only seems to
trigger on some specific hardware.

Insert an smp_mb barrier operation to ensure the correct ordering.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/virtio.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

Comments

Paolo Bonzini April 24, 2012, 2:03 p.m. UTC | #1
Il 23/04/2012 15:19, Michael S. Tsirkin ha scritto:
> @@ -694,7 +698,7 @@ static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
>      uint16_t old, new;
>      bool v;
>      /* We need to expose used array entries before checking used event. */
> -    mb();
> +    smp_mb();

This mb() is not in upstream QEMU, only in qemu-kvm.

Paolo
Michael S. Tsirkin April 24, 2012, 2:48 p.m. UTC | #2
On Tue, Apr 24, 2012 at 04:03:16PM +0200, Paolo Bonzini wrote:
> Il 23/04/2012 15:19, Michael S. Tsirkin ha scritto:
> > @@ -694,7 +698,7 @@ static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
> >      uint16_t old, new;
> >      bool v;
> >      /* We need to expose used array entries before checking used event. */
> > -    mb();
> > +    smp_mb();
> 
> This mb() is not in upstream QEMU, only in qemu-kvm.
> 
> Paolo

Actually patch 1/3 adds this by mistake.
I tested all 3 together so missed this but it would break
bisect. Will fix, thanks.
diff mbox

Patch

diff --git a/hw/virtio.c b/hw/virtio.c
index 6449746..def0bf1 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -209,6 +209,10 @@  void virtio_queue_set_notification(VirtQueue *vq, int enable)
     } else {
         vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
     }
+    if (enable) {
+        /* Expose avail event/used flags before caller checks the avail idx. */
+        smp_mb();
+    }
 }
 
 int virtio_queue_ready(VirtQueue *vq)
@@ -694,7 +698,7 @@  static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
     uint16_t old, new;
     bool v;
     /* We need to expose used array entries before checking used event. */
-    mb();
+    smp_mb();
     /* Always notify when queue is empty (when feature acknowledge) */
     if (((vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) &&
          !vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx)) {