]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
don't use cirrus by default for sane OS'
[qemu-server.git] / PVE / QemuServer.pm
index dc6bd6d9d37cb12b2bd85afd5d8bcdc428067613..79a65eeead5633046be34fdc3ce2f47c71e7e94a 100644 (file)
@@ -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 {