public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH pve-storage 1/5] add lvmqcow2 plugin
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 1/6] lvmqcow2: set disk write threshold Alexandre Derumier via pve-devel
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 10132 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH pve-storage 1/5] add lvmqcow2 plugin
Date: Mon, 26 Aug 2024 13:00:19 +0200
Message-ID: <20240826110030.1744732-2-alexandre.derumier@groupe-cyllene.com>

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 src/PVE/Storage.pm                |   2 +
 src/PVE/Storage/LVMQcow2Plugin.pm | 218 ++++++++++++++++++++++++++++++
 src/PVE/Storage/Makefile          |   3 +-
 3 files changed, 222 insertions(+), 1 deletion(-)
 create mode 100644 src/PVE/Storage/LVMQcow2Plugin.pm

diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm
index 57b2038..97e77c8 100755
--- a/src/PVE/Storage.pm
+++ b/src/PVE/Storage.pm
@@ -40,6 +40,7 @@ use PVE::Storage::ZFSPlugin;
 use PVE::Storage::PBSPlugin;
 use PVE::Storage::BTRFSPlugin;
 use PVE::Storage::ESXiPlugin;
+use PVE::Storage::LVMQcow2Plugin;
 
 # Storage API version. Increment it on changes in storage API interface.
 use constant APIVER => 10;
@@ -66,6 +67,7 @@ PVE::Storage::ZFSPlugin->register();
 PVE::Storage::PBSPlugin->register();
 PVE::Storage::BTRFSPlugin->register();
 PVE::Storage::ESXiPlugin->register();
+PVE::Storage::LVMQcow2Plugin->register();
 
 # load third-party plugins
 if ( -d '/usr/share/perl5/PVE/Storage/Custom' ) {
diff --git a/src/PVE/Storage/LVMQcow2Plugin.pm b/src/PVE/Storage/LVMQcow2Plugin.pm
new file mode 100644
index 0000000..bdb21cc
--- /dev/null
+++ b/src/PVE/Storage/LVMQcow2Plugin.pm
@@ -0,0 +1,218 @@
+package PVE::Storage::LVMQcow2Plugin;
+
+use strict;
+use warnings;
+
+use IO::File;
+
+use PVE::Tools qw(run_command trim);
+use PVE::Storage::Plugin;
+use PVE::Storage::LVMPlugin;
+use PVE::JSONSchema qw(get_standard_option);
+
+use base qw(PVE::Storage::LVMPlugin);
+
+sub type {
+    return 'lvmqcow2';
+}
+
+sub plugindata {
+    return {
+	content => [ {images => 1, rootdir => 1}, { images => 1, rootdir => 1}],
+    };
+}
+
+sub properties {
+
+    return {
+        chunksize => {
+            description => "Size of extension chunk in Gigabytes. (default 1GB)",
+            type => 'integer',
+	    default => 1,
+            minimum => 1,
+            optional => 1,
+        },
+	chunk_pct_extension => {
+            description => "Percentage usage of the last chunk before trigger extent. (default 50%)",
+            type => 'integer',
+	    default => 50,
+            minimum => 1,
+            optional => 1,
+	}
+
+    };
+}
+
+sub options {
+    return {
+	vgname => { fixed => 1 },
+        nodes => { optional => 1 },
+	disable => { optional => 1 },
+	content => { optional => 1 },
+	bwlimit => { optional => 1 },
+	preallocation => { optional => 1 },
+	shared => { optional => 1 },
+	chunksize => { optional => 1 },
+	sparse => { optional => 1 },
+    };
+}
+
+
+sub default_format {
+    my ($scfg) = @_;
+
+    return 'qcow2';
+}
+
+sub find_free_diskname {
+    my ($class, $storeid, $scfg, $vmid, $fmt, $add_fmt_suffix) = @_;
+
+    my $vg = $scfg->{vgname};
+
+    my $lvs = PVE::Storage::LVMPlugin::lvm_list_volumes($vg);
+
+    my $disk_list = [ keys %{$lvs->{$vg}} ];
+
+    return PVE::Storage::Plugin::get_next_vm_diskname($disk_list, $storeid, $vmid, 'qcow2', $scfg, 1);
+}
+
+sub alloc_image {
+    my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
+
+    my $sparse = $scfg->{sparse};
+
+    my $chunksize = $scfg->{chunksize} // 1;
+    $chunksize *= 1024000;
+
+    #set minimum size to chunksize
+    my $lv_size = $chunksize;
+
+    #if no provisioning, $lv_size = $size + a extra chunk for metadatas overhead
+    $lv_size = $size + $chunksize if !$sparse;
+
+    die "illegal name '$name' - should be 'vm-$vmid-*'\n"
+        if  $name && $name !~ m/^vm-$vmid-/;
+
+    my $vgs = PVE::Storage::LVMPlugin::lvm_vgs();
+
+    my $vg = $scfg->{vgname};
+
+    die "no such volume group '$vg'\n" if !defined ($vgs->{$vg});
+
+    my $free = int($vgs->{$vg}->{free});
+
+    die "not enough free space ($free < $lv_size)\n" if $free < $lv_size;
+
+    $name = $class->find_free_diskname($storeid, $scfg, $vmid)
+        if !$name;
+
+    PVE::Storage::LVMPlugin::lvcreate($vg, $name, $lv_size, ["pve-vm-$vmid"]);
+
+    #activate
+    $class->activate_volume($storeid, $scfg, $name, undef, {});
+
+    #format the lv with qcow2 with virtualsize (we can't preallocate for sparse image)
+    my $path = $class->path($scfg, $name);
+    my $cmd = ['/usr/bin/qemu-img', 'create'];
+
+    my $options = "extended_l2=on,cluster_size=128k";
+    #only metadata can be preallocated qcow2 on block device
+    $options .= ",preallocation=metadata" if !$sparse;
+
+    push @$cmd, '-o', $options;
+
+    push @$cmd, '-f', 'qcow2', $path, "${size}K";
+    run_command($cmd, errmsg => "unable to format image");
+
+    #desactivate
+    $class->deactivate_volume($storeid, $scfg, $name, undef, {});
+
+    return $name;
+}
+
+sub volume_size_info {
+    my ($class, $scfg, $storeid, $volname, $timeout) = @_;
+
+    my $path = $class->filesystem_path($scfg, $volname);
+
+    my $json = eval {
+        my $json = '';
+        run_command(['/usr/bin/qemu-img', 'measure', $path, '-O', 'qcow2', '--output=json'],
+           timeout => 5,
+            outfunc => sub { $json .= $_[0]; },
+            errfunc => sub { warn "$_[0]\n"; }
+        );
+        from_json($json)
+    };
+    die $@ if $@;
+
+    my $used = $json->{required};
+    my $size = $json->{'fully-allocated'};
+
+    return wantarray ? ($size, 'raw', $used, undef) : $size;
+}
+
+sub volume_resize {
+    my ($class, $scfg, $storeid, $volname, $size, $running) = @_;
+
+    return PVE::Storage::Plugin::volume_resize($class, $scfg, $storeid, $volname, $size, $running);
+}
+
+sub clone_image {
+    my ($class, $scfg, $storeid, $volname, $vmid, $snap) = @_;
+
+    die "not implemented";
+}
+
+sub create_base {
+    my ($class, $storeid, $scfg, $volname) = @_;
+
+    die "not implemented";
+}
+
+sub volume_snapshot {
+    my ($class, $scfg, $storeid, $volname, $snap) = @_;
+
+    return PVE::Storage::Plugin::volume_snapshot($class, $scfg, $storeid, $volname, $snap);
+}
+
+sub volume_snapshot_rollback {
+    my ($class, $scfg, $storeid, $volname, $snap) = @_;
+
+    return PVE::Storage::Plugin::volume_snapshot_rollback($class, $scfg, $storeid, $volname, $snap);
+}
+
+sub volume_snapshot_delete {
+    my ($class, $scfg, $storeid, $volname, $snap, $running) = @_;
+
+    return PVE::Storage::Plugin::volume_snapshot_delete($class, $scfg, $storeid, $volname, $snap, $running);
+}
+
+sub volume_has_feature {
+    my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
+
+    my $features = {
+	snapshot => { current => 1 },
+	clone => { base => 1, snap => 1},
+	template => { current => 1},
+	copy => { base => 1, current => 1, snap => 1},
+	sparseinit => { base => 1, current => 1},
+	rename => {current => 1},
+    };
+
+    my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
+	$class->parse_volname($volname);
+
+    my $key = undef;
+    if($snapname){
+	$key = 'snap';
+    }else{
+	$key =  $isBase ? 'base' : 'current';
+    }
+    return 1 if $features->{$feature}->{$key};
+
+    return undef;
+}
+
+1;
+
diff --git a/src/PVE/Storage/Makefile b/src/PVE/Storage/Makefile
index d5cc942..f5d40bf 100644
--- a/src/PVE/Storage/Makefile
+++ b/src/PVE/Storage/Makefile
@@ -14,7 +14,8 @@ SOURCES= \
 	PBSPlugin.pm \
 	BTRFSPlugin.pm \
 	LvmThinPlugin.pm \
-	ESXiPlugin.pm
+	ESXiPlugin.pm \
+	LVMQcow2Plugin.pm
 
 .PHONY: install
 install:
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [pve-devel] [PATCH qemu-server 1/6] lvmqcow2: set disk write threshold
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 1/5] add lvmqcow2 plugin Alexandre Derumier via pve-devel
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-manager 1/1] pvestatd: lvmqcow2 : extend disk on io-error Alexandre Derumier via pve-devel
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 7723 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH qemu-server 1/6] lvmqcow2: set disk write threshold
Date: Mon, 26 Aug 2024 13:00:20 +0200
Message-ID: <20240826110030.1744732-3-alexandre.derumier@groupe-cyllene.com>

