]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
disable hyper-v enlightment when xvga is enabled
[qemu-server.git] / PVE / QemuServer.pm
index e063c17db583ccaca6ad2c1d2a3f427232a9853b..7991f10ea1c811361d7ccaa664ac537a2f3eff0a 100644 (file)
@@ -30,6 +30,7 @@ use PVE::ProcFSTools;
 use PVE::QMPClient;
 use PVE::RPCEnvironment;
 use Time::HiRes qw(gettimeofday);
+use File::Copy qw(copy);
 
 my $qemu_snap_storage = {rbd => 1, sheepdog => 1};
 
@@ -373,7 +374,7 @@ EODESCR
     machine => {
        description => "Specific the Qemu machine type.",
        type => 'string',
-       pattern => '(pc|pc(-i440fx)?-\d+\.\d+|q35|pc-q35-\d+\.\d+)',
+       pattern => '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
        maxLength => 40,
        optional => 1,
     },
@@ -390,6 +391,13 @@ EODESCR
        description => "Sets the protection flag of the VM. This will prevent the remove operation.",
        default => 0,
     },
+    bios => {
+       optional => 1,
+       type => 'string',
+       enum => [ qw(seabios ovmf) ],
+       description => "Select BIOS implementation.",
+       default => 'seabios',
+    },
 };
 
 # what about other qemu settings ?
@@ -481,7 +489,7 @@ my $drivename_hash;
 my $idedesc = {
     optional => 1,
     type => 'string', format => 'pve-qm-drive',
-    typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on]',
+    typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on] [,detect_zeroes=on|off] [,serial=serial][,model=model]',
     description => "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
 };
 PVE::JSONSchema::register_standard_option("pve-qm-ide", $idedesc);
@@ -489,7 +497,7 @@ PVE::JSONSchema::register_standard_option("pve-qm-ide", $idedesc);
 my $scsidesc = {
     optional => 1,
     type => 'string', format => 'pve-qm-drive',
-    typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on] [,iothread=on] [,queues=<nbqueues>]',
+    typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on] [,detect_zeroes=on|off] [,iothread=on] [,queues=<nbqueues>] [,serial=serial]',
     description => "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
 };
 PVE::JSONSchema::register_standard_option("pve-qm-scsi", $scsidesc);
@@ -497,7 +505,7 @@ PVE::JSONSchema::register_standard_option("pve-qm-scsi", $scsidesc);
 my $satadesc = {
     optional => 1,
     type => 'string', format => 'pve-qm-drive',
-    typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads]  [,discard=ignore|on]',
+    typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads]  [,discard=ignore|on] [,detect_zeroes=on|off] [,serial=serial]',
     description => "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
 };
 PVE::JSONSchema::register_standard_option("pve-qm-sata", $satadesc);
@@ -505,7 +513,7 @@ PVE::JSONSchema::register_standard_option("pve-qm-sata", $satadesc);
 my $virtiodesc = {
     optional => 1,
     type => 'string', format => 'pve-qm-drive',
-    typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads]  [,discard=ignore|on] [,iothread=on]',
+    typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads]  [,discard=ignore|on] [,detect_zeroes=on|off] [,iothread=on] [,serial=serial]',
     description => "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
 };
 PVE::JSONSchema::register_standard_option("pve-qm-virtio", $virtiodesc);
