my $running = 0;
if (my $pid = PVE::QemuServer::check_running($vmid)) {
- die "cant migrate running VM without --online\n" if !$online;
+ die "can't migrate running VM without --online\n" if !$online;
$running = $pid;
$self->{forcemachine} = PVE::QemuServer::qemu_machine_pxe($vmid, $conf);
eval {
my $volhash = {};
- my $cdromhash = {};
my $sharedvm = 1;
my @sids = PVE::Storage::storage_ids($self->{storecfg});
- foreach my $storeid (@sids) {
+ foreach my $storeid (@sids) {
my $scfg = PVE::Storage::storage_config($self->{storecfg}, $storeid);
- next if $scfg->{shared};
+ next if $scfg->{shared};
next if !PVE::Storage::storage_check_enabled($self->{storecfg}, $storeid, undef, 1);
- # get list from PVE::Storage (for unused volumes)
- my $dl = PVE::Storage::vdisk_list($self->{storecfg}, $storeid, $vmid);
- PVE::Storage::foreach_volid($dl, sub {
- my ($volid, $sid, $volname) = @_;
+ # get list from PVE::Storage (for unused volumes)
+ my $dl = PVE::Storage::vdisk_list($self->{storecfg}, $storeid, $vmid);
- # check if storage is available on target node
- PVE::Storage::storage_check_node($self->{storecfg}, $sid, $self->{node});
+ next if @{$dl->{$storeid}} == 0;
- $volhash->{$volid} = 1;
- $sharedvm = 0; # there is a non-shared disk
- });
- }
+ # check if storage is available on target node
+ PVE::Storage::storage_check_node($self->{storecfg}, $storeid, $self->{node});
+ $sharedvm = 0; # there is a non-shared disk
+
+ PVE::Storage::foreach_volid($dl, sub {
+ my ($volid, $sid, $volname) = @_;
- # and add used, owned/non-shared disks (just to be sure we have all)
+ $volhash->{$volid} = 1;
+ });
+ }
- PVE::QemuServer::foreach_volid($conf, sub {
- my ($volid, $is_cdrom) = @_;
+ my $test_volid = sub {
+ my ($volid, $is_cdrom, $snapname) = @_;
return if !$volid;
die "can't migrate local file/device '$volid'\n" if $volid =~ m|^/|;
if ($is_cdrom) {
- die "cant migrate local cdrom drive\n" if $volid eq 'cdrom';
+ die "can't migrate local cdrom drive\n" if $volid eq 'cdrom';
return if $volid eq 'none';
- $cdromhash->{$volid} = 1;
}
my ($sid, $volname) = PVE::Storage::parse_volume_id($volid);
return if $scfg->{shared};
- die "can't migrate local cdrom '$volid'\n" if $cdromhash->{$volid};
-
$sharedvm = 0;
+ die "can't migrate local cdrom '$volid'\n" if $is_cdrom;
+
my ($path, $owner) = PVE::Storage::path($self->{storecfg}, $volid);
die "can't migrate volume '$volid' - owned by other VM (owner = VM $owner)\n"
if !$owner || ($owner != $self->{vmid});
- $volhash->{$volid} = 1;
- });
+ if (defined($snapname)) {
+ # we cannot migrate shapshots on local storage
+ # exceptions: 'zfspool' or 'qcow2' files (on directory storage)
+
+ my $format = PVE::QemuServer::qemu_img_format($scfg, $volname);
+
+ if (($scfg->{type} eq 'zfspool') || ($format eq 'qcow2')) {
+ $volhash->{$volid} = 1;
+ return;
+ }
+
+ die "can't migrate snapshot of local volume '$volid'\n";
+
+ } else {
+ $volhash->{$volid} = 1;
+ }
+ };
+
+ my $test_drive = sub {
+ my ($ds, $drive, $snapname) = @_;
+
+ &$test_volid($drive->{file}, PVE::QemuServer::drive_is_cdrom($drive), $snapname);
+ };
+
+ PVE::QemuServer::foreach_drive($conf, $test_drive);
+ foreach my $snapname (keys %{$conf->{snapshots}}) {
+ &$test_volid($conf->{snapshots}->{$snapname}->{'vmstate'}, 0, undef)
+ if defined($conf->{snapshots}->{$snapname}->{'vmstate'});
+ PVE::QemuServer::foreach_drive($conf->{snapshots}->{$snapname}, $test_drive, $snapname);
+ }
if ($self->{running} && !$sharedvm) {
die "can't do online migration - VM uses local disks\n";
}
- # do some checks first
+ # additional checks for local storage
foreach my $volid (keys %$volhash) {
my ($sid, $volname) = PVE::Storage::parse_volume_id($volid);
my $scfg = PVE::Storage::storage_config($self->{storecfg}, $sid);
+ my $migratable = ($scfg->{type} eq 'dir') || ($scfg->{type} eq 'zfspool') ||
+ ($scfg->{type} eq 'lvmthin') || ($scfg->{type} eq 'lvm');
+
die "can't migrate '$volid' - storage type '$scfg->{type}' not supported\n"
- if (!($scfg->{type} eq 'dir' || $scfg->{type} eq 'zfspool') && (!$sharedvm));
+ if !$migratable;
- # if file, check if a backing file exist
- if (!($scfg->{type} eq 'dir' || $scfg->{type} eq 'zfspool') && (!$sharedvm)) {
- my (undef, undef, undef, $parent) = PVE::Storage::volume_size_info($self->{storecfg}, $volid, 1);
- die "can't migrate '$volid' as it's a clone of '$parent'" if $parent;
+ # image is a linked clone on local storage, se we can't migrate.
+ if (my $basename = (PVE::Storage::parse_volname($self->{storecfg}, $volid))[3]) {
+ die "can't migrate '$volid' as it's a clone of '$basename'";
}
}