on vm start or when we hotplug a disk, we add a write threshold.

The threshold is: size of the lvm - (chunk_usage_percent * chunksize)

qemu will emit an event when the vm write on an offset higher than the threshold,
and the counter is reset to 0.
(So, we'll need to set threshold again when we extend the disk)

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 PVE/QemuServer.pm | 97 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 88c274d..3acb32e 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -4260,6 +4260,7 @@ sub vm_deviceplug {
 	    warn $@ if $@;
 	    die $err;
         }
+        eval { set_disks_write_threshold($storecfg, $conf->{pending}, $vmid, $deviceid) };
     } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
 	my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
 	my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
@@ -4289,6 +4290,7 @@ sub vm_deviceplug {
 	    warn $@ if $@;
 	    die $err;
         }
+        eval { PVE::QemuServer::set_disks_write_threshold($storecfg, $conf->{pending}, $vmid, $deviceid); };
     } elsif ($deviceid =~ m/^(net)(\d+)$/) {
 	return if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
 
@@ -6069,6 +6071,7 @@ sub vm_start_nolock {
 	    qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
 	}
 	add_nets_bridge_fdb($conf, $vmid);
+	PVE::QemuServer::set_disks_write_threshold($storecfg, $conf, $vmid);
     }
 
    if (!defined($conf->{balloon}) || $conf->{balloon}) {
@@ -8829,4 +8832,98 @@ sub delete_ifaces_ipams_ips {
     }
 }
 
