[pve-devel] [PATCH] add a forcemachine parameter to force a specific qemu machine version

Stefan Priebe s.priebe at profihost.ag
Mon Jun 3 10:22:00 CEST 2013


- this allows us to restore old snapshots and migrate machines running older qemu versions

Signed-off-by: Stefan Priebe <s.priebe at profihost.ag>
---
 PVE/API2/Qemu.pm   |    6 ++++--
 PVE/QemuMigrate.pm |    6 +++++-
 PVE/QemuServer.pm  |   51 ++++++++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 8ed9d5d..3cc66e8 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -1327,7 +1327,7 @@ __PACKAGE__->register_method({
 	    skiplock => get_standard_option('skiplock'),
 	    stateuri => get_standard_option('pve-qm-stateuri'),
 	    migratedfrom => get_standard_option('pve-node',{ optional => 1 }),
-
+	    forcemachine => get_standard_option('forcemachine',{ optional => 1 }),
 	},
     },
     returns => {
@@ -1356,6 +1356,8 @@ __PACKAGE__->register_method({
 	raise_param_exc({ migratedfrom => "Only root may use this option." })
 	    if $migratedfrom && $authuser ne 'root at pam';
 
+	my $forcemachine = extract_param($param, 'forcemachine');
+
 	my $storecfg = PVE::Storage::config();
 
 	if (&$vm_is_ha_managed($vmid) && !$stateuri &&
@@ -1384,7 +1386,7 @@ __PACKAGE__->register_method({
 
 		syslog('info', "start VM $vmid: $upid\n");
 
-		PVE::QemuServer::vm_start($storecfg, $vmid, $stateuri, $skiplock, $migratedfrom);
+		PVE::QemuServer::vm_start($storecfg, $vmid, $stateuri, $skiplock, $migratedfrom, undef, $forcemachine);
 
 		return;
 	    };
diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm
index aa960ae..15d6c06 100644
--- a/PVE/QemuMigrate.pm
+++ b/PVE/QemuMigrate.pm
@@ -166,6 +166,10 @@ sub prepare {
     eval { $self->cmd_quiet($cmd); };
     die "Can't connect to destination address using public key\n" if $@;
 
+    # save running qemu version
+    my $current_machine = PVE::QemuServer::get_current_qemu_machine($vmid);
+    $self->{current_machine} = $current_machine if ($current_machine);
+
     return $running;
 }
 
@@ -317,7 +321,7 @@ sub phase2 {
 
     ## start on remote node
     my $cmd = [@{$self->{rem_ssh}}, 'qm', 'start',
-               $vmid, '--stateuri', 'tcp', '--skiplock', '--migratedfrom', $nodename];
+               $vmid, '--stateuri', 'tcp', '--skiplock', '--migratedfrom', $nodename, '--forcemachine', $self->{current_machine} ];
 
     PVE::Tools::run_command($cmd, outfunc => sub {
 	my $line = shift;
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 440f4a1..7642f0f 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -49,6 +49,13 @@ PVE::JSONSchema::register_standard_option('skiplock', {
     optional => 1,
 });
 
+PVE::JSONSchema::register_standard_option('forcemachine', {
+    description => "Force a specific qemu machine type.",
+    type => 'string',
+    maxLength => 128,
+    optional => 1,
+});
+
 PVE::JSONSchema::register_standard_option('pve-qm-stateuri', {
     description => "Some command save/restore state from this location.",
     type => 'string',
@@ -136,6 +143,26 @@ sub fairsched_cpulimit {
     return fairsched_rate($id, $op, $cpulim1024);
 }
 
+my $minimal_qemu_machine = "pc-i440fx-1.4";
+
+sub get_current_qemu_machine {
+    my ($vmid) = @_;
+
+    my $machine = eval {
+        my $cmd = { execute => 'query-machines', arguments => {} };
+        my $res = PVE::QemuServer::vm_qmp_command($vmid, $cmd); 
+
+        my $cur = eval { (grep { $_->{'is-current'} } @$res)[0]->{name} };
+        my $def = eval { (grep { $_->{'is-default'} } @$res)[0]->{name} };
+
+        # fallback to the default machine if current is not supported by qemu
+        return $cur || $def;
+    };
+
+    # could be undef if machine is not running
+    return $machine;
+}
+
 my $nodename = PVE::INotify::nodename();
 
 mkdir "/etc/pve/nodes/$nodename";
@@ -416,6 +443,11 @@ EODESCR
 	type => 'integer',
 	minimum => 0,
     },
+    current_machine => {
+	optional => 1,
+	description => "Currently running qemu machine type.",
+	type => 'string',
+    },
     vmstate => {
 	optional => 1,
 	type => 'string', format => 'pve-volume-id',
@@ -1439,7 +1471,7 @@ sub json_config_properties {
     my $prop = shift;
 
     foreach my $opt (keys %$confdesc) {
-	next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
+	next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'current_machine';
 	$prop->{$opt} = $confdesc->{$opt};
     }
 
@@ -2230,7 +2262,7 @@ sub foreach_volid {
 }
 
 sub config_to_command {
-    my ($storecfg, $vmid, $conf, $defaults) = @_;
+    my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
 
     my $cmd = [];
     my $globalFlags = [];
@@ -2250,6 +2282,10 @@ sub config_to_command {
 
     push @$cmd, '-id', $vmid;
 
+    # if we restore an old snapshot or migrate from an older qemu version
+    # we need to force the original machine version
+    push @$machineFlags, $forcemachine if $forcemachine;
+
     my $use_virtio = 0;
 
     my $qmpsocket = qmp_socket($vmid);
@@ -2974,7 +3010,7 @@ sub qga_unfreezefs {
 }
 
 sub vm_start {
-    my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused) = @_;
+    my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused, $forcemachine) = @_;
 
     lock_config($vmid, sub {
 	my $conf = load_config($vmid, $migratedfrom);
@@ -2990,7 +3026,7 @@ sub vm_start {
 	# set environment variable useful inside network script
 	$ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
 
-	my ($cmd, $vollist) = config_to_command($storecfg, $vmid, $conf, $defaults);
+	my ($cmd, $vollist) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
 
 	my $migrate_port = 0;
 	my $migrate_uri;
@@ -4133,6 +4169,7 @@ my $snapshot_copy_config = sub {
 	next if $k eq 'snapshots';
 	next if $k eq 'snapstate';
 	next if $k eq 'snaptime';
+	next if $k eq 'current_machine';
 	next if $k eq 'vmstate';
 	next if $k eq 'lock';
 	next if $k eq 'digest';
@@ -4259,6 +4296,8 @@ my $snapshot_prepare = sub {
 	$snap->{snapstate} = "prepare";
 	$snap->{snaptime} = time();
 	$snap->{description} = $comment if $comment;
+	my $current_machine = get_current_qemu_machine($vmid);
+	$snap->{current_machine} = $current_machine if ($current_machine);
 
 	update_config_nolock($vmid, $conf, 1);
     };
@@ -4345,7 +4384,9 @@ sub snapshot_rollback {
 
 	if (!$prepare && $snap->{vmstate}) {
 	    my $statefile = PVE::Storage::path($storecfg, $snap->{vmstate});
-	    vm_start($storecfg, $vmid, $statefile);
+
+	    # machine was not saved at snapshot time so assume the minimal version
+	    vm_start($storecfg, $vmid, $statefile, undef, undef, undef, ($snap->{current_machine} || $minimal_qemu_machine));
 	}
     };
 
-- 
1.7.10.4




More information about the pve-devel mailing list