coreduo => 'GenuineIntel',
core2duo => 'GenuineIntel',
Conroe => 'GenuineIntel',
- Penryn => 'GenuineIntel',
+ Penryn => 'GenuineIntel',
Nehalem => 'GenuineIntel',
+ 'Nehalem-IBRS' => 'GenuineIntel',
Westmere => 'GenuineIntel',
+ 'Westmere-IBRS' => 'GenuineIntel',
SandyBridge => 'GenuineIntel',
+ 'SandyBridge-IBRS' => 'GenuineIntel',
IvyBridge => 'GenuineIntel',
+ 'IvyBridge-IBRS' => 'GenuineIntel',
Haswell => 'GenuineIntel',
+ 'Haswell-IBRS' => 'GenuineIntel',
'Haswell-noTSX' => 'GenuineIntel',
+ 'Haswell-noTSX-IBRS' => 'GenuineIntel',
Broadwell => 'GenuineIntel',
+ 'Broadwell-IBRS' => 'GenuineIntel',
'Broadwell-noTSX' => 'GenuineIntel',
+ 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
'Skylake-Client' => 'GenuineIntel',
-
+ 'Skylake-Client-IBRS' => 'GenuineIntel',
+ 'Skylake-Server' => 'GenuineIntel',
+ 'Skylake-Server-IBRS' => 'GenuineIntel',
+
# AMD CPUs
athlon => 'AuthenticAMD',
phenom => 'AuthenticAMD',
Opteron_G3 => 'AuthenticAMD',
Opteron_G4 => 'AuthenticAMD',
Opteron_G5 => 'AuthenticAMD',
+ EPYC => 'AuthenticAMD',
+ 'EPYC-IBPB' => 'AuthenticAMD',
# generic types, use vendor from host node
host => 'default',
kvm64 => 'default',
qemu32 => 'default',
qemu64 => 'default',
+ max => 'default',
};
+my $cpu_flag = qr/[+-](pcid|spec-ctrl)/;
+
my $cpu_fmt = {
cputype => {
description => "Emulated CPU type.",
optional => 1,
default => 0
},
+ flags => {
+ description => "List of additional CPU flags separated by ';'."
+ . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
+ . " Currently supported flags: 'pcid', 'spec-ctrl'.",
+ format_description => '+FLAG[;-FLAG...]',
+ type => 'string',
+ pattern => qr/$cpu_flag(;$cpu_flag)*/,
+ optional => 1,
+ },
};
my $watchdog_fmt = {
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.conf' configuration file.".
+ "It should not be necessary to set it.",
enum => PVE::Tools::kvmkeymaplist(),
- default => 'en-us',
+ default => undef,
},
name => {
optional => 1,
w2k8;; Microsoft Windows 2008
wvista;; Microsoft Windows Vista
win7;; Microsoft Windows 7
-win8;; Microsoft Windows 8/2012
+win8;; Microsoft Windows 8/2012/2012r2
+win10;; Microsoft Windows 10/2016
l24;; Linux 2.4 Kernel
l26;; Linux 2.6/3.X Kernel
solaris;; Solaris/OpenSolaris/OpenIndiania kernel
},
snapshot => {
type => 'boolean',
- description => "Whether the drive should be included when making snapshots.",
+ description => "Controls qemu's snapshot mode feature."
+ . " If activated, changes made to the disk are temporary and will"
+ . " be discarded when the VM is shutdown.",
optional => 1,
},
cache => {
maxLength => 20*3, # *3 since it's %xx url enoded
description => "The drive's reported serial number, url-encoded, up to 20 bytes long.",
optional => 1,
+ },
+ shared => {
+ type => 'boolean',
+ description => 'Mark this locally-managed volume as available on all nodes',
+ verbose_description => "Mark this locally-managed volume as available on all nodes.\n\nWARNING: This option does not share the volume automatically, it assumes it is shared already!",
+ optional => 1,
+ default => 0,
}
);
}
my $opts = '';
- my @qemu_drive_options = qw(heads secs cyls trans media format cache snapshot rerror werror aio discard);
+ my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
foreach my $o (@qemu_drive_options) {
- $opts .= ",$o=$drive->{$o}" if $drive->{$o};
+ $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
}
+
+ # snapshot only accepts on|off
+ if (defined($drive->{snapshot})) {
+ my $v = $drive->{snapshot} ? 'on' : 'off';
+ $opts .= ",snapshot=$v";
+ }
+
foreach my $type (['', '-total'], [_rd => '-read'], [_wr => '-write']) {
my ($dir, $qmpname) = @$type;
if (my $v = $drive->{"mbps$dir"}) {
my $storecfg = PVE::Storage::config();
my $list = vzlist();
+ my $defaults = load_defaults();
+
my ($uptime) = PVE::ProcFSTools::read_proc_uptime(1);
my $cpucount = $cpuinfo->{cpus} || 1;
$d->{maxdisk} = 0;
}
- $d->{cpus} = ($conf->{sockets} || 1) * ($conf->{cores} || 1);
+ $d->{cpus} = ($conf->{sockets} || $defaults->{sockets})
+ * ($conf->{cores} || $defaults->{cores});
$d->{cpus} = $cpucount if $d->{cpus} > $cpucount;
$d->{cpus} = $conf->{vcpus} if $conf->{vcpus};
$d->{name} = $conf->{name} || "VM $vmid";
- $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024) : 0;
+ $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024)
+ : $defaults->{memory}*(1024*1024);
if ($conf->{balloon}) {
$d->{balloon_min} = $conf->{balloon}*(1024*1024);
- $d->{shares} = defined($conf->{shares}) ? $conf->{shares} : 1000;
+ $d->{shares} = defined($conf->{shares}) ? $conf->{shares}
+ : $defaults->{shares};
}
$d->{uptime} = 0;
$d->{template} = PVE::QemuConfig->is_template($conf);
+ $d->{serial} = 1 if conf_has_serial($conf);
+
$res->{$vmid} = $d;
}
my $volhash = {};
my $test_volid = sub {
- my ($volid, $is_cdrom, $replicate, $snapname) = @_;
+ my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
return if !$volid;
$volhash->{$volid}->{replicate} //= 0;
$volhash->{$volid}->{replicate} = 1 if $replicate;
+ $volhash->{$volid}->{shared} //= 0;
+ $volhash->{$volid}->{shared} = 1 if $shared;
+
$volhash->{$volid}->{referenced_in_config} //= 0;
$volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
foreach_drive($conf, sub {
my ($ds, $drive) = @_;
- $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, undef);
+ $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $drive->{shared}, undef);
});
foreach my $snapname (keys %{$conf->{snapshots}}) {
$test_volid->($snap->{vmstate}, 0, 1, $snapname);
foreach_drive($snap, sub {
my ($ds, $drive) = @_;
- $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $snapname);
+ $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $drive->{shared}, $snapname);
});
}
}
}
+sub conf_has_serial {
+ my ($conf) = @_;
+
+ for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
+ if ($conf->{"serial$i"}) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
sub vga_conf_has_spice {
my ($vga) = @_;
die "uefi base image not found\n" if ! -f $OVMF_CODE;
my $path;
+ my $format;
if (my $efidisk = $conf->{efidisk0}) {
my $d = PVE::JSONSchema::parse_property_string($efidisk_fmt, $efidisk);
my ($storeid, $volname) = PVE::Storage::parse_volume_id($d->{file}, 1);
+ $format = $d->{format};
if ($storeid) {
$path = PVE::Storage::path($storecfg, $d->{file});
+ if (!defined($format)) {
+ my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
+ $format = qemu_img_format($scfg, $volname);
+ }
} else {
$path = $d->{file};
+ die "efidisk format must be specified\n"
+ if !defined($format);
}
} else {
warn "no efidisk configured! Using temporary efivars disk.\n";
$path = "/tmp/$vmid-ovmf.fd";
PVE::Tools::file_copy($OVMF_VARS, $path, -s $OVMF_VARS);
+ $format = 'raw';
}
push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
- push @$cmd, '-drive', "if=pflash,unit=1,id=drive-efidisk0,file=$path";
+ push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
}
or die "Cannot parse cpu description: $cputype\n";
$cpu = $cpuconf->{cputype};
$kvm_off = 1 if $cpuconf->{hidden};
+
+ if (defined(my $flags = $cpuconf->{flags})) {
+ push @$cpuFlags, split(";", $flags);
+ }
}
push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
} elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
- #qemu 2.3 segfault on drive_del with virtioscsi + iothread
- my $device = parse_drive($deviceid, $conf->{$deviceid});
- die "virtioscsi with iothread is not hot-unplugglable currently" if $device->{iothread};
-
qemu_devicedel($vmid, $deviceid);
qemu_drivedel($vmid, $deviceid);
qemu_deletescsihw($conf, $vmid, $deviceid);
my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
: $defaults->{cpuunits};
- my %run_params = (timeout => $statefile ? undef : 30, umask => 0077);
+ my $start_timeout = $conf->{hugepages} ? 300 : 30;
+ my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
my %properties = (
Slice => 'qemu.slice',
} else {
print $outfd $line;
}
+ } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
+ my ($uuid, $uuid_str);
+ UUID::generate($uuid);
+ UUID::unparse($uuid, $uuid_str);
+ my $smbios1 = parse_smbios1($2);
+ $smbios1->{uuid} = $uuid_str;
+ print $outfd $1.print_smbios1($smbios1)."\n";
} else {
print $outfd $line;
}
my $changes;
- my $used = {};
+ # used and unused disks
+ my $referenced = {};
# Note: it is allowed to define multiple storages with same path (alias), so
# we need to check both 'volid' and real 'path' (two different volid can point
# to the same path).
- my $usedpath = {};
+ my $referencedpath = {};
# update size info
foreach my $opt (keys %$conf) {
my $volid = $drive->{file};
next if !$volid;
- $used->{$volid} = 1;
+ $referenced->{$volid} = 1;
if ($volid_hash->{$volid} &&
(my $path = $volid_hash->{$volid}->{path})) {
- $usedpath->{$path} = 1;
+ $referencedpath->{$path} = 1;
}
next if drive_is_cdrom($drive);
next if $opt !~ m/^unused\d+$/;
my $volid = $conf->{$opt};
my $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
- if ($used->{$volid} || ($path && $usedpath->{$path})) {
+ if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
$changes = 1;
delete $conf->{$opt};
}
+
+ $referenced->{$volid} = 1;
+ $referencedpath->{$path} = 1 if $path;
}
foreach my $volid (sort keys %$volid_hash) {
next if $volid =~ m/vm-$vmid-state-/;
- next if $used->{$volid};
+ next if $referenced->{$volid};
my $path = $volid_hash->{$volid}->{path};
next if !$path; # just to be sure
- next if $usedpath->{$path};
+ next if $referencedpath->{$path};
$changes = 1;
PVE::QemuConfig->add_unused_volume($conf, $volid);
- $usedpath->{$path} = 1; # avoid to add more than once (aliases)
+ $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
}
return $changes;
eval { vm_mon_cmd($vmid, "guest-ping", timeout => 3); };
if ($@) {
- warn "Qemu Guest Agent are not running - $@";
+ warn "Qemu Guest Agent is not running - $@";
return 0;
}
return 1;
my $format;
$jobs->{"drive-$drive"} = {};
- if ($dst_volid =~ /^nbd:(localhost|[\d\.]+|\[[\d\.:a-fA-F]+\]):(\d+):exportname=(\S+)/) {
- my $server = $1;
- my $port = $2;
- my $exportname = $3;
-
+ if ($dst_volid =~ /^nbd:/) {
+ $qemu_target = $dst_volid;
$format = "nbd";
- my $unixsocket = "/run/qemu-server/$vmid.mirror-drive-$drive";
- $qemu_target = "nbd+unix:///$exportname?socket=$unixsocket";
- my $cmd = ['socat', '-T30', "UNIX-LISTEN:$unixsocket,fork", "TCP:$server:$2,connect-timeout=5"];
-
- my $pid = fork();
- if (!defined($pid)) {
- die "forking socat tunnel failed\n";
- } elsif ($pid == 0) {
- exec(@$cmd);
- warn "exec failed: $!\n";
- POSIX::_exit(-1);
- }
- $jobs->{"drive-$drive"}->{pid} = $pid;
-
- my $timeout = 0;
- while (!-S $unixsocket) {
- die "nbd connection helper timed out\n"
- if $timeout++ > 5;
- sleep 1;
- }
} else {
my $storecfg = PVE::Storage::config();
my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
last if $skipcomplete; #do the complete later
if ($vmiddst && $vmiddst != $vmid) {
- if ($qga) {
+ my $agent_running = $qga && qga_check_running($vmid);
+ if ($agent_running) {
print "freeze filesystem\n";
eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-freeze"); };
} else {
# if we clone a disk for a new target vm, we don't switch the disk
PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs);
- if ($qga) {
+ if ($agent_running) {
print "unfreeze filesystem\n";
eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-thaw"); };
} else {
}else {
print "$job: Completed successfully.\n";
$jobs->{$job}->{complete} = 1;
- eval { qemu_blockjobs_finish_tunnel($vmid, $job, $jobs->{$job}->{pid}) } ;
}
}
}
if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
print "$job: Done.\n";
- eval { qemu_blockjobs_finish_tunnel($vmid, $job, $jobs->{$job}->{pid}) } ;
delete $jobs->{$job};
}
}
}
}
-sub qemu_blockjobs_finish_tunnel {
- my ($vmid, $job, $cpid) = @_;
-
- return if !$cpid;
-
- for (my $i = 1; $i < 20; $i++) {
- my $waitpid = waitpid($cpid, WNOHANG);
- last if (defined($waitpid) && ($waitpid == $cpid));
-
- if ($i == 10) {
- kill(15, $cpid);
- } elsif ($i >= 15) {
- kill(9, $cpid);
- }
- sleep (1);
- }
- unlink "/run/qemu-server/$vmid.mirror-$job";
-}
-
sub clone_disk {
my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
$newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;