From: Fiona Ebner <f.ebner@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH qemu 2/6] async snapshot: allow skipping VM start after successful completion
Date: Wed, 27 May 2026 13:00:46 +0200 [thread overview]
Message-ID: <20260527110106.287916-3-f.ebner@proxmox.com> (raw)
In-Reply-To: <20260527110106.287916-1-f.ebner@proxmox.com>
When creating a snapshot for hibernation, the VM must not be started
again after a successful snapshot operation. The VM should remain
stopped so that the management layer can issue a QMP 'quit' without
further activity from the VM.
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
---
...async-for-background-state-snapshots.patch | 49 +++++++++++++------
...add-optional-buffer-size-to-QEMUFile.patch | 6 +--
...ckup-Proxmox-backup-patches-for-QEMU.patch | 2 +-
...se-migration-blocker-check-for-snaps.patch | 4 +-
4 files changed, 40 insertions(+), 21 deletions(-)
diff --git a/debian/patches/pve/0017-PVE-add-savevm-async-for-background-state-snapshots.patch b/debian/patches/pve/0017-PVE-add-savevm-async-for-background-state-snapshots.patch
index 21ebd78182..192f3abf46 100644
--- a/debian/patches/pve/0017-PVE-add-savevm-async-for-background-state-snapshots.patch
+++ b/debian/patches/pve/0017-PVE-add-savevm-async-for-background-state-snapshots.patch
@@ -34,6 +34,7 @@ Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
improve setting state in savevm-end handler
improve runstate preservation
use dedicated iothread for state file to avoid deadlock, bug #6262
+ add parameter to skip vm start to be used for hibernation
rebase for 11.0.0]
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
---
@@ -42,13 +43,13 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
include/migration/snapshot.h | 2 +
include/monitor/hmp.h | 3 +
migration/meson.build | 1 +
- migration/savevm-async.c | 586 +++++++++++++++++++++++++++++++++++
+ migration/savevm-async.c | 597 +++++++++++++++++++++++++++++++++++
monitor/hmp-cmds.c | 38 +++
qapi/migration.json | 34 ++
- qapi/misc.json | 18 ++
+ qapi/misc.json | 25 ++
qemu-options.hx | 12 +
system/vl.c | 10 +
- 11 files changed, 734 insertions(+)
+ 11 files changed, 752 insertions(+)
create mode 100644 migration/savevm-async.c
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
@@ -146,10 +147,10 @@ index 0222d5ea6e..90d62d5723 100644
), gnutls, zlib)
diff --git a/migration/savevm-async.c b/migration/savevm-async.c
new file mode 100644
-index 0000000000..d973d8300c
+index 0000000000..2a860f11a1
--- /dev/null
+++ b/migration/savevm-async.c
-@@ -0,0 +1,586 @@
+@@ -0,0 +1,597 @@
+#include "qemu/osdep.h"
+#include "migration/channel-savevm-async.h"
+#include "migration/migration.h"
@@ -204,7 +205,8 @@ index 0000000000..d973d8300c
+ int state;
+ Error *error;
+ Error *blocker;
-+ int vm_needs_start;
++ bool vm_needs_start;
++ bool skip_vm_start;
+ QEMUFile *file;
+ int64_t total_time;
+ QEMUBH *finalize_bh;
@@ -219,6 +221,10 @@ index 0000000000..d973d8300c
+ snap_state.state == SAVE_STATE_ERROR;
+}
+
++static bool should_skip_vm_start(void) {
++ return snap_state.state == SAVE_STATE_COMPLETED && snap_state.skip_vm_start;
++}
++
+SaveVMInfo *qmp_query_savevm(Error **errp)
+{
+ SaveVMInfo *info = g_malloc0(sizeof(*info));
@@ -380,7 +386,9 @@ index 0000000000..d973d8300c
+ snap_state.state);
+ }
+ if (snap_state.vm_needs_start) {
-+ vm_start();
++ if (!should_skip_vm_start()) {
++ vm_start();
++ }
+ snap_state.vm_needs_start = false;
+ }
+
@@ -490,7 +498,8 @@ index 0000000000..d973d8300c
+ }
+}
+
-+void qmp_savevm_start(const char *statefile, Error **errp)
++void qmp_savevm_start(const char *statefile, bool has_skip_vm_start,
++ bool skip_vm_start, Error **errp)
+{
+ Error *local_err = NULL;
+ MigrationState *ms = migrate_get_current();
@@ -514,6 +523,7 @@ index 0000000000..d973d8300c
+ snap_state.total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+ snap_state.blocker = NULL;
+ snap_state.target_close_wait = (QemuCoSleep){ .to_wake = NULL };
++ snap_state.skip_vm_start = has_skip_vm_start && skip_vm_start;
+
+ if (snap_state.error) {
+ error_free(snap_state.error);
@@ -657,7 +667,9 @@ index 0000000000..d973d8300c
+ }
+
+ if (snap_state.vm_needs_start) {
-+ vm_start();
++ if (!should_skip_vm_start()) {
++ vm_start();
++ }
+ snap_state.vm_needs_start = false;
+ }
+
@@ -737,7 +749,7 @@ index 0000000000..d973d8300c
+ return ret;
+}
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
-index bc26b39d70..cbedf13103 100644
+index bc26b39d70..e7afe15e97 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -27,6 +27,7 @@
@@ -757,7 +769,7 @@ index bc26b39d70..cbedf13103 100644
+ Error *errp = NULL;
+ const char *statefile = qdict_get_try_str(qdict, "statefile");
+
-+ qmp_savevm_start(statefile, &errp);
++ qmp_savevm_start(statefile, false, false, &errp);
+ hmp_handle_error(mon, errp);
+}
+
@@ -838,22 +850,29 @@ index 7134d4ce47..8dc8d52b23 100644
# @query-migrate:
#
diff --git a/qapi/misc.json b/qapi/misc.json
-index 28c641fe2f..5d2f12259a 100644
+index 28c641fe2f..cfa10c849b 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
-@@ -449,6 +449,24 @@
+@@ -449,6 +449,31 @@
##
{ 'command': 'query-fdsets', 'returns': ['FdsetInfo'] }
+##
+# @savevm-start:
+#
-+# Prepare for snapshot and halt VM. Save VM state to statefile.
++# Prepare for snapshot and halt VM. Save VM state to statefile. When
++# a @statefile is used, then the VM is only halted before completion.
++# Use @query-savevm to check the state of the operation.
+#
+# @statefile: target file that state should be written to.
+#
++# @skip-vm-start: Do not resume the VM after the snapshot is done
++# successfully, even if the VM was running before
++# snapshot completion. Useful for hibernation.
++#
+##
-+{ 'command': 'savevm-start', 'data': { '*statefile': 'str' } }
++{ 'command': 'savevm-start', 'data': { '*statefile': 'str',
++ '*skip-vm-start': 'bool' } }
+
+##
+# @savevm-end:
diff --git a/debian/patches/pve/0018-PVE-add-optional-buffer-size-to-QEMUFile.patch b/debian/patches/pve/0018-PVE-add-optional-buffer-size-to-QEMUFile.patch
index 4c8bb44560..ab8aac16a5 100644
--- a/debian/patches/pve/0018-PVE-add-optional-buffer-size-to-QEMUFile.patch
+++ b/debian/patches/pve/0018-PVE-add-optional-buffer-size-to-QEMUFile.patch
@@ -184,10 +184,10 @@ index a390554208..eda093b16a 100644
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QEMUFile, qemu_fclose)
diff --git a/migration/savevm-async.c b/migration/savevm-async.c
-index d973d8300c..edc4c5b6ac 100644
+index 2a860f11a1..f5a4819e27 100644
--- a/migration/savevm-async.c
+++ b/migration/savevm-async.c
-@@ -409,7 +409,7 @@ void qmp_savevm_start(const char *statefile, Error **errp)
+@@ -418,7 +418,7 @@ void qmp_savevm_start(const char *statefile, bool has_skip_vm_start,
QIOChannel *ioc = QIO_CHANNEL(qio_channel_savevm_async_new(snap_state.target,
&snap_state.bs_pos));
@@ -196,7 +196,7 @@ index d973d8300c..edc4c5b6ac 100644
if (!snap_state.file) {
error_setg(errp, "failed to open '%s'", statefile);
-@@ -544,7 +544,8 @@ int load_snapshot_from_blockdev(const char *filename, Error **errp)
+@@ -555,7 +555,8 @@ int load_snapshot_from_blockdev(const char *filename, Error **errp)
bdrv_op_block_all(bs, blocker);
/* restore the VM state */
diff --git a/debian/patches/pve/0029-PVE-Backup-Proxmox-backup-patches-for-QEMU.patch b/debian/patches/pve/0029-PVE-Backup-Proxmox-backup-patches-for-QEMU.patch
index 73117a6f3a..a4ac880fa7 100644
--- a/debian/patches/pve/0029-PVE-Backup-Proxmox-backup-patches-for-QEMU.patch
+++ b/debian/patches/pve/0029-PVE-Backup-Proxmox-backup-patches-for-QEMU.patch
@@ -275,7 +275,7 @@ index f747bc3cb2..7aa0ed1b5a 100644
# libselinux
selinux = dependency('libselinux',
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
-index cbedf13103..33c1c81b3c 100644
+index e7afe15e97..ce374de2ec 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -25,6 +25,7 @@
diff --git a/debian/patches/pve/0046-savevm-async-reuse-migration-blocker-check-for-snaps.patch b/debian/patches/pve/0046-savevm-async-reuse-migration-blocker-check-for-snaps.patch
index 6bd48361f1..df9f3df96b 100644
--- a/debian/patches/pve/0046-savevm-async-reuse-migration-blocker-check-for-snaps.patch
+++ b/debian/patches/pve/0046-savevm-async-reuse-migration-blocker-check-for-snaps.patch
@@ -136,10 +136,10 @@ index b6888daced..80eb0dcd1f 100644
bool migration_in_postcopy(void);
bool migration_postcopy_is_alive(MigrationStatus state);
diff --git a/migration/savevm-async.c b/migration/savevm-async.c
-index edc4c5b6ac..acd1a4de6e 100644
+index f5a4819e27..41376406eb 100644
--- a/migration/savevm-async.c
+++ b/migration/savevm-async.c
-@@ -375,7 +375,7 @@ void qmp_savevm_start(const char *statefile, Error **errp)
+@@ -384,7 +384,7 @@ void qmp_savevm_start(const char *statefile, bool has_skip_vm_start,
return;
}
--
2.47.3
next prev parent reply other threads:[~2026-05-27 11:01 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-27 11:00 [PATCH-SERIES qemu/qemu-server 0/6] fix #6424: avoid timeout issue for QMP 'quit' for bulk suspend Fiona Ebner
2026-05-27 11:00 ` [PATCH qemu 1/6] regenerate patches to restore incremental numbering Fiona Ebner
2026-05-27 11:00 ` Fiona Ebner [this message]
2026-05-27 11:00 ` [PATCH qemu 3/6] update submodule and patches to QEMU 11.0.1 Fiona Ebner
2026-05-27 11:00 ` [PATCH qemu-server 4/6] fix #6424: increase timeout for QMP 'quit' to 60s to avoid issue with bulk suspend Fiona Ebner
2026-05-27 11:00 ` [PATCH qemu-server 5/6] run state: use v5.36 and signatures in module Fiona Ebner
2026-05-27 11:00 ` [PATCH qemu-server 6/6] suspend: skip VM start after successfully saving state Fiona Ebner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260527110106.287916-3-f.ebner@proxmox.com \
--to=f.ebner@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox