[pve-devel] [PATCH qemu-server] fix efidisks on storages with minimum sizes bigger than OVMF_VARS.fd

Dominik Csapak d.csapak at proxmox.com
Wed Feb 5 16:36:32 CET 2020


on storages where the minimum size of images is bigger than the real
OVMF_VARS.fd file, they get padded to their minimum size

when using such an image, qemu maps it fully to the vm, but the efi
does not find the vars region and creates a file on the first efi
partition it finds

this breaks some settings in the ovmf, such as resolution

to fix this, we have to specify the size for the pflash, so that
qemu only maps the first n bytes in the vm (this only works for
raw files, not for qcow2)

we also have to use the correct size when converting between storages
in 'clone_disk' (used for move disk and cloning vms) and when
live migrating to different storages

when we now expect that the source image is always correctly used/created
(e.g. raw with size=x in pflash argument) then we always create the
target correctly

when encountering users which have a non-valid image (e.g. a efidisk
moved from zfs to qcow2 before this patch), we have to tell them to
recreate the efidisk and the settings on it

for all this to work, we have to bump the pve machine version
(and adapt the tests)

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 PVE/API2/Qemu.pm                              |  4 +-
 PVE/QemuMigrate.pm                            |  6 +++
 PVE/QemuServer.pm                             | 43 +++++++++++++++++--
 PVE/QemuServer/Machine.pm                     |  2 +-
 test/cfg2cmd/i440fx-win10-hostpci.conf.cmd    |  2 +-
 test/cfg2cmd/minimal-defaults.conf.cmd        |  2 +-
 .../q35-linux-hostpci-multifunction.conf.cmd  |  2 +-
 test/cfg2cmd/q35-linux-hostpci.conf.cmd       |  2 +-
 test/cfg2cmd/q35-win10-hostpci.conf.cmd       |  2 +-
 test/cfg2cmd/spice-linux-4.1.conf.cmd         |  2 +-
 10 files changed, 55 insertions(+), 12 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index d0dd2dc..bf5bb16 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -2908,7 +2908,7 @@ __PACKAGE__->register_method({
 
 			my $newdrive = PVE::QemuServer::clone_disk($storecfg, $vmid, $running, $opt, $drive, $snapname,
 								   $newid, $storage, $format, $fullclone->{$opt}, $newvollist,
-								   $jobs, $skipcomplete, $oldconf->{agent}, $clonelimit);
+								   $jobs, $skipcomplete, $oldconf->{agent}, $clonelimit, $oldconf);
 
 			$newconf->{$opt} = PVE::QemuServer::print_drive($newdrive);
 
@@ -3095,7 +3095,7 @@ __PACKAGE__->register_method({
 		    my $movelimit = PVE::Storage::get_bandwidth_limit('move', [$oldstoreid, $storeid], $bwlimit);
 
 		    my $newdrive = PVE::QemuServer::clone_disk($storecfg, $vmid, $running, $disk, $drive, undef,
-							       $vmid, $storeid, $format, 1, $newvollist, undef, undef, undef, $movelimit);
+							       $vmid, $storeid, $format, 1, $newvollist, undef, undef, undef, $movelimit, $conf);
 
 		    $conf->{$disk} = PVE::QemuServer::print_drive($newdrive);
 
diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm
index 1f6e306..4914a1c 100644
--- a/PVE/QemuMigrate.pm
+++ b/PVE/QemuMigrate.pm
@@ -454,6 +454,12 @@ sub sync_disks {
 	    }
 	});
 
+	# we want to set the efidisk size in the config to the size of the
+	# real OVMF_VARS.fd image, else we can create a too big image, which does not work
+	if (defined($conf->{efidisk0})) {
+	    PVE::QemuServer::update_efidisk_size($conf);
+	}
+
 	$self->log('info', "copying local disk images") if scalar(%$local_volumes);
 
 	foreach my $volid (keys %$local_volumes) {
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 214140c..3aef95c 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -3520,8 +3520,14 @@ sub config_to_command {
 	    $format = 'raw';
 	}
 
+	my $size_str = "";
+
+	if (min_version($machine_version, 4, 1, 2) && $format eq 'raw') {
+	    $size_str = ",size=" . (-s $ovmf_vars);
+	}
+
 	push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
-	push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
+	push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0$size_str,file=$path";
     }
 
     # load q35 config
@@ -6987,7 +6993,7 @@ sub qemu_blockjobs_cancel {
 
 sub clone_disk {
     my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
-	$newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga, $bwlimit) = @_;
+	$newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga, $bwlimit, $conf) = @_;
 
     my $newvolid;
 
@@ -7010,6 +7016,8 @@ sub clone_disk {
 	    $name .= ".$dst_format" if $dst_format ne 'raw';
 	    $snapname = undef;
 	    $size = PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE;
+	} elsif ($drivename eq 'efidisk0') {
+	    $size = get_efivars_size($conf);
 	}
 	$newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
 	push @$newvollist, $newvolid;
