]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
use pve-edk2-firmware for supporting OVMF
[qemu-server.git] / PVE / QemuServer.pm
index 628ca3359cf11140ebb1d1242dabfb1e8e1c9aba..061effa9ea7c71f2aa96aa81a4f9c2b29c24384b 100644 (file)
@@ -38,8 +38,9 @@ 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};
 
@@ -1971,7 +1972,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 +2573,6 @@ sub load_defaults {
        }
     }
 
-    my $conf = PVE::Cluster::cfs_read_file('datacenter.cfg');
-    $res->{keyboard} = $conf->{keyboard} if $conf->{keyboard};
-
     return $res;
 }
 
@@ -3093,6 +3090,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 +3250,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 +3386,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};
@@ -4168,81 +4164,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) = @_;
 
@@ -4894,10 +4815,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}
@@ -5047,10 +4969,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";
        }
@@ -5718,21 +5636,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 +5698,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 +5714,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 +5754,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 +5814,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 +5840,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 +5893,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 +5906,6 @@ sub restore_vma_archive {
        push @$vollist, $volid if $volid;
     }
 
-    my $cfg = PVE::Storage::config();
     PVE::Storage::deactivate_volumes($cfg, $vollist);
 
     unlink $mapfifo;