586cba
From 433106c286a1961737300ebaece6f10b2747e7d8 Mon Sep 17 00:00:00 2001
586cba
From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= <eperezma@redhat.com>
586cba
Date: Thu, 21 Jul 2022 15:38:55 +0200
586cba
Subject: [PATCH 20/32] vhost: Add svq avail_handler callback
586cba
MIME-Version: 1.0
586cba
Content-Type: text/plain; charset=UTF-8
586cba
Content-Transfer-Encoding: 8bit
586cba
586cba
RH-Author: Eugenio Pérez <eperezma@redhat.com>
586cba
RH-MergeRequest: 108: Net Control Virtqueue shadow Support
586cba
RH-Commit: [20/27] d228eb89d204f8be623bc870503bbf0078dfc9ae (eperezmartin/qemu-kvm)
586cba
RH-Bugzilla: 1939363
586cba
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
586cba
RH-Acked-by: Cindy Lu <lulu@redhat.com>
586cba
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
586cba
586cba
Bugzilla: https://bugzilla.redhat.com/1939363
586cba
586cba
Upstream Status: git://git.qemu.org/qemu.git
586cba
586cba
commit e966c0b781aebabd2c0f5eef91678f08ce1d068c
586cba
Author: Eugenio Pérez <eperezma@redhat.com>
586cba
Date:   Wed Jul 20 08:59:39 2022 +0200
586cba
586cba
    vhost: Add svq avail_handler callback
586cba
586cba
    This allows external handlers to be aware of new buffers that the guest
586cba
    places in the virtqueue.
586cba
586cba
    When this callback is defined the ownership of the guest's virtqueue
586cba
    element is transferred to the callback. This means that if the user
586cba
    wants to forward the descriptor it needs to manually inject it. The
586cba
    callback is also free to process the command by itself and use the
586cba
    element with svq_push.
586cba
586cba
    Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
586cba
    Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
586cba
    Signed-off-by: Jason Wang <jasowang@redhat.com>
586cba
586cba
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
586cba
---
586cba
 hw/virtio/vhost-shadow-virtqueue.c | 14 ++++++++++++--
586cba
 hw/virtio/vhost-shadow-virtqueue.h | 31 +++++++++++++++++++++++++++++-
586cba
 hw/virtio/vhost-vdpa.c             |  3 ++-
586cba
 3 files changed, 44 insertions(+), 4 deletions(-)
586cba
586cba
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
586cba
index 95d0d7a7ee..e53aac45f6 100644
586cba
--- a/hw/virtio/vhost-shadow-virtqueue.c
586cba
+++ b/hw/virtio/vhost-shadow-virtqueue.c
586cba
@@ -306,7 +306,11 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq)
586cba
                 break;
586cba
             }
586cba
 
586cba
-            r = vhost_svq_add_element(svq, elem);
586cba
+            if (svq->ops) {
586cba
+                r = svq->ops->avail_handler(svq, elem, svq->ops_opaque);
586cba
+            } else {
586cba
+                r = vhost_svq_add_element(svq, elem);
586cba
+            }
586cba
             if (unlikely(r != 0)) {
586cba
                 if (r == -ENOSPC) {
586cba
                     /*
586cba
@@ -685,12 +689,16 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq)
586cba
  * shadow methods and file descriptors.
586cba
  *
586cba
  * @iova_tree: Tree to perform descriptors translations
586cba
+ * @ops: SVQ owner callbacks
586cba
+ * @ops_opaque: ops opaque pointer
586cba
  *
586cba
  * Returns the new virtqueue or NULL.
586cba
  *
586cba
  * In case of error, reason is reported through error_report.
586cba
  */
586cba
-VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree)
586cba
+VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree,
586cba
+                                    const VhostShadowVirtqueueOps *ops,
586cba
+                                    void *ops_opaque)
586cba
 {
586cba
     g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1);
586cba
     int r;
586cba
@@ -712,6 +720,8 @@ VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree)
586cba
     event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND);
586cba
     event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call);
586cba
     svq->iova_tree = iova_tree;
586cba
+    svq->ops = ops;
586cba
+    svq->ops_opaque = ops_opaque;
586cba
     return g_steal_pointer(&svq);
586cba
 
586cba
 err_init_hdev_call:
586cba
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
586cba
index cf442f7dea..d04c34a589 100644
586cba
--- a/hw/virtio/vhost-shadow-virtqueue.h
586cba
+++ b/hw/virtio/vhost-shadow-virtqueue.h
586cba
@@ -25,6 +25,27 @@ typedef struct SVQDescState {
586cba
     unsigned int ndescs;
586cba
 } SVQDescState;
586cba
 
586cba
+typedef struct VhostShadowVirtqueue VhostShadowVirtqueue;
586cba
+
586cba
+/**
586cba
+ * Callback to handle an avail buffer.
586cba
+ *
586cba
+ * @svq:  Shadow virtqueue
586cba
+ * @elem:  Element placed in the queue by the guest
586cba
+ * @vq_callback_opaque:  Opaque
586cba
+ *
586cba
+ * Returns 0 if the vq is running as expected.
586cba
+ *
586cba
+ * Note that ownership of elem is transferred to the callback.
586cba
+ */
586cba
+typedef int (*VirtQueueAvailCallback)(VhostShadowVirtqueue *svq,
586cba
+                                      VirtQueueElement *elem,
586cba
+                                      void *vq_callback_opaque);
586cba
+
586cba
+typedef struct VhostShadowVirtqueueOps {
586cba
+    VirtQueueAvailCallback avail_handler;
586cba
+} VhostShadowVirtqueueOps;
586cba
+
586cba
 /* Shadow virtqueue to relay notifications */
586cba
 typedef struct VhostShadowVirtqueue {
586cba
     /* Shadow vring */
586cba
@@ -69,6 +90,12 @@ typedef struct VhostShadowVirtqueue {
586cba
      */
586cba
     uint16_t *desc_next;
586cba
 
586cba
+    /* Caller callbacks */
586cba
+    const VhostShadowVirtqueueOps *ops;
586cba
+
586cba
+    /* Caller callbacks opaque */
586cba
+    void *ops_opaque;
586cba
+
586cba
     /* Next head to expose to the device */
586cba
     uint16_t shadow_avail_idx;
586cba
 
586cba
@@ -102,7 +129,9 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
586cba
                      VirtQueue *vq);
586cba
 void vhost_svq_stop(VhostShadowVirtqueue *svq);
586cba
 
586cba
-VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree);
586cba
+VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree,
586cba
+                                    const VhostShadowVirtqueueOps *ops,
586cba
+                                    void *ops_opaque);
586cba
 
586cba
 void vhost_svq_free(gpointer vq);
586cba
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free);
586cba
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
586cba
index 33dcaa135e..28df57b12e 100644
586cba
--- a/hw/virtio/vhost-vdpa.c
586cba
+++ b/hw/virtio/vhost-vdpa.c
586cba
@@ -416,8 +416,9 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
586cba
 
586cba
     shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free);
586cba
     for (unsigned n = 0; n < hdev->nvqs; ++n) {
586cba
-        g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(v->iova_tree);
586cba
+        g_autoptr(VhostShadowVirtqueue) svq;
586cba
 
586cba
+        svq = vhost_svq_new(v->iova_tree, NULL, NULL);
586cba
         if (unlikely(!svq)) {
586cba
             error_setg(errp, "Cannot create svq %u", n);
586cba
             return -1;
586cba
-- 
586cba
2.31.1
586cba