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 6B7231FF0B7 for ; Fri, 16 Oct 2026 15:31:59 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id D276E214DD; Fri, 16 Oct 2026 15:31:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dualfroz.com; s=dkim; t=1792157509; h=from:subject:date:message-id:to:mime-version: content-transfer-encoding; bh=uE6AIR838RzQacXtB++aggq5D/tHXQsE9h0UD9XjtzU=; b=lYrz4ma2aZIGiHyJP75dDE1jYmT7q8d3GbRi8uIDiU3H+FI/c+tbVAeea8e1u58r/gZVeU i1CJaldEiczlKJT9niXATXZex8cjb8axM5d3TNbuF+3YWNnRzy5+94xrr8MX7U80O3ad/9 ysDaV6zKMdWkBvjsr8G8yxwmc9rIJaYadB7SUU4qhMe9J4JrzbMmxcZvv/vVxEoqhPP1JT q6uMuXMTbnLqsA2UBNBAYktWm7bMGgR6bDgpupKpdTVR9zRLl4khstqNaTKnXUxxGXJu6k jEWA0gUZlRA/DT5DKT/vC5efMwKvYy37qBrsMYS4c6yjEhoWz6qDr6QrVZLE4w== From: Michal Fox 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 Message-ID: <20261016133142.7-1-me@dualfroz.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Last-TLS-Session-Version: TLSv1.3 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.127 Adjusted score from AWL reputation of From: address DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature DKIM_VALID_AU -0.1 Message has a valid DKIM or DK signature from author's domain DKIM_VALID_EF -0.1 Message has a valid DKIM or DK signature from envelope-from domain DMARC_PASS -0.1 DMARC pass policy 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: GWCEWMSKVSU7CMP7VPQL5FARA6ZFWVRV X-Message-ID-Hash: GWCEWMSKVSU7CMP7VPQL5FARA6ZFWVRV X-MailFrom: me@dualfroz.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: 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 --- 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