Compare commits

...

3 commits

Author SHA1 Message Date
Tiago Sousa
1ea3c1ae84 blockdev: add underlay resize 2025-10-15 22:32:58 +01:00
Tiago Sousa
102b8edd3d blockdev: add query-blockstats qmp command 2025-10-15 22:32:58 +01:00
Tiago Sousa
d006b5119d blockdev: add set write threshold 2025-10-15 22:32:54 +01:00
3 changed files with 109 additions and 0 deletions

View file

@ -5729,6 +5729,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}) {

View file

@ -113,6 +113,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) = @_;
@ -710,6 +725,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) = @_;
@ -830,6 +863,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_underlay_size_info($storecfg, $volid, 5);
my $write_threshold = $lv_size - $scfg->{chunksize} * $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) = @_;
@ -878,6 +954,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 {

View file

@ -253,6 +253,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 = (