]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
add downtime && expected_downtime query-migrate info
[qemu-server.git] / PVE / QemuServer.pm
index 91ee5c13d3049daf885a7bdc13740e1079eeede3..a9dd544629bd28e840c93758a41b10eee19bd07b 100644 (file)
@@ -235,7 +235,7 @@ my $confdesc = {
     ostype => {
        optional => 1,
        type => 'string',
-        enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 l24 l26)],
+        enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 l24 l26)],
        description => <<EODESC,
 Used to enable special optimization/features for specific
 operating systems:
@@ -247,11 +247,12 @@ w2k3   => Microsoft Windows 2003
 w2k8   => Microsoft Windows 2008
 wvista => Microsoft Windows Vista
 win7   => Microsoft Windows 7
+win8   => Microsoft Windows 8/2012
 l24    => Linux 2.4 Kernel
 l26    => Linux 2.6/3.X Kernel
 
-other|l24|l26                  ... no special behaviour
-wxp|w2k|w2k3|w2k8|wvista|win7  ... use --localtime switch
+other|l24|l26                       ... no special behaviour
+wxp|w2k|w2k3|w2k8|wvista|win7|win8  ... use --localtime switch
 EODESC
     },
     boot => {
@@ -309,8 +310,8 @@ EODESC
     tdf => {
        optional => 1,
        type => 'boolean',
-       description => "Enable/disable time drift fix. This is ignored for kvm versions newer that 1.0 (not needed anymore).",
-       default => 1,
+       description => "Enable/disable time drift fix.",
+       default => 0,
     },
     localtime => {
        optional => 1,
@@ -325,7 +326,7 @@ EODESC
     vga => {
        optional => 1,
        type => 'string',
-       description => "Select VGA type. If you want to use high resolution modes (>= 1280x1024x16) then you should use option 'std' or 'vmware'. Default is 'std' for win7/w2k8, and 'cirrur' for other OS types",
+       description => "Select VGA type. If you want to use high resolution modes (>= 1280x1024x16) then you should use option 'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and 'cirrur' for other OS types",
        enum => [qw(std cirrus vmware)],
     },
     watchdog => {
@@ -387,7 +388,7 @@ EODESCR
        optional => 1,
        description => "Emulated CPU type.",
        type => 'string',
-       enum => [ qw(486 athlon pentium pentium2 pentium3 coreduo core2duo kvm32 kvm64 qemu32 qemu64 phenom cpu64-rhel6 cpu64-rhel5 Conroe Penryn Nehalem Westmere Opteron_G1 Opteron_G2 Opteron_G3 host) ],
+       enum => [ qw(486 athlon pentium pentium2 pentium3 coreduo core2duo kvm32 kvm64 qemu32 qemu64 phenom Conroe Penryn Nehalem Westmere SandyBridge Haswell Opteron_G1 Opteron_G2 Opteron_G3 Opteron_G4 Opteron_G5 host) ],
        default => 'qemu64',
     },
     parent => get_standard_option('pve-snapshot-name', {
@@ -647,7 +648,7 @@ sub kvm_user_version {
 
     my $tmp = `kvm -help 2>/dev/null`;
 
-    if ($tmp =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?) /) {
+    if ($tmp =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)[,\s]/) {
        $kvm_user_version = $2;
     }
 
@@ -690,6 +691,7 @@ sub os_list_description {
        w2k8 => 'Windows 2008',
        wvista => 'Windows Vista',
        win7 => 'Windows 7',
+       win8 => 'Windows 8/2012',
        l24 => 'Linux 2.4',
        l26 => 'Linux 2.6',
     };
@@ -2082,10 +2084,45 @@ sub foreach_drive {
     }
 }
 
+sub foreach_volid {
+    my ($conf, $func) = @_;
+    
+    my $volhash = {};
+
+    my $test_volid = sub {
+       my ($volid, $is_cdrom) = @_;
+
+       return if !$volid;
+       
+       $volhash->{$volid} = $is_cdrom || 0;
+    };
+
+    PVE::QemuServer::foreach_drive($conf, sub {
+       my ($ds, $drive) = @_;
+       &$test_volid($drive->{file}, drive_is_cdrom($drive));
+    });
+
+    foreach my $snapname (keys %{$conf->{snapshots}}) {
+       my $snap = $conf->{snapshots}->{$snapname};
+       &$test_volid($snap->{vmstate}, 0);
+       PVE::QemuServer::foreach_drive($snap, sub {
+           my ($ds, $drive) = @_;
+           &$test_volid($drive->{file}, drive_is_cdrom($drive));
+        });
+    }
+
+    foreach my $volid (keys %$volhash) {
+       &$func($volid, $volhash->{$volid});     
+    }
+}
+
 sub config_to_command {
     my ($storecfg, $vmid, $conf, $defaults) = @_;
 
     my $cmd = [];
+    my $globalFlags = [];
+    my $machineFlags = [];
+    my $rtcFlags = [];
     my $devices = [];
     my $pciaddr = '';
     my $bridges = {};
@@ -2206,7 +2243,7 @@ sub config_to_command {
 
     my $vga = $conf->{vga};
     if (!$vga) {
-       if ($conf->{ostype} && ($conf->{ostype} eq 'win7' || $conf->{ostype} eq 'w2k8')) {
+       if ($conf->{ostype} && ($conf->{ostype} eq 'win8' || $conf->{ostype} eq 'win7' || $conf->{ostype} eq 'w2k8')) {
            $vga = 'std';
        } else {
            $vga = 'cirrus';
@@ -2217,43 +2254,42 @@ sub config_to_command {
 
     # time drift fix
     my $tdf = defined($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
-    # ignore - no longer supported by newer kvm
-    # push @$cmd, '-tdf' if $tdf;
 
     my $nokvm = defined($conf->{kvm}) && $conf->{kvm} == 0 ? 1 : 0;
+    my $useLocaltime = $conf->{localtime};
 
     if (my $ost = $conf->{ostype}) {
-       # other, wxp, w2k, w2k3, w2k8, wvista, win7, l24, l26
+       # other, wxp, w2k, w2k3, w2k8, wvista, win7, win8, l24, l26
 
        if ($ost =~ m/^w/) { # windows
-           push @$cmd, '-localtime' if !defined($conf->{localtime});
+           $useLocaltime = 1 if !defined($conf->{localtime});
 
-           # use rtc-td-hack when acpi is enabled
+           # use time drift fix when acpi is enabled
            if (!(defined($conf->{acpi}) && $conf->{acpi} == 0)) {
-               push @$cmd, '-rtc-td-hack';
+               $tdf = 1 if !defined($conf->{tdf});
            }
        }
 
-       if ($ost eq 'win7' || $ost eq 'w2k8' || $ost eq 'wvista') {
-           push @$cmd, '-no-kvm-pit-reinjection';
+       if ($ost eq 'win7' || $ost eq 'win8' || $ost eq 'w2k8' || 
+           $ost eq 'wvista') {
+           push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
            push @$cmd, '-no-hpet';
        }
-
-       # -tdf ?
-       # -no-acpi
-       # -no-kvm
-       # -win2k-hack ?
     }
 
+    push @$rtcFlags, 'driftfix=slew' if $tdf;
+
     if ($nokvm) {
-       push @$cmd, '-no-kvm';
+       push @$machineFlags, 'accel=tcg';
     } else {
        die "No accelerator found!\n" if !$cpuinfo->{hvm};
     }
 
-    push @$cmd, '-localtime' if $conf->{localtime};
-
-    push @$cmd, '-startdate', $conf->{startdate} if $conf->{startdate};
+    if ($conf->{startdate}) {
+       push @$rtcFlags, "base=$conf->{startdate}";
+    } elsif ($useLocaltime) {
+       push @$rtcFlags, 'base=localtime';
+    }
 
     push @$cmd, '-S' if $conf->{freeze};
 
@@ -2379,6 +2415,13 @@ sub config_to_command {
     }
 
     push @$cmd, @$devices;
+    push @$cmd, '-rtc', join(',', @$rtcFlags) 
+       if scalar(@$rtcFlags);
+    push @$cmd, '-machine', join(',', @$machineFlags) 
+       if scalar(@$machineFlags);
+    push @$cmd, '-global', join(',', @$globalFlags)
+       if scalar(@$globalFlags);
+
     return wantarray ? ($cmd, $vollist) : $cmd;
 }
 
@@ -2882,25 +2925,16 @@ sub vm_start {
 
        PVE::Storage::activate_volumes($storecfg, $vollist);
 
-       eval  { run_command($cmd, timeout => $migrate_port ? undef : 30); };
+       eval  { run_command($cmd, timeout => $statefile ? undef : 30,
+                   umask => 0077); };
        my $err = $@;
        die "start failed: $err" if $err;
 
        print "migration listens on port $migrate_port\n" if $migrate_port;
 
-       # always set migrate speed (overwrite kvm default of 32m)
-       # we set a very hight default of 8192m which is basically unlimited
-       my $migrate_speed = $defaults->{migrate_speed} || 8192;
-       $migrate_speed = $conf->{migrate_speed} || $migrate_speed;
-       $migrate_speed = $migrate_speed * 1048576;
-       eval {
-           vm_mon_cmd($vmid, "migrate_set_speed", value => $migrate_speed);
-       };
-
-       my $migrate_downtime = $defaults->{migrate_downtime};
-       $migrate_downtime = $conf->{migrate_downtime} if defined($conf->{migrate_downtime});
-       if (defined($migrate_downtime)) {
-           eval { vm_mon_cmd($vmid, "migrate_set_downtime", value => $migrate_downtime); };
+       if ($statefile && $statefile ne 'tcp')  {
+           eval { vm_mon_cmd_nocheck($vmid, "cont"); };
+           warn $@ if $@;
        }
 
        if($migratedfrom) {
@@ -2910,8 +2944,8 @@ sub vm_start {
            eval { PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => [$capabilities]); };
        }
 
-       vm_balloonset($vmid, $conf->{balloon}) if $conf->{balloon};
-
+       vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024) 
+           if $conf->{balloon};
     });
 }
 
@@ -3005,14 +3039,13 @@ sub get_vm_volumes {
     my ($conf) = @_;
 
     my $vollist = [];
-    foreach_drive($conf, sub {
-       my ($ds, $drive) = @_;
+    foreach_volid($conf, sub {
+       my ($volid, $is_cdrom) = @_;
 
-       my ($sid, $volname) = PVE::Storage::parse_volume_id($drive->{file}, 1);
-       return if !$sid;
+       return if $volid =~ m|^/|;
 
-       my $volid = $drive->{file};
-       return if !$volid || $volid =~ m|^/|;
+       my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
+       return if !$sid;
 
        push @$vollist, $volid;
     });
@@ -3345,7 +3378,7 @@ sub print_pci_addr {
 sub vm_balloonset {
     my ($vmid, $value) = @_;
 
-    vm_mon_cmd($vmid, "balloon", value => $value);
+    vm_mon_cmd($vmid, "balloon", value => $value*1024*1024);
 }
 
 # vzdump restore implementaion
@@ -3497,7 +3530,7 @@ sub restore_archive {
                $net->{macaddr} = PVE::Tools::random_ether_addr() if $net->{macaddr};
                $netstr = print_net($net);
                print $outfd "$id: $netstr\n";
-           } elsif ($line =~ m/^((ide|scsi|virtio)\d+):\s*(\S+)\s*$/) {
+           } elsif ($line =~ m/^((ide|scsi|virtio|sata)\d+):\s*(\S+)\s*$/) {
                my $virtdev = $1;
                my $value = $2;
                if ($line =~ m/backup=no/) {
@@ -3631,8 +3664,9 @@ my $alloc_vmstate_volid = sub {
 
     $target = 'local' if !$target;
 
-    my $driver_state_size = 32; # assume 32MB is enough to safe all driver state;
-    my $size = $conf->{memory} + $driver_state_size;
+    my $driver_state_size = 500; # assume 32MB is enough to safe all driver state;
+    # we abort live save after $conf->{memory}, so we need at max twice that space
+    my $size = $conf->{memory}*2 + $driver_state_size;
 
     my $name = "vm-$vmid-state-$snapname";
     my $scfg = PVE::Storage::storage_config($storecfg, $target);
@@ -3745,6 +3779,13 @@ sub snapshot_rollback {
 
        my $conf = load_config($vmid);
 
+       $snap = $conf->{snapshots}->{$snapname};
+
+       die "snapshot '$snapname' does not exist\n" if !defined($snap); 
+
+       die "unable to rollback to incomplete snapshot (snapstate = $snap->{snapstate})\n" 
+           if $snap->{snapstate};
+
        if ($prepare) {
            check_lock($conf);
            vm_stop($storecfg, $vmid, undef, undef, 5, undef, undef);
@@ -3760,13 +3801,6 @@ sub snapshot_rollback {
            delete $conf->{lock};
        }
 
-       $snap = $conf->{snapshots}->{$snapname};
-
-       die "snapshot '$snapname' does not exist\n" if !defined($snap); 
-
-       die "unable to rollback to incomplete snapshot (snapstate = $snap->{snapstate})\n" 
-           if $snap->{snapstate};
-
        if (!$prepare) {
            # copy snapshot config to current config
            $conf = &$snapshot_apply_config($conf, $snap);
@@ -3800,6 +3834,24 @@ sub snapshot_rollback {
     lock_config($vmid, $updatefn);
 }
 
+my $savevm_wait = sub {
+    my ($vmid) = @_;
+
+    for(;;) {
+       my $stat = PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "query-savevm");
+       if (!$stat->{status}) {
+           die "savevm not active\n";
+       } elsif ($stat->{status} eq 'active') {
+           sleep(1);
+           next;
+       } elsif ($stat->{status} eq 'completed') {
+           last;
+       } else {
+           die "query-savevm returned status '$stat->{status}'\n";
+       }
+    }
+};
+
 sub snapshot_create {
     my ($vmid, $snapname, $save_vmstate, $freezefs, $comment) = @_;
 
@@ -3819,9 +3871,10 @@ sub snapshot_create {
        if ($running) {
            if ($snap->{vmstate}) {
                my $path = PVE::Storage::path($storecfg, $snap->{vmstate});     
-               vm_mon_cmd($vmid, "snapshot-start", statefile => $path);
+               vm_mon_cmd($vmid, "savevm-start", statefile => $path);
+               &$savevm_wait($vmid);
            } else {
-               vm_mon_cmd($vmid, "snapshot-start");
+               vm_mon_cmd($vmid, "savevm-start");
            }
        };
 
@@ -3844,7 +3897,7 @@ sub snapshot_create {
     eval { gqa_unfreezefs($vmid) if $running && $freezefs; };
     warn $@ if $@;
 
-    eval { vm_mon_cmd($vmid, "snapshot-end") if $running; };
+    eval { vm_mon_cmd($vmid, "savevm-end") if $running; };
     warn $@ if $@;
 
     if ($err) {