When a ring is started, it may already hold requests: ones the driver
queued while the back-end was away and ones the previous instance left
in flight. libvhost-user handled them by writing to the kick fd it had
just received, which only works when that fd is an eventfd. With pipes
it is the read end, so the back-end was left relying on the front-end
sending a kick after SET_VRING_KICK.

Instead, flag the ring in vu_set_vring_kick_exec() and run the handler
of every flagged ring at the end of vu_dispatch(), once the reply has
gone out. This needs no writable fd and works the same with eventfds
and pipes.

Signed-off-by: Tim Pambor <[email protected]>
---
 subprojects/libvhost-user/libvhost-user.c | 44 ++++++++++++++++++++++---------
 subprojects/libvhost-user/libvhost-user.h |  1 +
 2 files changed, 32 insertions(+), 13 deletions(-)

diff --git a/subprojects/libvhost-user/libvhost-user.c 
b/subprojects/libvhost-user/libvhost-user.c
index ece2bfcdd7..5f649a3d52 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -1320,6 +1320,7 @@ vu_get_vring_base_exec(VuDev *dev, VhostUserMsg *vmsg)
     vmsg->size = sizeof(vmsg->payload.state);
 
     dev->vq[index].started = false;
+    dev->vq[index].kick_pending = false;
     if (dev->iface->queue_set_started) {
         dev->iface->queue_set_started(dev, index, false);
     }
@@ -1493,19 +1494,12 @@ vu_set_vring_kick_exec(VuDev *dev, VhostUserMsg *vmsg)
         vu_panic(dev, "Failed to check inflights for vq: %d\n", index);
     }
 
-    /* Inject a kick to look for available vq buffers */
-    if (dev->vq[index].kick_fd != -1) {
-        int ret;
-
-        do {
-            ret = eventfd_write(dev->vq[index].kick_fd, 1);
-        } while (ret != 0 && errno == EINTR);
-
-        if (ret != 0 && errno != EAGAIN /* already readable */) {
-            vu_panic(dev, "Failed to inject kick during SET_VRING_KICK "
-                     "on vq: %d with error: %m\n", index);
-        }
-    }
+    /*
+     * The ring may already hold requests: ones the driver queued while the
+     * back-end was away and ones the previous instance left in flight. Run
+     * the handler once the reply to this message has gone out.
+     */
+    dev->vq[index].kick_pending = true;
 
     return false;
 }
@@ -2313,6 +2307,25 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
     return false;
 }
 
+static void
+vu_run_pending_handlers(VuDev *dev)
+{
+    unsigned int i;
+
+    for (i = 0; i < dev->max_queues && !dev->broken; i++) {
+        VuVirtq *vq = &dev->vq[i];
+
+        /* Without a handler the request stays pending until one is set */
+        if (!vq->kick_pending || !vq->handler) {
+            continue;
+        }
+        vq->kick_pending = false;
+
+        DPRINT("Running handler for pending requests on vq: %u\n", i);
+        vq->handler(dev, i);
+    }
+}
+
 bool
 vu_dispatch(VuDev *dev)
 {
@@ -2345,6 +2358,11 @@ vu_dispatch(VuDev *dev)
 
 end:
     free(vmsg.data);
+
+    if (success) {
+        vu_run_pending_handlers(dev);
+    }
+
     return success;
 }
 
diff --git a/subprojects/libvhost-user/libvhost-user.h 
b/subprojects/libvhost-user/libvhost-user.h
index a534d70771..aedb1da96d 100644
--- a/subprojects/libvhost-user/libvhost-user.h
+++ b/subprojects/libvhost-user/libvhost-user.h
@@ -392,6 +392,7 @@ typedef struct VuVirtq {
     int err_fd;
     unsigned int enable;
     bool started;
+    bool kick_pending;
 
     /* Guest addresses of our ring */
     struct vhost_vring_addr vra;

-- 
2.55.0


Reply via email to