]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
vmstatus: define return propertries
[qemu-server.git] / PVE / QemuServer.pm
index 628ca3359cf11140ebb1d1242dabfb1e8e1c9aba..ba09fc3ae74be1dfd004da6f3605ec52488f648d 100644 (file)
@@ -34,12 +34,14 @@ use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr);
 use PVE::QemuServer::Memory;
 use PVE::QemuServer::USB qw(parse_usb_device);
 use PVE::QemuServer::Cloudinit;
+use PVE::Systemd;
 use Time::HiRes qw(gettimeofday);
 use File::Copy qw(copy);
 use URI::Escape;
 
-my $OVMF_CODE = '/usr/share/kvm/OVMF_CODE-pure-efi.fd';
-my $OVMF_VARS = '/usr/share/kvm/OVMF_VARS-pure-efi.fd';
+my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
+my $OVMF_CODE = "$EDK2_FW_BASE/OVMF_CODE.fd";
+my $OVMF_VARS = "$EDK2_FW_BASE/OVMF_VARS.fd";
 
 my $qemu_snap_storage = {rbd => 1, sheepdog => 1};
 
@@ -263,7 +265,7 @@ my $confdesc = {
     shares => {
         optional => 1,
         type => 'integer',
-        description => "Amount of memory shares for auto-ballooning. The larger the number is, the more memory this VM gets. Number is relative to weights of all other running VMs. Using zero disables auto-ballooning",
+        description => "Amount of memory shares for auto-ballooning. The larger the number is, the more memory this VM gets. Number is relative to weights of all other running VMs. Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
        minimum => 0,
        maximum => 50000,
        default => 1000,
@@ -271,7 +273,7 @@ my $confdesc = {
     keyboard => {
        optional => 1,
        type => 'string',
-       description => "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.conf' configuration file.".
+       description => "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
                       "It should not be necessary to set it.",
        enum => PVE::Tools::kvmkeymaplist(),
        default => undef,
@@ -1688,6 +1690,12 @@ sub print_drivedevice_full {
 
     $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex};
 
+    if (my $serial = $drive->{serial}) {
+       $serial = URI::Escape::uri_unescape($serial);
+       $device .= ",serial=$serial";
+    }
+
+
     return $device;
 }
 
@@ -1760,11 +1768,6 @@ sub print_drive_full {
        }
     }
 
-    if (my $serial = $drive->{serial}) {
-       $serial = URI::Escape::uri_unescape($serial);
-       $opts .= ",serial=$serial";
-    }
-
     $opts .= ",format=$format" if $format && !$drive->{format};
 
     my $cache_direct = 0;
@@ -1971,7 +1974,6 @@ sub parse_net {
        my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
        $res->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
     }
-    $res->{macaddr} = PVE::Tools::random_ether_addr() if !defined($res->{macaddr});
     return $res;
 }
 
@@ -2573,9 +2575,6 @@ sub load_defaults {
        }
     }
 
-    my $conf = PVE::Cluster::cfs_read_file('datacenter.cfg');
-    $res->{keyboard} = $conf->{keyboard} if $conf->{keyboard};
-
     return $res;
 }
 
@@ -2765,6 +2764,53 @@ sub disksize {
     return $drive->{size};
 }
 
+our $vmstatus_return_properties = {
+    vmid => get_standard_option('pve-vmid'),
+    status => {
+       description => "Qemu process status.",
+       type => 'string',
+       enum => ['stopped', 'running'],
+    },
+    maxmem => {
+       description => "Maximum memory in bytes.",
+       type => 'integer',
+       optional => 1,
+       renderer => 'bytes',
+    },
+    maxdisk => {
+       description => "Root disk size in bytes.",
+       type => 'integer',
+       optional => 1,
+       renderer => 'bytes',
+    },
+    name => {
+       description => "VM name.",
+       type => 'string',
+       optional => 1,
+    },
+    qmpstatus => {
+       description => "Qemu QMP agent status.",
+       type => 'string',
+       optional => 1,
+    },
+    pid => {
+       description => "PID of running qemu process.",
+       type => 'integer',
+       optional => 1,
+    },
+    uptime => {
+       description => "Uptime.",
+       type => 'integer',
+       optional => 1,
+       renderer => 'duration',
+    },
+    cpus => {
+       description => "Maximum usable CPUs.",
+       type => 'number',
+       optional => 1,
+    },
+};
+
 my $last_proc_pid_stat;
 
 # get VM status information
