]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
allow virtio-scsi + iothread controller hot-unplug
[qemu-server.git] / PVE / QemuServer.pm
index 3eed127ab2647b7928dda5753d777499b0d305ca..fb365849925849143247974fa8e8e2c2d4bc25ed 100644 (file)
@@ -127,6 +127,8 @@ my $cpu_vendor_list = {
     'Broadwell-noTSX-IBRS' => 'GenuineIntel',
     'Skylake-Client' => 'GenuineIntel',
     'Skylake-Client-IBRS' => 'GenuineIntel',
+    'Skylake-Server' => 'GenuineIntel',
+    'Skylake-Server-IBRS' => 'GenuineIntel',
 
     # AMD CPUs
     athlon => 'AuthenticAMD',
@@ -136,6 +138,8 @@ my $cpu_vendor_list = {
     Opteron_G3  => 'AuthenticAMD',
     Opteron_G4  => 'AuthenticAMD',
     Opteron_G5  => 'AuthenticAMD',
+    EPYC => 'AuthenticAMD',
+    'EPYC-IBPB' => 'AuthenticAMD',
 
     # generic types, use vendor from host node
     host => 'default',
@@ -143,8 +147,11 @@ my $cpu_vendor_list = {
     kvm64 => 'default',
     qemu32 => 'default',
     qemu64 => 'default',
+    max => 'default',
 };
 
+my $cpu_flag = qr/[+-](pcid|spec-ctrl)/;
+
 my $cpu_fmt = {
     cputype => {
        description => "Emulated CPU type.",
@@ -160,14 +167,13 @@ my $cpu_fmt = {
        default => 0
     },
     flags => {
-       description => "Override CPU flags. Currently only the 'pcid' flag is supported."
-                    . " Use '+pcid' or '-pcid' to enable or disable."
-                    . " This takes precedence over flags coming from the cpu type or changed implicitly via the OS type.",
-       format_description => 'flaglist',
+       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 => '[+-]pcid',
+       pattern => qr/$cpu_flag(;$cpu_flag)*/,
        optional => 1,
-       default => '',
     },
 };
 
@@ -749,7 +755,9 @@ my %drivedesc_base = (
     },
     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 => {
@@ -813,6 +821,13 @@ my %drivedesc_base = (
        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,
     }
 );
 
@@ -1618,10 +1633,17 @@ sub print_drive_full {
    }
 
     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"}) {
@@ -2664,6 +2686,8 @@ sub vmstatus {
 
         $d->{template} = PVE::QemuConfig->is_template($conf);
 
+       $d->{serial} = 1 if conf_has_serial($conf);
+
        $res->{$vmid} = $d;
     }
 
@@ -2822,7 +2846,7 @@ sub foreach_volid {
     my $volhash = {};
 
     my $test_volid = sub {
-       my ($volid, $is_cdrom, $replicate, $snapname) = @_;
+       my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
 
        return if !$volid;
 
@@ -2832,6 +2856,9 @@ sub foreach_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);
 
@@ -2841,7 +2868,7 @@ sub foreach_volid {
 
     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}}) {
@@ -2849,7 +2876,7 @@ sub foreach_volid {
        $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);
         });
     }
 
@@ -2858,6 +2885,18 @@ sub foreach_volid {
     }
 }
 
+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) = @_;
 
@@ -3164,7 +3203,7 @@ sub config_to_command {
        $kvm_off = 1 if $cpuconf->{hidden};
 
        if (defined(my $flags = $cpuconf->{flags})) {
-           push @$cpuFlags, $flags;
+           push @$cpuFlags, split(";", $flags);
        }
     }
 
@@ -3605,10 +3644,6 @@ sub vm_deviceunplug {
 
     } 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);
@@ -5329,6 +5364,13 @@ sub restore_update_config_line {
        } 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;
     }
@@ -6017,32 +6059,9 @@ sub qemu_drive_mirror {
     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);
@@ -6154,7 +6173,6 @@ sub qemu_drive_mirror_monitor {
                        }else {
                            print "$job: Completed successfully.\n";
                            $jobs->{$job}->{complete} = 1;
-                           eval { qemu_blockjobs_finish_tunnel($vmid, $job, $jobs->{$job}->{pid}) } ;
                        }
                    }
                }
@@ -6192,7 +6210,6 @@ sub qemu_blockjobs_cancel {
 
            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};
            }
        }
@@ -6203,25 +6220,6 @@ sub qemu_blockjobs_cancel {
     }
 }
 
-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) = @_;