]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
reenable steal time
[qemu-server.git] / PVE / QemuServer.pm
index fedb58e486fe7387a4faf1dedbcb76de3a660ae7..81f05843efdbbf681bb4be474d445bb5bc92269f 100644 (file)
@@ -373,7 +373,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,
     },
@@ -481,7 +481,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] [,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 +489,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] [,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 +497,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] [,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 +505,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] [,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);
@@ -534,7 +534,7 @@ PVE::JSONSchema::register_standard_option("pve-qm-usb", $usbdesc);
 my $hostpcidesc = {
         optional => 1,
         type => 'string', format => 'pve-qm-hostpci',
-        typetext => "[host=]HOSTPCIDEVICE [,driver=kvm|vfio] [,rombar=on|off] [,pcie=0|1] [,x-vga=on|off]",
+        typetext => "[host=]HOSTPCIDEVICE [,rombar=on|off] [,pcie=0|1] [,x-vga=on|off]",
         description => <<EODESCR,
 Map host pci devices. HOSTPCIDEVICE syntax is:
 
@@ -558,7 +558,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 +651,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;
     }
 
@@ -875,6 +875,7 @@ my $format_size = sub {
 #        [,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]
+#        [,serial=serial][,model=model]
 
 sub parse_drive {
     my ($key, $data) = @_;
@@ -895,7 +896,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|iothread|queues|serial|model)=(.+)$/) {
            my ($k, $v) = ($1, $2);
 
            $k = 'file' if $k eq 'volume';
@@ -957,7 +958,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,7 +976,7 @@ 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) = @_;
@@ -990,6 +990,10 @@ sub print_drive {
        $opts .= ",size=" . &$format_size($drive->{size});
     }
 
+    if (my $model = $drive->{model}) {
+       $opts .= ",model=$model";
+    }
+
     return "$drive->{file}$opts";
 }
 
@@ -1122,6 +1126,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;
@@ -1212,7 +1219,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 +1236,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 +1278,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";
     }
@@ -1319,8 +1344,6 @@ sub parse_hostpci {
                my $pcidevices = lspci($2);
                $res->{pciid} = $pcidevices->{$2};
            }
-       } elsif ($kv =~ m/^driver=(kvm|vfio)$/) {
-           $res->{driver} = $1;
        } elsif ($kv =~ m/^rombar=(on|off)$/) {
            $res->{rombar} = $1;
        } elsif ($kv =~ m/^x-vga=(on|off)$/) {
@@ -2135,6 +2158,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+$/;
     }
 
@@ -2621,6 +2646,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};
@@ -2629,6 +2656,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);
@@ -2714,13 +2744,11 @@ sub config_to_command {
        }
 
        my $rombar = $d->{rombar} && $d->{rombar} eq 'off' ? ",rombar=0" : "";
-       my $driver = $d->{driver} && $d->{driver} eq 'vfio' ? "vfio-pci" : "pci-assign";
        my $xvga = $d->{'x-vga'} && $d->{'x-vga'} eq 'on' ? ",x-vga=on" : "";
        if ($xvga && $xvga ne '') {
            push @$cpuFlags, 'kvm=off';
            $vga = 'none';
        }
-       $driver = "vfio-pci" if $xvga ne '';
        my $pcidevices = $d->{pciid};
        my $multifunction = 1 if @$pcidevices > 1;
 
@@ -2731,7 +2759,7 @@ sub config_to_command {
            $id .= ".$j" if $multifunction;
            my $addr = $pciaddr;
            $addr .= ".$j" if $multifunction;
-           my $devicestr = "$driver,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
+           my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
 
            if($j == 0){
                $devicestr .= "$rombar$xvga";
@@ -2799,7 +2827,7 @@ sub config_to_command {
 
     my $allowed_vcpus = $cpuinfo->{cpus};
 
-    die "MAX $maxcpus vcpus allowed per VM on this node\n"
+    die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
        if ($allowed_vcpus < $maxcpus);
 
     push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
@@ -3149,7 +3177,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;
     }
 
@@ -3314,7 +3342,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 = $@) {
@@ -3571,7 +3604,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);
@@ -3858,9 +3891,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");
@@ -4269,7 +4303,8 @@ sub vmconfig_update_disk {
 }
 
 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);
