From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 158F31FF0EA for ; Thu, 13 Aug 2026 13:27:40 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 607AF215AD; Thu, 13 Aug 2026 13:27:30 +0200 (CEST) From: Jakob Klocker To: pve-devel@lists.proxmox.com Subject: [PATCH qemu-server 4/6] fix #7213: qmeventd: pass `reset` to `qm cleanup` Date: Thu, 13 Aug 2026 13:27:15 +0200 Message-ID: <20260813112717.272254-5-j.klocker@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260813112717.272254-1-j.klocker@proxmox.com> References: <20260813112717.272254-1-j.klocker@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 1 AWL -0.548 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 1.274 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Message-ID-Hash: FRWFC3CG7YGEW6KA7MEDJMMJC2OKT4QP X-Message-ID-Hash: FRWFC3CG7YGEW6KA7MEDJMMJC2OKT4QP X-MailFrom: jklocker@iris.proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Jakob Klocker X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: With '-no-reboot', QEMU exits on a reset request instead of performing it. The resulting SHUTDOWN event is indistinguishable from the one for an ordinary shutdown except for its reason field. Evaluate that field and pass the result on as a fourth argument, which `qm cleanup` needs to decide whether the VM should be started again. Both a reset initiated inside the guest (`guest-reset`) and one requested through QMP (`host-qmp-system-reset`, used by `qm reset` and the API) are reported: a VM with `powercycle` set is started with '-no-reboot' either way, so both would otherwise leave it powered off. Link: https://bugzilla.proxmox.com/show_bug.cgi?id=7213 Signed-off-by: Jakob Klocker --- src/qmeventd/qmeventd.c | 36 ++++++++++++++++++++++++++++-------- src/qmeventd/qmeventd.h | 1 + 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/qmeventd/qmeventd.c b/src/qmeventd/qmeventd.c index 84ee11a1..14b17667 100644 --- a/src/qmeventd/qmeventd.c +++ b/src/qmeventd/qmeventd.c @@ -10,12 +10,15 @@ qmeventd listens on a given socket, and waits for qemu processes to connect. After accepting a connection qmeventd waits for shutdown events followed by the closing of the socket. Once that happens `qm cleanup` will - be executed with following three arguments: - VMID + be executed with following four arguments: + VMID Where `graceful` can be `1` or `0` depending if shutdown event was observed before the socket got closed. The second parameter `guest` is also boolean `1` or `0` depending if the shutdown was requested from the guest OS - (i.e., the "inside"). + (i.e., the "inside"). The third parameter `reset` is `1` if the shutdown + was caused by a reset request rather than an actual shutdown - either from + inside the guest or through QMP - which QEMU only reports as a shutdown + event when started with `-no-reboot`. */ #ifndef _GNU_SOURCE @@ -207,9 +210,20 @@ void handle_qmp_event(struct Client *client, struct json_object *obj) { client->qemu.graceful = 1; struct json_object *data; struct json_object *guest; - if (json_object_object_get_ex(obj, "data", &data) && - json_object_object_get_ex(data, "guest", &guest)) { - client->qemu.guest = (unsigned short)json_object_get_boolean(guest); + struct json_object *reason; + + if (json_object_object_get_ex(obj, "data", &data) && data) { + if (json_object_object_get_ex(data, "guest", &guest)) { + client->qemu.guest = (unsigned short)json_object_get_boolean(guest); + } + + if (json_object_object_get_ex(data, "reason", &reason)) { + const char *reason_str = json_object_get_string(reason); + if (reason_str && (!strcmp(reason_str, "guest-reset") || + !strcmp(reason_str, "host-qmp-system-reset"))) { + client->qemu.reset = true; + } + } } // check if a backup is running and kill QEMU process if not @@ -392,11 +406,14 @@ err: static void cleanup_qemu_client(struct Client *client) { unsigned short graceful = client->qemu.graceful; unsigned short guest = client->qemu.guest; + bool reset = client->qemu.reset; char vmid[sizeof(client->qemu.vmid)]; strncpy(vmid, client->qemu.vmid, sizeof(vmid)); vmid[sizeof(vmid) - 1] = '\0'; g_hash_table_remove(vm_clients, &vmid); // frees key, ignore errors - VERBOSE_PRINT("%s: executing cleanup (graceful: %d, guest: %d)\n", vmid, graceful, guest); + VERBOSE_PRINT( + "%s: executing cleanup (graceful: %d, guest: %d, reset: %d)\n", vmid, graceful, guest, reset + ); int pid = fork(); if (pid < 0) { @@ -406,7 +423,10 @@ static void cleanup_qemu_client(struct Client *client) { if (pid == 0) { char *script = "/usr/sbin/qm"; - char *args[] = {script, "cleanup", vmid, graceful ? "1" : "0", guest ? "1" : "0", NULL}; + char *args[] = { + script, "cleanup", vmid, graceful ? "1" : "0", guest ? "1" : "0", reset ? "1" : "0", + NULL + }; execvp(script, args); perror("execvp"); diff --git a/src/qmeventd/qmeventd.h b/src/qmeventd/qmeventd.h index 6a293b84..36f8bdcc 100644 --- a/src/qmeventd/qmeventd.h +++ b/src/qmeventd/qmeventd.h @@ -78,6 +78,7 @@ struct Client { unsigned short guest; bool term_check_queued; bool backup; + bool reset; } qemu; // only relevant for type=CLIENT_VZDUMP -- 2.47.3