From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id CCBB41FF0C2 for ; Thu, 22 Oct 2026 14:52:32 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id B7D1D21984; Thu, 22 Oct 2026 14:51:35 +0200 (CEST) From: Jakob Klocker To: pve-devel@lists.proxmox.com Subject: [PATCH qemu-server v2 6/8] fix #7213: qmeventd: pass `reset` to `qm cleanup` Date: Thu, 22 Oct 2026 14:51:09 +0200 Message-ID: <20261022125111.236538-7-j.klocker@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261022125111.236538-1-j.klocker@proxmox.com> References: <20261022125111.236538-1-j.klocker@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1792673489341 X-SPAM-LEVEL: Spam detection results: 0 AWL 1.525 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) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: 2UP7KNMBRZYPT6RJROSS75KWFPR556DL X-Message-ID-Hash: 2UP7KNMBRZYPT6RJROSS75KWFPR556DL X-MailFrom: j.klocker@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 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