5
0
mirror of git://git.proxmox.com/git/qemu-server.git synced 2025-03-09 08:58:25 +03:00

refactor: extract QEMU machine related helpers to package

...PVE::QemuServer::Machine.

qemu_machine_feature_enabled is exported since it has a *lot* of users
in PVE::QemuServer and a long enough name as it is.

Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
This commit is contained in:
Stefan Reiter 2019-11-19 12:23:48 +01:00 committed by Thomas Lamprecht
parent 0a13e08ec2
commit 3392d6cacf
6 changed files with 116 additions and 98 deletions

View File

@ -8,6 +8,7 @@ use PVE::INotify;
use PVE::QemuServer::Helpers;
use PVE::QemuServer::Monitor qw(mon_cmd);
use PVE::QemuServer;
use PVE::QemuServer::Machine;
use PVE::Storage;
use PVE::Tools;
@ -165,7 +166,7 @@ sub __snapshot_save_vmstate {
$name .= ".raw" if $scfg->{path}; # add filename extension for file base storage
my $statefile = PVE::Storage::vdisk_alloc($storecfg, $target, $vmid, 'raw', $name, $size*1024);
my $runningmachine = PVE::QemuServer::get_current_qemu_machine($vmid);
my $runningmachine = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
if ($suspend) {
$conf->{vmstate} = $statefile;

View File

@ -11,6 +11,7 @@ use PVE::Tools;
use PVE::Cluster;
use PVE::Storage;
use PVE::QemuServer;
use PVE::QemuServer::Machine;
use PVE::QemuServer::Monitor qw(mon_cmd);
use Time::HiRes qw( usleep );
use PVE::RPCEnvironment;
@ -216,7 +217,7 @@ sub prepare {
die "can't migrate running VM without --online\n" if !$online;
$running = $pid;
$self->{forcemachine} = PVE::QemuServer::qemu_machine_pxe($vmid, $conf);
$self->{forcemachine} = PVE::QemuServer::Machine::qemu_machine_pxe($vmid, $conf);
}
my $loc_res = PVE::QemuServer::check_local_resources($conf, 1);

View File

@ -43,6 +43,7 @@ use PVE::QMPClient;
use PVE::QemuConfig;
use PVE::QemuServer::Helpers;
use PVE::QemuServer::Cloudinit;
use PVE::QemuServer::Machine qw(qemu_machine_feature_enabled);
use PVE::QemuServer::Memory;
use PVE::QemuServer::Monitor qw(mon_cmd);
use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port);
@ -1814,20 +1815,14 @@ sub path_is_scsi {
return $res;
}
sub machine_type_is_q35 {
my ($conf) = @_;
return $conf->{machine} && ($conf->{machine} =~ m/q35/) ? 1 : 0;
}
sub print_tabletdevice_full {
my ($conf, $arch) = @_;
my $q35 = machine_type_is_q35($conf);
my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
# we use uhci for old VMs because tablet driver was buggy in older qemu
my $usbbus;
if (machine_type_is_q35($conf) || $arch eq 'aarch64') {
if (PVE::QemuServer::Machine::machine_type_is_q35($conf) || $arch eq 'aarch64') {
$usbbus = 'ehci';
} else {
$usbbus = 'uhci';
@ -2186,7 +2181,7 @@ sub print_vga_device {
$memory = ",ram_size=67108864,vram_size=33554432";
}
my $q35 = machine_type_is_q35($conf);
my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
my $vgaid = "vga" . ($id // '');
my $pciaddr;
@ -3468,7 +3463,7 @@ sub config_to_command {
die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
my $q35 = machine_type_is_q35($conf);
my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
my $use_old_bios_files = undef;
($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
@ -4109,7 +4104,7 @@ sub vm_devices_list {
sub vm_deviceplug {
my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
my $q35 = machine_type_is_q35($conf);
my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
my $devices_list = vm_devices_list($vmid);
return 1 if defined($devices_list->{$deviceid});
@ -4185,7 +4180,7 @@ sub vm_deviceplug {
return undef if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
my $machine_type = PVE::QemuServer::qemu_machine_pxe($vmid, $conf);
my $machine_type = PVE::QemuServer::Machine::qemu_machine_pxe($vmid, $conf);
my $use_old_bios_files = undef;
($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
@ -4499,7 +4494,7 @@ sub qemu_usb_hotplug {
sub qemu_cpu_hotplug {
my ($vmid, $conf, $vcpus) = @_;
my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
my $sockets = 1;
$sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
@ -7007,94 +7002,12 @@ no_data_clone:
return $disk;
}
# this only works if VM is running
sub get_current_qemu_machine {
my ($vmid) = @_;
my $res = mon_cmd($vmid, "query-machines");
my ($current, $default);
foreach my $e (@$res) {
$default = $e->{name} if $e->{'is-default'};
$current = $e->{name} if $e->{'is-current'};
}
# fallback to the default machine if current is not supported by qemu
return $current || $default || 'pc';
}
sub get_running_qemu_version {
my ($vmid) = @_;
my $res = mon_cmd($vmid, "query-version");
return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
}
sub qemu_machine_feature_enabled {
my ($machine, $kvmver, $version_major, $version_minor) = @_;
my $current_major;
my $current_minor;
if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
$current_major = $3;
$current_minor = $4;
} elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
$current_major = $1;
$current_minor = $2;
}
return 1 if version_cmp($current_major, $version_major, $current_minor, $version_minor) >= 0;
}
# gets in pairs the versions you want to compares, i.e.:
# ($a-major, $b-major, $a-minor, $b-minor, $a-extra, $b-extra, ...)
# returns 0 if same, -1 if $a is older than $b, +1 if $a is newer than $b
sub version_cmp {
my @versions = @_;
my $size = scalar(@versions);
return 0 if $size == 0;
die "cannot compare odd count of versions" if $size & 1;
for (my $i = 0; $i < $size; $i += 2) {
my ($a, $b) = splice(@versions, 0, 2);
$a //= 0;
$b //= 0;
return 1 if $a > $b;
return -1 if $a < $b;
}
return 0;
}
# dies if a) VM not running or not exisiting b) Version query failed
# So, any defined return value is valid, any invalid state can be caught by eval
sub runs_at_least_qemu_version {
my ($vmid, $major, $minor, $extra) = @_;
my $v = mon_cmd($vmid, "query-version");
die "could not query currently running version for VM $vmid\n" if !defined($v);
$v = $v->{qemu};
return version_cmp($v->{major}, $major, $v->{minor}, $minor, $v->{micro}, $extra) >= 0;
}
sub qemu_machine_pxe {
my ($vmid, $conf) = @_;
my $machine = PVE::QemuServer::get_current_qemu_machine($vmid);
if ($conf->{machine} && $conf->{machine} =~ m/\.pxe$/) {
$machine .= '.pxe';
}
return $machine;
}
sub qemu_use_old_bios_files {
my ($machine_type) = @_;

101
PVE/QemuServer/Machine.pm Normal file
View File

@ -0,0 +1,101 @@
package PVE::QemuServer::Machine;
use strict;
use warnings;
use PVE::QemuServer::Monitor;
use base 'Exporter';
our @EXPORT_OK = qw(
qemu_machine_feature_enabled
);
sub machine_type_is_q35 {
my ($conf) = @_;
return $conf->{machine} && ($conf->{machine} =~ m/q35/) ? 1 : 0;
}
# this only works if VM is running
sub get_current_qemu_machine {
my ($vmid) = @_;
my $res = PVE::QemuServer::Monitor::mon_cmd($vmid, 'query-machines');
my ($current, $default);
foreach my $e (@$res) {
$default = $e->{name} if $e->{'is-default'};
$current = $e->{name} if $e->{'is-current'};
}
# fallback to the default machine if current is not supported by qemu
return $current || $default || 'pc';
}
sub qemu_machine_feature_enabled {
my ($machine, $kvmver, $version_major, $version_minor) = @_;
my $current_major;
my $current_minor;
if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
$current_major = $3;
$current_minor = $4;
} elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
$current_major = $1;
$current_minor = $2;
}
return 1 if version_cmp($current_major, $version_major, $current_minor, $version_minor) >= 0;
}
# gets in pairs the versions you want to compares, i.e.:
# ($a-major, $b-major, $a-minor, $b-minor, $a-extra, $b-extra, ...)
# returns 0 if same, -1 if $a is older than $b, +1 if $a is newer than $b
sub version_cmp {
my @versions = @_;
my $size = scalar(@versions);
return 0 if $size == 0;
die "cannot compare odd count of versions" if $size & 1;
for (my $i = 0; $i < $size; $i += 2) {
my ($a, $b) = splice(@versions, 0, 2);
$a //= 0;
$b //= 0;
return 1 if $a > $b;
return -1 if $a < $b;
}
return 0;
}
# dies if a) VM not running or not exisiting b) Version query failed
# So, any defined return value is valid, any invalid state can be caught by eval
sub runs_at_least_qemu_version {
my ($vmid, $major, $minor, $extra) = @_;
my $v = PVE::QemuServer::Monitor::mon_cmd($vmid, 'query-version');
die "could not query currently running version for VM $vmid\n" if !defined($v);
$v = $v->{qemu};
return version_cmp($v->{major}, $major, $v->{minor}, $minor, $v->{micro}, $extra) >= 0;
}
sub qemu_machine_pxe {
my ($vmid, $conf) = @_;
my $machine = get_current_qemu_machine($vmid);
if ($conf->{machine} && $conf->{machine} =~ m/\.pxe$/) {
$machine .= '.pxe';
}
return $machine;
}
1;

View File

@ -7,6 +7,7 @@ SOURCES=PCI.pm \
Agent.pm \
Helpers.pm \
Monitor.pm \
Machine.pm \
.PHONY: install
install: ${SOURCES}

View File

@ -19,6 +19,7 @@ use PVE::Tools;
use PVE::VZDump;
use PVE::QemuServer;
use PVE::QemuServer::Machine;
use PVE::QemuServer::Monitor qw(mon_cmd);
use base qw (PVE::VZDump::Plugin);
@ -79,7 +80,7 @@ sub prepare {
$self->loginfo("exclude disk '$ds' '$volid' (backup=no)");
return;
} elsif ($self->{vm_was_running} && $drive->{iothread}) {
if (!PVE::QemuServer::runs_at_least_qemu_version($vmid, 4, 0, 1)) {
if (!PVE::QemuServer::Machine::runs_at_least_qemu_version($vmid, 4, 0, 1)) {
die "disk '$ds' '$volid' (iothread=on) can't use backup feature with running QEMU " .
"version < 4.0.1! Either set backup=no for this drive or upgrade QEMU and restart VM\n";
}