+# called in locked context by incoming migration
+sub vm_migrate_get_nbd_disks {
+ my ($storecfg, $conf, $replicated_volumes) = @_;
+
+ my $local_volumes = {};
+ PVE::QemuConfig->foreach_volume($conf, sub {
+ my ($ds, $drive) = @_;
+
+ return if drive_is_cdrom($drive);
+
+ my $volid = $drive->{file};
+
+ return if !$volid;
+
+ my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
+
+ my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
+ return if $scfg->{shared};
+
+ # 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];
+ });
+ return $local_volumes;
+}
+
+# called in locked context by incoming migration
+sub vm_migrate_alloc_nbd_disks {
+ my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
+
+ my $format = undef;
+
+ my $nbd = {};
+ foreach my $opt (sort keys %$source_volumes) {
+ my ($volid, $storeid, $volname, $drive, $use_existing) = @{$source_volumes->{$opt}};
+
+ if ($use_existing) {
+ $nbd->{$opt}->{drivestr} = print_drive($drive);
+ $nbd->{$opt}->{volid} = $volid;
+ $nbd->{$opt}->{replicated} = 1;
+ next;
+ }
+
+ # If a remote storage is specified and the format of the original
+ # volume is not available there, fall back to the default format.
+ # Otherwise use the same format as the original.
+ if (!$storagemap->{identity}) {
+ $storeid = map_storage($storagemap, $storeid);
+ my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
+ my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
+ my $fileFormat = qemu_img_format($scfg, $volname);
+ $format = (grep {$fileFormat eq $_} @{$validFormats}) ? $fileFormat : $defFormat;
+ } else {
+ my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
+ $format = qemu_img_format($scfg, $volname);
+ }
+
+ my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
+ my $newdrive = $drive;
+ $newdrive->{format} = $format;
+ $newdrive->{file} = $newvolid;
+ my $drivestr = print_drive($newdrive);
+ $nbd->{$opt}->{drivestr} = $drivestr;
+ $nbd->{$opt}->{volid} = $newvolid;
+ }
+
+ return $nbd;
+}
+
+# see vm_start_nolock for parameters, additionally:
+# migrate_opts:
+# storagemap = parsed storage map for allocating NBD disks