From: Alexandre Derumier via pve-devel <pve-devel@lists.proxmox.com>
To: pve-devel@lists.proxmox.com
Cc: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
Subject: [pve-devel] [PATCH qemu-server 09/13] blockdev: add blockdev_mirror
Date: Tue, 3 Jun 2025 09:55:53 +0200 [thread overview]
Message-ID: <mailman.218.1748937431.395.pve-devel@lists.proxmox.com> (raw)
In-Reply-To: <20250603075558.627850-1-alexandre.derumier@groupe-cyllene.com>
[-- Attachment #1: Type: message/rfc822, Size: 11188 bytes --]
From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH qemu-server 09/13] blockdev: add blockdev_mirror
Date: Tue, 3 Jun 2025 09:55:53 +0200
Message-ID: <20250603075558.627850-19-alexandre.derumier@groupe-cyllene.com>
FIXME:
port qemu bitmap drive-mirror patch to blockdev-mirror
Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
PVE/QemuMigrate.pm | 2 +-
PVE/QemuServer.pm | 115 ++++++++++++++++++++++----
test/MigrationTest/QemuMigrateMock.pm | 10 ++-
3 files changed, 104 insertions(+), 23 deletions(-)
diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm
index 5a54f173..ca9f59fb 100644
--- a/PVE/QemuMigrate.pm
+++ b/PVE/QemuMigrate.pm
@@ -1149,7 +1149,7 @@ sub phase2 {
my $bitmap = $target->{bitmap};
$self->log('info', "$drive: start migration to $nbd_uri");
- PVE::QemuServer::qemu_drive_mirror($vmid, $drive, $nbd_uri, $vmid, undef, $self->{storage_migration_jobs}, 'skip', undef, $bwlimit, $bitmap);
+ PVE::QemuServer::qemu_drive_mirror($vmid, $source_drive, $nbd_uri, $vmid, undef, $self->{storage_migration_jobs}, 'skip', undef, $bwlimit, $bitmap);
}
if (PVE::QemuServer::QMPHelpers::runs_at_least_qemu_version($vmid, 8, 2)) {
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 8e48f52b..f68c5bf2 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -8153,60 +8153,139 @@ sub qemu_img_convert {
die "copy failed: $err" if $err;
}
+
sub qemu_drive_mirror {
my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
$jobs = {} if !$jobs;
+ my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
+ if (PVE::QemuServer::Machine::is_machine_version_at_least($machine_type, 10, 0)) {
+ return qemu_blockdev_mirror($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap);
+ }
+
my $qemu_target;
my $format;
- $jobs->{"drive-$drive"} = {};
+
+ my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive);
+ my $deviceid = "drive-$drive_id";
+
+ $jobs->{$deviceid} = {};
if ($dst_volid =~ /^nbd:/) {
- $qemu_target = $dst_volid;
- $format = "nbd";
+ $qemu_target = $dst_volid;
+ $format = "nbd";
} else {
- my $storecfg = PVE::Storage::config();
+ my $storecfg = PVE::Storage::config();
+
+ $format = checked_volume_format($storecfg, $dst_volid);
- $format = checked_volume_format($storecfg, $dst_volid);
+ my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
- my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
+ $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
+ }
- $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
+ my $opts = {
+ timeout => 10,
+ device => $deviceid,
+ mode => "existing",
+ sync => "full",
+ target => $qemu_target,
+ 'auto-dismiss' => JSON::false,
+ };
+ $opts->{format} = $format if $format;
+
+ if (defined($src_bitmap)) {
+ $opts->{sync} = 'incremental';
+ $opts->{bitmap} = $src_bitmap;
+ print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
+ }
+
+ if (defined($bwlimit)) {
+ $opts->{speed} = $bwlimit * 1024;
+ print "drive mirror is starting for $deviceid with bandwidth limit: ${bwlimit} KB/s\n";
+ } else {
+ print "drive mirror is starting for $deviceid\n";
+ }
+
+ # if a job already runs for this device we get an error, catch it for cleanup
+ eval { mon_cmd($vmid, "drive-mirror", %$opts); };
+ if (my $err = $@) {
+ eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
+ warn "$@\n" if $@;
+ die "mirroring error: $err\n";
}
+ qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $completion, $qga);
+}
+
+sub qemu_blockdev_mirror {
+ my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
+
+ my $storecfg = PVE::Storage::config();
+
+ # copy original drive config (aio,cache,discard,...)
+ my $dst_drive = dclone($drive);
+ $dst_drive->{file} = $dst_volid;
+ $dst_drive->{zeroinit} = 1 if $is_zero_initialized;
+ #improve: if target storage don't support aio uring,change it to default native
+ #and remove clone_disk_check_io_uring()
+
+ #add new block device
+ my $target_drive_blockdev = generate_drive_blockdev($storecfg, $dst_drive);
+ my $target_blockdev = $target_drive_blockdev->{file}; #can be fmt or only file for nbd
+ PVE::QemuServer::Monitor::mon_cmd($vmid, 'blockdev-add', %$target_blockdev);
+ my $target_nodename = $target_blockdev->{'node-name'};
+
+ # we replace the original src_fmt node in the blockdev graph.
+ # need to be defined, or if not, it'll replace the root throttle-filter
+ my $src_drive_blockdev = generate_drive_blockdev($storecfg, $drive);
+ my $src_fmt_nodename = $src_drive_blockdev->{file}->{'node-name'};
+
+
+ my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive);
+ my $deviceid = "drive-$drive_id";
+
+ $jobs = {} if !$jobs;
+ my $jobid = "mirror-$deviceid";
+ $jobs->{$jobid} = {};
+
my $opts = {
+ 'job-id' => $jobid,
timeout => 10,
- device => "drive-$drive",
- mode => "existing",
+ device => $deviceid,
+ replaces => $src_fmt_nodename,
sync => "full",
- target => $qemu_target,
+ target => $target_nodename,
'auto-dismiss' => JSON::false,
};
- $opts->{format} = $format if $format;
if (defined($src_bitmap)) {
$opts->{sync} = 'incremental';
- $opts->{bitmap} = $src_bitmap;
+ $opts->{bitmap} = $src_bitmap; ##FIXME: port qemu bitmap drive-mirror patch to blockdev-mirror
print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
}
if (defined($bwlimit)) {
$opts->{speed} = $bwlimit * 1024;
- print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
+ print "drive mirror is starting for $deviceid with bandwidth limit: ${bwlimit} KB/s\n";
} else {
- print "drive mirror is starting for drive-$drive\n";
+ print "drive mirror is starting for $deviceid\n";
}
# if a job already runs for this device we get an error, catch it for cleanup
- eval { mon_cmd($vmid, "drive-mirror", %$opts); };
+ eval { mon_cmd($vmid, "blockdev-mirror", %$opts); };
+
if (my $err = $@) {
eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
warn "$@\n" if $@;
+ eval { mon_cmd($vmid, 'blockdev-del', 'node-name' => $target_blockdev->{file}->{'node-name'}) };
+ warn "$@\n" if $@;
+ eval { mon_cmd($vmid, 'blockdev-del', 'node-name' => $target_nodename) };
+ warn "$@\n" if $@;
die "mirroring error: $err\n";
}
-
- qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $completion, $qga);
+ qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $completion, $qga, 'mirror');
}
# $completion can be either
@@ -8565,7 +8644,7 @@ sub clone_disk {
my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
if ($use_drive_mirror) {
- qemu_drive_mirror($vmid, $src_drivename, $newvolid, $newvmid, $sparseinit, $jobs,
+ qemu_drive_mirror($vmid, $drive, $newvolid, $newvmid, $sparseinit, $jobs,
$completion, $qga, $bwlimit);
} else {
if ($dst_drivename eq 'efidisk0') {
diff --git a/test/MigrationTest/QemuMigrateMock.pm b/test/MigrationTest/QemuMigrateMock.pm
index 11c58c08..d156ff1b 100644
--- a/test/MigrationTest/QemuMigrateMock.pm
+++ b/test/MigrationTest/QemuMigrateMock.pm
@@ -132,14 +132,16 @@ $MigrationTest::Shared::qemu_server_module->mock(
qemu_drive_mirror => sub {
my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
+ my $drive_id = "$drive->{interface}$drive->{index}";
+
die "drive_mirror with wrong vmid: '$vmid'\n" if $vmid ne $test_vmid;
- die "qemu_drive_mirror '$drive' error\n"
- if $fail_config->{qemu_drive_mirror} && $fail_config->{qemu_drive_mirror} eq $drive;
+ die "qemu_drive_mirror '$drive_id' error\n"
+ if $fail_config->{qemu_drive_mirror} && $fail_config->{qemu_drive_mirror} eq $drive_id;
my $nbd_info = decode_json(file_get_contents("${RUN_DIR_PATH}/nbd_info"));
die "target does not expect drive mirror for '$drive'\n"
- if !defined($nbd_info->{$drive});
- delete $nbd_info->{$drive};
+ if !defined($nbd_info->{$drive_id});
+ delete $nbd_info->{$drive_id};
file_set_contents("${RUN_DIR_PATH}/nbd_info", to_json($nbd_info));
},
qemu_drive_mirror_monitor => sub {
--
2.39.5
[-- Attachment #2: Type: text/plain, Size: 160 bytes --]
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2025-06-03 7:58 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20250603075558.627850-1-alexandre.derumier@groupe-cyllene.com>
2025-06-03 7:55 ` [pve-devel] [PATCH pve-qemu 1/1] add fake 10.0 Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 01/13] blockdev: cmdline: add blockdev syntax support Alexandre Derumier via pve-devel
2025-06-05 13:23 ` Fiona Ebner
2025-06-05 14:17 ` Fabian Grünbichler
2025-06-05 14:39 ` DERUMIER, Alexandre via pve-devel
[not found] ` <ee4940c99e9866910405b492dad15c68718c49ea.camel@groupe-cyllene.com>
2025-06-06 7:50 ` Fiona Ebner
2025-06-06 8:27 ` Fabian Grünbichler
2025-06-06 9:54 ` DERUMIER, Alexandre via pve-devel
2025-06-06 8:50 ` Fiona Ebner
2025-06-06 9:42 ` DERUMIER, Alexandre via pve-devel
[not found] ` <0605a27428cfb920ffefc51abdfec050a0a6b535.camel@groupe-cyllene.com>
2025-06-06 10:57 ` DERUMIER, Alexandre via pve-devel
2025-06-10 14:03 ` Fiona Ebner
2025-06-11 6:37 ` DERUMIER, Alexandre via pve-devel
[not found] ` <405662415075c0248618833b512b58258f80e0f7.camel@groupe-cyllene.com>
2025-06-11 7:24 ` Fiona Ebner
2025-06-11 14:02 ` DERUMIER, Alexandre via pve-devel
[not found] ` <733f5eefb25b76a0794a84d4f93ada8d70aea7be.camel@groupe-cyllene.com>
2025-06-11 14:13 ` Fiona Ebner
2025-06-12 5:20 ` DERUMIER, Alexandre via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH pve-storage 1/9] common: add qemu_img_create an preallocation_cmd_option Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 02/13] blockdev: add support for ovmf && efidisk Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH pve-storage 2/9] common: add qemu_img_create_qcow2_backed Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 03/13] blockdev: vm_devices_list : fix block-query Alexandre Derumier via pve-devel
2025-06-17 14:44 ` Fiona Ebner
2025-06-03 7:55 ` [pve-devel] [PATCH pve-storage 3/9] common: add qemu_img_info helper Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 04/13] blockdev: add support to qemu_driveadd && qemu_drivedel Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH pve-storage 4/9] common: add qemu_img_measure Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 05/13] blockdev: add support to qemu_block_set_io_throttle Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH pve-storage 5/9] rename_volume: add source && target snap Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 06/13] blockdev: add support for cdrom media eject/insert Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH pve-storage 6/9] storage: volume_snapshot: add $running param + api bump Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 07/13] blockdev: add support for block_resize Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH pve-storage 7/9] qcow2: add external snapshot support Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 08/13] blockdev: add support for nbd_export: block-export-add Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH pve-storage 8/9] lvmplugin: add qcow2 snapshot Alexandre Derumier via pve-devel
2025-06-03 7:55 ` Alexandre Derumier via pve-devel [this message]
2025-06-03 7:55 ` [pve-devel] [PATCH pve-storage 9/9] storage: add volume_support_qemu_snapshot Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 10/13] blockdev: change aio on target if io_uring is not default Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 11/13] qemu_img convert : add external snapshot support Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 12/13] blockdev: add backing_chain support Alexandre Derumier via pve-devel
2025-06-03 7:55 ` [pve-devel] [PATCH qemu-server 13/13] qcow2: add external snapshot support Alexandre Derumier via pve-devel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=mailman.218.1748937431.395.pve-devel@lists.proxmox.com \
--to=pve-devel@lists.proxmox.com \
--cc=alexandre.derumier@groupe-cyllene.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal