[pve-devel] [PATCH storage v5 15/51] plugin: qemu blockdev options: parse protocol paths in default implementation
Fiona Ebner
f.ebner at proxmox.com
Wed Jul 2 18:27:48 CEST 2025
for better backwards compatibility. This also means using path()
rather than filesystem_path() as the latter does not return protocol
paths.
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
More information about the pve-devel
mailing list