This allows external handlers to be aware of new buffers that the guest places in the virtqueue.
When this callback is defined the ownership of guest's virtqueue element is transferred to the callback. This means that if the user wants to forward the descriptor it needs to manually inject it. The callback is also free to process the command by itself and use the element with svq_push. Signed-off-by: Eugenio Pérez <epere...@redhat.com> --- hw/virtio/vhost-shadow-virtqueue.h | 16 ++++++++++++++++ hw/virtio/vhost-shadow-virtqueue.c | 8 +++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h index 296fef6f21..4300cb66f8 100644 --- a/hw/virtio/vhost-shadow-virtqueue.h +++ b/hw/virtio/vhost-shadow-virtqueue.h @@ -27,12 +27,28 @@ typedef struct VhostShadowVirtqueue VhostShadowVirtqueue; typedef int (*ShadowVirtQueueStart)(VhostShadowVirtqueue *svq, void *opaque); +/** + * Callback to handle an avail buffer. + * + * @svq: Shadow virtqueue + * @elem: Element placed in the queue by the guest + * @vq_callback_opaque: Opaque + * + * Returns true if the vq is running as expected, false otherwise. + * + * Note that ownership of elem is transferred to the callback. + */ +typedef bool (*VirtQueueAvailCallback)(VhostShadowVirtqueue *svq, + VirtQueueElement *elem, + void *vq_callback_opaque); + typedef void (*VirtQueueUsedCallback)(VhostShadowVirtqueue *svq, void *used_elem_opaque, uint32_t written); typedef struct VhostShadowVirtqueueOps { ShadowVirtQueueStart start; + VirtQueueAvailCallback avail_handler; VirtQueueUsedCallback used_handler; } VhostShadowVirtqueueOps; diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c index b92ca4a63f..dffea256f1 100644 --- a/hw/virtio/vhost-shadow-virtqueue.c +++ b/hw/virtio/vhost-shadow-virtqueue.c @@ -371,7 +371,13 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) return; } - ok = vhost_svq_add_element(svq, g_steal_pointer(&elem)); + if (svq->ops) { + ok = svq->ops->avail_handler(svq, g_steal_pointer(&elem), + svq->ops_opaque); + } else { + ok = vhost_svq_add_element(svq, g_steal_pointer(&elem)); + } + if (unlikely(!ok)) { /* VQ is broken, just return and ignore any other kicks */ return; -- 2.31.1