@@ -7023,7 +7031,16 @@ sub clone_disk {
 	my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
 	if (!$running || $snapname) {
 	    # TODO: handle bwlimits
-	    qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
+	    if ($drivename eq 'efidisk0') {
+		# the relevant data on the efidisk may be smaller than the source
+		# e.g. on RBD/ZFS, so we use dd to copy only the amount
+		# that is given by the OVMF_VARS.fd
+		my $src_path = PVE::Storage::path($storecfg, $drive->{file});
+		my $dst_path = PVE::Storage::path($storecfg, $newvolid);
+		run_command(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=1", "count=$size", "if=$src_path", "of=$dst_path"]);
+	    } else {
+		qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
+	    }
 	} else {
 
 	    my $kvmver = get_running_qemu_version ($vmid);
@@ -7075,6 +7092,26 @@ sub qemu_use_old_bios_files {
     return ($use_old_bios_files, $machine_type);
 }
 
+sub get_efivars_size {
+    my ($conf) = @_;
+    my $arch = get_vm_arch($conf);
+    my (undef, $ovmf_vars) = get_ovmf_files($arch);
+    die "uefi vars image '$ovmf_vars' not found\n" if ! -f $ovmf_vars;
+    return -s $ovmf_vars;
+}
+
+sub update_efidisk_size {
+    my ($conf) = @_;
+
+    return if !defined($conf->{efidisk0});
+
+    my $disk = PVE::QemuServer::parse_drive('efidisk0', $conf->{efidisk0});
+    $disk->{size} = get_efivars_size($conf);
+    $conf->{efidisk0} = print_drive($disk);
+
+    return;
+}
+
 sub create_efidisk($$$$$) {
     my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
 
diff --git a/PVE/QemuServer/Machine.pm b/PVE/QemuServer/Machine.pm
index 8c13402..80c9467 100644
--- a/PVE/QemuServer/Machine.pm
+++ b/PVE/QemuServer/Machine.pm
@@ -8,7 +8,7 @@ use PVE::QemuServer::Monitor;
 
 # Bump this for VM HW layout changes during a release (where the QEMU machine
 # version stays the same)
-our $PVE_MACHINE_VERSION = 1;
+our $PVE_MACHINE_VERSION = 2;
 
 sub machine_type_is_q35 {
     my ($conf) = @_;
diff --git a/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd b/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd
index bda7f63..61cfcff 100644
--- a/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd
+++ b/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd
@@ -33,5 +33,5 @@
   -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown,vhost=on' \
   -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,bootindex=300' \
   -rtc 'driftfix=slew,base=localtime' \
-  -machine 'type=pc+pve1' \
+  -machine 'type=pc+pve2' \
   -global 'kvm-pit.lost_tick_policy=discard'
diff --git a/test/cfg2cmd/minimal-defaults.conf.cmd b/test/cfg2cmd/minimal-defaults.conf.cmd
index 83ae328..bd131a6 100644
--- a/test/cfg2cmd/minimal-defaults.conf.cmd
+++ b/test/cfg2cmd/minimal-defaults.conf.cmd
@@ -21,4 +21,4 @@
   -device 'VGA,id=vga,bus=pci.0,addr=0x2' \
   -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3' \
   -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \
-  -machine 'type=pc+pve1'
+  -machine 'type=pc+pve2'
diff --git a/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd b/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd
index e20be7d..567cd59 100644
--- a/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd
+++ b/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd
@@ -31,4 +31,4 @@
   -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \
   -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown,vhost=on' \
   -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,bootindex=300' \
-  -machine 'type=q35+pve1'
+  -machine 'type=q35+pve2'
diff --git a/test/cfg2cmd/q35-linux-hostpci.conf.cmd b/test/cfg2cmd/q35-linux-hostpci.conf.cmd
index 152624c..1cb08ba 100644
--- a/test/cfg2cmd/q35-linux-hostpci.conf.cmd
+++ b/test/cfg2cmd/q35-linux-hostpci.conf.cmd
@@ -36,4 +36,4 @@
   -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \
   -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown,vhost=on' \
   -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,bootindex=300' \
-  -machine 'type=q35+pve1'
+  -machine 'type=q35+pve2'
diff --git a/test/cfg2cmd/q35-win10-hostpci.conf.cmd b/test/cfg2cmd/q35-win10-hostpci.conf.cmd
index ff799ea..e790bc8 100644
--- a/test/cfg2cmd/q35-win10-hostpci.conf.cmd
+++ b/test/cfg2cmd/q35-win10-hostpci.conf.cmd
@@ -34,5 +34,5 @@
   -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown,vhost=on' \
   -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,bootindex=300' \
   -rtc 'driftfix=slew,base=localtime' \
-  -machine 'type=q35+pve1' \
+  -machine 'type=q35+pve2' \
   -global 'kvm-pit.lost_tick_policy=discard'
diff --git a/test/cfg2cmd/spice-linux-4.1.conf.cmd b/test/cfg2cmd/spice-linux-4.1.conf.cmd
index 4ed6fd2..ea5c375 100644
--- a/test/cfg2cmd/spice-linux-4.1.conf.cmd
+++ b/test/cfg2cmd/spice-linux-4.1.conf.cmd
@@ -27,4 +27,4 @@
   -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \
   -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown,vhost=on' \
   -device 'virtio-net-pci,mac=A2:C0:43:67:08:A1,netdev=net0,bus=pci.0,addr=0x12,id=net0,bootindex=300' \
-  -machine 'type=pc+pve1'
+  -machine 'type=pc+pve2'
-- 
2.20.1




More information about the pve-devel mailing list