+sub qemu_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 get_block_info {
+    my ($vmid, $disk, $block_info) = @_;
+
+    my $res = { deviceid => undef, blocknodeid => undef, wr_highest_offset => 0};
+
+    if($disk =~ m/block/) {
+	$res->{blocknodeid} = $disk;
+	for my $id (keys %$block_info) {
+	    if($block_info->{$id}->{parent}->{'node-name'} eq $disk) {
+		    $res->{deviceid} = $id;
+		    $res->{deviceid} =~ s/^drive-//;
+		    $res->{wr_highest_offset} = $block_info->{$id}->{parent}->{stats}->{wr_highest_offset};
+		    last;
+	    } elsif($block_info->{$id}->{parent}->{parent}->{'node-name'} eq $disk) {
+		    $res->{deviceid} = $id;
+		    $res->{deviceid} =~ s/^drive-//;
+		    $res->{wr_highest_offset} = $block_info->{$id}->{parent}->{parent}->{stats}->{wr_highest_offset};
+		    last;
+	    }
+	}
+    } else {
+	$res->{deviceid} = $disk;
+	#when backup is running, the chain of image is different
+	if($block_info->{"drive-$disk"}->{parent}->{parent}->{'node-name'} &&
+	    $block_info->{"drive-$disk"}->{parent}->{parent}->{'driver-specific'}->{driver} eq 'host_device'
+	) {
+	    $res->{blocknodeid} = $block_info->{"drive-$disk"}->{parent}->{parent}->{'node-name'};
+	    $res->{wr_highest_offset} = $block_info->{"drive-$disk"}->{parent}->{parent}->{stats}->{wr_highest_offset};
+	} elsif($block_info->{"drive-$disk"}->{parent}->{'node-name'} &&
+		$block_info->{"drive-$disk"}->{parent}->{'driver-specific'}->{driver} eq 'host_device'
+	) {
+	    $res->{blocknodeid} = $block_info->{"drive-$disk"}->{parent}->{'node-name'};
+	    $res->{wr_highest_offset} = $block_info->{"drive-$disk"}->{parent}->{stats}->{wr_highest_offset};
+	}
+    }
+    die "can't find blocknodeid" if !$res->{blocknodeid};
+    die "can't find devicedeid" if !$res->{deviceid};
+    return $res;
+}
+
+sub compute_write_threshold {
+    my ($size, $scfg) = @_;
+
+    my $chunksize = $scfg->{chunksize} // 1024 * 1024 * 1024;
+    my $chunk_pct_extension = $scfg->{chunk_pct_extension} // 0.5;
+
+    my $threshold = $size - ($chunksize * $chunk_pct_extension);
+
+    return $threshold;
+}
+
+sub set_disks_write_threshold {
+    my ($storecfg, $conf, $vmid, $deviceid) = @_;
+
+    $deviceid =~ s/^drive-// if $deviceid;
+
+    my $blockstats = mon_cmd($vmid, "query-blockstats");
+    $blockstats = { map { $_->{device} => $_ } $blockstats->@* };
+
+    PVE::QemuConfig->foreach_volume($conf, sub {
+	my ($ds, $drive) = @_;
+
+	return if $deviceid && $ds ne $deviceid;
+
+	my $volid = $drive->{file};
+	return if !$volid;
+
+	my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
+	return if !$sid;
+
+	my $scfg = PVE::Storage::storage_config($storecfg, $sid);
+	return if $scfg->{type} ne 'lvmqcow2';
+
+	my $size = PVE::Storage::volume_size_info($storecfg, $volid, 5);
+	my $threshold = compute_write_threshold($size, $scfg);
+
+	my $blockinfo = get_block_info($vmid, $ds, $blockstats);
+	qemu_block_set_write_threshold($vmid, $blockinfo->{blocknodeid}, $threshold);
+    });
+}
+
 1;
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [pve-devel] [PATCH pve-manager 1/1] pvestatd: lvmqcow2 : extend disk on io-error
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 1/5] add lvmqcow2 plugin Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 1/6] lvmqcow2: set disk write threshold Alexandre Derumier via pve-devel
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 2/6] qm cli: add blockextend Alexandre Derumier via pve-devel
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 5775 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH pve-manager 1/1] pvestatd: lvmqcow2 : extend disk on io-error
Date: Mon, 26 Aug 2024 13:00:21 +0200
Message-ID: <20240826110030.1744732-4-alexandre.derumier@groupe-cyllene.com>

if the write are really too fast, and the auto extend from
qmp event is too slow, the vm could try to write to an qcow2 offset
highter than the lvm underlay.

In this case, the vm will be paused in "io-error" mode.

To fix it, try to extend drive and resume the vm.

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 PVE/Service/pvestatd.pm | 62 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/PVE/Service/pvestatd.pm b/PVE/Service/pvestatd.pm
index 8661f774..72244451 100755
--- a/PVE/Service/pvestatd.pm
+++ b/PVE/Service/pvestatd.pm
@@ -230,12 +230,74 @@ sub auto_balloning {
     }
 }
 
