[pve-devel] [PATCH storage v5 15/51] plugin: qemu blockdev options: parse protocol paths in default implementation
Fabian Grünbichler
f.gruenbichler at proxmox.com
Thu Jul 3 11:38:50 CEST 2025
Quoting Fiona Ebner (2025-07-02 18:27:48)
> for better backwards compatibility. This also means using path()
> rather than filesystem_path() as the latter does not return protocol
> paths.
I guess I should have read until here before replying to the other patch, sorry
for the noise ;)
>
> Some protocol paths are not implemented (considered all that are
> listed by grepping for '\.protocol_name' in QEMU):
> - ftp(s)/http(s), which would access web servers via curl. This one
> could be added if there is enough interest.
> - nvme://XXXX:XX:XX.X/X, which would access a host NVME device.
> - null-{aio,co}, which are mainly useful for debugging.
> - pbs, because path-based access is not used anymore for PBS,
> live-restore in qemu-server already defines a driver-based device.
> - nfs and ssh, because the QEMU build script used by Proxmox VE does
> not enable them.
> - blk{debug,verify}, because they are for debugging.
> - the ones used by blkio, i.e. io_uring, nvme-io_uring,
> virtio-blk-vfio-pci, virtio-blk-vhost-user and
> virtio-blk-vhost-vdpa, because the QEMU build script used by Proxmox
> VE does not enable blkio.
> - backup-dump and zeroinit, because they should not be used by the
> storage layer directly.
> - gluster, because support is dropped in Proxmox VE 9.
> - host_cdrom, because the storage layer should not access host CD-ROM
> devices.
> - fat, because it hopefully isn't used by any third-party plugin here.
>
> Co-developed-by: Alexandre Derumier <alexandre.derumier at groupe-cyllene.com>
> Signed-off-by: Fiona Ebner <f.ebner at proxmox.com>
> ---
>
> New in v5.
>
> src/PVE/Storage/Plugin.pm | 95 ++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 94 insertions(+), 1 deletion(-)
>
> diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm
> index 3f2c638..c2f376b 100644
> --- a/src/PVE/Storage/Plugin.pm
> +++ b/src/PVE/Storage/Plugin.pm
> @@ -1961,6 +1961,34 @@ sub rename_volume {
> return "${storeid}:${base}${target_vmid}/${target_volname}";
> }
>
> +my sub blockdev_options_nbd_tcp {
> + my ($host, $port, $export) = @_;
> +
> + die "blockdev_options_nbd_tcp: no host" if !defined($host);
> +
> + my $blockdev = {};
> +
> + my $server = { type => 'inet', host => "$host" };
> + # port is also a string in QAPI, not optional, default for NBD is 10809
> + $server->{port} = defined($port) ? "$port" : "10809";
> + $blockdev = { driver => 'nbd', server => $server };
> + $blockdev->{export} = "$export" if defined($export);
> +
> + return $blockdev;
> +}
> +
> +my sub blockdev_options_nbd_unix {
> + my ($socket_path, $export) = @_;
> +
> + my $blockdev = {};
> +
> + my $server = { type => 'unix', path => "$socket_path" };
> + $blockdev = { driver => 'nbd', server => $server };
> + $blockdev->{export} = "$export" if defined($export);
> +
> + return $blockdev;
> +}
> +
> =pod
>
> =head3 qemu_blockdev_options
> @@ -2031,7 +2059,7 @@ sub qemu_blockdev_options {
>
> my $blockdev = {};
>
> - my ($path) = $class->filesystem_path($scfg, $volname, $options->{'snapshot-name'});
> + my ($path) = $class->path($scfg, $volname, $storeid, $options->{'snapshot-name'});
>
> if ($path =~ m|^/|) {
> # For qcow2 and qed the path of a snapshot will be the same, but it's not possible to attach
> @@ -2046,6 +2074,71 @@ sub qemu_blockdev_options {
> my $st = File::stat::stat($path) or die "stat for '$path' failed - $!\n";
> my $driver = (S_ISCHR($st->mode) || S_ISBLK($st->mode)) ? 'host_device' : 'file';
> $blockdev = { driver => $driver, filename => $path };
> + } elsif ($path =~ m|^file:(\S+)|) {
> + $blockdev = { driver => 'file', filename => "$1" };
> + } elsif ($path =~ m|^host_device:(\S+)|) {
> + $blockdev = { driver => 'host_device', filename => "$1" };
> + } elsif ($path =~ m|^iscsi://(\S+)/(\S+)/(\d+)$|) {
> + $blockdev =
> + { driver => 'iscsi', portal => "$1", target => "$2", lun => "$3", transport => "tcp" };
> + } elsif ($path =~ m|^iser://(\S+)/(\S+)/(\d+)$|) {
> + $blockdev =
> + { driver => 'iscsi', portal => "$1", target => "$2", lun => "$3", transport => "iser" };
> + } elsif ($path =~ m|^nbd(?:\+tcp)?://(\S+?)(?::(\d+))?/(\S+)?$|) { # new style NBD TCP URI
> + $blockdev = blockdev_options_nbd_tcp($1, $2, $3);
> + } elsif ($path =~ m|^nbd(?:\+tcp)?:(\S+):(\d+)(?::exportname=(\S+))?$|) {
> + # old style NBD TCP URI
> + $blockdev = blockdev_options_nbd_tcp($1, $2, $3);
> + } elsif ($path =~ m|^nbd\+unix:///(\S+)?\?socket=(\S+)$|) { # new style NBD unix URI
> + $blockdev = blockdev_options_nbd_unix($2, $1); # note the order!
> + } elsif ($path =~ m|^nbd:unix:(\S+?)(?::exportname=(\S+))?$|) { # old style NBD unix URI
> + $blockdev = blockdev_options_nbd_unix($1, $2);
> + } elsif ($path =~ m/^rbd:(\S+)$/) {
> + my $rbd_options = $1;
> + $blockdev->{driver} = 'rbd';
> +
> + #map options to key=value pair (if not key is provided, this is the image)
> + #options are seprated with : but we need to exclude \: used for ipv6 address
> + my $options = {
> + map {
> + s/\\:/:/g;
> + /^(.*?)=(.*)/ ? ($1 => $2) : (image => $_)
> + } $rbd_options =~ /(?:\\:|\[[^\]]*\]|[^:\\])+/g
> + };
> +
> + $blockdev->{'auth-client-required'} = [$options->{'auth_supported'}]
> + if $options->{'auth_supported'};
> + $blockdev->{'conf'} = $options->{'conf'} if $options->{'conf'};
> + $blockdev->{'user'} = $options->{'id'} if $options->{'id'};
> +
> + if ($options->{'mon_host'}) {
> + my $server = [];
> + my @mons = split(';', $options->{'mon_host'});
> + for my $mon (@mons) {
> + $mon =~ s/[\[\]]//g;
> + my ($host, $port) = PVE::Tools::parse_host_and_port($mon);
> + $port = '3300' if !$port;
> + push @$server, { host => $host, port => $port };
> + }
> + $blockdev->{server} = $server;
> + }
> +
> + if ($options->{'image'} =~ m|^(\S+)/(\S+)$|) {
> + $blockdev->{pool} = $1;
> + $blockdev->{image} = $2;
> + if ($blockdev->{image} =~ m|^(\S+)/(\S+)$|) {
> + $blockdev->{namespace} = $1;
> + $blockdev->{image} = $2;
> + }
> + }
> +
> + delete($options->@{qw(auth_supported conf id mon_host image)});
> +
> + # Map rest directly. With -drive, it was possible to use arbitrary key-value-pairs. Like
> + # this, there will be warnings for those that are not allowed via blockdev.
> + for my $opt (keys $options->%*) {
> + $blockdev->{$opt} = $options->{$opt};
> + }
> } else {
> die "storage plugin doesn't implement qemu_blockdev_options() method\n";
> }
> --
> 2.47.2
>
>
>
> _______________________________________________
> pve-devel mailing list
> pve-devel at lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>
>
More information about the pve-devel
mailing list