]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
vmspawn: add QmpClient userdata and VmspawnQmpBridge.setup_done flag
authorChristian Brauner <brauner@kernel.org>
Thu, 16 Apr 2026 20:44:58 +0000 (22:44 +0200)
committerChristian Brauner <brauner@kernel.org>
Fri, 24 Apr 2026 12:39:24 +0000 (14:39 +0200)
Add qmp_client_set_userdata()/qmp_client_get_userdata() accessors
mirroring the sd_varlink API, and wire up the VmspawnQmpBridge as
userdata on the QmpClient so that command callbacks can retrieve it.

Add a setup_done flag to VmspawnQmpBridge, set by on_cont_complete()
when the VM has booted and all boot-time device setup is finished.
This lets command callbacks differentiate boot-time errors (fatal —
exit event loop) from runtime errors (recoverable — log and continue).

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
src/shared/qmp-client.c
src/shared/qmp-client.h
src/vmspawn/vmspawn-qmp.c
src/vmspawn/vmspawn-qmp.h
src/vmspawn/vmspawn-varlink.c

index cc51259cd1290970827eb8831684104b18b30561..ad8f8bb24ac5f05235b0a4282c9d6ff16717ebf7 100644 (file)
@@ -49,6 +49,8 @@ struct QmpClient {
 
         QmpClientState state;
         sd_json_variant *current;  /* most recently parsed message, pending dispatch */
+
+        void *userdata;
 };
 
 static void qmp_slot_hash_func(const QmpSlot *p, struct siphash *state) {
@@ -508,6 +510,21 @@ bool qmp_client_is_disconnected(QmpClient *c) {
         return c->state == QMP_CLIENT_DISCONNECTED;
 }
 
+void* qmp_client_set_userdata(QmpClient *c, void *userdata) {
+        void *old;
+
+        assert(c);
+
+        old = c->userdata;
+        c->userdata = userdata;
+        return old;
+}
+
+void* qmp_client_get_userdata(QmpClient *c) {
+        assert(c);
+        return c->userdata;
+}
+
 /* Map our state to the transport phase used for POLLIN / salvage / timeout decisions. */
 static JsonStreamPhase qmp_client_phase(void *userdata) {
         QmpClient *c = ASSERT_PTR(userdata);
index 7a477f7e4fa375b9be89d02c49544481263ae174..8f784731280da4be0541707af055fe10763002db 100644 (file)
@@ -54,6 +54,9 @@ bool qmp_client_is_idle(QmpClient *c);
 /* True iff the connection is dead. Stable terminal state — once set, it stays set. */
 bool qmp_client_is_disconnected(QmpClient *c);
 
+void* qmp_client_set_userdata(QmpClient *c, void *userdata);
+void* qmp_client_get_userdata(QmpClient *c);
+
 /* Async send. Returns 0 on send (callback will fire later), negative errno on failure. If
  * ret_slot is non-NULL, returns a reference to a QmpSlot which can be used to cancel the call
  * (by unreffing it before the reply arrives). */
index f69d2a5e7c64c5107fb3adc5e5d9ee58b11292b5..f0f987082c695dc99e3037229ed2fbbb3927d868 100644 (file)
@@ -1042,6 +1042,8 @@ static int on_cont_complete(
                 int error,
                 void *userdata) {
 
+        VmspawnQmpBridge *bridge = ASSERT_PTR(qmp_client_get_userdata(client));
+
         assert(client);
 
         if (error < 0) {
@@ -1049,6 +1051,8 @@ static int on_cont_complete(
                 return sd_event_exit(qmp_client_get_event(client), error);
         }
 
+        /* VM is running — all boot-time device setup has completed. */
+        bridge->setup_done = true;
         return 0;
 }
 
index 8f8c26fb03e7dce9a5226a0b40dd663a4eeffa49..15949c40a5e83eb6deecc17e64e28bc82dbaba19 100644 (file)
@@ -28,6 +28,7 @@ typedef struct VmspawnQmpBridge {
         QmpClient *qmp;
         Hashmap *pending_jobs;  /* job_id (string, owned) -> PendingJob* */
         VmspawnQmpFeatureFlags features;
+        bool setup_done;
 } VmspawnQmpBridge;
 
 VmspawnQmpBridge* vmspawn_qmp_bridge_free(VmspawnQmpBridge *b);
index 4a11b6fd4e103ae1d5963c18f75b6594d394666e..98d3fc73e911c99501639109f67c4b4a5cf59bcd 100644 (file)
@@ -387,6 +387,7 @@ int vmspawn_varlink_setup(
         ctx->bridge = bridge;
         qmp_client_bind_event(ctx->bridge->qmp, on_qmp_event, ctx);
         qmp_client_bind_disconnect(ctx->bridge->qmp, on_qmp_disconnect, ctx);
+        qmp_client_set_userdata(ctx->bridge->qmp, ctx->bridge);
 
         log_debug("Varlink control server listening on %s", listen_address);