+sub auto_extend_vm_disk_on_error {
+    my ($vmstatus) =  @_;
+
+    my $storecfg = PVE::Storage::config();
+
+    foreach my $vmid (keys %$vmstatus) {
+	my $d = $vmstatus->{$vmid};
+	my $status = $d->{qmpstatus} || $d->{status} || 'stopped';
+	next if $status ne 'io-error';
+	my $resume = undef;
+
+	my $blockstats = PVE::QemuServer::mon_cmd($vmid, "query-blockstats");
+	$blockstats = { map { $_->{device} => $_ } $blockstats->@* };
+
+	my $conf = eval { PVE::QemuConfig->load_config($vmid) };
+	if (my $err = $@) {
+	    warn $err;
+	    next;
+	}
+
+	PVE::QemuConfig->foreach_volume($conf, sub {
+	    my ($ds, $drive) = @_;
+
+	    my $volid = $drive->{file};
+	    return if !$volid;
+
+	    my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
+	    return if !$sid;
+
+	    my $scfg = PVE::Storage::storage_config($storecfg, $sid);
+	    return if $scfg->{type} ne 'lvmqcow2';
+
+	    my $blockinfo = PVE::QemuServer::get_block_info($vmid, $ds, $blockstats);
+	    my $wr_highest_offset = $blockinfo->{wr_highest_offset};
+
+	    my $size = PVE::Storage::volume_size_info($storecfg, $volid, 5);
+
+	    #if offset is bigger than size, increase lvm size to highest offset + chunksize
+	    if ($wr_highest_offset >= $size) {
+		my $chunksize = $scfg->{chunksize} // 1024 * 1024 * 1024;
+		my $newsize = $wr_highest_offset + $chunksize;
+		syslog('info', "auto extend disk underlay storage of $blockinfo->{deviceid} to $newsize");
+		PVE::Storage::volume_resize($storecfg, $volid, $newsize, 1, 1);
+		my $threshold = compute_write_threshold($newsize);
+		qemu_block_set_write_threshold($vmid, $blockinfo->{blocknodeid}, $threshold);
+	    }
+	    #if offset is lower, than mean that size has already been increased async but not fast enough
+	    #we just need to resume
+	    $resume = 1;
+	});
+
+	if($resume) {
+	    syslog('info', "resume $vmid");
+	    eval { PVE::QemuServer::vm_resume($vmid, 1, 1); };
+	    warn $@ if $@;
+	}
+    }
+}
+
 sub update_qemu_status {
     my ($status_cfg) = @_;
 
     my $ctime = time();
     my $vmstatus = PVE::QemuServer::vmstatus(undef, 1);
 
+    eval { auto_extend_vm_disk_on_error($vmstatus); };
+    syslog('err', "auto extend disk error: $@") if $@;
+
     eval { auto_balloning($vmstatus); };
     syslog('err', "auto ballooning error: $@") if $@;
 
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [pve-devel] [PATCH qemu-server 2/6] qm cli: add blockextend
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
                   ` (2 preceding siblings ...)
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-manager 1/1] pvestatd: lvmqcow2 : extend disk on io-error Alexandre Derumier via pve-devel
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 2/5] vdisk_alloc: add underlay_size option Alexandre Derumier via pve-devel
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 6494 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH qemu-server 2/6] qm cli: add blockextend
Date: Mon, 26 Aug 2024 13:00:22 +0200
Message-ID: <20240826110030.1744732-5-alexandre.derumier@groupe-cyllene.com>

Increase the underlay storage size to an higher value than current
max offset or 1 chunk bigger we max write offset is 0

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 PVE/CLI/qm.pm     | 31 ++++++++++++++++++++++++++++
 PVE/QemuServer.pm | 52 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/PVE/CLI/qm.pm b/PVE/CLI/qm.pm
index d3dbf7b..1410ad5 100755
--- a/PVE/CLI/qm.pm
+++ b/PVE/CLI/qm.pm
@@ -608,6 +608,36 @@ __PACKAGE__->register_method ({
 	return;
     }});
 
+__PACKAGE__->register_method({
+    name => 'blockextend',
+    path => 'blockextend',
+    method => 'POST',
+    protected => 1,
+    description => "Extend underlay storage to higher value than write threshold.",
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    node => get_standard_option('pve-node'),
+	    vmid => get_standard_option('pve-vmid', {
+		    completion => \&PVE::QemuServer::complete_vmid_running }),
+	    disk => {
+		type => 'string',
+		description => 'underlay blocknodeid or drive',
+	    },
+	},
+    },
+    returns => { type => 'null', },
+    code => sub {
+	my ($param) = @_;
+
+	my $vmid = PVE::Tools::extract_param($param, 'vmid');
+	my $disk = PVE::Tools::extract_param($param, 'disk');
+	PVE::QemuServer::block_extend($vmid, $disk);
+
+	return;
+    }
+});
+
 __PACKAGE__->register_method ({
     name => 'terminal',
     path => 'terminal',
@@ -1171,6 +1201,7 @@ our $cmddef = {
 	rescan => [ __PACKAGE__, 'rescan', []],
 	resize => [ "PVE::API2::Qemu", 'resize_vm', ['vmid', 'disk', 'size'], { %node } ],
 	unlink => [ "PVE::API2::Qemu", 'unlink', ['vmid'], { %node } ],
+	blockextend => [ __PACKAGE__, 'blockextend', ['vmid', 'disk'], { %node }],
     },
 
     monitor  => [ __PACKAGE__, 'monitor', ['vmid']],
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 3acb32e..fb67ac9 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -8926,4 +8926,56 @@ sub set_disks_write_threshold {
     });
 }
 
+sub lock_blockextend {
+    my ($vmid, $timeout, $sub) = @_;
+
+    my $filename = "/var/lock/qemu-server/blockextend-$vmid.lck";
+
+    my $res = PVE::Tools::lock_file($filename, $timeout, $sub);
+    die $@ if $@;
+
+    return $res;
+}
+
+sub block_extend {
+    my ($vmid, $disk) = @_;
+
+    return if !PVE::QemuServer::check_running($vmid);
+
+    my $storecfg = PVE::Storage::config();
+
+    my $blockstats = mon_cmd($vmid, "query-blockstats");
+    $blockstats = { map { $_->{device} => $_ } $blockstats->@* };
+
+    lock_blockextend($vmid, 60, sub {
+
+	# return if we do not have the config anymore
+	return if !-f PVE::QemuConfig->config_file($vmid);
+
+	my $conf = PVE::QemuConfig->load_config($vmid);
+
+	my $blockinfo = get_block_info($vmid, $disk, $blockstats);
+	my $deviceid = $blockinfo->{deviceid};
+	my $drive = PVE::QemuServer::parse_drive($deviceid, $conf->{$deviceid});
+	my $volid = $drive->{file};
+
+	die "can't find volid" if !$volid;
+	my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
+	die "can't find sid" if !$sid;
+	my $scfg = PVE::Storage::storage_config($storecfg, $sid);
+
+	my $size = PVE::Storage::volume_size_info($storecfg, $volid, 5);
+	my $chunksize = $scfg->{chunksize} // 1024 * 1024 * 1024;
+	my $newsize = $size + $chunksize;
+
+	#if write are really fast, wr_highest_offset could be already higher than the increment
+	if ($blockinfo->{wr_highest_offset} > $newsize) {
+	    $newsize = $blockinfo->{wr_highest_offset} + $chunksize;
+	}
+
+	PVE::Storage::volume_underlay_resize($storecfg, $volid, $newsize);
+	my $threshold = compute_write_threshold($newsize);
+	qemu_block_set_write_threshold($vmid, $blockinfo->{blocknodeid}, $threshold);
+    });
+}
 1;
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [pve-devel] [PATCH pve-storage 2/5] vdisk_alloc: add underlay_size option
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
                   ` (3 preceding siblings ...)
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 2/6] qm cli: add blockextend Alexandre Derumier via pve-devel
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 3/5] add volume_underlay_resize Alexandre Derumier via pve-devel
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 4624 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH pve-storage 2/5] vdisk_alloc: add underlay_size option
Date: Mon, 26 Aug 2024 13:00:23 +0200
Message-ID: <20240826110030.1744732-6-alexandre.derumier@groupe-cyllene.com>

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 src/PVE/Storage.pm                | 4 ++--
 src/PVE/Storage/LVMQcow2Plugin.pm | 5 ++++-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm
