machine => {
description => "Specific the Qemu machine type.",
type => 'string',
- pattern => '(pc|pc(-i440fx)?-\d+\.\d+|q35|pc-q35-\d+\.\d+)',
+ pattern => '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
maxLength => 40,
optional => 1,
},
my $idedesc = {
optional => 1,
type => 'string', format => 'pve-qm-drive',
- typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on]',
+ typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on] [,serial=serial][,model=model]',
description => "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
};
PVE::JSONSchema::register_standard_option("pve-qm-ide", $idedesc);
my $scsidesc = {
optional => 1,
type => 'string', format => 'pve-qm-drive',
- typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on] [,iothread=on] [,queues=<nbqueues>]',
+ typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on] [,iothread=on] [,queues=<nbqueues>] [,serial=serial]',
description => "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
};
PVE::JSONSchema::register_standard_option("pve-qm-scsi", $scsidesc);
my $satadesc = {
optional => 1,
type => 'string', format => 'pve-qm-drive',
- typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on]',
+ typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on] [,serial=serial]',
description => "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
};
PVE::JSONSchema::register_standard_option("pve-qm-sata", $satadesc);
my $virtiodesc = {
optional => 1,
type => 'string', format => 'pve-qm-drive',
- typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on] [,iothread=on]',
+ typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe|directsync] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads] [,discard=ignore|on] [,iothread=on] [,serial=serial]',
description => "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
};
PVE::JSONSchema::register_standard_option("pve-qm-virtio", $virtiodesc);
my $hostpcidesc = {
optional => 1,
type => 'string', format => 'pve-qm-hostpci',
- typetext => "[host=]HOSTPCIDEVICE [,driver=kvm|vfio] [,rombar=on|off] [,pcie=0|1] [,x-vga=on|off]",
+ typetext => "[host=]HOSTPCIDEVICE [,rombar=on|off] [,pcie=0|1] [,x-vga=on|off]",
description => <<EODESCR,
Map host pci devices. HOSTPCIDEVICE syntax is:
description => <<EODESCR,
Create a serial device inside the VM (n is 0 to 3), and pass through a host serial device (i.e. /dev/ttyS0), or create a unix socket on the host side (use 'qm terminal' to open a terminal connection).
-Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
+Note: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
Experimental: user reported problems with this option.
EODESCR
my $tmp = `kvm -help 2>/dev/null`;
- if ($tmp =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)[,\s]/) {
+ if ($tmp =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
$kvm_user_version = $2;
}
# [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
# [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
# [,aio=native|threads][,discard=ignore|on][,iothread=on]
+# [,serial=serial][,model=model]
sub parse_drive {
my ($key, $data) = @_;
foreach my $p (split (/,/, $data)) {
next if $p =~ m/^\s*$/;
- if ($p =~ m/^(file|volume|cyls|heads|secs|trans|media|snapshot|cache|format|rerror|werror|backup|aio|bps|mbps|mbps_max|bps_rd|mbps_rd|mbps_rd_max|bps_wr|mbps_wr|mbps_wr_max|iops|iops_max|iops_rd|iops_rd_max|iops_wr|iops_wr_max|size|discard|iothread|queues)=(.+)$/) {
+ if ($p =~ m/^(file|volume|cyls|heads|secs|trans|media|snapshot|cache|format|rerror|werror|backup|aio|bps|mbps|mbps_max|bps_rd|mbps_rd|mbps_rd_max|bps_wr|mbps_wr|mbps_wr_max|iops|iops_max|iops_rd|iops_rd_max|iops_wr|iops_wr_max|size|discard|iothread|queues|serial|model)=(.+)$/) {
my ($k, $v) = ($1, $2);
$k = 'file' if $k eq 'volume';
return undef if $res->{iops_wr} && $res->{iops_wr} !~ m/^\d+$/;
return undef if $res->{iops_wr_max} && $res->{iops_wr_max} !~ m/^\d+$/;
-
if ($res->{size}) {
return undef if !defined($res->{size} = &$parse_size($res->{size}));
}
return $res;
}
-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 iops iops_rd iops_wr iops_max iops_rd_max iops_wr_max serial);
sub print_drive {
my ($vmid, $drive) = @_;
$opts .= ",size=" . &$format_size($drive->{size});
}
+ if (my $model = $drive->{model}) {
+ $opts .= ",model=$model";
+ }
+
return "$drive->{file}$opts";
}
my $devicetype = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd";
$device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
+ if ($devicetype eq 'hd' && (my $model = $drive->{model})) {
+ $device .= ",model=$model";
+ }
} elsif ($drive->{interface} eq 'sata'){
my $controller = int($drive->{index} / $MAX_SATA_DISKS);
my $unit = $drive->{index} % $MAX_SATA_DISKS;
}
sub print_netdevice_full {
- my ($vmid, $conf, $net, $netid, $bridges) = @_;
+ my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
my $bootorder = $conf->{boot} || $confdesc->{boot}->{default};
$tmpstr .= ",vectors=$vectors,mq=on";
}
$tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex} ;
+
+ if ($use_old_bios_files) {
+ my $romfile;
+ if ($device eq 'virtio-net-pci') {
+ $romfile = 'pxe-virtio.rom';
+ } elsif ($device eq 'e1000') {
+ $romfile = 'pxe-e1000.rom';
+ } elsif ($device eq 'ne2k') {
+ $romfile = 'pxe-ne2k_pci.rom';
+ } elsif ($device eq 'pcnet') {
+ $romfile = 'pxe-pcnet.rom';
+ } elsif ($device eq 'rtl8139') {
+ $romfile = 'pxe-rtl8139.rom';
+ }
+ $tmpstr .= ",romfile=$romfile" if $romfile;
+ }
+
return $tmpstr;
}
sub print_netdev_full {
- my ($vmid, $conf, $net, $netid) = @_;
+ my ($vmid, $conf, $net, $netid, $hotplug) = @_;
my $i = '';
if ($netid =~ m/^net(\d+)$/) {
my $vmname = $conf->{name} || "vm$vmid";
my $netdev = "";
+ my $script = $hotplug ? "pve-bridge-hotplug" : "pve-bridge";
if ($net->{bridge}) {
- $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
+ $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
} else {
$netdev = "type=user,id=$netid,hostname=$vmname";
}
my $pcidevices = lspci($2);
$res->{pciid} = $pcidevices->{$2};
}
- } elsif ($kv =~ m/^driver=(kvm|vfio)$/) {
- $res->{driver} = $1;
} elsif ($kv =~ m/^rombar=(on|off)$/) {
$res->{rombar} = $1;
} elsif ($kv =~ m/^x-vga=(on|off)$/) {
foreach my $k (keys %$conf) {
next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
+ # sockets are safe: they will recreated be on the target side post-migrate
+ next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
$loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
}
my $q35 = machine_type_is_q35($conf);
my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
my $machine_type = $forcemachine || $conf->{machine};
+ my $use_old_bios_files = undef;
+ ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
my $cpuunits = defined($conf->{cpuunits}) ?
$conf->{cpuunits} : $defaults->{cpuunits};
push @$cmd, '--scope';
push @$cmd, '--slice', "qemu";
push @$cmd, '--unit', $vmid;
+ # set KillMode=none, so that systemd don't kill those scopes
+ # at shutdown (pve-manager service should stop the VMs instead)
+ push @$cmd, '-p', "KillMode=none";
push @$cmd, '-p', "CPUShares=$cpuunits";
if ($conf->{cpulimit}) {
my $cpulimit = int($conf->{cpulimit} * 100);
}
my $rombar = $d->{rombar} && $d->{rombar} eq 'off' ? ",rombar=0" : "";
- my $driver = $d->{driver} && $d->{driver} eq 'vfio' ? "vfio-pci" : "pci-assign";
my $xvga = $d->{'x-vga'} && $d->{'x-vga'} eq 'on' ? ",x-vga=on" : "";
if ($xvga && $xvga ne '') {
push @$cpuFlags, 'kvm=off';
$vga = 'none';
}
- $driver = "vfio-pci" if $xvga ne '';
my $pcidevices = $d->{pciid};
my $multifunction = 1 if @$pcidevices > 1;
$id .= ".$j" if $multifunction;
my $addr = $pciaddr;
$addr .= ".$j" if $multifunction;
- my $devicestr = "$driver,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
+ my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
if($j == 0){
$devicestr .= "$rombar$xvga";
my $allowed_vcpus = $cpuinfo->{cpus};
- die "MAX $maxcpus vcpus allowed per VM on this node\n"
+ die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
if ($allowed_vcpus < $maxcpus);
push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
my $netdevfull = print_netdev_full($vmid,$conf,$d,"net$i");
push @$devices, '-netdev', $netdevfull;
- my $netdevicefull = print_netdevice_full($vmid,$conf,$d,"net$i",$bridges);
+ my $netdevicefull = print_netdevice_full($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
push @$devices, '-device', $netdevicefull;
}
} elsif ($deviceid =~ m/^(net)(\d+)$/) {
return undef if !qemu_netdevadd($vmid, $conf, $device, $deviceid);
- my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid);
+
+ my $machine_type = PVE::QemuServer::qemu_machine_pxe($vmid, $conf);
+ my $use_old_bios_files = undef;
+ ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
+
+ my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
qemu_deviceadd($vmid, $netdevicefull);
eval { qemu_deviceaddverify($vmid, $deviceid); };
if (my $err = $@) {
sub qemu_netdevadd {
my ($vmid, $conf, $device, $deviceid) = @_;
- my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid);
+ my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
my %options = split(/[=,]/, $netdev);
vm_mon_cmd($vmid, "netdev_add", %options);
my $enabled_cap = {
"auto-converge" => 1,
- "xbzrle" => 0,
+ "xbzrle" => 1,
"x-rdma-pin-all" => 0,
"zero-blocks" => 0,
+ "compress" => 0
};
my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
}
sub vm_start {
- my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused, $forcemachine, $spice_ticket) = @_;
+ my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
+ $forcemachine, $spice_ticket) = @_;
lock_config($vmid, sub {
my $conf = load_config($vmid, $migratedfrom);
my $nodename = PVE::INotify::nodename();
if ($datacenterconf->{migration_unsecure}) {
$localip = PVE::Cluster::remote_node_ip($nodename, 1);
+ $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
}
my $pfamily = PVE::Tools::get_host_address_family($nodename);
$migrate_port = PVE::Tools::next_migrate_port($pfamily);
- $migrate_uri = "tcp:[${localip}]:${migrate_port}";
+ $migrate_uri = "tcp:${localip}:${migrate_port}";
push @$cmd, '-incoming', $migrate_uri;
push @$cmd, '-S';
} else {
my $info = pci_device_info("0000:$pciid");
die "IOMMU not present\n" if !check_iommu_support();
die "no pci device info for device '$pciid'\n" if !$info;
-
- if ($d->{driver} && $d->{driver} eq "vfio") {
- die "can't unbind/bind pci group to vfio '$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
- } else {
- die "can't unbind/bind to stub pci device '$pciid'\n" if !pci_dev_bind_to_stub($info);
- }
-
+ die "can't unbind/bind pci group to vfio '$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
die "can't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
}
}
}
sub vm_resume {
- my ($vmid, $skiplock) = @_;
+ my ($vmid, $skiplock, $nocheck) = @_;
lock_config($vmid, sub {
- my $conf = load_config($vmid);
+ if (!$nocheck) {
- check_lock($conf) if !($skiplock || ($conf->{lock} && $conf->{lock} eq 'backup'));
+ my $conf = load_config($vmid);
+
+ check_lock($conf) if !($skiplock || ($conf->{lock} && $conf->{lock} eq 'backup'));
+
+ vm_mon_cmd($vmid, "cont");
- vm_mon_cmd($vmid, "cont");
+ } else {
+ vm_mon_cmd_nocheck($vmid, "cont");
+ }
});
}
return file_write($fn, "1");
}
-sub pci_dev_bind_to_stub {
- my ($dev) = @_;
-
- my $name = $dev->{name};
-
- my $testdir = "$pcisysfs/drivers/pci-stub/$name";
- return 1 if -d $testdir;
-
- my $data = "$dev->{vendor} $dev->{product}";
- return undef if !file_write("$pcisysfs/drivers/pci-stub/new_id", $data);
-
- my $fn = "$pcisysfs/devices/$name/driver/unbind";
- if (!file_write($fn, $name)) {
- return undef if -f $fn;
- }
-
- $fn = "$pcisysfs/drivers/pci-stub/bind";
- if (! -d $testdir) {
- return undef if !file_write($fn, $name);
- }
-
- return -d $testdir;
-}
-
sub pci_dev_bind_to_vfio {
my ($dev) = @_;
$d->{volid} = $volid;
my $path = PVE::Storage::path($cfg, $volid);
+ PVE::Storage::activate_volumes($cfg,[$volid]);
+
my $write_zeros = 1;
# fixme: what other storages types initialize volumes with zero?
if ($scfg->{type} eq 'dir' || $scfg->{type} eq 'nfs' || $scfg->{type} eq 'glusterfs' ||
alarm($oldtimeout) if $oldtimeout;
+ my $vollist = [];
+ foreach my $devname (keys %$devinfo) {
+ my $volid = $devinfo->{$devname}->{volid};
+ push @$vollist, $volid if $volid;
+ }
+
+ my $cfg = cfs_read_file('storage.cfg');
+ PVE::Storage::deactivate_volumes($cfg, $vollist);
+
unlink $mapfifo;
if ($err) {
rmtree $tmpdir;
unlink $tmpfn;
- my $cfg = cfs_read_file('storage.cfg');
foreach my $devname (keys %$devinfo) {
my $volid = $devinfo->{$devname}->{volid};
next if !$volid;
my $storage_name = PVE::Storage::parse_volume_id($volid);
- if ($qemu_snap_storage->{$storecfg->{ids}->{$storage_name}->{type}} ){
+ if ($qemu_snap_storage->{$storecfg->{ids}->{$storage_name}->{type}}
+ && !$storecfg->{ids}->{$storage_name}->{krbd}){
return 1;
}
my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
if ($src_storeid && $dst_storeid) {
+
+ PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
+
my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
}
+sub qemu_machine_pxe {
+ my ($vmid, $conf, $machine) = @_;
+
+ $machine = PVE::QemuServer::get_current_qemu_machine($vmid) if !$machine;
+
+ foreach my $opt (keys %$conf) {
+ next if $opt !~ m/^net(\d+)$/;
+ my $net = PVE::QemuServer::parse_net($conf->{$opt});
+ next if !$net;
+ my $romfile = PVE::QemuServer::vm_mon_cmd_nocheck($vmid, 'qom-get', path => $opt, property => 'romfile');
+ return $machine.".pxe" if $romfile =~ m/pxe/;
+ last;
+ }
+
+}
+
+sub qemu_use_old_bios_files {
+ my ($machine_type) = @_;
+
+ return if !$machine_type;
+
+ my $use_old_bios_files = undef;
+
+ if ($machine_type =~ m/^(\S+)\.pxe$/) {
+ $machine_type = $1;
+ $use_old_bios_files = 1;
+ } else {
+ # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
+ # load new efi bios files on migration. So this hack is required to allow
+ # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
+ # updrading from proxmox-ve-3.X to proxmox-ve 4.0
+ $use_old_bios_files = !qemu_machine_feature_enabled ($machine_type, undef, 2, 4);
+ }
+
+ return ($use_old_bios_files, $machine_type);
+}
+
sub lspci {
my $devices = {};
my $res = [];
foreach my $sid (keys %$ids) {
next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
+ next if !$ids->{$sid}->{content}->{images};
push @$res, $sid;
}