X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;ds=sidebyside;f=PVE%2FQemuServer.pm;h=79a65eeead5633046be34fdc3ce2f47c71e7e94a;hb=85909c04c49879f5fffa366fc3233eee2b157e97;hp=dc6bd6d9d37cb12b2bd85afd5d8bcdc428067613;hpb=456a6fec00a6d19154a0ea6ec377bb77ab3b84f7;p=qemu-server.git diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index dc6bd6d..79a65ee 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -56,12 +56,6 @@ cfs_register_file('/qemu-server/', \&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', @@ -124,6 +118,7 @@ my $cpu_vendor_list = { 'Haswell-noTSX' => 'GenuineIntel', Broadwell => 'GenuineIntel', 'Broadwell-noTSX' => 'GenuineIntel', + 'Skylake-Client' => 'GenuineIntel', # AMD CPUs athlon => 'AuthenticAMD', @@ -752,6 +747,18 @@ my %drivedesc_base = ( description => "Whether the drive should be included when making backups.", optional => 1, }, + replicate => { + type => 'boolean', + description => 'Whether the drive should considered for replication jobs.', + optional => 1, + default => 1, + }, + rerror => { + type => 'string', + enum => [qw(ignore report stop)], + description => 'Read error action.', + optional => 1, + }, werror => { type => 'string', enum => [qw(enospc ignore report stop)], @@ -785,15 +792,6 @@ my %drivedesc_base = ( } ); -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", @@ -820,6 +818,15 @@ my %queues_fmt = ( } ); +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 = { @@ -851,16 +858,21 @@ $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'io $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second'); # burst lengths -$add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1); -$add_throttle_desc->('bps_rd_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1); -$add_throttle_desc->('bps_wr_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1); -$add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1); -$add_throttle_desc->('iops_rd_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1); -$add_throttle_desc->('iops_wr_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1); +$add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1); +$add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1); +$add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1); +$add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1); +$add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1); +$add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1); + +# legacy support +$drivedesc_base{'bps_rd_length'} = { alias => 'bps_rd_max_length' }; +$drivedesc_base{'bps_wr_length'} = { alias => 'bps_wr_max_length' }; +$drivedesc_base{'iops_rd_length'} = { alias => 'iops_rd_max_length' }; +$drivedesc_base{'iops_wr_length'} = { alias => 'iops_wr_max_length' }; my $ide_fmt = { %drivedesc_base, - %rerror_fmt, %model_fmt, }; PVE::JSONSchema::register_format("pve-qm-ide", $ide_fmt); @@ -876,6 +888,7 @@ my $scsi_fmt = { %drivedesc_base, %iothread_fmt, %queues_fmt, + %scsiblock_fmt, }; my $scsidesc = { optional => 1, @@ -886,7 +899,6 @@ PVE::JSONSchema::register_standard_option("pve-qm-scsi", $scsidesc); my $sata_fmt = { %drivedesc_base, - %rerror_fmt, }; my $satadesc = { optional => 1, @@ -898,7 +910,6 @@ PVE::JSONSchema::register_standard_option("pve-qm-sata", $satadesc); my $virtio_fmt = { %drivedesc_base, %iothread_fmt, - %rerror_fmt, }; my $virtiodesc = { optional => 1, @@ -909,10 +920,10 @@ PVE::JSONSchema::register_standard_option("pve-qm-virtio", $virtiodesc); my $alldrive_fmt = { %drivedesc_base, - %rerror_fmt, %iothread_fmt, %model_fmt, %queues_fmt, + %scsiblock_fmt, }; my $efidisk_fmt = { @@ -1353,6 +1364,12 @@ sub parse_drive { # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases" for my $requirement ( + [mbps_max => 'mbps'], + [mbps_rd_max => 'mbps_rd'], + [mbps_wr_max => 'mbps_wr'], + [miops_max => 'miops'], + [miops_rd_max => 'miops_rd'], + [miops_wr_max => 'miops_wr'], [bps_max_length => 'mbps_max'], [bps_rd_max_length => 'mbps_rd_max'], [bps_wr_max_length => 'mbps_wr_max'], @@ -1493,7 +1510,7 @@ sub print_drivedevice_full { 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'; @@ -1577,10 +1594,32 @@ sub print_drive_full { } my $opts = ''; - 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); foreach my $o (@qemu_drive_options) { $opts .= ",$o=$drive->{$o}" if $drive->{$o}; } + foreach my $type (['', '-total'], [_rd => '-read'], [_wr => '-write']) { + my ($dir, $qmpname) = @$type; + if (my $v = $drive->{"mbps$dir"}) { + $opts .= ",throttling.bps$qmpname=".int($v*1024*1024); + } + if (my $v = $drive->{"mbps${dir}_max"}) { + $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024); + } + if (my $v = $drive->{"bps${dir}_max_length"}) { + $opts .= ",throttling.bps$qmpname-max-length=$v"; + } + if (my $v = $drive->{"iops${dir}"}) { + $opts .= ",throttling.iops$qmpname=$v"; + } + if (my $v = $drive->{"iops${dir}_max"}) { + $opts .= ",throttling.iops$qmpname=-max$v"; + } + if (my $v = $drive->{"iops${dir}_max_length"}) { + $opts .= ",throttling.iops$qmpname=-max-length$v"; + } + } + if (my $serial = $drive->{serial}) { $serial = URI::Escape::uri_unescape($serial); $opts .= ",serial=$serial"; @@ -1588,11 +1627,6 @@ sub print_drive_full { $opts .= ",format=$format" if $format && !$drive->{format}; - foreach my $o (qw(bps bps_rd bps_wr)) { - my $v = $drive->{"m$o"}; - $opts .= ",$o=" . int($v*1024*1024) if $v; - } - my $cache_direct = 0; if (my $cache = $drive->{cache}) { @@ -1714,12 +1748,10 @@ sub print_cpu_device { $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"; } @@ -2744,24 +2776,34 @@ sub foreach_volid { my $volhash = {}; my $test_volid = sub { - my ($volid, $is_cdrom) = @_; + my ($volid, $is_cdrom, $replicate, $snapname) = @_; return if !$volid; - $volhash->{$volid} = $is_cdrom || 0; + $volhash->{$volid}->{cdrom} //= 1; + $volhash->{$volid}->{cdrom} = 0 if !$is_cdrom; + + $volhash->{$volid}->{replicate} //= 0; + $volhash->{$volid}->{replicate} = 1 if $replicate; + + $volhash->{$volid}->{referenced_in_config} //= 0; + $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname); + + $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1 + if defined($snapname); }; foreach_drive($conf, sub { my ($ds, $drive) = @_; - &$test_volid($drive->{file}, drive_is_cdrom($drive)); + $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, undef); }); foreach my $snapname (keys %{$conf->{snapshots}}) { my $snap = $conf->{snapshots}->{$snapname}; - &$test_volid($snap->{vmstate}, 0); + $test_volid->($snap->{vmstate}, 0, 1, $snapname); foreach_drive($snap, sub { my ($ds, $drive) = @_; - &$test_volid($drive->{file}, drive_is_cdrom($drive)); + $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $snapname); }); } @@ -2883,7 +2925,7 @@ sub config_to_command { $vga = 'qxl' if $qxlnum; if (!$vga) { - $vga = $winversion >= 6 ? 'std' : 'cirrus'; + $vga = (!$winversion || $winversion >= 6) ? 'std' : 'cirrus'; } # enable absolute mouse coordinates (needed by vnc) @@ -2915,7 +2957,7 @@ sub config_to_command { } my $rombar = defined($d->{rombar}) && !$d->{rombar} ? ',rombar=0' : ''; - my $romfile = $d->{romfile} if $d->{romfile}; + my $romfile = $d->{romfile}; my $xvga = ''; if ($d->{'x-vga'}) { @@ -3154,9 +3196,12 @@ sub config_to_command { 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"; @@ -3980,7 +4025,7 @@ sub qemu_block_resize { 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; @@ -4660,7 +4705,7 @@ sub vm_start { print "migration listens on $migrate_uri\n" if $migrate_uri; - if ($statefile && $statefile ne 'tcp') { + if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') { eval { vm_mon_cmd_nocheck($vmid, "cont"); }; warn $@ if $@; } @@ -4811,7 +4856,7 @@ sub get_vm_volumes { my $vollist = []; foreach_volid($conf, sub { - my ($volid, $is_cdrom) = @_; + my ($volid, $attr) = @_; return if $volid =~ m|^/|; @@ -6014,7 +6059,7 @@ sub qemu_drive_mirror_monitor { print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n"; } - $readycounter++ if $running_mirror_jobs->{$job}->{ready} eq 'true'; + $readycounter++ if $running_mirror_jobs->{$job}->{ready}; } last if scalar(keys %$jobs) == 0; @@ -6140,20 +6185,11 @@ sub clone_disk { my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file}); $storeid = $storage if $storage; - my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid); - if (!$format) { - my $scfg = PVE::Storage::storage_config($storecfg, $storeid); - $format = qemu_img_format($scfg, $volname); - } - - # test if requested format is supported - else use default - my $supported = grep { $_ eq $format } @$validFormats; - $format = $defFormat if !$supported; - + my $dst_format = resolve_dst_disk_format($storecfg, $storeid, $volname, $format); my ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 3); print "create full clone of drive $drivename ($drive->{file})\n"; - $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $format, undef, ($size/1024)); + $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, undef, ($size/1024)); push @$newvollist, $newvolid; PVE::Storage::activate_volumes($storecfg, [$newvolid]); @@ -6278,6 +6314,12 @@ sub lspci { 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; } @@ -6299,7 +6341,7 @@ sub scsihw_infos { 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; @@ -6359,6 +6401,26 @@ sub windows_version { return $winversion; } +sub resolve_dst_disk_format { + my ($storecfg, $storeid, $src_volname, $format) = @_; + my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid); + + if (!$format) { + # if no target format is specified, use the source disk format as hint + if ($src_volname) { + my $scfg = PVE::Storage::storage_config($storecfg, $storeid); + $format = qemu_img_format($scfg, $src_volname); + } else { + return $defFormat; + } + } + + # test if requested format is supported - else use default + my $supported = grep { $_ eq $format } @$validFormats; + $format = $defFormat if !$supported; + return $format; +} + # bash completion helper sub complete_backup_archives {