@@ -2790,7 +2836,7 @@ sub vmstatus {
        my $cfspath = PVE::QemuConfig->cfs_config_path($vmid);
        my $conf = PVE::Cluster::cfs_read_file($cfspath) || {};
 
-       my $d = {};
+       my $d = { vmid => $vmid };
        $d->{pid} = $list->{$vmid}->{pid};
 
        # fixme: better status?
@@ -3093,6 +3139,10 @@ sub config_to_command {
 
     push @$cmd, '-id', $vmid;
 
+    my $vmname = $conf->{name} || "vm$vmid";
+
+    push @$cmd, '-name', $vmname;
+
     my $use_virtio = 0;
 
     my $qmpsocket = qmp_socket($vmid);
@@ -3249,9 +3299,6 @@ sub config_to_command {
        }
     }
 
-    my $vmname = $conf->{name} || "vm$vmid";
-
-    push @$cmd, '-name', $vmname;
 
     my $sockets = 1;
     $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
@@ -3388,9 +3435,7 @@ sub config_to_command {
     
     push @$cmd, '-S' if $conf->{freeze};
 
-    # set keyboard layout
-    my $kb = $conf->{keyboard} || $defaults->{keyboard};
-    push @$cmd, '-k', $kb if $kb;
+    push @$cmd, '-k', $conf->{keyboard} if defined($conf->{keyboard});
 
     # enable sound
     #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
@@ -3412,7 +3457,7 @@ sub config_to_command {
            if ($winversion){
                for(my $i = 1; $i < $qxlnum; $i++){
                    my $pciaddr = print_pci_addr("vga$i", $bridges);
-                   push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
+                   push @$devices, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
                }
            } else {
                # assume other OS works like Linux
@@ -3604,21 +3649,22 @@ sub vm_devices_list {
     my ($vmid) = @_;
 
     my $res = vm_mon_cmd($vmid, 'query-pci');
+    my $devices_to_check = [];
     my $devices = {};
     foreach my $pcibus (@$res) {
-       foreach my $device (@{$pcibus->{devices}}) {
-           next if !$device->{'qdev_id'};
-           if ($device->{'pci_bridge'}) {
-               $devices->{$device->{'qdev_id'}} = 1;
-               foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices}}) {
-                   next if !$bridge_device->{'qdev_id'};
-                   $devices->{$bridge_device->{'qdev_id'}} = 1;
-                   $devices->{$device->{'qdev_id'}}++;
-               }
-           } else {
-               $devices->{$device->{'qdev_id'}} = 1;
-           }
+       push @$devices_to_check, @{$pcibus->{devices}},
+    }
+
+    while (@$devices_to_check) {
+       my $to_check = [];
+       for my $d (@$devices_to_check) {
+           $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
+           next if !$d->{'pci_bridge'};
+
+           $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices}});
+           push @$to_check, @{$d->{'pci_bridge'}->{devices}};
        }
+       $devices_to_check = $to_check;
     }
 
     my $resblock = vm_mon_cmd($vmid, 'query-block');
@@ -4168,81 +4214,6 @@ sub __read_avail {
     return $res;
 }
 
