};
PVE::JSONSchema::register_format('pve-qm-cicustom', $cicustom_fmt);
+# any new option might need to be added to $cloudinitoptions in PVE::API2::Qemu
my $confdesc_cloudinit = {
citype => {
optional => 1,
ciupgrade => {
optional => 1,
type => 'boolean',
- description => 'cloud-init: do an automatic package upgrade after the first boot.'
+ description => 'cloud-init: do an automatic package upgrade after the first boot.',
+ default => 1,
},
cicustom => {
optional => 1,
my $maxdev = ($drive->{interface} eq 'sata') ? $PVE::QemuServer::Drive::MAX_SATA_DISKS : 2;
my $controller = int($drive->{index} / $maxdev);
my $unit = $drive->{index} % $maxdev;
+
+ # machine type q35 only supports unit=0 for IDE rather than 2 units. This wasn't handled
+ # correctly before, so e.g. index=2 was mapped to controller=1,unit=0 rather than
+ # controller=2,unit=0. Note that odd indices never worked, as they would be mapped to
+ # unit=1, so to keep backwards compat for migration, it suffices to keep even ones as they
+ # were before. Move odd ones up by 2 where they don't clash.
+ if (PVE::QemuServer::Machine::machine_type_is_q35($conf) && $drive->{interface} eq 'ide') {
+ $controller += 2 * ($unit % 2);
+ $unit = 0;
+ }
+
my $devicetype = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd";
$device = "ide-$devicetype";
}
if (min_version($machine_version, 7, 1) && $net->{model} eq 'virtio'){
- $tmpstr .= ",rx_queue_size=1024,tx_queue_size=1024";
+ $tmpstr .= ",rx_queue_size=1024,tx_queue_size=256";
}
$tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex} ;
push @$devices, @$audio_devs;
}
- add_tpm_device($vmid, $devices, $conf);
+ # Add a TPM only if the VM is not a template,
+ # to support backing up template VMs even if the TPM disk is write-protected.
+ add_tpm_device($vmid, $devices, $conf) if (!PVE::QemuConfig->is_template($conf));
my $sockets = 1;
$sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
my $volhash = {};
my $test_volid = sub {
- my ($key, $drive, $snapname) = @_;
+ my ($key, $drive, $snapname, $pending) = @_;
my $volid = $drive->{file};
return if !$volid;
$volhash->{$volid}->{shared} //= 0;
$volhash->{$volid}->{shared} = 1 if $drive->{shared};
- $volhash->{$volid}->{referenced_in_config} //= 0;
- $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
+ $volhash->{$volid}->{is_unused} //= 0;
+ $volhash->{$volid}->{is_unused} = 1 if $key =~ /^unused\d+$/;
+
+ $volhash->{$volid}->{is_attached} //= 0;
+ $volhash->{$volid}->{is_attached} = 1
+ if !$volhash->{$volid}->{is_unused} && !defined($snapname) && !$pending;
$volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
if defined($snapname);
+ $volhash->{$volid}->{referenced_in_pending} = 1 if $pending;
+
my $size = $drive->{size};
$volhash->{$volid}->{size} //= $size if $size;
$volhash->{$volid}->{is_tpmstate} //= 0;
$volhash->{$volid}->{is_tpmstate} = 1 if $key eq 'tpmstate0';
- $volhash->{$volid}->{is_unused} //= 0;
- $volhash->{$volid}->{is_unused} = 1 if $key =~ /^unused\d+$/;
-
$volhash->{$volid}->{drivename} = $key if is_valid_drivename($key);
};
};
PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $test_volid);
+
+ PVE::QemuConfig->foreach_volume_full($conf->{pending}, $include_opts, $test_volid, undef, 1)
+ if defined($conf->{pending}) && $conf->{pending}->%*;
+
foreach my $snapname (keys %{$conf->{snapshots}}) {
my $snap = $conf->{snapshots}->{$snapname};
PVE::QemuConfig->foreach_volume_full($snap, $include_opts, $test_volid, $snapname);
my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
return if $scfg->{shared};
+ my $format = qemu_img_format($scfg, $volname);
+
# replicated disks re-use existing state via bitmap
my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
- $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
+ $local_volumes->{$ds} = [$volid, $storeid, $drive, $use_existing, $format];
});
return $local_volumes;
}
my $nbd = {};
foreach my $opt (sort keys %$source_volumes) {
- my ($volid, $storeid, $volname, $drive, $use_existing, $format) = @{$source_volumes->{$opt}};
+ my ($volid, $storeid, $drive, $use_existing, $format) = @{$source_volumes->{$opt}};
if ($use_existing) {
$nbd->{$opt}->{drivestr} = print_drive($drive);
next;
}
- # storage mapping + volname = regular migration
- # storage mapping + format = remote migration
+ $storeid = PVE::JSONSchema::map_id($storagemap, $storeid);
+
# order of precedence, filtered by whether storage supports it:
# 1. explicit requested format
- # 2. format of current volume
- # 3. default format of storage
- if (!$storagemap->{identity}) {
- $storeid = PVE::JSONSchema::map_id($storagemap, $storeid);
- my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
- if (!$format || !grep { $format eq $_ } @$validFormats) {
- if ($volname) {
- my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
- my $fileFormat = qemu_img_format($scfg, $volname);
- $format = $fileFormat
- if grep { $fileFormat eq $_ } @$validFormats;
- }
- $format //= $defFormat;
- }
- } else {
- # can't happen for remote migration, so $volname is always defined
- my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
- $format = qemu_img_format($scfg, $volname);
- }
+ # 2. default format of storage
+ my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
+ $format = $defFormat if !$format || !grep { $format eq $_ } $validFormats->@*;
my $size = $drive->{size} / 1024;
my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, $size);
my %silence_std_outs = (outfunc => sub {}, errfunc => sub {});
+ eval { run_command(['/bin/systemctl', 'reset-failed', "$vmid.scope"], %silence_std_outs) };
eval { run_command(['/bin/systemctl', 'stop', "$vmid.scope"], %silence_std_outs) };
# Issues with the above 'stop' not being fully completed are extremely rare, a very low
# timeout should be more than enough here...
PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %systemd_properties);
my $tpmpid;
- if (my $tpm = $conf->{tpmstate0}) {
+ if ((my $tpm = $conf->{tpmstate0}) && !PVE::QemuConfig->is_template($conf)) {
# start the TPM emulator so QEMU can connect on start
$tpmpid = start_swtpm($storecfg, $vmid, $tpm, $migratedfrom);
}
$add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
my $oldtimeout;
- my $timeout = 5;
+ my $timeout = 5; # for reading the VMA header - might hang with a corrupted one
my $devinfo = {}; # info about drives included in backup
my $virtdev_hash = {}; # info about allocated drives
$devinfo->{$devname} = { size => $size, dev_id => $dev_id };
} elsif ($line =~ m/^CTIME: /) {
# we correctly received the vma config, so we can disable
- # the timeout now for disk allocation (set to 10 minutes, so
- # that we always timeout if something goes wrong)
- alarm(600);
+ # the timeout now for disk allocation
+ alarm($oldtimeout || 0);
+ $oldtimeout = undef;
&$print_devmap();
print $fifofh "done\n";
- my $tmp = $oldtimeout || 0;
- $oldtimeout = undef;
- alarm($tmp);
close($fifofh);
$fifofh = undef;
}