[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