-# old code, only used to shutdown old VM after update
-sub vm_monitor_command {
-    my ($vmid, $cmdstr, $nocheck) = @_;
-
-    my $res;
-
-    eval {
-       die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
-
-       my $sname = "${var_run_tmpdir}/$vmid.mon";
-
-       my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
-           die "unable to connect to VM $vmid socket - $!\n";
-
-       my $timeout = 3;
-
-       # hack: migrate sometime blocks the monitor (when migrate_downtime
-       # is set)
-       if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
-           $timeout = 60*60; # 1 hour
-       }
-
-       # read banner;
-       my $data = __read_avail($sock, $timeout);
-
-       if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
-           die "got unexpected qemu monitor banner\n";
-       }
-
-       my $sel = new IO::Select;
-       $sel->add($sock);
-
-       if (!scalar(my @ready = $sel->can_write($timeout))) {
-           die "monitor write error - timeout";
-       }
-
-       my $fullcmd = "$cmdstr\r";
-
-       # syslog('info', "VM $vmid monitor command: $cmdstr");
-
-       my $b;
-       if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
-           die "monitor write error - $!";
-       }
-
-       return if ($cmdstr eq 'q') || ($cmdstr eq 'quit');
-
-       $timeout = 20;
-
-       if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
-           $timeout = 60*60; # 1 hour
-       } elsif ($cmdstr =~ m/^(eject|change)/) {
-           $timeout = 60; # note: cdrom mount command is slow
-       }
-       if ($res = __read_avail($sock, $timeout)) {
-
-           my @lines = split("\r?\n", $res);
-
-           shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
-
-           $res = join("\n", @lines);
-           $res .= "\n";
-       }
-    };
-
-    my $err = $@;
-
-    if ($err) {
-       syslog("err", "VM $vmid monitor command failed - $err");
-       die $err;
-    }
-
-    return $res;
-}
-
 sub qemu_block_resize {
     my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
 
@@ -4273,6 +4244,16 @@ sub qemu_volume_snapshot_delete {
 
     my $running = check_running($vmid);
 
+    if($running) {
+
+       $running = undef;
+       my $conf = PVE::QemuConfig->load_config($vmid);
+       foreach_drive($conf, sub {
+           my ($ds, $drive) = @_;
+           $running = 1 if $drive->{file} eq $volid;
+       });
+    }
+
     if ($running && do_snapshots_with_qemu($storecfg, $volid)){
        vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
     } else {
@@ -4374,7 +4355,10 @@ sub vmconfig_hotplug_pending {
                qemu_cpu_hotplug($vmid, $conf, undef);
             } elsif ($opt eq 'balloon') {
                # enable balloon device is not hotpluggable
-               die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
+               die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
+               # here we reset the ballooning value to memory
+               my $balloon = $conf->{memory} || $defaults->{memory};
+               vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
            } elsif ($fast_plug_option->{$opt}) {
                # do nothing
            } elsif ($opt =~ m/^net(\d+)$/) {
@@ -4894,10 +4878,11 @@ sub vm_start {
 
        PVE::Storage::activate_volumes($storecfg, $vollist);
 
-       if (!check_running($vmid, 1) && -d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
-           my $cmd = [];
-           push @$cmd, '/bin/systemctl', 'stop', "$vmid.scope";
-           eval  { run_command($cmd); };
+       if (!check_running($vmid, 1)) {
+           eval {
+               run_command(['/bin/systemctl', 'stop', "$vmid.scope"],
+                   outfunc => sub {}, errfunc => sub {});
+           };
        }
 
        my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
@@ -4917,6 +4902,13 @@ sub vm_start {
        }
        $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
 
+       my $run_qemu = sub {
+           PVE::Tools::run_fork sub {
+               PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
+               run_command($cmd, %run_params);
+           };
+       };
+
        if ($conf->{hugepages}) {
 
            my $code = sub {
@@ -4926,11 +4918,7 @@ sub vm_start {
                PVE::QemuServer::Memory::hugepages_mount();
                PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
 
-               eval  {
-                   PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
-                   run_command($cmd, %run_params);
-               };
-
+               eval { $run_qemu->() };
                if (my $err = $@) {
                    PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
                    die $err;
@@ -4941,10 +4929,7 @@ sub vm_start {
            eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
 
        } else {
-           eval  {
-               PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
-               run_command($cmd, %run_params);
-           };
+           eval { $run_qemu->() };
        }
 
        if (my $err = $@) {
@@ -4995,10 +4980,8 @@ sub vm_start {
            }
 
        } else {
-           if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
-               vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
-                   if $conf->{balloon};
-           }
+           vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
+               if !$statefile && $conf->{balloon};
 
            foreach my $opt (keys %$conf) {
                next if $opt !~  m/^net\d+$/;
@@ -5047,10 +5030,6 @@ sub vm_qmp_command {
            my $qmpclient = PVE::QMPClient->new();
 
            $res = $qmpclient->cmd($vmid, $cmd, $timeout);
-       } elsif (-e "${var_run_tmpdir}/$vmid.mon") {
-           die "can't execute complex command on old monitor - stop/start your vm to fix the problem\n"
-               if scalar(%{$cmd->{arguments}});
-           vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
        } else {
            die "unable to open monitor socket\n";
        }
@@ -5249,6 +5228,13 @@ sub vm_resume {
 
     PVE::QemuConfig->lock_config($vmid, sub {
 
+       my $res = vm_mon_cmd($vmid, 'query-status');
+       my $resume_cmd = 'cont';
+
+       if ($res->{status} && $res->{status} eq 'suspended') {
+           $resume_cmd = 'system_wakeup';
+       }
+
        if (!$nocheck) {
 
            my $conf = PVE::QemuConfig->load_config($vmid);
@@ -5256,10 +5242,10 @@ sub vm_resume {
            PVE::QemuConfig->check_lock($conf)
                if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
 
-           vm_mon_cmd($vmid, "cont");
+           vm_mon_cmd($vmid, $resume_cmd);
 
        } else {
-           vm_mon_cmd_nocheck($vmid, "cont");
+           vm_mon_cmd_nocheck($vmid, $resume_cmd);
        }
     });
 }
@@ -5609,6 +5595,7 @@ sub update_disksize {
     my ($vmid, $conf, $volid_hash) = @_;
 
     my $changes;
+    my $prefix = "VM $vmid:";
 
     # used and unused disks
     my $referenced = {};
@@ -5640,6 +5627,7 @@ sub update_disksize {
            if ($new ne $conf->{$opt}) {
                $changes = 1;
                $conf->{$opt} = $new;
+               print "$prefix update disk '$opt' information.\n";
            }
        }
     }
@@ -5650,6 +5638,7 @@ sub update_disksize {
        my $volid = $conf->{$opt};
        my $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
        if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
+           print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
            $changes = 1;
            delete $conf->{$opt};
        }
@@ -5665,7 +5654,8 @@ sub update_disksize {
        next if !$path; # just to be sure
        next if $referencedpath->{$path};
        $changes = 1;
-       PVE::QemuConfig->add_unused_volume($conf, $volid);
+       my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
+       print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
        $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
     }
 
@@ -5673,10 +5663,17 @@ sub update_disksize {
 }
 
 sub rescan {
-    my ($vmid, $nolock) = @_;
+    my ($vmid, $nolock, $dryrun) = @_;
 
     my $cfg = PVE::Storage::config();
 
+    # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
+    # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
+    foreach my $stor (keys %{$cfg->{ids}}) {
+       delete($cfg->{ids}->{$stor}) if ! $cfg->{ids}->{$stor}->{content}->{images};
+    }
+
+    print "rescan volumes...\n";
     my $volid_hash = scan_volids($cfg, $vmid);
 
     my $updatefn =  sub {
@@ -5694,7 +5691,7 @@ sub rescan {
 
        my $changes = update_disksize($vmid, $conf, $vm_volids);
 
-       PVE::QemuConfig->write_config($vmid, $conf) if $changes;
+       PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
     };
 
     if (defined($vmid)) {
@@ -5718,21 +5715,49 @@ sub rescan {
 sub restore_vma_archive {
     my ($archive, $vmid, $user, $opts, $comp) = @_;
 
-    my $input = $archive eq '-' ? "<&STDIN" : undef;
     my $readfrom = $archive;
 
-    my $uncomp = '';
-    if ($comp) {
+    my $cfg = PVE::Storage::config();
+    my $commands = [];
+    my $bwlimit = $opts->{bwlimit};
+
+    my $dbg_cmdstring = '';
+    my $add_pipe = sub {
+       my ($cmd) = @_;
+       push @$commands, $cmd;
+       $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
+       $dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
        $readfrom = '-';
-       my $qarchive = PVE::Tools::shellquote($archive);
+    };
+
+    my $input = undef;
+    if ($archive eq '-') {
+       $input = '<&STDIN';
+    } else {
+       # If we use a backup from a PVE defined storage we also consider that
+       # storage's rate limit:
+       my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
+       if (defined($volid)) {
+           my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
+           my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
+           if ($readlimit) {
+               print STDERR "applying read rate limit: $readlimit\n";
+               my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
+               $add_pipe->($cstream);
+           }
+       }
+    }
+
+    if ($comp) {
+       my $cmd;
        if ($comp eq 'gzip') {
-           $uncomp = "zcat $qarchive|";
+           $cmd = ['zcat', $readfrom];
        } elsif ($comp eq 'lzop') {
-           $uncomp = "lzop -d -c $qarchive|";
+           $cmd = ['lzop', '-d', '-c', $readfrom];
        } else {
            die "unknown compression method '$comp'\n";
        }
-
+       $add_pipe->($cmd);
     }
 
     my $tmpdir = "/var/tmp/vzdumptmp$$";
@@ -5752,7 +5777,7 @@ sub restore_vma_archive {
        open($fifofh, '>', $mapfifo) || die $!;
     };
 
-    my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
+    $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
 
     my $oldtimeout;
     my $timeout = 5;
@@ -5768,6 +5793,8 @@ sub restore_vma_archive {
     my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
     my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
 
+    my %storage_limits;
+
     my $print_devmap = sub {
        my $virtdev_hash = {};
 
@@ -5806,17 +5833,24 @@ sub restore_vma_archive {
                    $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
                }
 
+               $storage_limits{$storeid} = $bwlimit;
+
                $virtdev_hash->{$virtdev} = $devinfo->{$devname};
            }
        }
 
+       foreach my $key (keys %storage_limits) {
+           my $limit = PVE::Storage::get_bandwidth_limit('restore', [$key], $bwlimit);
+           next if !$limit;
+           print STDERR "rate limit for storage $key: $limit KiB/s\n";
+           $storage_limits{$key} = $limit * 1024;
+       }
+
        foreach my $devname (keys %$devinfo) {
            die "found no device mapping information for device '$devname'\n"
                if !$devinfo->{$devname}->{virtdev};
        }
 
-       my $cfg = PVE::Storage::config();
-
        # create empty/temp config
        if ($oldconf) {
            PVE::Tools::file_set_contents($conffile, "memory: 128\n");
@@ -5859,14 +5893,20 @@ sub restore_vma_archive {
        foreach my $virtdev (sort keys %$virtdev_hash) {
            my $d = $virtdev_hash->{$virtdev};
            my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
-           my $scfg = PVE::Storage::storage_config($cfg, $d->{storeid});
+           my $storeid = $d->{storeid};
+           my $scfg = PVE::Storage::storage_config($cfg, $storeid);
+
+           my $map_opts = '';
+           if (my $limit = $storage_limits{$storeid}) {
+               $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
+           }
 
            # test if requested format is supported
-           my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($cfg, $d->{storeid});
+           my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($cfg, $storeid);
            my $supported = grep { $_ eq $d->{format} } @$validFormats;
            $d->{format} = $defFormat if !$supported;
 
-           my $volid = PVE::Storage::vdisk_alloc($cfg, $d->{storeid}, $vmid,
+           my $volid = PVE::Storage::vdisk_alloc($cfg, $storeid, $vmid,
                                                  $d->{format}, undef, $alloc_size);
            print STDERR "new volume ID is '$volid'\n";
            $d->{volid} = $volid;
@@ -5879,7 +5919,7 @@ sub restore_vma_archive {
                $write_zeros = 0;
            }
 
-           print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
+           print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
 
            print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
            $map->{$virtdev} = $volid;
@@ -5932,8 +5972,8 @@ sub restore_vma_archive {
            }
        };
 
-       print "restore vma archive: $cmd\n";
-       run_command($cmd, input => $input, outfunc => $parser, afterfork => $openfifo);
+       print "restore vma archive: $dbg_cmdstring\n";
+       run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
     };
     my $err = $@;
 
@@ -5945,7 +5985,6 @@ sub restore_vma_archive {
        push @$vollist, $volid if $volid;
     }
 
-    my $cfg = PVE::Storage::config();
     PVE::Storage::deactivate_volumes($cfg, $vollist);
 
     unlink $mapfifo;
@@ -6132,11 +6171,11 @@ sub do_snapshots_with_qemu {
 }
 
 sub qga_check_running {
-    my ($vmid) = @_;
+    my ($vmid, $nowarn) = @_;
 
     eval { vm_mon_cmd($vmid, "guest-ping", timeout => 3); };
     if ($@) {
-       warn "Qemu Guest Agent is not running - $@";
+       warn "Qemu Guest Agent is not running - $@" if !$nowarn;
        return 0;
     }
     return 1;
@@ -6186,6 +6225,8 @@ sub qemu_img_convert {
        my $cmd = [];
        push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
        push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
+       push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
+       push @$cmd, '-T', 'none' if $src_scfg->{type} eq 'zfspool';
        push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
        if ($is_zero_initialized) {
            push @$cmd, "zeroinit:$dst_path";
@@ -6501,13 +6542,8 @@ sub qemu_machine_pxe {
 
     $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;
+    if ($conf->{machine} && $conf->{machine} =~ m/\.pxe$/) {
+       $machine .= '.pxe';
     }
 
     return $machine;
@@ -6762,4 +6798,10 @@ sub complete_storage {
     return $res;
 }
 
+sub nbd_stop {
+    my ($vmid) = @_;
+
+    vm_mon_cmd($vmid, 'nbd-server-stop');
+}
+
 1;