vhost: factor out the get of last used desc in SVQ
This code path is modified to handle in order devices. Abstract here so we can generalize on the caller. Signed-off-by: Eugenio Pérez <eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-Id: <20260304173535.2702587-5-eperezma@redhat.com>
Eugenio Pérez committed
Mar 4, 2026 at 18:35 UTC
90369a1165c4ffc5a22c9e0fb1743bc0ff896861
1 file changed
+29
-16
hw/virtio/vhost-shadow-virtqueue.c
+29
-16
@@ -444,6 +444,25 @@ static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq)
444
}
445
}
446
447
+/*
448
+ * Gets the next buffer id and moves forward the used idx, so the next time
449
+ * SVQ calls this function will get the next one.
450
+ *
451
+ * @svq: Shadow VirtQueue
452
+ * @len: Consumed length by the device.
453
+ *
454
+ * Return the next descriptor consumed by the device.
455
+ */
456
+static uint16_t vhost_svq_get_last_used_split(VhostShadowVirtqueue *svq,
457
+ uint32_t *len)
458
+{
459
+ const vring_used_t *used = svq->vring.used;
460
+ uint16_t last_used = svq->last_used_idx++ & (svq->vring.num - 1);
461
+
462
+ *len = le32_to_cpu(used->ring[last_used].len);
463
+ return le32_to_cpu(used->ring[last_used].id);
464
+}
465
+
466
static uint16_t vhost_svq_last_desc_of_chain(const VhostShadowVirtqueue *svq,
467
uint16_t num, uint16_t i)
468
{
@@ -458,8 +477,6 @@ G_GNUC_WARN_UNUSED_RESULT
477
static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
478
uint32_t *len)
479
{
461
- const vring_used_t *used = svq->vring.used;
462
- vring_used_elem_t used_elem;
480
uint16_t last_used, last_used_chain, num;
481
482
if (!vhost_svq_more_used(svq)) {
@@ -468,33 +485,29 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
485
486
/* Only get used array entries after they have been exposed by dev */
487
smp_rmb();
471
- last_used = svq->last_used_idx & (svq->vring.num - 1);
472
- used_elem.id = le32_to_cpu(used->ring[last_used].id);
473
- used_elem.len = le32_to_cpu(used->ring[last_used].len);
488
+ last_used = vhost_svq_get_last_used_split(svq, len);
489
475
- svq->last_used_idx++;
476
- if (unlikely(used_elem.id >= svq->vring.num)) {
490
+ if (unlikely(last_used >= svq->vring.num)) {
491
qemu_log_mask(LOG_GUEST_ERROR, "Device %s says index %u is used",
478
- svq->vdev->name, used_elem.id);
492
+ svq->vdev->name, last_used);
493
return NULL;
494
}
495
482
- if (unlikely(!svq->desc_state[used_elem.id].ndescs)) {
496
+ if (unlikely(!svq->desc_state[last_used].ndescs)) {
497
qemu_log_mask(LOG_GUEST_ERROR,
498
"Device %s says index %u is used, but it was not available",
485
- svq->vdev->name, used_elem.id);
499
+ svq->vdev->name, last_used);
500
return NULL;
501
}
502
489
- num = svq->desc_state[used_elem.id].ndescs;
490
- svq->desc_state[used_elem.id].ndescs = 0;
491
- last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id);
503
+ num = svq->desc_state[last_used].ndescs;
504
+ svq->desc_state[last_used].ndescs = 0;
505
+ last_used_chain = vhost_svq_last_desc_of_chain(svq, num, last_used);
506
svq->desc_state[last_used_chain].next = svq->free_head;
493
- svq->free_head = used_elem.id;
507
+ svq->free_head = last_used;
508
svq->num_free += num;
509
496
- *len = used_elem.len;
497
- return g_steal_pointer(&svq->desc_state[used_elem.id].elem);
510
+ return g_steal_pointer(&svq->desc_state[last_used].elem);
511
}
512
513
/**