From f4c026c38fdab111028c078e09fec65eb959a654 Mon Sep 17 00:00:00 2001 From: Tiago Sousa Date: Sat, 2 Aug 2025 16:58:53 +0100 Subject: [PATCH 1/3] blockdev: add set write threshold --- src/PVE/QemuServer.pm | 22 ++++++++++++++++ src/PVE/QemuServer/Blockdev.pm | 47 ++++++++++++++++++++++++++++++++++ src/PVE/QemuServer/Drive.pm | 7 +++++ 3 files changed, 76 insertions(+) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index e30b27cb..df849ca1 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -5822,6 +5822,28 @@ sub vm_start_nolock { warn $@ if $@; } + # set write threshold for LVM thin provisioning disks + PVE::QemuConfig->foreach_volume( + $conf, + sub { + my ($ds, $drive) = @_; + return if PVE::QemuServer::drive_is_cdrom($drive, 1); + my $volid = $drive->{file}; + if ( $volid ne 'none') { + my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive); + my $snapshots = PVE::Storage::volume_snapshot_info($storecfg, $volid); + my $parentid = $snapshots->{'current'}->{parent}; + # for now only set write_threshold for volumes that have snapshots + # FIX: Change to only thin drives + if ($parentid) { + PVE::QemuServer::Blockdev::set_write_threshold( + $storecfg, $vmid, $drive_id, $volid + ); + } + } + }, + ); + #start nbd server for storage migration if (my $nbd = $migrate_opts->{nbd}) { diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm index d0d7e684..b05a5872 100644 --- a/src/PVE/QemuServer/Blockdev.pm +++ b/src/PVE/QemuServer/Blockdev.pm @@ -820,6 +820,49 @@ sub set_io_throttle { } } +sub block_set_write_threshold { + my ($vmid, $nodename, $threshold) = @_; + + print "set threshold $nodename $threshold\n"; + + PVE::QemuServer::mon_cmd( + $vmid, + "block-set-write-threshold", + 'node-name' => $nodename, + 'write-threshold' => int($threshold), + ); +} + +sub compute_write_threshold { + my ($storecfg, $scfg, $volid) = @_; + + my $lv_size = PVE::Storage::volume_size_info($storecfg, $volid, 5); + + my $write_threshold = $lv_size - $scfg->{chunksize} * (1 - $scfg->{'chunk-percentage'}); + + return $write_threshold; +} + +sub set_write_threshold { + my ($storecfg, $vmid, $drive_id, $volid, $options) = @_; + + my ($storeid) = PVE::Storage::parse_volume_id($volid); + my $scfg = PVE::Storage::storage_config($storecfg, $storeid); + my $support_qemu_snapshots = PVE::Storage::volume_qemu_snapshot_method($storecfg, $volid); + + # set write threshold is only supported for lvm storage using + # qcow2+external snapshots + return if $scfg->{type} ne 'lvm' || $support_qemu_snapshots ne 'mixed'; + # return if drive is not set as thin + # return if !$drive->{thin}; + + my $nodename = get_node_name('file', $drive_id, $volid, $options); + my $write_threshold = compute_write_threshold($storecfg, $scfg, $volid); + + print "setting threshold for $volid from $storeid\n"; + block_set_write_threshold($vmid, $nodename, $write_threshold); +} + sub blockdev_external_snapshot { my ($storecfg, $vmid, $machine_version, $deviceid, $drive, $snap, $parent_snap) = @_; @@ -868,6 +911,10 @@ sub blockdev_external_snapshot { node => $snap_fmt_blockdev->{'node-name'}, overlay => $new_fmt_blockdev->{'node-name'}, ); + + # FIX: only if thin + my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive); + set_write_threshold($storecfg, $vmid, $drive_id, $volid); } sub blockdev_delete { diff --git a/src/PVE/QemuServer/Drive.pm b/src/PVE/QemuServer/Drive.pm index 9dc4e674..8d5ddebf 100644 --- a/src/PVE/QemuServer/Drive.pm +++ b/src/PVE/QemuServer/Drive.pm @@ -254,6 +254,13 @@ my %drivedesc_base = ( optional => 1, default => 0, }, + thin => { + type => 'boolean', + description => + 'Controls whether a drive should be thin provisioned', + optional => 1, + default => 0, + }, ); my %iothread_fmt = ( From a64abe3e5d6e2e0385b52b4d9e6d0b7cce18f2fb Mon Sep 17 00:00:00 2001 From: Tiago Sousa Date: Sat, 13 Sep 2025 18:54:06 +0100 Subject: [PATCH 2/3] blockdev: add query-blockstats qmp command --- src/PVE/QemuServer/Blockdev.pm | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm index b05a5872..55344784 100644 --- a/src/PVE/QemuServer/Blockdev.pm +++ b/src/PVE/QemuServer/Blockdev.pm @@ -111,6 +111,21 @@ sub get_block_info { return $block_info; } +sub get_block_stats { + my ($vmid) = @_; + + my $block_stats = {}; + + my $qmp_block_stats = mon_cmd($vmid, "query-blockstats"); + for my $info ($qmp_block_stats->@*) { + my $qdev_id = $info->{qdev} or next; + my $drive_id = qdev_id_to_drive_id($qdev_id); + $block_stats->{$drive_id} = $info; + } + + return $block_stats; +} + my sub get_node_name { my ($type, $drive_id, $volid, $options) = @_; From 0efbeddfb4ab1a9c0f1d18d73141b5fa3b5e23b1 Mon Sep 17 00:00:00 2001 From: Tiago Sousa Date: Fri, 10 Oct 2025 18:11:29 +0100 Subject: [PATCH 3/3] blockdev: add underlay resize --- src/PVE/QemuServer/Blockdev.pm | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm index 55344784..3d78dcde 100644 --- a/src/PVE/QemuServer/Blockdev.pm +++ b/src/PVE/QemuServer/Blockdev.pm @@ -715,6 +715,24 @@ sub resize { ); } +sub underlay_resize { + my ($storecfg, $vmid, $drive_id, $volid) = @_; + + my $running = PVE::QemuServer::Helpers::vm_running_locally($vmid); + + # get backing_snap + my $snapshots = PVE::Storage::volume_snapshot_info($storecfg, $volid); + my $backing_snap = $snapshots->{current}->{parent}; + my $size = PVE::Storage::volume_underlay_resize($storecfg, $volid, $backing_snap); + + return if !$running; + my $block_info = get_block_info($vmid); + my $inserted = $block_info->{$drive_id}->{inserted} + or die "no block node inserted for drive '$drive_id'\n"; + + set_write_threshold($storecfg, $vmid, $drive_id, $volid); +} + my sub blockdev_change_medium { my ($storecfg, $vmid, $qdev_id, $drive) = @_; @@ -851,7 +869,7 @@ sub block_set_write_threshold { sub compute_write_threshold { my ($storecfg, $scfg, $volid) = @_; - my $lv_size = PVE::Storage::volume_size_info($storecfg, $volid, 5); + my $lv_size = PVE::Storage::volume_underlay_size_info($storecfg, $volid, 5); my $write_threshold = $lv_size - $scfg->{chunksize} * (1 - $scfg->{'chunk-percentage'});