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

Dominik Csapak d.csapak at proxmox.com
Mon Mar 30 09:09:38 CEST 2020


any further comment?
i guess it does need a rebase?

On 2/12/20 1:31 PM, Dominik Csapak wrote:
> 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
> 
> we have to version_guard it to 4.1+pve2 (since we haven't bumped yet
> since the change to pve2)
> 
> also add 2 tests, one for the old version and one for the new
> 
> Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
> ---
> changes from v1:
> * rebase on master (drop PVE version increase; drop test adaptions)
> * use version_guard instead of min_version
> * add tests for raw efidisk
> 
>   PVE/API2/Qemu.pm                  |  4 +--
>   PVE/QemuMigrate.pm                |  6 +++++
>   PVE/QemuServer.pm                 | 43 ++++++++++++++++++++++++++++---
>   test/cfg2cmd/efi-raw-old.conf     |  5 ++++
>   test/cfg2cmd/efi-raw-old.conf.cmd | 26 +++++++++++++++++++
>   test/cfg2cmd/efi-raw.conf         |  4 +++
>   test/cfg2cmd/efi-raw.conf.cmd     | 26 +++++++++++++++++++
>   7 files changed, 109 insertions(+), 5 deletions(-)
>   create mode 100644 test/cfg2cmd/efi-raw-old.conf
>   create mode 100644 test/cfg2cmd/efi-raw-old.conf.cmd
>   create mode 100644 test/cfg2cmd/efi-raw.conf
>   create mode 100644 test/cfg2cmd/efi-raw.conf.cmd
> 
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index caca430..86af4a1 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 6db5e62..ca3feb2 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 23176dd..3700ced 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -3544,8 +3544,14 @@ sub config_to_command {
>   	    $format = 'raw';
>   	}
>   
> +	my $size_str = "";
> +
> +	if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
> +	    $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
> @@ -7021,7 +7027,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;
>   
> @@ -7044,6 +7050,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;
> @@ -7057,7 +7065,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);
> @@ -7109,6 +7126,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/test/cfg2cmd/efi-raw-old.conf b/test/cfg2cmd/efi-raw-old.conf
> new file mode 100644
> index 0000000..549cd25
> --- /dev/null
> +++ b/test/cfg2cmd/efi-raw-old.conf
> @@ -0,0 +1,5 @@
> +# TEST: Test raw efidisk size parameter on old version
> +smbios1: uuid=7b10d7af-b932-4c66-b2c3-3996152ec465
> +bios: ovmf
> +machine: pc-i440fx-4.1+pve1
> +efidisk0: local:100/vm-disk-100-0.raw
> diff --git a/test/cfg2cmd/efi-raw-old.conf.cmd b/test/cfg2cmd/efi-raw-old.conf.cmd
> new file mode 100644
> index 0000000..5526a48
> --- /dev/null
> +++ b/test/cfg2cmd/efi-raw-old.conf.cmd
> @@ -0,0 +1,26 @@
> +/usr/bin/kvm \
> +  -id 8006 \
> +  -name vm8006 \
> +  -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server,nowait' \
> +  -mon 'chardev=qmp,mode=control' \
> +  -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5' \
> +  -mon 'chardev=qmp-event,mode=control' \
> +  -pidfile /var/run/qemu-server/8006.pid \
> +  -daemonize \
> +  -smbios 'type=1,uuid=7b10d7af-b932-4c66-b2c3-3996152ec465' \
> +  -drive 'if=pflash,unit=0,format=raw,readonly,file=/usr/share/pve-edk2-firmware//OVMF_CODE.fd' \
> +  -drive 'if=pflash,unit=1,format=raw,id=drive-efidisk0,file=/var/lib/vz/images/100/vm-disk-100-0.raw' \
> +  -smp '1,sockets=1,cores=1,maxcpus=1' \
> +  -nodefaults \
> +  -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \
> +  -vnc unix:/var/run/qemu-server/8006.vnc,password \
> +  -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \
> +  -m 512 \
> +  -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \
> +  -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \
> +  -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \
> +  -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \
> +  -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-i440fx-4.1+pve0'
> diff --git a/test/cfg2cmd/efi-raw.conf b/test/cfg2cmd/efi-raw.conf
> new file mode 100644
> index 0000000..11e6a3e
> --- /dev/null
> +++ b/test/cfg2cmd/efi-raw.conf
> @@ -0,0 +1,4 @@
> +# TEST: Test raw efidisk size parameter
> +smbios1: uuid=7b10d7af-b932-4c66-b2c3-3996152ec465
> +bios: ovmf
> +efidisk0: local:100/vm-disk-100-0.raw
> diff --git a/test/cfg2cmd/efi-raw.conf.cmd b/test/cfg2cmd/efi-raw.conf.cmd
> new file mode 100644
> index 0000000..1330ef6
> --- /dev/null
> +++ b/test/cfg2cmd/efi-raw.conf.cmd
> @@ -0,0 +1,26 @@
> +/usr/bin/kvm \
> +  -id 8006 \
> +  -name vm8006 \
> +  -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server,nowait' \
> +  -mon 'chardev=qmp,mode=control' \
> +  -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5' \
> +  -mon 'chardev=qmp-event,mode=control' \
> +  -pidfile /var/run/qemu-server/8006.pid \
> +  -daemonize \
> +  -smbios 'type=1,uuid=7b10d7af-b932-4c66-b2c3-3996152ec465' \
> +  -drive 'if=pflash,unit=0,format=raw,readonly,file=/usr/share/pve-edk2-firmware//OVMF_CODE.fd' \
> +  -drive 'if=pflash,unit=1,format=raw,id=drive-efidisk0,size=131072,file=/var/lib/vz/images/100/vm-disk-100-0.raw' \
> +  -smp '1,sockets=1,cores=1,maxcpus=1' \
> +  -nodefaults \
> +  -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \
> +  -vnc unix:/var/run/qemu-server/8006.vnc,password \
> +  -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \
> +  -m 512 \
> +  -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \
> +  -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \
> +  -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \
> +  -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \
> +  -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+pve2'
> 




More information about the pve-devel mailing list