[PATCH kvmtool] virtio: Fix ordering of virt_queue__available()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



After adding buffers to the virtio queue, the guest increments the avail
index. It then reads the event index to check if it needs to notify the
guest. If the event index corresponds to the previous avail value, then
the guest notifies the host. Otherwise it means that the guest is still
processing the queue and hasn't had a chance to increment the event
index yet. Once it gets there, the host will see the new avail index and
process the descriptors, so there is no need for a notification.

This is only guaranteed to work if both threads write and read the
indices in the right order. Currently a barrier is missing from
virt_queue__available(), and the host may not see an up-to-date value of
event index after writing avail.

             HOST            |           GUEST
                             |
                             |    write avail = 1
                             |    mb()
                             |    read event -> 0
        write event = 0      |      == prev_avail -> notify
        read avail -> 1      |
                             |
        write event = 1      |
        read avail -> 1      |
        wait()               |    write avail = 2
                             |    mb()
                             |    read event -> 0
                             |      != prev_avail -> no notification

By adding a memory barrier on the host side, we ensure that it doesn't
miss any notification.

Reviewed-By: Steven Price <steven.price@xxxxxxx>
Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@xxxxxxx>
---
 include/kvm/virtio.h | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h
index db758b125..72290fc58 100644
--- a/include/kvm/virtio.h
+++ b/include/kvm/virtio.h
@@ -124,8 +124,15 @@ static inline bool virt_queue__available(struct virt_queue *vq)
 	if (!vq->vring.avail)
 		return 0;
 
-	if (vq->use_event_idx)
+	if (vq->use_event_idx) {
 		vring_avail_event(&vq->vring) = last_avail_idx;
+		/*
+		 * After the driver writes a new avail index, it reads the event
+		 * index to see if we need any notification. Ensure that it
+		 * reads the updated index, or else we'll miss the notification.
+		 */
+		mb();
+	}
 
 	return vq->vring.avail->idx != last_avail_idx;
 }
-- 
2.19.1




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux