Retrieve the used ring buffers in the indirect descriptor area
of split shadow virtqueues.

Signed-off-by: Wafer Xie <[email protected]>
---
 hw/virtio/vhost-shadow-virtqueue.c | 36 ++++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/hw/virtio/vhost-shadow-virtqueue.c 
b/hw/virtio/vhost-shadow-virtqueue.c
index 94ad5c3a57..0ffb884196 100644
--- a/hw/virtio/vhost-shadow-virtqueue.c
+++ b/hw/virtio/vhost-shadow-virtqueue.c
@@ -636,12 +636,40 @@ static VirtQueueElement 
*vhost_svq_get_buf(VhostShadowVirtqueue *svq,
         return NULL;
     }
 
+    bool used_indirect = (svq->desc_state[used_elem.id].indirect_desc != NULL);
+
+    /* Free indirect descriptor table if it was used */
+    if (used_indirect) {
+        if (svq->indirect_ops && svq->indirect_ops->free) {
+            svq->indirect_ops->free(svq,
+                                    
svq->desc_state[used_elem.id].indirect_desc,
+                                    
svq->desc_state[used_elem.id].indirect_iova,
+                                    
svq->desc_state[used_elem.id].indirect_size,
+                                    svq->indirect_ops->opaque);
+        }
+        svq->desc_state[used_elem.id].indirect_desc = NULL;
+        svq->desc_state[used_elem.id].indirect_iova = 0;
+        svq->desc_state[used_elem.id].indirect_size = 0;
+    }
+
     num = svq->desc_state[used_elem.id].ndescs;
     svq->desc_state[used_elem.id].ndescs = 0;
-    last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id);
-    svq->desc_next[last_used_chain] = svq->free_head;
-    svq->free_head = used_elem.id;
-    svq->num_free += num;
+
+    /*
+     * If using indirect descriptors, only 1 main descriptor is used.
+     * To maintain consistency with `add split`,
+     * we used 'num' as free descriptors.
+     */
+    if (used_indirect) {
+        svq->desc_next[used_elem.id] = svq->free_head;
+        svq->free_head = used_elem.id;
+        svq->num_free += num;
+    } else {
+        last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id);
+        svq->desc_next[last_used_chain] = svq->free_head;
+        svq->free_head = used_elem.id;
+        svq->num_free += num;
+    }
 
     *len = used_elem.len;
     return g_steal_pointer(&svq->desc_state[used_elem.id].elem);
-- 
2.34.1


Reply via email to