Check if all descriptors of the queue are available. In other words, is
the complete opposite of virtio_queue_empty: If the queue is full, the
driver cannot transfer more buffers to the device until the latter
make some as used.

In Shadow vq this situation happens with the correct guest network
driver, since the rx queue is filled for the device to write. Since
Shadow Virtqueue forward the available ones blindly, it will call the
driver forever for them, reaching the point where no more descriptors
are available.

While a straightforward solution is to keep the count of them in SVQ,
this specific issue is the only need for that counter. Exposing this
check helps to keep the SVQ simpler storing as little status as
possible.

Signed-off-by: Eugenio Pérez <epere...@redhat.com>
---
 include/hw/virtio/virtio.h |  2 ++
 hw/virtio/virtio.c         | 18 ++++++++++++++++--
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index c2c7cee993..899c5e3506 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -232,6 +232,8 @@ int virtio_queue_ready(VirtQueue *vq);
 
 int virtio_queue_empty(VirtQueue *vq);
 
+bool virtio_queue_full(const VirtQueue *vq);
+
 /* Host binding interface.  */
 
 uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr);
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index a86b3f9c26..e9a4d9ffae 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -670,6 +670,20 @@ int virtio_queue_empty(VirtQueue *vq)
     }
 }
 
+/*
+ * virtio_queue_full:
+ * @vq The #VirtQueue
+ *
+ * Check if all descriptors of the queue are available. In other words, is the
+ * complete opposite of virtio_queue_empty: If the queue is full, the driver
+ * cannot transfer more buffers to the device until the latter make some as
+ * used.
+ */
+bool virtio_queue_full(const VirtQueue *vq)
+{
+    return vq->inuse >= vq->vring.num;
+}
+
 static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem,
                                unsigned int len)
 {
@@ -1439,7 +1453,7 @@ static void *virtqueue_split_pop(VirtQueue *vq, size_t sz)
 
     max = vq->vring.num;
 
-    if (vq->inuse >= vq->vring.num) {
+    if (unlikely(virtio_queue_full(vq))) {
         virtio_error(vdev, "Virtqueue size exceeded");
         goto done;
     }
@@ -1574,7 +1588,7 @@ static void *virtqueue_packed_pop(VirtQueue *vq, size_t 
sz)
 
     max = vq->vring.num;
 
-    if (vq->inuse >= vq->vring.num) {
+    if (unlikely(virtio_queue_full(vq))) {
         virtio_error(vdev, "Virtqueue size exceeded");
         goto done;
     }
-- 
2.27.0


Reply via email to