index 97e77c8..385150e 100755
--- a/src/PVE/Storage.pm
+++ b/src/PVE/Storage.pm
@@ -982,7 +982,7 @@ sub unmap_volume {
 }
 
 sub vdisk_alloc {
-    my ($cfg, $storeid, $vmid, $fmt, $name, $size) = @_;
+    my ($cfg, $storeid, $vmid, $fmt, $name, $size, $underlay_size) = @_;
 
     die "no storage ID specified\n" if !$storeid;
 
@@ -1005,7 +1005,7 @@ sub vdisk_alloc {
     # lock shared storage
     return $plugin->cluster_lock_storage($storeid, $scfg->{shared}, undef, sub {
 	my $old_umask = umask(umask|0037);
-	my $volname = eval { $plugin->alloc_image($storeid, $scfg, $vmid, $fmt, $name, $size) };
+	my $volname = eval { $plugin->alloc_image($storeid, $scfg, $vmid, $fmt, $name, $size, $underlay_size) };
 	my $err = $@;
 	umask $old_umask;
 	die $err if $err;
diff --git a/src/PVE/Storage/LVMQcow2Plugin.pm b/src/PVE/Storage/LVMQcow2Plugin.pm
index bdb21cc..2a56c46 100644
--- a/src/PVE/Storage/LVMQcow2Plugin.pm
+++ b/src/PVE/Storage/LVMQcow2Plugin.pm
@@ -77,7 +77,7 @@ sub find_free_diskname {
 }
 
 sub alloc_image {
-    my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
+    my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size, $underlay_size) = @_;
 
     my $sparse = $scfg->{sparse};
 
@@ -87,6 +87,9 @@ sub alloc_image {
     #set minimum size to chunksize
     my $lv_size = $chunksize;
 
+    # we can force the min lv_size for copy. Add a extra chunk.
+    $lv_size = $underlay_size + $chunksize if $underlay_size;
+
     #if no provisioning, $lv_size = $size + a extra chunk for metadatas overhead
     $lv_size = $size + $chunksize if !$sparse;
 
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [pve-devel] [PATCH pve-storage 3/5] add volume_underlay_resize
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
                   ` (4 preceding siblings ...)
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 2/5] vdisk_alloc: add underlay_size option Alexandre Derumier via pve-devel
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 3/6] qmevent: call qm disk blockextend when write_threshold event is received Alexandre Derumier via pve-devel
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 5235 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH pve-storage 3/5] add volume_underlay_resize
Date: Mon, 26 Aug 2024 13:00:24 +0200
Message-ID: <20240826110030.1744732-7-alexandre.derumier@groupe-cyllene.com>

Allow to resize the underlay vm volume

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 src/PVE/Storage.pm                | 18 ++++++++++++++++++
 src/PVE/Storage/LVMQcow2Plugin.pm | 12 ++++++++++++
 src/PVE/Storage/Plugin.pm         |  7 +++++++
 3 files changed, 37 insertions(+)

diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm
index 385150e..8e0f8f1 100755
--- a/src/PVE/Storage.pm
+++ b/src/PVE/Storage.pm
@@ -317,6 +317,24 @@ sub volume_resize {
     }
 }
 
+sub volume_underlay_resize {
+    my ($cfg, $volid, $size) = @_;
+
+    my $padding = (1024 - $size % 1024) % 1024;
+    $size = $size + $padding;
+
+    my ($storeid, $volname) = parse_volume_id($volid, 1);
+    if ($storeid) {
+	my $scfg = storage_config($cfg, $storeid);
+	my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+	return $plugin->volume_underlay_resize($scfg, $storeid, $volname, $size);
+    } elsif ($volid =~ m|^(/.+)$| && -e $volid) {
+	die "resize file/device '$volid' is not possible\n";
+    } else {
+	die "unable to parse volume ID '$volid'\n";
+    }
+}
+
 sub volume_rollback_is_possible {
     my ($cfg, $volid, $snap, $blockers) = @_;
 
diff --git a/src/PVE/Storage/LVMQcow2Plugin.pm b/src/PVE/Storage/LVMQcow2Plugin.pm
index 2a56c46..3b98eeb 100644
--- a/src/PVE/Storage/LVMQcow2Plugin.pm
+++ b/src/PVE/Storage/LVMQcow2Plugin.pm
@@ -191,6 +191,18 @@ sub volume_snapshot_delete {
     return PVE::Storage::Plugin::volume_snapshot_delete($class, $scfg, $storeid, $volname, $snap, $running);
 }
 
+sub volume_underlay_resize {
+    my ($class, $scfg, $storeid, $volname, $size) = @_;
+
+    my $path = $class->filesystem_path($scfg, $volname);
+
+    $size = ($size/1024/1024) . "M";
+    my $cmd = ['/sbin/lvextend', '-L', $size, $path];
+
+    #don't use global cluster lock here, use on native local lvm lock
+    run_command($cmd, errmsg => "error resizing volume '$path'");
+}
+
 sub volume_has_feature {
     my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
 
diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm
index 6444390..e930102 100644
--- a/src/PVE/Storage/Plugin.pm
+++ b/src/PVE/Storage/Plugin.pm
@@ -1071,6 +1071,13 @@ sub volume_resize {
     return undef;
 }
 
+sub volume_underlay_resize {
+    my ($class, $scfg, $storeid, $volname, $size) = @_;
+
+    # do nothing by default
+    return undef;
+}
+
 sub volume_snapshot {
     my ($class, $scfg, $storeid, $volname, $snap) = @_;
 
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [pve-devel] [PATCH qemu-server 3/6] qmevent: call qm disk blockextend when write_threshold event is received
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
                   ` (5 preceding siblings ...)
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 3/5] add volume_underlay_resize Alexandre Derumier via pve-devel
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 4/5] add refresh volume Alexandre Derumier via pve-devel
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 3977 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH qemu-server 3/6] qmevent: call qm disk blockextend when write_threshold event is received
Date: Mon, 26 Aug 2024 13:00:25 +0200
Message-ID: <20240826110030.1744732-8-alexandre.derumier@groupe-cyllene.com>

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 qmeventd/qmeventd.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/qmeventd/qmeventd.c b/qmeventd/qmeventd.c
index d8f3ee7..4f45b6f 100644
--- a/qmeventd/qmeventd.c
+++ b/qmeventd/qmeventd.c
@@ -229,6 +229,33 @@ handle_qmp_event(struct Client *client, struct json_object *obj)
 
 	// check if a backup is running and kill QEMU process if not
 	terminate_check(client);
+    } else if (!strcmp(json_object_get_string(event), "BLOCK_WRITE_THRESHOLD")) {
+
+	struct json_object *data;
+	struct json_object *nodename;
+	if (json_object_object_get_ex(obj, "data", &data) &&
+	    json_object_object_get_ex(data, "node-name", &nodename))
+	{
+	    int pid = fork();
+	    if (pid < 0) {
+		fprintf(stderr, "fork failed: %s\n", strerror(errno));
+		return;
+	    }
+	    if (pid == 0) {
+		char *script = "/usr/sbin/qm";
+		char *args[] = {
+		    script,
+		    "disk",
+		    "blockextend",
+		    client->qemu.vmid,
+		    (char *)json_object_get_string(nodename),
+		    NULL
+		};
+		execvp(script, args);
+		perror("execvp");
+		_exit(1);
+	    }
+	}
     }
 }
 
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [pve-devel] [PATCH pve-storage 4/5] add refresh volume
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
                   ` (6 preceding siblings ...)
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 3/6] qmevent: call qm disk blockextend when write_threshold event is received Alexandre Derumier via pve-devel
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 4/6] migration: refresh remote disk size before resume Alexandre Derumier via pve-devel
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 4783 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH pve-storage 4/5] add refresh volume
Date: Mon, 26 Aug 2024 13:00:26 +0200
Message-ID: <20240826110030.1744732-9-alexandre.derumier@groupe-cyllene.com>

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 src/PVE/Storage.pm                | 13 +++++++++++++
 src/PVE/Storage/LVMQcow2Plugin.pm |  8 ++++++++
 src/PVE/Storage/Plugin.pm         |  6 ++++++
 3 files changed, 27 insertions(+)

diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm
index 8e0f8f1..367b672 100755
--- a/src/PVE/Storage.pm
+++ b/src/PVE/Storage.pm
@@ -1279,6 +1279,19 @@ sub deactivate_volumes {
 	if scalar(@errlist);
 }
 
+sub refresh_volumes {
+    my ($cfg, $vollist) = @_;
+
+    return if !($vollist && scalar(@$vollist));
+
+    foreach my $volid (@$vollist) {
+	my ($storeid, $volname) = parse_volume_id($volid);
+	my $scfg = storage_config($cfg, $storeid);
+	my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+	$plugin->refresh_volume($storeid, $scfg, $volname);
+    }
+}
+
 sub storage_info {
     my ($cfg, $content, $includeformat) = @_;
 
diff --git a/src/PVE/Storage/LVMQcow2Plugin.pm b/src/PVE/Storage/LVMQcow2Plugin.pm
index 3b98eeb..2c17c69 100644
--- a/src/PVE/Storage/LVMQcow2Plugin.pm
+++ b/src/PVE/Storage/LVMQcow2Plugin.pm
@@ -203,6 +203,14 @@ sub volume_underlay_resize {
     run_command($cmd, errmsg => "error resizing volume '$path'");
 }
 
+sub refresh_volume {
+    my ($class, $storeid, $scfg, $volname) = @_;
+
+    my $path = $class->path($scfg, $volname);
+    my $cmd = ['/sbin/lvchange', '--refresh', $path];
+    run_command($cmd, errmsg => "can't refresh LV '$path' for activation");
+}
+
 sub volume_has_feature {
     my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
 
diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm
index e930102..8ff9fbd 100644
--- a/src/PVE/Storage/Plugin.pm
+++ b/src/PVE/Storage/Plugin.pm
@@ -1479,6 +1479,12 @@ sub deactivate_volume {
     # do nothing by default
 }
 
+sub refresh_volume {
+    my ($class, $storeid, $scfg, $volname) = @_;
+
+    # do nothing by default
+}
+
 sub check_connection {
     my ($class, $storeid, $scfg) = @_;
     # do nothing by default
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [pve-devel] [PATCH qemu-server 4/6] migration: refresh remote disk size before resume
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
                   ` (7 preceding siblings ...)
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 4/5] add refresh volume Alexandre Derumier via pve-devel
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 5/5] add volume_underlay_shrink Alexandre Derumier via pve-devel
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 6305 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH qemu-server 4/6] migration: refresh remote disk size before resume
Date: Mon, 26 Aug 2024 13:00:27 +0200
Message-ID: <20240826110030.1744732-10-alexandre.derumier@groupe-cyllene.com>

