From: wafer Xie <[email protected]>

For the used ring, based on the state of the SVQ descriptor,
if it is indirect, retrieve the corresponding indirect buffer by index
and then increment the freeing counter.
Once all descriptors in this buffer have been released,
update the current buffer state to SVQ_INDIRECT_BUF_FREED.

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

diff --git a/hw/virtio/vhost-shadow-virtqueue.c 
b/hw/virtio/vhost-shadow-virtqueue.c
index 85eff1d841..adee52f50b 100644
--- a/hw/virtio/vhost-shadow-virtqueue.c
+++ b/hw/virtio/vhost-shadow-virtqueue.c
@@ -469,12 +469,47 @@ static VirtQueueElement 
*vhost_svq_get_buf(VhostShadowVirtqueue *svq,
         return NULL;
     }
 
+    /* Check if indirect descriptors were used */
+    int indirect_buf_idx = svq->desc_state[used_elem.id].indirect_buf_idx;
+    bool used_indirect = (indirect_buf_idx >= 0);
+
+    /* Update indirect buffer state if it was used */
+    if (used_indirect) {
+        SVQIndirectDescBuf *buf = &svq->indirect_bufs[indirect_buf_idx];
+        unsigned int ndescs = svq->desc_state[used_elem.id].ndescs;
+
+        /* Increment freeing_descs for descriptors returned from used ring */
+        buf->freeing_descs += ndescs;
+
+        /* Check if all descs are accounted for (freed + freeing == num) */
+        if (buf->freed_descs + buf->freeing_descs >= buf->num_descs) {
+            /* Reset buffer to freed state */
+            buf->state = SVQ_INDIRECT_BUF_FREED;
+            buf->freed_descs = buf->num_descs;
+            buf->freeing_descs = 0;
+            buf->freed_head = 0;
+        }
+
+        svq->desc_state[used_elem.id].indirect_buf_idx = -1;
+    }
+
     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.
+     * Otherwise, we used 'num' descriptors in a chain.
+     */
+    if (used_indirect) {
+        svq->desc_next[used_elem.id] = svq->free_head;
+        svq->free_head = used_elem.id;
+        svq->num_free += 1;
+    } 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.48.1


Reply via email to