net/virtio: add barrier before reading the flags
authorIlya Maximets <i.maximets@samsung.com>
Wed, 9 Jan 2019 14:50:13 +0000 (17:50 +0300)
committerFerruh Yigit <ferruh.yigit@intel.com>
Mon, 14 Jan 2019 16:44:29 +0000 (17:44 +0100)
Reading the used->flags could be reordered with avail->idx update.
vhost in kernel disables notifications for the time of packets
receiving, like this:

    1. disable notify
    2. process packets
    3. enable notify
    4. has more packets ? goto 1

In case of reordering, virtio driver could read the flags on
step 2 while notifications disabled and update avail->idx after
the step 4, i.e. vhost will exit the loop on step 4 with
notifications enabled, but virtio will not notify.

Fixes: c1f86306a026 ("virtio: add new driver")
Cc: stable@dpdk.org
Reported-by: Shahaf Shuler <shahafs@mellanox.com>
Signed-off-by: Ilya Maximets <i.maximets@samsung.com>
Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
drivers/net/virtio/virtqueue.h

index d8ae5cd..dffa036 100644 (file)
@@ -415,6 +415,11 @@ vq_update_avail_ring(struct virtqueue *vq, uint16_t desc_idx)
 static inline int
 virtqueue_kick_prepare(struct virtqueue *vq)
 {
+       /*
+        * Ensure updated avail->idx is visible to vhost before reading
+        * the used->flags.
+        */
+       virtio_mb();
        return !(vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY);
 }
 
@@ -423,6 +428,9 @@ virtqueue_kick_prepare_packed(struct virtqueue *vq)
 {
        uint16_t flags;
 
+       /*
+        * Ensure updated data is visible to vhost before reading the flags.
+        */
        virtio_mb();
        flags = vq->ring_packed.device_event->desc_event_flags;