From: "Fabian Grünbichler" <f.gruenbichler@proxmox.com>
To: Proxmox VE development discussion <pve-devel@lists.proxmox.com>
Subject: Re: [pve-devel] [PATCH storage 13/26] plugin, btrfs: update list_images and list_volumes
Date: Wed, 30 Jul 2025 10:36:55 +0200 [thread overview]
Message-ID: <1753862076.pz6d0yemxs.astroid@yuna.none> (raw)
In-Reply-To: <20250729111557.136012-14-w.bumiller@proxmox.com>
On July 29, 2025 1:15 pm, Wolfgang Bumiller wrote:
> `list_images()` now takes a vtype.
>
> If it is not set, we act like we did previously by listing *all*
> images. This now includes the vm-vol and ct-vol types ones.
>
> If a new vtype is set (vm-vol or ct-vol), then we list only those.
>
> For "images" we list both 'vm-vol', for "rootdir" we list both
> "ct-vol" and the "rootdir" type.
>
> NOTE: Previously the "rootdir" `content-dirs` option did not take
> effect, which is why the `list_images()` implementation for `rootdir`
> uses the `images` subdir.
> This means that `list_images()` in particular lists all/the same
> untyped images regardless of whether `images` or `rootdir` is used as
> a type. For `list_volumes()`, the previous strategy of using the
> existing VMs to decide the volume-type will be used.
>
> Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
> ---
> src/PVE/Storage/BTRFSPlugin.pm | 44 ++++++++++-
> src/PVE/Storage/Plugin.pm | 139 +++++++++++++++++++++++++++++----
> 2 files changed, 163 insertions(+), 20 deletions(-)
>
> diff --git a/src/PVE/Storage/BTRFSPlugin.pm b/src/PVE/Storage/BTRFSPlugin.pm
> index d1c0cf9..585489c 100644
> --- a/src/PVE/Storage/BTRFSPlugin.pm
> +++ b/src/PVE/Storage/BTRFSPlugin.pm
> @@ -645,13 +645,40 @@ sub volume_has_feature {
> }
>
> sub list_images {
> - my ($class, $storeid, $scfg, $vmid, $vollist, $cache) = @_;
> - my $imagedir = $class->get_subdir($scfg, 'images');
> + my ($class, $storeid, $scfg, $vmid, $vollist, $cache, $content_type) = @_;
> +
> + my @image_dirs;
> + if (defined($content_type)) {
> + if ($content_type eq 'images') {
> + @image_dirs = (
> + [undef, $class->get_subdir($scfg, 'images')],
> + ['vm-vol', $class->get_subdir($scfg, 'vm-vol')],
> + );
> + } elsif ($content_type eq 'rootdir') {
> + # In the legacy case, the 'rootdir' `content-dir` option did not take
> + # effect, so use the 'images' dir for it, as that is what it used to return!
> + @image_dirs = (
> + [undef, $class->get_subdir($scfg, 'images')],
> + ['ct-vol', $class->get_subdir($scfg, 'ct-vol')],
> + );
> + } else {
> + @image_dirs = [$content_type, $class->get_subdir($scfg, $content_type)];
> + }
> + } else {
> + @image_dirs = (
> + [undef, $class->get_subdir($scfg, 'images')],
> + ['vm-vol', $class->get_subdir($scfg, 'vm-vol')],
> + ['ct-vol', $class->get_subdir($scfg, 'ct-vol')],
> + );
> + }
>
> my $res = [];
>
> # Copied from Plugin.pm, with file_size_info calls adapted:
> - foreach my $fn (<$imagedir/[0-9][0-9]*/*>) {
> + my $current_type;
> + my $code = sub {
> + my ($fn) = @_;
> +
> # different to in Plugin.pm the regex below also excludes '@' as valid file name
> next if $fn !~ m@^(/.+/(\d+)/([^/\@.]+(?:\.(qcow2|vmdk|subvol))?))$@;
> $fn = $1; # untaint
> @@ -701,9 +728,20 @@ sub list_images {
> parent => $parent,
> };
>
> + # Only add vtype if it is not 'images'...
> + $info->{vtype} = $current_type if defined($current_type);
> +
> $info->{ctime} = $ctime if $ctime;
>
> push @$res, $info;
> + };
> +
> + my %dedup;
> + for my $dir_entry (@image_dirs) {
> + ($current_type, my $dir) = @$dir_entry;
> + next if $dedup{$dir};
> + $dedup{$dir} = 1;
> + PVE::Storage::Plugin::foreach_guest_file($dir, $code);
> }
>
> return $res;
> diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm
> index 047b2fc..660045d 100644
> --- a/src/PVE/Storage/Plugin.pm
> +++ b/src/PVE/Storage/Plugin.pm
> @@ -10,8 +10,9 @@ use File::chdir;
> use File::Path;
> use File::Basename;
> use File::stat qw();
> +use IO::Dir;
>
> -use PVE::Tools qw(run_command);
> +use PVE::Tools qw(dir_glob_foreach run_command);
> use PVE::JSONSchema qw(get_standard_option register_standard_option);
> use PVE::Cluster qw(cfs_register_file);
>
> @@ -1567,36 +1568,91 @@ sub volume_has_feature {
>
> return undef;
> }
> +#
> +# Given an volume directory, this iterates over vmid directories and recurses
> +# once to the files inside.
> +#
> +# In other words, this is `glob($dir/[0-9][0-9]*/*)`.
> +my $MAX_VMID;
> +
> +sub foreach_guest_file : prototype($$) {
should this go into PVE::Storage::Common?
> + my ($dir, $code) = @_;
> +
> + $MAX_VMID = get_standard_option("pve-vmid")->{maximum} if !defined($MAX_VMID);
> +
> + dir_glob_foreach(
> + $dir,
> + qr/\d+/,
> + sub {
> + my ($vmid) = @_;
> + $vmid = int($vmid);
> + return if $vmid < 100 || $vmid > $MAX_VMID;
this now means list_images lists less than before - somebody might have
used a very high ID as a placeholder not realizing its outside the "allowed" range..
not sure it's worth it to have this restriction here..
> + my $dir = "$dir/$vmid";
> + my $dh = IO::Dir->new($dir) or return;
> + while (defined(my $entry = $dh->read)) {
> + next if $entry eq '.' || $entry eq '..';
> + $code->("$dir/$entry");
> + }
> + close $dh;
> + },
> + );
> +}
>
> sub list_images {
> - my ($class, $storeid, $scfg, $vmid, $vollist, $cache) = @_;
> -
> - my $imagedir = $class->get_subdir($scfg, 'images');
> + my ($class, $storeid, $scfg, $vmid, $vollist, $cache, $content_type) = @_;
> +
> + my @image_dirs;
> + if (defined($content_type)) {
> + if ($content_type eq 'images') {
> + @image_dirs = (
> + [undef, $class->get_subdir($scfg, 'images')],
> + ['vm-vol', $class->get_subdir($scfg, 'vm-vol')],
> + );
> + } elsif ($content_type eq 'rootdir') {
> + # In the legacy case, the 'rootdir' `content-dir` option did not take
> + # effect, so use the 'images' dir for it, as that is what it used to return!
> + @image_dirs = (
> + [undef, $class->get_subdir($scfg, 'images')],
> + ['ct-vol', $class->get_subdir($scfg, 'ct-vol')],
> + );
> + } else {
> + @image_dirs = [$content_type, $class->get_subdir($scfg, $content_type)];
> + }
> + } else {
> + @image_dirs = (
> + [undef, $class->get_subdir($scfg, 'images')],
> + ['vm-vol', $class->get_subdir($scfg, 'vm-vol')],
> + ['ct-vol', $class->get_subdir($scfg, 'ct-vol')],
> + );
> + }
>
> my $format_info = $class->get_formats($scfg, $storeid);
> my $fmts = join('|', sort keys $format_info->{valid}->%*);
>
> my $res = [];
>
> - foreach my $fn (<$imagedir/[0-9][0-9]*/*>) {
> + my $current_type;
> + my $code = sub {
> + my ($fn) = @_;
>
> - next if $fn !~ m!^(/.+/(\d+)/([^/]+\.($fmts)))$!;
> + return if $fn !~ m!^(/.+/(\d+)/([^/]+\.($fmts)))$!;
> $fn = $1; # untaint
>
> my $owner = $2;
> my $name = $3;
> my $format = $4;
>
> - next if !$vollist && defined($vmid) && ($owner ne $vmid);
> + return if !$vollist && defined($vmid) && ($owner ne $vmid);
>
> - my ($size, undef, $used, $parent, $ctime) = eval { file_size_info($fn, undef, $format); };
> + my ($size, undef, $used, $parent, $ctime) =
> + eval { file_size_info($fn, undef, $format); };
> if (my $err = $@) {
> die $err if $err !~ m/Image is not in \S+ format$/;
> warn "image '$fn' is not in expected format '$format', querying as raw\n";
> ($size, undef, $used, $parent, $ctime) = file_size_info($fn, undef, 'raw');
> $format = 'invalid';
> }
> - next if !defined($size);
> + return if !defined($size);
>
> my $volid;
> if ($parent && $parent =~ m!^../(\d+)/([^/]+\.($fmts))$!) {
> @@ -1608,7 +1664,7 @@ sub list_images {
>
> if ($vollist) {
> my $found = grep { $_ eq $volid } @$vollist;
> - next if !$found;
> + return if !$found;
> }
>
> my $info = {
> @@ -1620,9 +1676,19 @@ sub list_images {
> parent => $parent,
> };
>
> + # Only add vtype if it is not 'images'...
> + $info->{vtype} = $current_type if defined($current_type);
> $info->{ctime} = $ctime if $ctime;
>
> push @$res, $info;
> + };
> +
> + my %dedup;
> + for my $dir_entry (@image_dirs) {
> + ($current_type, my $dir) = @$dir_entry;
> + next if $dedup{$dir};
> + $dedup{$dir} = 1;
> + foreach_guest_file($dir, $code);
> }
>
> return $res;
> @@ -1709,12 +1775,29 @@ sub list_volumes {
>
> my $res = [];
> my $vmlist = PVE::Cluster::get_vmlist();
> +
> + my $guest_dirs = 0;
> + my $DIRS_IMAGES = 1 << 0;
> + my $DIRS_VMS = 1 << 1;
> + my $DIRS_CTS = 1 << 2;
> + my $DIRS_ALL = $DIRS_IMAGES | $DIRS_VMS | $DIRS_CTS;
> foreach my $type (@$content_types) {
> my $data;
> + if ($type eq 'images') {
> + $guest_dirs |= $DIRS_IMAGES | $DIRS_VMS;
> + next;
> + } elsif ($type eq 'rootdir') {
> + $guest_dirs |= $DIRS_IMAGES | $DIRS_CTS;
> + next;
> + } elsif ($type eq 'vm-vol') {
> + $guest_dirs |= $DIRS_VMS;
> + next;
> + } elsif ($type eq 'ct-vol') {
> + $guest_dirs |= $DIRS_CTS;
> + next;
> + }
>
> - if ($type eq 'images' || $type eq 'rootdir') {
> - $data = $class->list_images($storeid, $scfg, $vmid);
> - } elsif ($scfg->{path}) {
> + if ($scfg->{path}) {
> my $path = $class->get_subdir($scfg, $type);
>
> if ($type eq 'iso' && !defined($vmid)) {
> @@ -1733,7 +1816,32 @@ sub list_volumes {
> next if !$data;
>
> foreach my $item (@$data) {
> - if ($type eq 'images' || $type eq 'rootdir') {
> + $item->{content} = $type;
> + push @$res, $item;
> + }
> + }
> +
> + if ($guest_dirs) {
> + my $data;
> +
> + if ($guest_dirs == $DIRS_ALL) {
> + $data = $class->list_images($storeid, $scfg, $vmid, undef, undef, undef);
> + } elsif ($guest_dirs == ($DIRS_IMAGES | $DIRS_VMS)) {
> + $data = $class->list_images($storeid, $scfg, $vmid, undef, undef, 'images');
> + } elsif ($guest_dirs == ($DIRS_IMAGES | $DIRS_CTS)) {
> + $data = $class->list_images($storeid, $scfg, $vmid, undef, undef, 'rootdir');
> + } elsif ($guest_dirs == $DIRS_VMS) {
> + $data = $class->list_images($storeid, $scfg, $vmid, undef, undef, 'vm-vol');
> + } elsif ($guest_dirs == $DIRS_CTS) {
> + $data = $class->list_images($storeid, $scfg, $vmid, undef, undef, 'ct-vol');
> + } else {
> + die "unexpected request to list only untyped images\n";
> + }
> +
> + for my $item (@$data) {
> + if (defined(my $vtype = $item->{vtype})) {
> + $item->{content} = $vtype;
> + } else {
> my $vminfo = $vmlist->{ids}->{ $item->{vmid} };
> my $vmtype;
> if (defined($vminfo)) {
> @@ -1744,9 +1852,6 @@ sub list_volumes {
> } else {
> $item->{content} = 'images';
> }
> - next if $type ne $item->{content};
> - } else {
> - $item->{content} = $type;
> }
>
> push @$res, $item;
> --
> 2.47.2
>
>
>
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>
>
>
_______________________________________________
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-30 8:36 UTC|newest]
Thread overview: 74+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-29 11:15 [pve-devel] [RFC storage 00/26+10+3] unify vtype and content-type and Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 01/26] btrfs: remove unnecessary mkpath call Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 02/26] parse_volname: remove openvz 'rootdir' case Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 03/26] drop rootdir case in path_to_volume_id Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 04/26] escape dirs in path_to_volume_id regexes Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 05/26] tests: drop rootdir/ tests Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 06/26] common: use v5.36 Wolfgang Bumiller
2025-07-29 13:59 ` Fiona Ebner
2025-07-29 14:42 ` Thomas Lamprecht
2025-07-29 11:15 ` [pve-devel] [PATCH storage 07/26] common: add pve-storage-vtype standard option with new types Wolfgang Bumiller
2025-07-29 13:50 ` Fiona Ebner
2025-07-29 11:15 ` [pve-devel] [PATCH storage 08/26] prepare for vm-vol and ct-vol content and vtypes Wolfgang Bumiller
2025-07-30 8:38 ` Fabian Grünbichler
2025-08-08 12:01 ` Wolfgang Bumiller
2025-07-30 9:14 ` Fabian Grünbichler
2025-08-08 12:05 ` Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 09/26] plugins: add new content types to all plugindata Wolfgang Bumiller
2025-07-30 8:38 ` Fabian Grünbichler
2025-08-08 12:10 ` Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 10/26] plugins: update volname parsing for new naming convention Wolfgang Bumiller
2025-07-30 8:37 ` Fabian Grünbichler
2025-07-30 8:53 ` Wolfgang Bumiller
2025-07-30 8:58 ` Fabian Grünbichler
2025-07-29 11:15 ` [pve-devel] [PATCH storage 11/26] plugin: add vm/ct-vol to 'local' storage default content types Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 12/26] plugin: support new vtypes in activate_storage checks Wolfgang Bumiller
2025-07-30 8:36 ` Fabian Grünbichler
2025-08-08 13:16 ` Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 13/26] plugin, btrfs: update list_images and list_volumes Wolfgang Bumiller
2025-07-30 8:36 ` Fabian Grünbichler [this message]
2025-07-30 8:41 ` Fiona Ebner
2025-07-29 11:15 ` [pve-devel] [PATCH storage 14/26] plugins: update image/volume listing to support new types Wolfgang Bumiller
2025-07-30 8:36 ` Fabian Grünbichler
2025-07-29 11:15 ` [pve-devel] [PATCH storage 15/26] common: add is_volume_type and is_type_change_allowed helpers Wolfgang Bumiller
2025-07-30 9:01 ` Fabian Grünbichler
2025-07-29 11:15 ` [pve-devel] [PATCH storage 16/26] common: add volume_type_from_name convenience helper Wolfgang Bumiller
2025-07-30 8:36 ` Fabian Grünbichler
2025-07-30 9:09 ` Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 17/26] plugins: add vtype parameter to alloc_image Wolfgang Bumiller
2025-07-30 9:24 ` Fabian Grünbichler
2025-07-30 14:00 ` Max R. Carrara
2025-07-30 14:05 ` Max R. Carrara
2025-07-30 14:26 ` Fabian Grünbichler
2025-07-30 14:49 ` Max R. Carrara
2025-07-30 15:01 ` Fabian Grünbichler
2025-07-29 11:15 ` [pve-devel] [PATCH storage 18/26] plugins: update create_base methods Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 19/26] plugins: update clone_image methods Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 20/26] plugins: update rename_volumes methods Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 21/26] plugins: update volume_import methods Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 22/26] zfs: update 'path' method for new naming scheme Wolfgang Bumiller
2025-07-30 9:31 ` Fabian Grünbichler
2025-07-29 11:15 ` [pve-devel] [PATCH storage 23/26] pvesm: add vtype parameter to import command Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 24/26] api: add vtype parameter to create call Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH storage 25/26] update tests Wolfgang Bumiller
2025-07-29 16:33 ` Max R. Carrara
2025-07-29 11:15 ` [pve-devel] [PATCH storage 26/26] update ApiChangeLog Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH container 1/3] add vtype to vdisk_alloc and vdisk_clone calls Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH container 2/3] expect 'vm-vol' vtype in get_replicatable_volumes Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH container 3/3] add vtype to rename_volume call Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH qemu-server 01/10] add vtype to vdisk_alloc and vdisk_clone calls Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH qemu-server 02/10] add vtype parameter to rename_volume call Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH qemu-server 03/10] expect 'vm-vol' vtype in get_replicatable_volumes Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH qemu-server 04/10] expect 'vm-vol' vtype wherever 'images' was expected Wolfgang Bumiller
2025-07-30 8:40 ` Fabian Grünbichler
2025-07-30 9:17 ` Fiona Ebner
2025-07-30 9:33 ` Fiona Ebner
2025-07-29 11:15 ` [pve-devel] [PATCH qemu-server 05/10] tests: update QmMock to support vtypes Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH qemu-server 06/10] tests: scripted: update tests to new vtypes and paths Wolfgang Bumiller
2025-07-29 14:13 ` Max R. Carrara
2025-07-29 11:15 ` [pve-devel] [PATCH qemu-server 07/10] make tidy Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH qemu-server 08/10] tests: fixup restore test to use new volume naming scheme Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH qemu-server 09/10] tests: update remaining tests to new snapshot paths Wolfgang Bumiller
2025-07-29 11:15 ` [pve-devel] [PATCH qemu-server 10/10] tests: regenerate cfg2cmd files Wolfgang Bumiller
2025-07-29 14:19 ` Max R. Carrara
2025-07-29 15:34 ` [pve-devel] partially-applied: [RFC storage 00/26+10+3] unify vtype and content-type and Fiona Ebner
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=1753862076.pz6d0yemxs.astroid@yuna.none \
--to=f.gruenbichler@proxmox.com \
--cc=pve-devel@lists.proxmox.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