A blockextend occur on source just before the switch.

we want to be sure that lvm size on target is correctly refreshed,

or we could have io-error is the vm is writing to non available
sectors

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 PVE/CLI/qm.pm                         | 26 ++++++++++++++++++++++++++
 PVE/QemuMigrate.pm                    | 13 +++++++++++++
 test/MigrationTest/QemuMigrateMock.pm |  2 ++
 3 files changed, 41 insertions(+)

diff --git a/PVE/CLI/qm.pm b/PVE/CLI/qm.pm
index 1410ad5..6e258f3 100755
--- a/PVE/CLI/qm.pm
+++ b/PVE/CLI/qm.pm
@@ -553,6 +553,30 @@ __PACKAGE__->register_method ({
 	return;
     }});
 
+__PACKAGE__->register_method ({
+    name => 'refresh',
+    path => 'refresh',
+    method => 'POST',
+    description => "Force storage volume size cache refresh.",
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }),
+	},
+    },
+    returns => { type => 'null'},
+    code => sub {
+	my ($param) = @_;
+
+	my $vmid = extract_param($param, 'vmid');
+	my $conf = PVE::QemuConfig->load_config($vmid);
+	my $storecfg = PVE::Storage::config();
+	my $vols = PVE::QemuServer::get_vm_volumes($conf);
+	PVE::Storage::refresh_volumes($storecfg, $vols);
+
+	return;
+    }});
+
 __PACKAGE__->register_method ({
     name => 'importdisk',
     path => 'importdisk',
@@ -1192,6 +1216,7 @@ our $cmddef = {
     'move-disk' => { alias => 'disk move' },
     move_disk => { alias => 'disk move' },
     rescan => { alias => 'disk rescan' },
+    refresh => { alias => 'disk refresh' },
     resize => { alias => 'disk resize' },
     unlink => { alias => 'disk unlink' },
 
@@ -1202,6 +1227,7 @@ our $cmddef = {
 	resize => [ "PVE::API2::Qemu", 'resize_vm', ['vmid', 'disk', 'size'], { %node } ],
 	unlink => [ "PVE::API2::Qemu", 'unlink', ['vmid'], { %node } ],
 	blockextend => [ __PACKAGE__, 'blockextend', ['vmid', 'disk'], { %node }],
+	refresh => [ __PACKAGE__, 'refresh', ['vmid']],
     },
 
     monitor  => [ __PACKAGE__, 'monitor', ['vmid']],
diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm
index bdcc2e5..9ae9ea1 100644
--- a/PVE/QemuMigrate.pm
+++ b/PVE/QemuMigrate.pm
@@ -1503,6 +1503,19 @@ sub phase3_cleanup {
 	PVE::QemuServer::del_nets_bridge_fdb($conf, $vmid);
 
 	if (!$self->{vm_was_paused}) {
+
+	    # refresh remote volumes size if extend have occured
+            my $cmd = [@{$self->{rem_ssh}}, 'qm', 'disk', 'refresh', $vmid];
+	    my $logf = sub {
+		my $line = shift;
+		$self->log('err', $line);
+	    };
+	    eval { PVE::Tools::run_command($cmd, outfunc => sub {}, errfunc => $logf); };
+	    if (my $err = $@) {
+		$self->log('err', $err);
+		$self->{errors} = 1;
+	    }
+
 	    # config moved and nbd server stopped - now we can resume vm on target
 	    if ($tunnel && $tunnel->{version} && $tunnel->{version} >= 1) {
 		my $cmd = $tunnel->{version} == 1 ? "resume $vmid" : "resume";
diff --git a/test/MigrationTest/QemuMigrateMock.pm b/test/MigrationTest/QemuMigrateMock.pm
index 1efabe2..0057868 100644
--- a/test/MigrationTest/QemuMigrateMock.pm
+++ b/test/MigrationTest/QemuMigrateMock.pm
@@ -306,6 +306,8 @@ $MigrationTest::Shared::tools_module->mock(
 			return 0;
 		    } elsif ($cmd eq 'resume') {
 			return 0;
+		    } elsif ($cmd eq 'disk') {
+			return 0;
 		    } elsif ($cmd eq 'unlock') {
 			my $vmid = shift @{$cmd_tail};;
 			die "unlocking wrong vmid: $vmid\n" if $vmid ne $test_vmid;
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [pve-devel] [PATCH pve-storage 5/5] add volume_underlay_shrink
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
                   ` (8 preceding siblings ...)
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 4/6] migration: refresh remote disk size before resume Alexandre Derumier via pve-devel
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 5/6] qemu_img_format: lvmqcow2 is a path_storage Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 6/6] clone: allocate && shrink lvmcow2 underlay Alexandre Derumier via pve-devel
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 5765 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH pve-storage 5/5] add volume_underlay_shrink
Date: Mon, 26 Aug 2024 13:00:28 +0200
Message-ID: <20240826110030.1744732-11-alexandre.derumier@groupe-cyllene.com>

reduce underlay volume size to minimum used

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 src/PVE/Storage.pm                | 15 +++++++++++++++
 src/PVE/Storage/LVMQcow2Plugin.pm | 31 +++++++++++++++++++++++++++++++
 src/PVE/Storage/Plugin.pm         |  7 +++++++
 3 files changed, 53 insertions(+)

diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm
index 367b672..f3c1a2c 100755
--- a/src/PVE/Storage.pm
+++ b/src/PVE/Storage.pm
@@ -335,6 +335,21 @@ sub volume_underlay_resize {
     }
 }
 
+sub volume_underlay_shrink {
+    my ($cfg, $volid) = @_;
+
+    my ($storeid, $volname) = parse_volume_id($volid, 1);
+    if ($storeid) {
+	my $scfg = storage_config($cfg, $storeid);
+	my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+	return $plugin->volume_underlay_shrink($scfg, $storeid, $volname);
+    } elsif ($volid =~ m|^(/.+)$| && -e $volid) {
+	die "trim file/device '$volid' is not possible\n";
+    } else {
+	die "unable to parse volume ID '$volid'\n";
+    }
+}
+
 sub volume_rollback_is_possible {
     my ($cfg, $volid, $snap, $blockers) = @_;
 
diff --git a/src/PVE/Storage/LVMQcow2Plugin.pm b/src/PVE/Storage/LVMQcow2Plugin.pm
index 2c17c69..7780270 100644
--- a/src/PVE/Storage/LVMQcow2Plugin.pm
+++ b/src/PVE/Storage/LVMQcow2Plugin.pm
@@ -4,6 +4,7 @@ use strict;
 use warnings;
 
 use IO::File;
+use JSON qw(from_json);
 
 use PVE::Tools qw(run_command trim);
 use PVE::Storage::Plugin;
@@ -203,6 +204,36 @@ sub volume_underlay_resize {
     run_command($cmd, errmsg => "error resizing volume '$path'");
 }
 
+sub volume_underlay_shrink {
+    my ($class, $scfg, $storeid, $volname) = @_;
+
+    return if !$scfg->{sparse};
+
+    my ($allocated_size, $format , $required_size, undef) = volume_size_info($class, $scfg, $storeid, $volname, 5);
+
+    #don't reduce if it's full allocated
+    return if $required_size == $allocated_size;
+
+    if(!$required_size) {
+	warn "can't get required size, skip shrinking" if !$required_size;
+    }
+
+    my $chunksize = $scfg->{chunksize} // 1;
+    $chunksize *= 1073741824;
+    my $size = $required_size + $chunksize;
+    my $padding = (1024 - $size % 1024) % 1024;
+    $size = $size + $padding;
+    $size = ($size/1024/1024) . "M";
+
+    my $path = $class->filesystem_path($scfg, $volname);
+
+    my $cmd = ['/sbin/lvreduce', '-y', '-L', $size, $path];
+    eval {
+	run_command($cmd, errmsg => "error shrinking volume '$path'");
+    };
+    warn $@ if $@;
+}
+
 sub refresh_volume {
     my ($class, $storeid, $scfg, $volname) = @_;
 
diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm
index 8ff9fbd..13b049e 100644
--- a/src/PVE/Storage/Plugin.pm
+++ b/src/PVE/Storage/Plugin.pm
@@ -1078,6 +1078,13 @@ sub volume_underlay_resize {
     return undef;
 }
 
+sub volume_underlay_shrink {
+    my ($class, $scfg, $storeid, $volname) = @_;
+
+    # do nothing by default
+    return undef;
+}
+
 sub volume_snapshot {
     my ($class, $scfg, $storeid, $volname, $snap) = @_;
 
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [pve-devel] [PATCH qemu-server 5/6] qemu_img_format: lvmqcow2 is a path_storage
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
                   ` (9 preceding siblings ...)
  2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 5/5] add volume_underlay_shrink Alexandre Derumier via pve-devel
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 6/6] clone: allocate && shrink lvmcow2 underlay Alexandre Derumier via pve-devel
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 3584 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH qemu-server 5/6] qemu_img_format: lvmqcow2 is a path_storage
Date: Mon, 26 Aug 2024 13:00:29 +0200
Message-ID: <20240826110030.1744732-12-alexandre.derumier@groupe-cyllene.com>

needed for snapshot

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 PVE/QemuServer.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index fb67ac9..a6a40cd 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -7922,7 +7922,7 @@ sub qemu_img_format {
 
     # FIXME: this entire function is kind of weird given that `parse_volname`
     # also already gives us a format?
-    my $is_path_storage = $scfg->{path} || $scfg->{type} eq 'esxi';
+    my $is_path_storage = $scfg->{path} || $scfg->{type} eq 'esxi' || $scfg->{type} eq 'lvmqcow2';
 
     if ($is_path_storage && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
 	return $1;
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [pve-devel] [PATCH qemu-server 6/6] clone: allocate && shrink lvmcow2 underlay
       [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
                   ` (10 preceding siblings ...)
  2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 5/6] qemu_img_format: lvmqcow2 is a path_storage Alexandre Derumier via pve-devel
@ 2024-08-26 11:00 ` Alexandre Derumier via pve-devel
  11 siblings, 0 replies; 12+ messages in thread
From: Alexandre Derumier via pve-devel @ 2024-08-26 11:00 UTC (permalink / raw)
  To: pve-devel; +Cc: Alexandre Derumier

[-- Attachment #1: Type: message/rfc822, Size: 3962 bytes --]

From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH qemu-server 6/6] clone: allocate && shrink lvmcow2 underlay
Date: Mon, 26 Aug 2024 13:00:30 +0200
Message-ID: <20240826110030.1744732-13-alexandre.derumier@groupe-cyllene.com>

We allocated the full size for underlay, as we can't easily known what
is the used size of the source.
(we could use qemu-img measure, but for some storage like nfs, it need full read
 to detected sparsiness for example).

Then, after the copy, we use qemu-img measure to detect the exact used size,
and we shrink the underlay

Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
 PVE/QemuServer.pm | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index a6a40cd..7a9641a 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -8274,7 +8274,7 @@ sub clone_disk {
 	    $size = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 10);
 	}
 	$newvolid = PVE::Storage::vdisk_alloc(
-	    $storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024)
+	    $storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024), ($size/1024)
 	);
 	push @$newvollist, $newvolid;
 
@@ -8321,6 +8321,7 @@ sub clone_disk {
 	    }
 	}
     }
+    PVE::Storage::volume_underlay_shrink($storecfg, $newvolid);
 
 no_data_clone:
     my $size = eval { PVE::Storage::volume_size_info($storecfg, $newvolid, 10) };
-- 
2.39.2



[-- 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2024-08-26 11:01 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20240826110030.1744732-1-alexandre.derumier@groupe-cyllene.com>
2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 1/5] add lvmqcow2 plugin Alexandre Derumier via pve-devel
2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 1/6] lvmqcow2: set disk write threshold Alexandre Derumier via pve-devel
2024-08-26 11:00 ` [pve-devel] [PATCH pve-manager 1/1] pvestatd: lvmqcow2 : extend disk on io-error Alexandre Derumier via pve-devel
2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 2/6] qm cli: add blockextend Alexandre Derumier via pve-devel
2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 2/5] vdisk_alloc: add underlay_size option Alexandre Derumier via pve-devel
2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 3/5] add volume_underlay_resize Alexandre Derumier via pve-devel
2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 3/6] qmevent: call qm disk blockextend when write_threshold event is received Alexandre Derumier via pve-devel
2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 4/5] add refresh volume Alexandre Derumier via pve-devel
2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 4/6] migration: refresh remote disk size before resume Alexandre Derumier via pve-devel
2024-08-26 11:00 ` [pve-devel] [PATCH pve-storage 5/5] add volume_underlay_shrink Alexandre Derumier via pve-devel
2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 5/6] qemu_img_format: lvmqcow2 is a path_storage Alexandre Derumier via pve-devel
2024-08-26 11:00 ` [pve-devel] [PATCH qemu-server 6/6] clone: allocate && shrink lvmcow2 underlay Alexandre Derumier via pve-devel

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