From: Michal Fox <me@dualfroz.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH qemu-server] fix #6391: restore: fall back to automatic VM state storage if unavailable
Date: Fri, 16 Oct 2026 13:31:42 +0000 [thread overview]
Message-ID: <20261016133142.7-1-me@dualfroz.com> (raw)
Restoring a backup keeps the 'vmstatestorage' option of the backed up
VM. When the backup is restored on another node or cluster, that
storage might not exist there or not be enabled for the node, so that
hibernating the VM or taking a snapshot including RAM fails later on,
for example with "storage 'local-zfs-pve1' does not exist".
If the configured VM state storage is not available on the node the
backup is restored to, drop the option, so that the storage is
selected automatically, like for VMs without it, and log that in the
restore task log.
A 'vmstatestorage' passed explicitly when restoring is applied after
this and is not affected.
Signed-off-by: Michal Fox <me@dualfroz.com>
---
Tested with new restore config test cases for a VM state storage that
exists, does not exist, is restricted to another node and is disabled.
Without the fix, the last three keep the option. The whole qemu-server
test suite passes.
The message is printed as a plain log line, not as a warning, since
the restore itself is fine. Happy to switch to log_warn() if that is
preferred.
src/PVE/QemuServer.pm | 10 +++++++++
src/test/restore-config-expected/201.conf | 13 ++++++++++++
src/test/restore-config-expected/202.conf | 12 +++++++++++
src/test/restore-config-expected/203.conf | 12 +++++++++++
src/test/restore-config-expected/204.conf | 12 +++++++++++
src/test/restore-config-input/201.conf | 14 +++++++++++++
src/test/restore-config-input/202.conf | 14 +++++++++++++
src/test/restore-config-input/203.conf | 14 +++++++++++++
src/test/restore-config-input/204.conf | 14 +++++++++++++
src/test/run_qemu_restore_config_tests.pl | 25 ++++++++++++++++++++++-
10 files changed, 139 insertions(+), 1 deletion(-)
create mode 100644 src/test/restore-config-expected/201.conf
create mode 100644 src/test/restore-config-expected/202.conf
create mode 100644 src/test/restore-config-expected/203.conf
create mode 100644 src/test/restore-config-expected/204.conf
create mode 100644 src/test/restore-config-input/201.conf
create mode 100644 src/test/restore-config-input/202.conf
create mode 100644 src/test/restore-config-input/203.conf
create mode 100644 src/test/restore-config-input/204.conf
diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm
index f199371d..62fb72ef 100644
--- a/src/PVE/QemuServer.pm
+++ b/src/PVE/QemuServer.pm
@@ -6697,6 +6697,16 @@ sub restore_update_config_line {
} else {
$res .= $line;
}
+ } elsif ($line =~ m/^vmstatestorage:\s*(\S+)\s*$/) {
+ my $storeid = $1;
+ my $storecfg = PVE::Storage::config();
+ my $scfg = PVE::Storage::storage_config($storecfg, $storeid, 1);
+ if ($scfg && PVE::Storage::storage_check_enabled($storecfg, $storeid, undef, 1)) {
+ $res .= $line;
+ } else {
+ print "VM state storage '$storeid' is not available on this node, using"
+ . " automatic selection instead\n";
+ }
} elsif (($line =~ m/^vmgenid: (.*)/)) {
my $vmgenid = $1;
if ($vmgenid ne '0') {
diff --git a/src/test/restore-config-expected/201.conf b/src/test/restore-config-expected/201.conf
new file mode 100644
index 00000000..c76a010e
--- /dev/null
+++ b/src/test/restore-config-expected/201.conf
@@ -0,0 +1,13 @@
+# VM state storage available on the target is kept
+boot: order=scsi0
+cores: 1
+memory: 2048
+name: hibernated
+net0: virtio=BC:24:11:6B:2A:5F,bridge=vmbr0
+ostype: win10
+scsi0: target:201/vm-201-disk-0.qcow2,size=32G
+scsihw: virtio-scsi-single
+smbios1: uuid=0c5a8b3e-9d43-4bd1-8a0e-3f6f2b1f3c11
+sockets: 1
+vmgenid: 0
+vmstatestorage: mydir
diff --git a/src/test/restore-config-expected/202.conf b/src/test/restore-config-expected/202.conf
new file mode 100644
index 00000000..f46451fe
--- /dev/null
+++ b/src/test/restore-config-expected/202.conf
@@ -0,0 +1,12 @@
+# VM state storage missing on the target falls back to automatic selection
+boot: order=scsi0
+cores: 1
+memory: 2048
+name: hibernated
+net0: virtio=BC:24:11:6B:2A:5F,bridge=vmbr0
+ostype: win10
+scsi0: target:202/vm-202-disk-0.qcow2,size=32G
+scsihw: virtio-scsi-single
+smbios1: uuid=0c5a8b3e-9d43-4bd1-8a0e-3f6f2b1f3c11
+sockets: 1
+vmgenid: 0
diff --git a/src/test/restore-config-expected/203.conf b/src/test/restore-config-expected/203.conf
new file mode 100644
index 00000000..6f93f8c0
--- /dev/null
+++ b/src/test/restore-config-expected/203.conf
@@ -0,0 +1,12 @@
+# VM state storage not available on this node falls back to automatic selection
+boot: order=scsi0
+cores: 1
+memory: 2048
+name: hibernated
+net0: virtio=BC:24:11:6B:2A:5F,bridge=vmbr0
+ostype: win10
+scsi0: target:203/vm-203-disk-0.qcow2,size=32G
+scsihw: virtio-scsi-single
+smbios1: uuid=0c5a8b3e-9d43-4bd1-8a0e-3f6f2b1f3c11
+sockets: 1
+vmgenid: 0
diff --git a/src/test/restore-config-expected/204.conf b/src/test/restore-config-expected/204.conf
new file mode 100644
index 00000000..926dab25
--- /dev/null
+++ b/src/test/restore-config-expected/204.conf
@@ -0,0 +1,12 @@
+# disabled VM state storage falls back to automatic selection
+boot: order=scsi0
+cores: 1
+memory: 2048
+name: hibernated
+net0: virtio=BC:24:11:6B:2A:5F,bridge=vmbr0
+ostype: win10
+scsi0: target:204/vm-204-disk-0.qcow2,size=32G
+scsihw: virtio-scsi-single
+smbios1: uuid=0c5a8b3e-9d43-4bd1-8a0e-3f6f2b1f3c11
+sockets: 1
+vmgenid: 0
diff --git a/src/test/restore-config-input/201.conf b/src/test/restore-config-input/201.conf
new file mode 100644
index 00000000..4459b739
--- /dev/null
+++ b/src/test/restore-config-input/201.conf
@@ -0,0 +1,14 @@
+# VM state storage available on the target is kept
+boot: order=scsi0
+cores: 1
+memory: 2048
+name: hibernated
+net0: virtio=BC:24:11:6B:2A:5F,bridge=vmbr0
+ostype: win10
+scsi0: mydir:201/vm-201-disk-0.qcow2,size=32G
+scsihw: virtio-scsi-single
+smbios1: uuid=0c5a8b3e-9d43-4bd1-8a0e-3f6f2b1f3c11
+sockets: 1
+vmgenid: 0
+vmstatestorage: mydir
+#qmdump#map:scsi0:drive-scsi0:mydir:qcow2:
diff --git a/src/test/restore-config-input/202.conf b/src/test/restore-config-input/202.conf
new file mode 100644
index 00000000..15c340d2
--- /dev/null
+++ b/src/test/restore-config-input/202.conf
@@ -0,0 +1,14 @@
+# VM state storage missing on the target falls back to automatic selection
+boot: order=scsi0
+cores: 1
+memory: 2048
+name: hibernated
+net0: virtio=BC:24:11:6B:2A:5F,bridge=vmbr0
+ostype: win10
+scsi0: mydir:202/vm-202-disk-0.qcow2,size=32G
+scsihw: virtio-scsi-single
+smbios1: uuid=0c5a8b3e-9d43-4bd1-8a0e-3f6f2b1f3c11
+sockets: 1
+vmgenid: 0
+vmstatestorage: local-zfs-pve1
+#qmdump#map:scsi0:drive-scsi0:mydir:qcow2:
diff --git a/src/test/restore-config-input/203.conf b/src/test/restore-config-input/203.conf
new file mode 100644
index 00000000..8f152775
--- /dev/null
+++ b/src/test/restore-config-input/203.conf
@@ -0,0 +1,14 @@
+# VM state storage not available on this node falls back to automatic selection
+boot: order=scsi0
+cores: 1
+memory: 2048
+name: hibernated
+net0: virtio=BC:24:11:6B:2A:5F,bridge=vmbr0
+ostype: win10
+scsi0: mydir:203/vm-203-disk-0.qcow2,size=32G
+scsihw: virtio-scsi-single
+smbios1: uuid=0c5a8b3e-9d43-4bd1-8a0e-3f6f2b1f3c11
+sockets: 1
+vmgenid: 0
+vmstatestorage: othernode
+#qmdump#map:scsi0:drive-scsi0:mydir:qcow2:
diff --git a/src/test/restore-config-input/204.conf b/src/test/restore-config-input/204.conf
new file mode 100644
index 00000000..bb8f5788
--- /dev/null
+++ b/src/test/restore-config-input/204.conf
@@ -0,0 +1,14 @@
+# disabled VM state storage falls back to automatic selection
+boot: order=scsi0
+cores: 1
+memory: 2048
+name: hibernated
+net0: virtio=BC:24:11:6B:2A:5F,bridge=vmbr0
+ostype: win10
+scsi0: mydir:204/vm-204-disk-0.qcow2,size=32G
+scsihw: virtio-scsi-single
+smbios1: uuid=0c5a8b3e-9d43-4bd1-8a0e-3f6f2b1f3c11
+sockets: 1
+vmgenid: 0
+vmstatestorage: disabledstore
+#qmdump#map:scsi0:drive-scsi0:mydir:qcow2:
diff --git a/src/test/run_qemu_restore_config_tests.pl b/src/test/run_qemu_restore_config_tests.pl
index 4d5ebb5f..8982fe90 100755
--- a/src/test/run_qemu_restore_config_tests.pl
+++ b/src/test/run_qemu_restore_config_tests.pl
@@ -17,7 +17,7 @@ my $INPUT_DIR = './restore-config-input';
my $EXPECTED_DIR = './restore-config-expected';
# NOTE update when you add/remove tests
-plan tests => 4;
+plan tests => 8;
my $pve_cluster_module = Test::MockModule->new("PVE::Cluster");
$pve_cluster_module->mock(
@@ -32,6 +32,29 @@ $pve_cluster_module->mock(
},
);
+my $pve_storage_module = Test::MockModule->new("PVE::Storage");
+$pve_storage_module->mock(
+ config => sub {
+ return {
+ ids => {
+ mydir => { type => 'dir', path => '/mnt/mydir', content => { images => 1 } },
+ othernode => {
+ type => 'dir',
+ path => '/mnt/othernode',
+ content => { images => 1 },
+ nodes => { 'some-other-node' => 1 },
+ },
+ disabledstore => {
+ type => 'dir',
+ path => '/mnt/disabled',
+ content => { images => 1 },
+ disable => 1,
+ },
+ },
+ };
+ },
+);
+
dir_glob_foreach(
'./restore-config-input',
'[0-9]+.conf',
--
2.43.0
reply other threads:[~2026-10-16 13:31 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20261016133142.7-1-me@dualfroz.com \
--to=me@dualfroz.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