diff --git a/PVE/CLI/pve8to9.pm b/PVE/CLI/pve8to9.pm index 7305a7b..b147f56 100644 --- a/PVE/CLI/pve8to9.pm +++ b/PVE/CLI/pve8to9.pm @@ -27,6 +27,7 @@ use PVE::Storage::Plugin; use PVE::Tools qw(run_command split_list file_get_contents trim); use PVE::QemuConfig; use PVE::QemuServer; +use PVE::QemuServer::Drive; use PVE::QemuServer::Machine; use PVE::QemuServer::Network; use PVE::VZDump::Common; @@ -1076,6 +1077,51 @@ my sub check_qemu_machine_versions { } } +sub check_qemu_tpmstate_volumes { + log_info("Checking VM TPM state volumes for qcow2 files containing raw data.."); + + my $storecfg = PVE::Storage::config(); + my $affected = []; + + my $vms = PVE::QemuServer::config_list(); + for my $vmid (sort { $a <=> $b } keys $vms->%*) { + my $conf = PVE::QemuConfig->load_config($vmid); + next if !$conf->{tpmstate0}; + + my $volid = PVE::QemuServer::Drive::parse_drive('tpmstate0', $conf->{tpmstate0})->{file}; + eval { + my ($storeid) = PVE::Storage::parse_volume_id($volid); + my $format = (PVE::Storage::parse_volname($storecfg, $volid))[6]; + my $scfg = PVE::Storage::storage_config($storecfg, $storeid); + # only volumes on file based storages could end up like this + return if $format ne 'qcow2' || !$scfg->{path}; + + my $path = PVE::Storage::path($storecfg, $volid); + open(my $fh, '<', $path) or die "unable to open '$path' - $!\n"; + my $magic = ''; + read($fh, $magic, 4); + close($fh); + + # before qemu-server 8.3.3, swtpm_setup used the qcow2 overlay of linked clones as raw + # file and overwrote it with a new state + push $affected->@*, "VM $vmid: $volid" if $magic ne "QFI\xfb"; + }; + log_skip("could not check TPM state volume '$volid' of VM $vmid - $@") if $@; + } + + if (!scalar($affected->@*)) { + log_pass("No qcow2 TPM state volumes with raw data found."); + return; + } + + log_warn( + "The TPM state volumes of the following VMs are qcow2 files that contain raw data, which" + . " happened with linked clones. Such a VM fails to start in Proxmox VE 9. Rename the" + . " file to end with '.raw' and adapt the 'tpmstate0' line of the VM config accordingly," + . " also dropping the base volume, like '101/base-101-disk-2.raw/':\n\t" + . join("\n\t", $affected->@*)); +} + my sub check_max_length { my ($raw, $max_length, $warning) = @_; log_warn($warning) if defined($raw) && length($raw) > $max_length; @@ -2098,6 +2144,8 @@ sub check_virtual_guests { } check_qemu_machine_versions(); + + check_qemu_tpmstate_volumes(); } my $LEGACY_IPAM_DB = "/etc/pve/priv/ipam.db";