From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 3F1981FF13A for ; Wed, 27 May 2026 13:01:51 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 3FB271884D; Wed, 27 May 2026 13:01:19 +0200 (CEST) From: Fiona Ebner 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 Message-ID: <20260527110106.287916-3-f.ebner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260527110106.287916-1-f.ebner@proxmox.com> References: <20260527110106.287916-1-f.ebner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1779879644016 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.009 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [meson.build] Message-ID-Hash: P5GHB3G6QWWZBUUVSAWXTT3PPQ6FYRO3 X-Message-ID-Hash: P5GHB3G6QWWZBUUVSAWXTT3PPQ6FYRO3 X-MailFrom: f.ebner@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: 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 --- ...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 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 --- @@ -42,13 +43,13 @@ Signed-off-by: Fiona Ebner 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