vmspawn: add QmpClient userdata and VmspawnQmpBridge.setup_done flag
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>
This commit is contained in:
@@ -49,6 +49,8 @@ struct QmpClient {
|
|||||||
|
|
||||||
QmpClientState state;
|
QmpClientState state;
|
||||||
sd_json_variant *current; /* most recently parsed message, pending dispatch */
|
sd_json_variant *current; /* most recently parsed message, pending dispatch */
|
||||||
|
|
||||||
|
void *userdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void qmp_slot_hash_func(const QmpSlot *p, struct siphash *state) {
|
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;
|
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. */
|
/* Map our state to the transport phase used for POLLIN / salvage / timeout decisions. */
|
||||||
static JsonStreamPhase qmp_client_phase(void *userdata) {
|
static JsonStreamPhase qmp_client_phase(void *userdata) {
|
||||||
QmpClient *c = ASSERT_PTR(userdata);
|
QmpClient *c = ASSERT_PTR(userdata);
|
||||||
|
|||||||
@@ -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. */
|
/* True iff the connection is dead. Stable terminal state — once set, it stays set. */
|
||||||
bool qmp_client_is_disconnected(QmpClient *c);
|
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
|
/* 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
|
* 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). */
|
* (by unreffing it before the reply arrives). */
|
||||||
|
|||||||
@@ -1042,6 +1042,8 @@ static int on_cont_complete(
|
|||||||
int error,
|
int error,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
|
VmspawnQmpBridge *bridge = ASSERT_PTR(qmp_client_get_userdata(client));
|
||||||
|
|
||||||
assert(client);
|
assert(client);
|
||||||
|
|
||||||
if (error < 0) {
|
if (error < 0) {
|
||||||
@@ -1049,6 +1051,8 @@ static int on_cont_complete(
|
|||||||
return sd_event_exit(qmp_client_get_event(client), error);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ typedef struct VmspawnQmpBridge {
|
|||||||
QmpClient *qmp;
|
QmpClient *qmp;
|
||||||
Hashmap *pending_jobs; /* job_id (string, owned) -> PendingJob* */
|
Hashmap *pending_jobs; /* job_id (string, owned) -> PendingJob* */
|
||||||
VmspawnQmpFeatureFlags features;
|
VmspawnQmpFeatureFlags features;
|
||||||
|
bool setup_done;
|
||||||
} VmspawnQmpBridge;
|
} VmspawnQmpBridge;
|
||||||
|
|
||||||
VmspawnQmpBridge* vmspawn_qmp_bridge_free(VmspawnQmpBridge *b);
|
VmspawnQmpBridge* vmspawn_qmp_bridge_free(VmspawnQmpBridge *b);
|
||||||
|
|||||||
@@ -387,6 +387,7 @@ int vmspawn_varlink_setup(
|
|||||||
ctx->bridge = bridge;
|
ctx->bridge = bridge;
|
||||||
qmp_client_bind_event(ctx->bridge->qmp, on_qmp_event, ctx);
|
qmp_client_bind_event(ctx->bridge->qmp, on_qmp_event, ctx);
|
||||||
qmp_client_bind_disconnect(ctx->bridge->qmp, on_qmp_disconnect, 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);
|
log_debug("Varlink control server listening on %s", listen_address);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user