Skip to content

Commit 0d6d2c9

Browse files
braunerdaandemeyer
authored andcommitted
vmspawn-varlink: treat QMP disconnect as success for Terminate
QMP "quit" tells QEMU to exit, which races the reply with the socket EOF: sometimes the disconnect lands in qmp_client_fail_pending() with -ECONNRESET before the reply has been parsed. The shared completion callback then translates that into io.systemd.MachineInstance.NotConnected, turning the desired outcome into a varlink error. This is exactly what TEST-87-AUX-UTILS-VM exposes during its repeated start/pause/resume/terminate stress loop: a successful Pause/Describe followed milliseconds later by a Terminate that fails with NotConnected when the disconnect path wins the race. Give Terminate its own completion callback that treats disconnect-class errors as success, since QEMU shutting down is the whole point of "quit". The other simple commands (Pause, Resume, PowerOff, Reboot) keep the existing semantics: they expect QMP to remain alive, so NotConnected is the correct reply for them. Link: https://github.com/systemd/systemd/actions/runs/24986080288/job/73159585425?pr=41835 Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
1 parent d92b511 commit 0d6d2c9

1 file changed

Lines changed: 24 additions & 1 deletion

File tree

src/vmspawn/vmspawn-varlink.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,29 @@ static int on_qmp_simple_complete(
6060
return 0;
6161
}
6262

63+
/* "quit" tells QEMU to exit, which races the QMP reply with the socket EOF — sometimes the
64+
* disconnect lands in qmp_client_fail_pending() before the reply has been parsed. For Terminate
65+
* that's the desired outcome, so treat disconnect-class errors as success. */
66+
static int on_qmp_terminate_complete(
67+
QmpClient *client,
68+
sd_json_variant *result,
69+
const char *error_desc,
70+
int error,
71+
void *userdata) {
72+
73+
sd_varlink *link = ASSERT_PTR(userdata);
74+
75+
assert(client);
76+
77+
if (error < 0 && !ERRNO_IS_DISCONNECT(error))
78+
(void) qmp_error_to_varlink(link, error_desc, error);
79+
else
80+
(void) sd_varlink_reply(link, NULL);
81+
82+
sd_varlink_unref(link);
83+
return 0;
84+
}
85+
6386
static int qmp_execute_varlink_async(
6487
VmspawnVarlinkContext *ctx,
6588
sd_varlink *link,
@@ -87,7 +110,7 @@ static int qmp_execute_simple_async(sd_varlink *link, VmspawnVarlinkContext *ctx
87110
}
88111

89112
static int vl_method_terminate(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
90-
return qmp_execute_simple_async(link, ASSERT_PTR(userdata), "quit");
113+
return qmp_execute_varlink_async(ASSERT_PTR(userdata), link, "quit", /* arguments= */ NULL, on_qmp_terminate_complete);
91114
}
92115

93116
static int vl_method_pause(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {

0 commit comments

Comments
 (0)