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 FOLLOW-UP storage 02/14] helpers: move qemu_img* to Common module
Date: Wed, 16 Jul 2025 08:31:39 +0200 [thread overview]
Message-ID: <mailman.1490.1752647526.395.pve-devel@lists.proxmox.com> (raw)
In-Reply-To: <20250716063153.1647681-1-alexandre.derumier@groupe-cyllene.com>
[-- Attachment #1: Type: message/rfc822, Size: 16264 bytes --]
From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH FOLLOW-UP storage 02/14] helpers: move qemu_img* to Common module
Date: Wed, 16 Jul 2025 08:31:39 +0200
Message-ID: <20250716063153.1647681-5-alexandre.derumier@groupe-cyllene.com>
From: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
src/PVE/Storage/Common.pm | 147 ++++++++++++++++++++++++++++++---
src/PVE/Storage/LVMPlugin.pm | 10 +--
src/PVE/Storage/Plugin.pm | 153 +++--------------------------------
3 files changed, 152 insertions(+), 158 deletions(-)
diff --git a/src/PVE/Storage/Common.pm b/src/PVE/Storage/Common.pm
index aa89e68..71d123a 100644
--- a/src/PVE/Storage/Common.pm
+++ b/src/PVE/Storage/Common.pm
@@ -111,18 +111,7 @@ sub deallocate : prototype($$$) {
}
}
-=pod
-
-=head3 run_qemu_img_json
-
- run_qemu_img_json($cmd, $timeout)
-
-Execute qemu_img command C<$cmd> with a timeout C<$timeout>.
-Parse the output result and return a json.
-
-=cut
-
-sub run_qemu_img_json {
+my sub run_qemu_img_json {
my ($cmd, $timeout) = @_;
my $json = '';
my $err_output = '';
@@ -143,4 +132,138 @@ sub run_qemu_img_json {
}
return $json;
}
+
+=pod
+
+=head3 qemu_img_create
+
+ qemu_img_create($fmt, $size, $path, $options)
+
+Create a new qemu image with a specific format C<$format> and size C<$size> for a target C<$path>.
+
+C<$options> currently allows setting the C<preallocation> value
+
+=cut
+
+sub qemu_img_create {
+ my ($fmt, $size, $path, $options) = @_;
+
+ my $cmd = ['/usr/bin/qemu-img', 'create'];
+
+ push @$cmd, '-o', "preallocation=$options->{preallocation}"
+ if defined($options->{preallocation});
+
+ push @$cmd, '-f', $fmt, $path, "${size}K";
+
+ run_command($cmd, errmsg => "unable to create image");
+}
+
+=pod
+
+=head3 qemu_img_create_qcow2_backed
+
+ qemu_img_create_qcow2_backed($path, $backing_path, $backing_format, $options)
+
+Create a new qemu qcow2 image C<$path> using an existing backing image C<$backing_path> with backing_format C<$backing_format>.
+
+C<$options> currently allows setting the C<preallocation> value.
+
+=cut
+
+sub qemu_img_create_qcow2_backed {
+ my ($path, $backing_path, $backing_format, $options) = @_;
+
+ my $cmd = [
+ '/usr/bin/qemu-img',
+ 'create',
+ '-F',
+ $backing_format,
+ '-b',
+ $backing_path,
+ '-f',
+ 'qcow2',
+ $path,
+ ];
+
+ # TODO make this configurable for all volumes/types and pass in via $options
+ my $opts = ['extended_l2=on', 'cluster_size=128k'];
+
+ push @$opts, "preallocation=$options->{preallocation}"
+ if defined($options->{preallocation});
+ push @$cmd, '-o', join(',', @$opts) if @$opts > 0;
+
+ run_command($cmd, errmsg => "unable to create image");
+}
+
+=pod
+
+=head3 qemu_img_info
+
+ qemu_img_info($filename, $file_format, $timeout, $follow_backing_files)
+
+Returns a json with qemu image C<$filename> informations with format <$file_format>.
+If C<$follow_backing_files> option is defined, return a json with the whole chain
+of backing files images.
+
+=cut
+
+sub qemu_img_info {
+ my ($filename, $file_format, $timeout, $follow_backing_files) = @_;
+
+ my $cmd = ['/usr/bin/qemu-img', 'info', '--output=json', $filename];
+ push $cmd->@*, '-f', $file_format if $file_format;
+ push $cmd->@*, '--backing-chain' if $follow_backing_files;
+
+ return run_qemu_img_json($cmd, $timeout);
+}
+
+=pod
+
+=head3 qemu_img_measure
+
+ qemu_img_measure($size, $fmt, $timeout, $options)
+
+Returns a json with the maximum size including all metadatas overhead for an image with format C<$fmt> and original size C<$size>Kb.
+
+C<$options> allows specifying qemu-img options that might affect the sizing calculation, such as cluster size.
+
+=cut
+
+sub qemu_img_measure {
+ my ($size, $fmt, $timeout, $options) = @_;
+
+ die "format is missing" if !$fmt;
+
+ my $cmd = ['/usr/bin/qemu-img', 'measure', '--output=json', '--size', "${size}K", '-O', $fmt];
+ if ($options) {
+ push $cmd->@*, '-o', join(',', @$options) if @$options > 0;
+ }
+ return run_qemu_img_json($cmd, $timeout);
+}
+
+=pod
+
+=head3 qemu_img_resize
+
+ qemu_img_resize($scfg, $path, $format, $size, $preallocation, $timeout)
+
+Resize a qemu image C<$path> with format C<$format> to a target Kb size C<$size>.
+Default timeout C<$timeout> is 10s if not specified.
+C<$preallocation> allows to specify the preallocation option for the resize operation.
+
+=cut
+
+sub qemu_img_resize {
+ my ($scfg, $path, $format, $size, $preallocation, $timeout) = @_;
+
+ die "format is missing" if !$format;
+
+ my $cmd = ['/usr/bin/qemu-img', 'resize'];
+ push $cmd->@*, "--preallocation=$preallocation" if $preallocation;
+ push $cmd->@*, '-f', $format, $path, $size;
+
+ $timeout = 10 if !$timeout;
+ run_command($cmd, timeout => $timeout);
+}
+
1;
diff --git a/src/PVE/Storage/LVMPlugin.pm b/src/PVE/Storage/LVMPlugin.pm
index f90df18..4b60e32 100644
--- a/src/PVE/Storage/LVMPlugin.pm
+++ b/src/PVE/Storage/LVMPlugin.pm
@@ -584,9 +584,9 @@ my sub lvm_qcow2_format {
};
if ($backing_snap) {
my $backing_path = $class->path($scfg, $name, $storeid, $backing_snap);
- PVE::Storage::Plugin::qemu_img_create_qcow2_backed($path, $backing_path, $fmt, $options);
+ PVE::Storage::Common::qemu_img_create_qcow2_backed($path, $backing_path, $fmt, $options);
} else {
- PVE::Storage::Plugin::qemu_img_create($fmt, $size, $path, $options);
+ PVE::Storage::Common::qemu_img_create($fmt, $size, $path, $options);
}
}
@@ -598,7 +598,7 @@ my sub calculate_lvm_size {
my $options = $backing_snap ? ['extended_l2=on', 'cluster_size=128k'] : [];
- my $json = PVE::Storage::Plugin::qemu_img_measure($size, $fmt, 5, $options);
+ my $json = PVE::Storage::Common::qemu_img_measure($size, $fmt, 5, $options);
die "failed to query file information with qemu-img measure\n" if !$json;
my $info = eval { decode_json($json) };
if ($@) {
@@ -871,8 +871,8 @@ sub volume_resize {
);
if (!$running && $format eq 'qcow2') {
- my $preallocation = PVE::Storage::Plugin::preallocation_cmd_opt($scfg, $fmt);
- PVE::Storage::Plugin::qemu_img_resize($path, $format, $size, $preallocation, 10);
+ my $preallocation = PVE::Storage::Plugin::preallocation_cmd_opt($scfg, $format);
+ PVE::Storage::Common::qemu_img_resize($path, $format, $size, $preallocation, 10);
}
return 1;
diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm
index 6eb91b7..aee145f 100644
--- a/src/PVE/Storage/Plugin.pm
+++ b/src/PVE/Storage/Plugin.pm
@@ -51,10 +51,6 @@ our $RAW_PREALLOCATION = {
full => 1,
};
-my $QCOW2_CLUSTERS = {
- backed => ['extended_l2=on', 'cluster_size=128k'],
-};
-
our $MAX_VOLUMES_PER_GUEST = 1024;
cfs_register_file(
@@ -640,137 +636,6 @@ sub preallocation_cmd_opt {
return;
}
-=pod
-
-=head3 qemu_img_create
-
- qemu_img_create($fmt, $size, $path, $options)
-
-Create a new qemu image with a specific format C<$format> and size C<$size> for a target C<$path>.
-
-C<$options> currently allows setting the C<preallocation> value
-
-=cut
-
-sub qemu_img_create {
- my ($fmt, $size, $path, $options) = @_;
-
- my $cmd = ['/usr/bin/qemu-img', 'create'];
-
- push @$cmd, '-o', "preallocation=$options->{preallocation}"
- if defined($options->{preallocation});
-
- push @$cmd, '-f', $fmt, $path, "${size}K";
-
- run_command($cmd, errmsg => "unable to create image");
-}
-
-=pod
-
-=head3 qemu_img_create_qcow2_backed
-
- qemu_img_create_qcow2_backed($path, $backing_path, $backing_format, $options)
-
-Create a new qemu qcow2 image C<$path> using an existing backing image C<$backing_path> with backing_format C<$backing_format>.
-
-C<$options> currently allows setting the C<preallocation> value.
-
-=cut
-
-sub qemu_img_create_qcow2_backed {
- my ($path, $backing_path, $backing_format, $options) = @_;
-
- my $cmd = [
- '/usr/bin/qemu-img',
- 'create',
- '-F',
- $backing_format,
- '-b',
- $backing_path,
- '-f',
- 'qcow2',
- $path,
- ];
-
- my $opts = $QCOW2_CLUSTERS->{backed};
-
- push @$opts, $options->{preallocation} if defined($options->{preallocation});
- push @$cmd, '-o', join(',', @$opts) if @$opts > 0;
-
- run_command($cmd, errmsg => "unable to create image");
-}
-
-=pod
-
-=head3 qemu_img_info
-
- qemu_img_info($filename, $file_format, $timeout, $follow_backing_files)
-
-Returns a json with qemu image C<$filename> informations with format <$file_format>.
-If C<$follow_backing_files> option is defined, return a json with the whole chain
-of backing files images.
-
-=cut
-
-sub qemu_img_info {
- my ($filename, $file_format, $timeout, $follow_backing_files) = @_;
-
- my $cmd = ['/usr/bin/qemu-img', 'info', '--output=json', $filename];
- push $cmd->@*, '-f', $file_format if $file_format;
- push $cmd->@*, '--backing-chain' if $follow_backing_files;
-
- return PVE::Storage::Common::run_qemu_img_json($cmd, $timeout);
-}
-
-=pod
-
-=head3 qemu_img_measure
-
- qemu_img_measure($size, $fmt, $timeout, $options)
-
-Returns a json with the maximum size including all metadatas overhead for an image with format C<$fmt> and original size C<$size>Kb.
-
-C<$options> allows specifying qemu-img options that might affect the sizing calculation, such as cluster size.
-
-=cut
-
-sub qemu_img_measure {
- my ($size, $fmt, $timeout, $options) = @_;
-
- die "format is missing" if !$fmt;
-
- my $cmd = ['/usr/bin/qemu-img', 'measure', '--output=json', '--size', "${size}K", '-O', $fmt];
- if ($options) {
- push $cmd->@*, '-o', join(',', @$options) if @$options > 0;
- }
- return PVE::Storage::Common::run_qemu_img_json($cmd, $timeout);
-}
-
-=pod
-
-=head3 qemu_img_resize
-
- qemu_img_resize($scfg, $path, $format, $size, $preallocation, $timeout)
-
-Resize a qemu image C<$path> with format C<$format> to a target Kb size C<$size>.
-Default timeout C<$timeout> is 10s if not specified.
-C<$preallocation> allows to specify the preallocation option for the resize operation.
-
-=cut
-
-sub qemu_img_resize {
- my ($scfg, $path, $format, $size, $preallocation, $timeout) = @_;
-
- die "format is missing" if !$format;
-
- my $cmd = ['/usr/bin/qemu-img', 'resize'];
- push $cmd->@*, "--preallocation=$preallocation" if $preallocation;
- push $cmd->@*, '-f', $format, $path, $size;
-
- $timeout = 10 if !$timeout;
- run_command($cmd, timeout => $timeout);
-}
-
# Storage implementation
# called during addition of storage (before the new storage config got written)
@@ -1076,7 +941,9 @@ sub clone_image {
my $options = {
preallocation => preallocation_cmd_opt($scfg, $format),
};
- qemu_img_create_qcow2_backed($path, "../$basevmid/$basename", $format, $options);
+ PVE::Storage::Common::qemu_img_create_qcow2_backed(
+ $path, "../$basevmid/$basename", $format, $options,
+ );
};
my $err = $@;
@@ -1117,7 +984,7 @@ sub alloc_image {
my $preallocation = preallocation_cmd_opt($scfg, $fmt);
my $options = {};
$options->{preallocation} = $preallocation if $preallocation;
- eval { qemu_img_create($fmt, $size, $path, $options) };
+ eval { PVE::Storage::Common::qemu_img_create($fmt, $size, $path, $options) };
if ($@) {
unlink $path;
rmdir $imagedir;
@@ -1139,7 +1006,11 @@ my sub alloc_backed_image {
$options->{preallocation} = $preallocation if $preallocation;
my $backing_volname = get_snap_name($class, $volname, $backing_snap);
#qemu_img use relative path from base image for the backing_volname by default
- eval { qemu_img_create_qcow2_backed($path, $backing_volname, $backing_format, $options) };
+ eval {
+ PVE::Storage::Common::qemu_img_create_qcow2_backed(
+ $path, $backing_volname, $backing_format, $options,
+ );
+ };
if ($@) {
unlink $path;
die "$@";
@@ -1271,7 +1142,7 @@ sub file_size_info {
"file_size_info: '$filename': falling back to 'raw' from unknown format '$file_format'\n";
$file_format = 'raw';
}
- my $json = qemu_img_info($filename, $file_format, $timeout);
+ my $json = PVE::Storage::Common::qemu_img_info($filename, $file_format, $timeout);
if (!$json) {
die "failed to query file information with qemu-img\n" if $untrusted;
# skip decoding if there was no output, e.g. if there was a timeout.
@@ -1387,7 +1258,7 @@ sub volume_resize {
my $format = ($class->parse_volname($volname))[6];
my $preallocation = preallocation_cmd_opt($scfg, $format);
- qemu_img_resize($path, $format, $size, $preallocation, 10);
+ PVE::Storage::Common::qemu_img_resize($path, $format, $size, $preallocation, 10);
return undef;
}
@@ -1879,7 +1750,7 @@ sub volume_snapshot_info {
my ($vtype, $name, $vmid, $basename, $basevmid, $isBase, $format) =
$class->parse_volname($volname);
- my $json = qemu_img_info($path, undef, 10, 1);
+ my $json = PVE::Storage::Common::qemu_img_info($path, undef, 10, 1);
die "failed to query file information with qemu-img\n" if !$json;
my $json_decode = eval { decode_json($json) };
if ($@) {
--
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-07-16 6:31 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20250716063153.1647681-1-alexandre.derumier@groupe-cyllene.com>
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP qemu-server 1/4] api2: move_disk: use parse_volname to find old volume format Alexandre Derumier via pve-devel
2025-07-16 13:58 ` [pve-devel] applied-series: " Wolfgang Bumiller
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 01/14] helpers: make qemu_img* storage config independent Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP qemu-server 2/4] blockdev_rename: remove old left-over rename() Alexandre Derumier via pve-devel
2025-07-16 6:31 ` Alexandre Derumier via pve-devel [this message]
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP qemu-server 3/4] generate_backing_blockdev: use current_sub for private recursive Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 03/14] rename_snapshot: fix parameter checks Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP qemu-server 4/4] blockdev_external_snapshot: rework to avoid $running param Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 04/14] lvm snapshot: activate volume Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 05/14] common: fix qemu_img_resize Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 06/14] plugin: volume_export: don't allow export of external snapshots Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 07/14] lvmplugin: alloc_snap_image: die if file_size_info return empty size Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 08/14] lvmplugin: snapshot: use relative path for backing image Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 09/14] plugin|lvmplugin: don't allow volume rename if external snapshots exist Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 10/14] lvmplugin: add volume_snapshot_info Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 11/14] plugin: lvmplugin: add parse_snap_name Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 12/14] plugin : improve parse_namedir warning Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 13/14] lvmplugin: add external-snapshots option && forbid creation of qcow2 volumes without it Alexandre Derumier via pve-devel
2025-07-16 6:31 ` [pve-devel] [PATCH FOLLOW-UP storage 14/14] storage: remove $running param from volume_snapshot 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.1490.1752647526.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.