@@ -558,7 +566,7 @@ my $serialdesc = {
        description =>  <<EODESCR,
 Create a serial device inside the VM (n is 0 to 3), and pass through a host serial device (i.e. /dev/ttyS0), or create a unix socket on the host side (use 'qm terminal' to open a terminal connection).
 
-Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
+Note: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
 
 Experimental: user reported problems with this option.
 EODESCR
@@ -651,7 +659,7 @@ sub kvm_user_version {
 
     my $tmp = `kvm -help 2>/dev/null`;
 
-    if ($tmp =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)[,\s]/) {
+    if ($tmp =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
        $kvm_user_version = $2;
     }
 
@@ -874,7 +882,8 @@ my $format_size = sub {
 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
 #        [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
 #        [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
-#        [,aio=native|threads][,discard=ignore|on][,iothread=on]
+#        [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
+#        [,iothread=on][,serial=serial][,model=model]
 
 sub parse_drive {
     my ($key, $data) = @_;
@@ -895,7 +904,7 @@ sub parse_drive {
     foreach my $p (split (/,/, $data)) {
        next if $p =~ m/^\s*$/;
 
-       if ($p =~ m/^(file|volume|cyls|heads|secs|trans|media|snapshot|cache|format|rerror|werror|backup|aio|bps|mbps|mbps_max|bps_rd|mbps_rd|mbps_rd_max|bps_wr|mbps_wr|mbps_wr_max|iops|iops_max|iops_rd|iops_rd_max|iops_wr|iops_wr_max|size|discard|iothread|queues)=(.+)$/) {
+       if ($p =~ m/^(file|volume|cyls|heads|secs|trans|media|snapshot|cache|format|rerror|werror|backup|aio|bps|mbps|mbps_max|bps_rd|mbps_rd|mbps_rd_max|bps_wr|mbps_wr|mbps_wr_max|iops|iops_max|iops_rd|iops_rd_max|iops_wr|iops_wr_max|size|discard|detect_zeroes|iothread|queues|serial|model)=(.+)$/) {
            my ($k, $v) = ($1, $2);
 
            $k = 'file' if $k eq 'volume';
@@ -933,6 +942,7 @@ sub parse_drive {
     return undef if $res->{backup} && $res->{backup} !~ m/^(yes|no)$/;
     return undef if $res->{aio} && $res->{aio} !~ m/^(native|threads)$/;
     return undef if $res->{discard} && $res->{discard} !~ m/^(ignore|on)$/;
+    return undef if $res->{detect_zeroes} && $res->{detect_zeroes} !~ m/^(on|off)$/;
     return undef if $res->{iothread} && $res->{iothread} !~ m/^(on)$/;
     return undef if $res->{queues} && ($res->{queues} !~ m/^\d+$/ || $res->{queues} < 2);
 
@@ -957,7 +967,6 @@ sub parse_drive {
     return undef if $res->{iops_wr} && $res->{iops_wr} !~ m/^\d+$/;
     return undef if $res->{iops_wr_max} && $res->{iops_wr_max} !~ m/^\d+$/;
 
-
     if ($res->{size}) {
        return undef if !defined($res->{size} = &$parse_size($res->{size}));
     }
@@ -976,13 +985,13 @@ sub parse_drive {
     return $res;
 }
 
-my @qemu_drive_options = qw(heads secs cyls trans media format cache snapshot rerror werror aio discard iops iops_rd iops_wr iops_max iops_rd_max iops_wr_max);
+my @qemu_drive_options = qw(heads secs cyls trans media format cache snapshot rerror werror aio discard iops iops_rd iops_wr iops_max iops_rd_max iops_wr_max serial);
 
 sub print_drive {
     my ($vmid, $drive) = @_;
 
     my $opts = '';
-    foreach my $o (@qemu_drive_options, 'mbps', 'mbps_rd', 'mbps_wr', 'mbps_max', 'mbps_rd_max', 'mbps_wr_max', 'backup', 'iothread', 'queues') {
+    foreach my $o (@qemu_drive_options, qw(mbps mbps_rd mbps_wr mbps_max mbps_rd_max mbps_wr_max backup iothread queues detect_zeroes)) {
        $opts .= ",$o=$drive->{$o}" if $drive->{$o};
     }
 
@@ -990,6 +999,10 @@ sub print_drive {
        $opts .= ",size=" . &$format_size($drive->{size});
     }
 
+    if (my $model = $drive->{model}) {
+       $opts .= ",model=$model";
+    }
+
     return "$drive->{file}$opts";
 }
 
@@ -1122,6 +1135,9 @@ sub print_drivedevice_full {
        my $devicetype = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd";
 
        $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
+       if ($devicetype eq 'hd' && (my $model = $drive->{model})) {
+           $device .= ",model=$model";
+       }
     } elsif ($drive->{interface} eq 'sata'){
        my $controller = int($drive->{index} / $MAX_SATA_DISKS);
        my $unit = $drive->{index} % $MAX_SATA_DISKS;
@@ -1203,8 +1219,18 @@ sub print_drive_full {
        }
     }
 
-    my $detectzeroes = $drive->{discard} ? "unmap" : "on";
-    $opts .= ",detect-zeroes=$detectzeroes" if !drive_is_cdrom($drive);
+    if (!drive_is_cdrom($drive)) {
+       my $detectzeroes;
+       if ($drive->{detect_zeroes} && $drive->{detect_zeroes} eq 'off') {
+           $detectzeroes = 'off';
+       } elsif ($drive->{discard}) {
+           $detectzeroes = $drive->{discard} eq 'on' ? 'unmap' : 'on';
+       } else {
+           # This used to be our default with discard not being specified:
+           $detectzeroes = 'on';
+       }
+       $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
+    }
 
     my $pathinfo = $path ? "file=$path," : '';
 
@@ -1212,7 +1238,7 @@ sub print_drive_full {
 }
 
 sub print_netdevice_full {
-    my ($vmid, $conf, $net, $netid, $bridges) = @_;
+    my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
 
     my $bootorder = $conf->{boot} || $confdesc->{boot}->{default};
 
@@ -1229,11 +1255,28 @@ sub print_netdevice_full {
        $tmpstr .= ",vectors=$vectors,mq=on";
     }
     $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex} ;
+
+    if ($use_old_bios_files) {
+       my $romfile;
+       if ($device eq 'virtio-net-pci') {
+           $romfile = 'pxe-virtio.rom';
+       } elsif ($device eq 'e1000') {
+           $romfile = 'pxe-e1000.rom';
+       } elsif ($device eq 'ne2k') {
+           $romfile = 'pxe-ne2k_pci.rom';
+       } elsif ($device eq 'pcnet') {
+           $romfile = 'pxe-pcnet.rom';
+       } elsif ($device eq 'rtl8139') {
+           $romfile = 'pxe-rtl8139.rom';
+       }
+       $tmpstr .= ",romfile=$romfile" if $romfile;
+    }
+
     return $tmpstr;
 }
 
 sub print_netdev_full {
-    my ($vmid, $conf, $net, $netid) = @_;
+    my ($vmid, $conf, $net, $netid, $hotplug) = @_;
 
     my $i = '';
     if ($netid =~ m/^net(\d+)$/) {
@@ -1254,9 +1297,10 @@ sub print_netdev_full {
     my $vmname = $conf->{name} || "vm$vmid";
 
     my $netdev = "";
+    my $script = $hotplug ? "pve-bridge-hotplug" : "pve-bridge";
 
     if ($net->{bridge}) {
-        $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
+        $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
     } else {
         $netdev = "type=user,id=$netid,hostname=$vmname";
     }
@@ -2133,6 +2177,8 @@ sub check_local_resources {
 
     foreach my $k (keys %$conf) {
        next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
+       # sockets are safe: they will recreated be on the target side post-migrate
+       next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
        $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
     }
 
@@ -2619,6 +2665,8 @@ sub config_to_command {
     my $q35 = machine_type_is_q35($conf);
     my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
     my $machine_type = $forcemachine || $conf->{machine};
+    my $use_old_bios_files = undef;
+    ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
 
     my $cpuunits = defined($conf->{cpuunits}) ?
             $conf->{cpuunits} : $defaults->{cpuunits};
@@ -2627,6 +2675,9 @@ sub config_to_command {
     push @$cmd, '--scope';
     push @$cmd, '--slice', "qemu";
     push @$cmd, '--unit', $vmid;
+    # set KillMode=none, so that systemd don't kill those scopes
+    # at shutdown (pve-manager service should stop the VMs instead)
+    push @$cmd, '-p', "KillMode=none";
     push @$cmd, '-p', "CPUShares=$cpuunits";
     if ($conf->{cpulimit}) {
        my $cpulimit = int($conf->{cpulimit} * 100);
@@ -2654,6 +2705,15 @@ sub config_to_command {
        push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
     }
 
+    if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
+       my $ovmfvar = "OVMF_VARS-pure-efi.fd";
+       my $ovmfvar_src = "/usr/share/kvm/$ovmfvar";
+       my $ovmfvar_dst = "/tmp/$vmid-$ovmfvar";
+       PVE::Tools::file_copy($ovmfvar_src, $ovmfvar_dst, 256*1024);
+       push @$cmd, '-drive', "if=pflash,format=raw,readonly,file=/usr/share/kvm/OVMF-pure-efi.fd";
+       push @$cmd, '-drive', "if=pflash,format=raw,file=$ovmfvar_dst";
+    }
+
     if ($q35) {
        # the q35 chipset support native usb2, so we enable usb controller
        # by default for this machine type
@@ -2698,6 +2758,7 @@ sub config_to_command {
 
     push @$devices, '-device', print_tabletdevice_full($conf) if $tablet;
 
+    my $nohyperv;
     # host pci devices
     for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++)  {
        my $d = parse_hostpci($conf->{"hostpci$i"});
@@ -2716,6 +2777,7 @@ sub config_to_command {
        if ($xvga && $xvga ne '') {
            push @$cpuFlags, 'kvm=off';
            $vga = 'none';
+           $nohyperv = 1;
        }
        my $pcidevices = $d->{pciid};
        my $multifunction = 1 if @$pcidevices > 1;
@@ -2842,17 +2904,17 @@ sub config_to_command {
            push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
            push @$cmd, '-no-hpet';
            if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) {
-               push @$cpuFlags , 'hv_spinlocks=0x1fff' if !$nokvm;
-               push @$cpuFlags , 'hv_vapic' if !$nokvm;
-               push @$cpuFlags , 'hv_time' if !$nokvm;
+               push @$cpuFlags , 'hv_spinlocks=0x1fff' if !$nokvm && !$nohyperv;
+               push @$cpuFlags , 'hv_vapic' if !$nokvm && !$nohyperv;
+               push @$cpuFlags , 'hv_time' if !$nokvm && !$nohyperv;
 
            } else {
-               push @$cpuFlags , 'hv_spinlocks=0xffff' if !$nokvm;
+               push @$cpuFlags , 'hv_spinlocks=0xffff' if !$nokvm && !$nohyperv;
            }
        }
 
        if ($ost eq 'win7' || $ost eq 'win8') {
-           push @$cpuFlags , 'hv_relaxed' if !$nokvm;
+           push @$cpuFlags , 'hv_relaxed' if !$nokvm && !$nohyperv;
        }
     }
 
@@ -3145,7 +3207,7 @@ sub config_to_command {
          my $netdevfull = print_netdev_full($vmid,$conf,$d,"net$i");
          push @$devices, '-netdev', $netdevfull;
 
-         my $netdevicefull = print_netdevice_full($vmid,$conf,$d,"net$i",$bridges);
+         my $netdevicefull = print_netdevice_full($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
          push @$devices, '-device', $netdevicefull;
     }
 
@@ -3310,7 +3372,12 @@ sub vm_deviceplug {
     } elsif ($deviceid =~ m/^(net)(\d+)$/) {
 
         return undef if !qemu_netdevadd($vmid, $conf, $device, $deviceid);
-        my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid);
+
+        my $machine_type = PVE::QemuServer::qemu_machine_pxe($vmid, $conf); 
+        my $use_old_bios_files = undef;
+        ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
+
+        my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
         qemu_deviceadd($vmid, $netdevicefull);
         eval { qemu_deviceaddverify($vmid, $deviceid); };
        if (my $err = $@) {
@@ -3567,7 +3634,7 @@ sub qemu_set_link_status {
 sub qemu_netdevadd {
     my ($vmid, $conf, $device, $deviceid) = @_;
 
-    my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid);
+    my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
     my %options =  split(/[=,]/, $netdev);
 
     vm_mon_cmd($vmid, "netdev_add",  %options);
@@ -3854,9 +3921,10 @@ sub set_migration_caps {
 
     my $enabled_cap = {
        "auto-converge" => 1,
-       "xbzrle" => 0,
+       "xbzrle" => 1,
        "x-rdma-pin-all" => 0,
        "zero-blocks" => 0,
+       "compress" => 0
     };
 
     my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
@@ -4033,10 +4101,8 @@ sub try_deallocate_drive {
            $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
 
            # check if the disk is really unused
-           my $used_paths = PVE::QemuServer::get_used_paths($vmid, $storecfg, $conf, 1, $key);
-           my $path = PVE::Storage::path($storecfg, $volid);
            die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
-                  if $used_paths->{$path};
+               if is_volume_in_use($storecfg, $conf, $key, $volid);
            PVE::Storage::vdisk_free($storecfg, $volid);
            return 1;
        } else {
@@ -4261,11 +4327,13 @@ sub vmconfig_update_disk {
 
     die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
     # hotplug new disks
+    PVE::Storage::activate_volumes($storecfg, [$drive->{file}]);
     vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
 }
 
 sub vm_start {
-    my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused, $forcemachine, $spice_ticket) = @_;
+    my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
+       $forcemachine, $spice_ticket) = @_;
 
     lock_config($vmid, sub {
        my $conf = load_config($vmid, $migratedfrom);
@@ -4297,10 +4365,11 @@ sub vm_start {
                my $nodename = PVE::INotify::nodename();
                if ($datacenterconf->{migration_unsecure}) {
                        $localip = PVE::Cluster::remote_node_ip($nodename, 1);
+                       $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
                }
                my $pfamily = PVE::Tools::get_host_address_family($nodename);
                $migrate_port = PVE::Tools::next_migrate_port($pfamily);
-               $migrate_uri = "tcp:[${localip}]:${migrate_port}";
+               $migrate_uri = "tcp:${localip}:${migrate_port}";
                push @$cmd, '-incoming', $migrate_uri;
                push @$cmd, '-S';
            } else {
@@ -4606,15 +4675,21 @@ sub vm_suspend {
 }
 
 sub vm_resume {
-    my ($vmid, $skiplock) = @_;
+    my ($vmid, $skiplock, $nocheck) = @_;
 
     lock_config($vmid, sub {
 
-       my $conf = load_config($vmid);
+       if (!$nocheck) {
 
-       check_lock($conf) if !($skiplock || ($conf->{lock} && $conf->{lock} eq 'backup'));
+           my $conf = load_config($vmid);
 
-       vm_mon_cmd($vmid, "cont");
+           check_lock($conf) if !($skiplock || ($conf->{lock} && $conf->{lock} eq 'backup'));
+
+           vm_mon_cmd($vmid, "cont");
+
+       } else {
+           vm_mon_cmd_nocheck($vmid, "cont");
+       }
     });
 }
 
@@ -5049,10 +5124,10 @@ sub scan_volids {
     return $volid_hash;
 }
 
-sub get_used_paths {
-    my ($vmid, $storecfg, $conf, $scan_snapshots, $skip_drive) = @_;
+sub is_volume_in_use {
+    my ($storecfg, $conf, $skip_drive, $volid) = @_;
 
-    my $used_path = {};
+    my $path = PVE::Storage::path($storecfg, $volid);
 
     my $scan_config = sub {
        my ($cref, $snapname) = @_;
@@ -5063,31 +5138,31 @@ sub get_used_paths {
                next if $skip_drive && $key eq $skip_drive;
                my $drive = parse_drive($key, $value);
                next if !$drive || !$drive->{file} || drive_is_cdrom($drive);
+               return 1 if $volid eq $drive->{file};
                if ($drive->{file} =~ m!^/!) {
-                   $used_path->{$drive->{file}}++; # = 1;
+                   return 1 if $drive->{file} eq $path;
                } else {
                    my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file}, 1);
                    next if !$storeid;
                    my $scfg = PVE::Storage::storage_config($storecfg, $storeid, 1);
                    next if !$scfg;
-                   my $path = PVE::Storage::path($storecfg, $drive->{file}, $snapname);
-                   $used_path->{$path}++; # = 1;
+                   return 1 if $path eq PVE::Storage::path($storecfg, $drive->{file}, $snapname);
                }
            }
        }
+
+       return 0;
     };
 
-    &$scan_config($conf);
+    return 1 if &$scan_config($conf);
 
     undef $skip_drive;
 
-    if ($scan_snapshots) {
-       foreach my $snapname (keys %{$conf->{snapshots}}) {
-           &$scan_config($conf->{snapshots}->{$snapname}, $snapname);
-       }
+    foreach my $snapname (keys %{$conf->{snapshots}}) {
+       return 1 if &$scan_config($conf->{snapshots}->{$snapname}, $snapname);
     }
 
-    return $used_path;
+    return 0;
 }
 
 sub update_disksize {
@@ -5256,6 +5331,10 @@ sub restore_vma_archive {
        my $fh = IO::File->new($cfgfn, "r") ||
            "unable to read qemu-server.conf - $!\n";
 
+       my $fwcfgfn = "$tmpdir/qemu-server.fw";
+       PVE::Tools::file_copy($fwcfgfn, "/etc/pve/firewall/$vmid.fw")
+           if -f $fwcfgfn;
+
        while (defined(my $line = <$fh>)) {
            if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
                my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
@@ -6113,6 +6192,9 @@ sub qemu_img_convert {
     my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
 
     if ($src_storeid && $dst_storeid) {
+
+       PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
+
        my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
        my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
 
@@ -6317,6 +6399,43 @@ sub qemu_machine_feature_enabled {
 
 }
 
+sub qemu_machine_pxe {
+    my ($vmid, $conf, $machine) = @_;
+
+    $machine =  PVE::QemuServer::get_current_qemu_machine($vmid) if !$machine;
+
+    foreach my $opt (keys %$conf) {
+       next if $opt !~ m/^net(\d+)$/;
+       my $net = PVE::QemuServer::parse_net($conf->{$opt});
+       next if !$net;
+       my $romfile = PVE::QemuServer::vm_mon_cmd_nocheck($vmid, 'qom-get', path => $opt, property => 'romfile');
+       return $machine.".pxe" if $romfile =~ m/pxe/;
+       last;
+    }
+
+}
+
+sub qemu_use_old_bios_files {
+    my ($machine_type) = @_;
+
+    return if !$machine_type;
+
+    my $use_old_bios_files = undef;
+
+    if ($machine_type =~ m/^(\S+)\.pxe$/) {
+        $machine_type = $1;
+        $use_old_bios_files = 1;
+    } else {
+        # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
+        # load new efi bios files on migration. So this hack is required to allow
+        # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
+        # updrading from proxmox-ve-3.X to proxmox-ve 4.0
+        $use_old_bios_files = !qemu_machine_feature_enabled ($machine_type, undef, 2, 4);
+    }
+
+    return ($use_old_bios_files, $machine_type);
+}
+
 sub lspci {
 
     my $devices = {};
@@ -6428,6 +6547,7 @@ sub complete_storage {
     my $res = [];
     foreach my $sid (keys %$ids) {
        next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
+       next if !$ids->{$sid}->{content}->{images};
        push @$res, $sid;
     }