[pve-devel] [PATCH] Add Multipath direct storage plugin and enable it.

Wolfgang Bumiller w.bumiller at proxmox.com
Wed Jun 29 15:34:33 CEST 2016


Before going over the code I want to bring to your attention this code
snippet from the iSCSI (non-direct) plugin:

|	    #check multipath           
|	    if (-d "/sys/block/$bdev/holders") { 
|		my $multipathdev = dir_glob_regex("/sys/block/$bdev/holders", '[A-Za-z]\S*');
|		$bdev = $multipathdev if $multipathdev;
|	    }

The iSCSI plugin *should* notice multipath devices and make use of them
if I'm not mistaken here.
I wonder if it might be better to do the same in the iSCSI-direct
plugin?

Because currently there's one major problem with your current code: it
seems to include more than just multipath devices, iow. all disks on my
machine here.

I wonder if this is maybe a too general approach to what you're really
after?

A few inline comments follow:

On Wed, Jun 29, 2016 at 02:00:42PM +0300, Dmitry Petuhov wrote:
> Signed-off-by: Dmitry Petuhov <mityapetuhov at gmail.com>
> ---
>  PVE/Storage.pm                |   2 +
>  PVE/Storage/MPDirectPlugin.pm | 208 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 210 insertions(+)
>  create mode 100644 PVE/Storage/MPDirectPlugin.pm
> 
> diff --git a/PVE/Storage.pm b/PVE/Storage.pm
> index 011c4f3..ddf9ffe 100755
> --- a/PVE/Storage.pm
> +++ b/PVE/Storage.pm
> @@ -32,6 +32,7 @@ use PVE::Storage::GlusterfsPlugin;
>  use PVE::Storage::ZFSPoolPlugin;
>  use PVE::Storage::ZFSPlugin;
>  use PVE::Storage::DRBDPlugin;
> +use PVE::Storage::MPDirectPlugin;
>  
>  # load and initialize all plugins
>  PVE::Storage::DirPlugin->register();
> @@ -46,6 +47,7 @@ PVE::Storage::GlusterfsPlugin->register();
>  PVE::Storage::ZFSPoolPlugin->register();
>  PVE::Storage::ZFSPlugin->register();
>  PVE::Storage::DRBDPlugin->register();
> +PVE::Storage::MPDirectPlugin->register();
>  PVE::Storage::Plugin->init();
>  
>  my $UDEVADM = '/sbin/udevadm';
> diff --git a/PVE/Storage/MPDirectPlugin.pm b/PVE/Storage/MPDirectPlugin.pm
> new file mode 100644
> index 0000000..76ced94
> --- /dev/null
> +++ b/PVE/Storage/MPDirectPlugin.pm
> @@ -0,0 +1,208 @@
> +package PVE::Storage::MPDirectPlugin;
> +
> +use strict;
> +use warnings;
> +use Data::Dumper;
> +use IO::File;
> +use PVE::Tools qw(run_command trim);
> +use PVE::Storage::Plugin;
> +use PVE::JSONSchema qw(get_standard_option);
> +
> +use base qw(PVE::Storage::Plugin);
> +
> +# Configuration
> +
> +sub type {
> +    return 'mpdirect';
> +}
> +
> +sub plugindata {
> +    return {
> +	content => [ {images => 1, rootdir => 1, none => 1}, { images => 1 }],
> +    };
> +}
> +
> +sub properties {
> +    return {
> +    };
> +}
> +
> +sub options {
> +    return {
> +	content => { optional => 1 },
> +    };
> +}
> +
> +# Storage implementation
> +
> +sub parse_volname {
> +    my ($class, $volname) = @_;
> +
> +    return ('images', $volname, undef, undef, undef, undef, 'raw');
> +}
> +
> +sub filesystem_path {
> +    my ($class, $scfg, $volname, $snapname) = @_;
> +
> +    die "Direct attached device snapshot is not implemented" if defined($snapname);
> +
> +    my ($vtype, $name, $vmid) = $class->parse_volname($volname);
> +
> +    my $path = "/dev/disk/by-id/wwn-0x$name";
> +
> +    return wantarray ? ($path, $vmid, $vtype) : $path;
> +}
> +
> +sub create_base {
> +    my ($class, $storeid, $scfg, $volname) = @_;
> +
> +    die "Cannot create physical device";
> +}
> +
> +sub clone_image {
> +    my ($class, $scfg, $storeid, $volname, $vmid, $snap) = @_;
> +
> +    die "Cannot create physical device";
> +}
> +
> +sub alloc_image {
> +    my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
> +
> +    die "Cannot create physical device";
> +}
> +
> +sub free_image {
> +    my ($class, $storeid, $scfg, $volname, $isBase) = @_;
> +
> +    die "Cannot create physical device";
> +}
> +
> +sub list_images {
> +    my ($class, $storeid, $scfg, $vmid, $vollist, $cache) = @_;
> +
> +    my $vgname = $scfg->{vgname};
> +
> +    my $res = [];
> +
> +    opendir my $dir, '/dev/disk/by-id' || die "Cannot list disks";
> +
> +    while (my $disk = readdir $dir) {
> +	# We don't want partitions here
> +	next if $disk =~ m/-part\d+$/;
> +
> +	next if $disk !~ m/^wwn-0x(.+)$/;
> +	my $wwid = $1;

This includes all disks, not just multipath devices.

# multipath -ll
# ls -l /dev/disk/by-id |grep wwn- |grep -v -- -part
lrwxrwxrwx 1 root root  9 Jun 29 09:09 wwn-0x5000c50064bbed7d -> ../../sdd
lrwxrwxrwx 1 root root  9 Jun 29 09:09 wwn-0x5002538d409de6ec -> ../../sdb
lrwxrwxrwx 1 root root  9 Jun 29 09:09 wwn-0x500a07510e6af4b5 -> ../../sdc
lrwxrwxrwx 1 root root  9 Jun 29 09:09 wwn-0x55cd2e404c608ca2 -> ../../sda
lrwxrwxrwx 1 root root  9 Jun 29 09:11 wwn-0x60014059c03c50c2e8b4d99972140221 -> ../../sdf

> +
> +	my $volid = "$storeid:$wwid";
> +
> +	if ($vollist) {
> +	    my $found = grep { $_ eq $volid } @$vollist;
> +	    next if !$found;
> +	} else {
> +	    next if defined($vmid);
> +	}
> +
> +	my $actualdev = readlink "/dev/disk/by-id/$disk";
> +	$actualdev =~ s/..\/..\///;

would be easier to read with a different regex symbol, eg: s at ../../@@;

> +
> +	my $size;
> +	if (open SZ, "/sys/block/$actualdev/size" ) {

We have a helper for this:
  file_read_firstline("/sys/block/$actualdev/size");

For future reference: for new code our prefered style there should use
variables and include the open-mode:
  open my $sz, '<', "/sys/block/$actualdev/size"

> +	    $size = <SZ>;
> +	    $size *= 512;
> +	    close SZ;
> +	} else {
> +	    $size = undef;
> +	}
> +
> +	push @$res, {
> +	    volid => $volid, format => 'raw', size => $size,
> +	};
> +    }
> +    closedir $dir;
> +
> +    return $res;
> +}
> +
> +sub status {
> +    my ($class, $storeid, $scfg, $cache) = @_;
> +
> +    # We cannot know status of undefined set of devices
> +    return undef;
> +}
> +
> +sub activate_storage {
> +    my ($class, $storeid, $scfg, $cache) = @_;
> +
> +    # Server's SCSI subsystem is always up, so there's nothing to do
> +    # Maybe we could control selected controllers/ports in future.
> +    return 1;
> +}
> +
> +sub deactivate_storage {
> +    my ($class, $storeid, $scfg, $cache) = @_;
> +
> +    return 1;
> +}
> +
> +sub activate_volume {
> +    my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
> +
> +    die "volume snapshot is not possible on direct-attached storage device" if $snapname;
> +
> +    return 1;
> +}
> +
> +sub deactivate_volume {
> +    my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
> +
> +    die "volume snapshot is not possible on direct-attached storage  device" if $snapname;
> +
> +    return 1;
> +}
> +
> +sub volume_resize {
> +    my ($class, $scfg, $storeid, $volname, $size, $running) = @_;
> +
> +    die "Direct-attached storage device cannot be resized";
> +}
> +
> +sub volume_snapshot {
> +    my ($class, $scfg, $storeid, $volname, $snap) = @_;
> +
> +    die "Direct-attached storage snapshot is not implemented";
> +}
> +
> +sub volume_snapshot_rollback {
> +    my ($class, $scfg, $storeid, $volname, $snap) = @_;
> +
> +    die "Direct-attached storage snapshot rollback is not implemented";
> +}
> +
> +sub volume_snapshot_delete {
> +    my ($class, $scfg, $storeid, $volname, $snap) = @_;
> +
> +    die "Direct-attached storage snapshot delete is not implemented";
> +}
> +
> +sub volume_has_feature {
> +    my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
> +
> +    my $features = {
> +	copy => { base => 1, 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;
> -- 
> 2.1.4



More information about the pve-devel mailing list