diff options
Diffstat (limited to 'util/vhost-user-server.c')
| -rw-r--r-- | util/vhost-user-server.c | 39 |
1 files changed, 31 insertions, 8 deletions
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c index 5ccc6d24a0..a9a48fffb8 100644 --- a/util/vhost-user-server.c +++ b/util/vhost-user-server.c @@ -132,8 +132,7 @@ vu_message_read(VuDev *vu_dev, int conn_fd, VhostUserMsg *vmsg) qio_channel_yield(ioc, G_IO_IN); server->in_qio_channel_yield = false; } else { - /* Wait until attached to an AioContext again */ - qemu_coroutine_yield(); + return false; } continue; } else { @@ -201,8 +200,16 @@ static coroutine_fn void vu_client_trip(void *opaque) VuServer *server = opaque; VuDev *vu_dev = &server->vu_dev; - while (!vu_dev->broken && vu_dispatch(vu_dev)) { - /* Keep running */ + while (!vu_dev->broken) { + if (server->quiescing) { + server->co_trip = NULL; + aio_wait_kick(); + return; + } + /* vu_dispatch() returns false if server->ctx went away */ + if (!vu_dispatch(vu_dev) && server->ctx) { + break; + } } if (vhost_user_server_has_in_flight(server)) { @@ -353,8 +360,7 @@ static void vu_accept(QIONetListener *listener, QIOChannelSocket *sioc, qio_channel_set_follow_coroutine_ctx(server->ioc, true); - server->co_trip = qemu_coroutine_create(vu_client_trip, server); - + /* Attaching the AioContext starts the vu_client_trip coroutine */ aio_context_acquire(server->ctx); vhost_user_server_attach_aio_context(server, server->ctx); aio_context_release(server->ctx); @@ -413,8 +419,25 @@ void vhost_user_server_attach_aio_context(VuServer *server, AioContext *ctx) NULL, NULL, vu_fd_watch); } - assert(!server->in_qio_channel_yield); - aio_co_schedule(ctx, server->co_trip); + if (server->co_trip) { + /* + * The caller didn't fully shut down co_trip (this can happen on + * non-polling drains like in bdrv_graph_wrlock()). This is okay as long + * as it no longer tries to shut it down and we're guaranteed to still + * be in the same AioContext as before. + * + * co_ctx can still be NULL if we get multiple calls and only just + * scheduled a new coroutine in the else branch. + */ + AioContext *co_ctx = qemu_coroutine_get_aio_context(server->co_trip); + + assert(!server->quiescing); + assert(!co_ctx || co_ctx == ctx); + } else { + server->co_trip = qemu_coroutine_create(vu_client_trip, server); + assert(!server->in_qio_channel_yield); + aio_co_schedule(ctx, server->co_trip); + } } /* Called with server->ctx acquired */ |