@@ -4301,10 +4336,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 {
@@ -4325,13 +4361,7 @@ sub vm_start {
                my $info = pci_device_info("0000:$pciid");
                die "IOMMU not present\n" if !check_iommu_support();
                die "no pci device info for device '$pciid'\n" if !$info;
-
-               if ($d->{driver} && $d->{driver} eq "vfio") {
-                   die "can't unbind/bind pci group to vfio '$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
-               } else {
-                   die "can't unbind/bind to stub pci device '$pciid'\n" if !pci_dev_bind_to_stub($info);
-               }
-
+               die "can't unbind/bind pci group to vfio '$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
                die "can't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
          }
         }
@@ -4616,15 +4646,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);
+
+           check_lock($conf) if !($skiplock || ($conf->{lock} && $conf->{lock} eq 'backup'));
+
+           vm_mon_cmd($vmid, "cont");
 
-       vm_mon_cmd($vmid, "cont");
+       } else {
+           vm_mon_cmd_nocheck($vmid, "cont");
+       }
     });
 }
 
@@ -4714,30 +4750,6 @@ sub pci_dev_reset {
     return file_write($fn, "1");
 }
 
-sub pci_dev_bind_to_stub {
-    my ($dev) = @_;
-
-    my $name = $dev->{name};
-
-    my $testdir = "$pcisysfs/drivers/pci-stub/$name";
-    return 1 if -d $testdir;
-
-    my $data = "$dev->{vendor} $dev->{product}";
-    return undef if !file_write("$pcisysfs/drivers/pci-stub/new_id", $data);
-
-    my $fn = "$pcisysfs/devices/$name/driver/unbind";
-    if (!file_write($fn, $name)) {
-       return undef if -f $fn;
-    }
-
-    $fn = "$pcisysfs/drivers/pci-stub/bind";
-    if (! -d $testdir) {
-       return undef if !file_write($fn, $name);
-    }
-
-    return -d $testdir;
-}
-
 sub pci_dev_bind_to_vfio {
     my ($dev) = @_;
 
@@ -5363,6 +5375,8 @@ sub restore_vma_archive {
            $d->{volid} = $volid;
            my $path = PVE::Storage::path($cfg, $volid);
 
+           PVE::Storage::activate_volumes($cfg,[$volid]);
+
            my $write_zeros = 1;
            # fixme: what other storages types initialize volumes with zero?
            if ($scfg->{type} eq 'dir' || $scfg->{type} eq 'nfs' || $scfg->{type} eq 'glusterfs' ||
@@ -5428,13 +5442,21 @@ sub restore_vma_archive {
 
     alarm($oldtimeout) if $oldtimeout;
 
+    my $vollist = [];
+    foreach my $devname (keys %$devinfo) {
+       my $volid = $devinfo->{$devname}->{volid};
+       push @$vollist, $volid if $volid;
+    }
+
+    my $cfg = cfs_read_file('storage.cfg');
+    PVE::Storage::deactivate_volumes($cfg, $vollist);
+
     unlink $mapfifo;
 
     if ($err) {
        rmtree $tmpdir;
        unlink $tmpfn;
 
-       my $cfg = cfs_read_file('storage.cfg');
        foreach my $devname (keys %$devinfo) {
            my $volid = $devinfo->{$devname}->{volid};
            next if !$volid;
@@ -5881,7 +5903,8 @@ sub do_snapshots_with_qemu {
 
     my $storage_name = PVE::Storage::parse_volume_id($volid);
 
-    if ($qemu_snap_storage->{$storecfg->{ids}->{$storage_name}->{type}} ){
+    if ($qemu_snap_storage->{$storecfg->{ids}->{$storage_name}->{type}} 
+       && !$storecfg->{ids}->{$storage_name}->{krbd}){
        return 1;
     }
 
@@ -6136,6 +6159,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);
 
@@ -6340,6 +6366,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 = {};
@@ -6451,6 +6514,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;
     }