\&parse_vm_config,
\&write_vm_config);
-PVE::JSONSchema::register_standard_option('skiplock', {
- description => "Ignore locks - only root is allowed to use this option.",
- type => 'boolean',
- optional => 1,
-});
-
PVE::JSONSchema::register_standard_option('pve-qm-stateuri', {
description => "Some command save/restore state from this location.",
type => 'string',
'Haswell-noTSX' => 'GenuineIntel',
Broadwell => 'GenuineIntel',
'Broadwell-noTSX' => 'GenuineIntel',
+ 'Skylake-Client' => 'GenuineIntel',
# AMD CPUs
athlon => 'AuthenticAMD',
description => "Whether the drive should be included when making backups.",
optional => 1,
},
+ rerror => {
+ type => 'string',
+ enum => [qw(ignore report stop)],
+ description => 'Read error action.',
+ optional => 1,
+ },
werror => {
type => 'string',
enum => [qw(enospc ignore report stop)],
}
);
-my %rerror_fmt = (
- rerror => {
- type => 'string',
- enum => [qw(ignore report stop)],
- description => 'Read error action.',
- optional => 1,
- },
-);
-
my %iothread_fmt = ( iothread => {
type => 'boolean',
description => "Whether to use iothreads for this drive",
}
);
+my %scsiblock_fmt = (
+ scsiblock => {
+ type => 'boolean',
+ description => "whether to use scsi-block for full passthrough of host block device\n\nWARNING: can lead to I/O errors in combination with low memory or high memory fragmentation on host",
+ optional => 1,
+ default => 0,
+ },
+);
+
my $add_throttle_desc = sub {
my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
my $d = {
my $ide_fmt = {
%drivedesc_base,
- %rerror_fmt,
%model_fmt,
};
PVE::JSONSchema::register_format("pve-qm-ide", $ide_fmt);
%drivedesc_base,
%iothread_fmt,
%queues_fmt,
+ %scsiblock_fmt,
};
my $scsidesc = {
optional => 1,
my $sata_fmt = {
%drivedesc_base,
- %rerror_fmt,
};
my $satadesc = {
optional => 1,
my $virtio_fmt = {
%drivedesc_base,
%iothread_fmt,
- %rerror_fmt,
};
my $virtiodesc = {
optional => 1,
my $alldrive_fmt = {
%drivedesc_base,
- %rerror_fmt,
%iothread_fmt,
%model_fmt,
%queues_fmt,
+ %scsiblock_fmt,
};
my $efidisk_fmt = {
optional => 1,
default => 1,
},
+ romfile => {
+ type => 'string',
+ pattern => '[^,;]+',
+ format_description => 'string',
+ description => "Custom pci device rom filename (must be located in /usr/share/kvm/).",
+ optional => 1,
+ },
pcie => {
type => 'boolean',
description => "Choose the PCI-express bus (needs the 'q35' machine model).",
if ($drive->{file} =~ m|^/|) {
$path = $drive->{file};
if (my $info = path_is_scsi($path)) {
- if ($info->{type} == 0) {
+ if ($info->{type} == 0 && $drive->{scsiblock}) {
$devicetype = 'block';
} elsif ($info->{type} == 1) { # tape
$devicetype = 'generic';
$cpu = $cpuconf->{cputype};
}
- my $sockets = 1;
- $sockets = $conf->{sockets} if $conf->{sockets};
my $cores = $conf->{cores} || 1;
my $current_core = ($id - 1) % $cores;
- my $current_socket = int(($id - $current_core)/$cores);
+ my $current_socket = int(($id - 1 - $current_core)/$cores);
return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
}
$vga = 'qxl' if $qxlnum;
if (!$vga) {
- $vga = $winversion >= 6 ? 'std' : 'cirrus';
+ if (qemu_machine_feature_enabled($machine_type, $kvmver, 2, 9)) {
+ $vga = (!$winversion || $winversion >= 6) ? 'std' : 'cirrus';
+ } else {
+ $vga = ($winversion >= 6) ? 'std' : 'cirrus';
+ }
}
# enable absolute mouse coordinates (needed by vnc)
}
my $rombar = defined($d->{rombar}) && !$d->{rombar} ? ',rombar=0' : '';
+ my $romfile = $d->{romfile};
+
my $xvga = '';
if ($d->{'x-vga'}) {
$xvga = ',x-vga=on';
if($j == 0){
$devicestr .= "$rombar$xvga";
$devicestr .= ",multifunction=on" if $multifunction;
+ $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
}
push @$devices, '-device', $devicestr;
my $nodename = PVE::INotify::nodename();
my $pfamily = PVE::Tools::get_host_address_family($nodename);
- $spice_port = PVE::Tools::next_spice_port($pfamily);
+ my @nodeaddrs = PVE::Tools::getaddrinfo_all('localhost', family => $pfamily);
+ die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
+ my $localhost = PVE::Network::addr_to_ip($nodeaddrs[0]->{addr});
+ $spice_port = PVE::Tools::next_spice_port($pfamily, $localhost);
- push @$devices, '-spice', "tls-port=${spice_port},addr=localhost,tls-ciphers=DES-CBC3-SHA,seamless-migration=on";
+ push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
my $running = check_running($vmid);
- return if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
+ $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
return if !$running;
$format = "nbd";
my $unixsocket = "/run/qemu-server/$vmid.mirror-drive-$drive";
$qemu_target = "nbd+unix:///$exportname?socket=$unixsocket";
- my $cmd = ['socat', "UNIX-LISTEN:$unixsocket,fork", "TCP:$server:$2,connect-timeout=1"];
+ 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";
+ die "forking socat tunnel failed\n";
} elsif ($pid == 0) {
exec(@$cmd);
- exit(-1);
- } else {
- $jobs->{"drive-$drive"}->{pid} = $pid;
+ warn "exec failed: $!\n";
+ POSIX::_exit(-1);
+ }
+ $jobs->{"drive-$drive"}->{pid} = $pid;
- my $timeout = 0;
- while (1) {
- last if -S $unixsocket;
- die if $timeout > 5;
- $timeout++;
- sleep 1;
- }
+ my $timeout = 0;
+ while (!-S $unixsocket) {
+ die "nbd connection helper timed out\n"
+ if $timeout++ > 5;
+ sleep 1;
}
} else {
my $storecfg = PVE::Storage::config();
next;
}
- die "$job: mirroring has been cancelled. Maybe do you have bad sectors?" if !defined($running_mirror_jobs->{$job});
+ die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
my $busy = $running_mirror_jobs->{$job}->{busy};
my $ready = $running_mirror_jobs->{$job}->{ready};
foreach my $job (keys %$jobs) {
# try to switch the disk if source and destination are on the same guest
- print "$job : Try to complete block job\n";
+ print "$job: Completing block job...\n";
eval { vm_mon_cmd($vmid, "block-job-complete", device => $job) };
if ($@ =~ m/cannot be completed/) {
- print "$job : block job cannot be complete. Try again \n";
+ print "$job: Block job cannot be completed, try again.\n";
$err_complete++;
}else {
- print "$job : complete ok : flushing pending writes\n";
+ print "$job: Completed successfully.\n";
$jobs->{$job}->{complete} = 1;
eval { qemu_blockjobs_finish_tunnel($vmid, $job, $jobs->{$job}->{pid}) } ;
}
my ($vmid, $jobs) = @_;
foreach my $job (keys %$jobs) {
- print "$job: try to cancel block job\n";
+ print "$job: Cancelling block job\n";
eval { vm_mon_cmd($vmid, "block-job-cancel", device => $job); };
$jobs->{$job}->{cancel} = 1;
}
foreach my $job (keys %$jobs) {
- if(defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
- print "$job : finished\n";
+ 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};
}
push @{$devices->{$id}}, $res;
});
+ # Entries should be sorted by functions.
+ foreach my $id (keys %$devices) {
+ my $dev = $devices->{$id};
+ $devices->{$id} = [ sort { $a->{function} <=> $b->{function} } @$dev ];
+ }
+
return $devices;
}
my $maxdev = 0;
- if ($conf->{scsihw} && ($conf->{scsihw} =~ m/^lsi/)) {
+ if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) {
$maxdev = 7;
} elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
$maxdev = 1;