From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <f.ebner@proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by lists.proxmox.com (Postfix) with ESMTPS id 39E5273508
 for <pve-devel@lists.proxmox.com>; Thu, 15 Apr 2021 13:32:31 +0200 (CEST)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
 by firstgate.proxmox.com (Proxmox) with ESMTP id 2731419265
 for <pve-devel@lists.proxmox.com>; Thu, 15 Apr 2021 13:32:01 +0200 (CEST)
Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com
 [212.186.127.180])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by firstgate.proxmox.com (Proxmox) with ESMTPS id 1FCF31925B
 for <pve-devel@lists.proxmox.com>; Thu, 15 Apr 2021 13:31:59 +0200 (CEST)
Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1])
 by proxmox-new.maurer-it.com (Proxmox) with ESMTP id D6F0A434CE
 for <pve-devel@lists.proxmox.com>; Thu, 15 Apr 2021 13:31:58 +0200 (CEST)
To: pve-devel@lists.proxmox.com, a.lauterer@proxmox.com
References: <20210402101923.13050-1-a.lauterer@proxmox.com>
 <20210402101923.13050-2-a.lauterer@proxmox.com>
 <f9a58dbd-9b10-52de-30a3-0be95cf020c3@proxmox.com>
From: Fabian Ebner <f.ebner@proxmox.com>
Message-ID: <b557a2f6-cb5f-86c4-8ecf-f3cd2049fe8a@proxmox.com>
Date: Thu, 15 Apr 2021 13:31:56 +0200
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101
 Thunderbird/78.9.0
MIME-Version: 1.0
In-Reply-To: <f9a58dbd-9b10-52de-30a3-0be95cf020c3@proxmox.com>
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Language: en-US
Content-Transfer-Encoding: 8bit
X-SPAM-LEVEL: Spam detection results:  0
 AWL 0.007 Adjusted score from AWL reputation of From: address
 KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment
 KAM_SHORT               0.001 Use of a URL Shortener for very short URL
 NICE_REPLY_A           -0.001 Looks like a legit reply (A)
 RCVD_IN_DNSWL_MED        -2.3 Sender listed at https://www.dnswl.org/,
 medium trust
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_PASS               -0.001 SPF: sender matches SPF record
 URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See
 http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more
 information. [proxmox.com, zfspoolplugin.pm, lvmthinplugin.pm, lvmplugin.pm,
 rbdplugin.pm, glusterfsplugin.pm, plugins.pm, cifsplugin.pm, dirplugin.pm,
 storage.pm, plugin.pm, nfsplugin.pm, gnu.org, basedirplugin.pm]
Subject: Re: [pve-devel] [PATCH v6 storage 1/1] add disk reassign feature
X-BeenThere: pve-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/>
List-Post: <mailto:pve-devel@lists.proxmox.com>
List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Thu, 15 Apr 2021 11:32:31 -0000

Am 15.04.21 um 13:07 schrieb Fabian Ebner:
> We often have a generic implementation in Plugin.pm for filesystem-based 
> storages (maybe erroring out if there is no $scfg->{path}). Is there a 
> reason not to use such an approach, i.e. making file_reassign_volume the 
> default reassign_volume implementation in Plugin.pm? This would avoid 

I mean together with adapting the default implementation for 
volume_has_feature too.

One more thing I noticed below:

> some fragmentation/duplication. Of course, the plugins that cannot use 
> the generic implementation need to provide their own or signal that they 
> do not have the feature.
> 
> More comments inline:
> 
> Am 02.04.21 um 12:19 schrieb Aaron Lauterer:
>> Functionality has been added for the following storage types:
>>
>> * dir based ones
>>      * directory
>>      * NFS
>>      * CIFS
>>      * gluster
> 
> What about CephFS? Can it use the generic implementation or not? If it 
> can and you choose the approach I suggested at the beginning, you don't 
> even need to add code to it ;)
> 
>> * ZFS
>> * (thin) LVM
>> * Ceph
>>
>> A new feature `reassign` has been introduced to mark which storage
>> plugin supports the feature.
>>
>> Version API and AGE have been bumped.
>>
>> Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
>> ---
>> v5 -> v6:
>> * refactor dir based feature check to reduce code repetition by
>>    introducing the file_can_reassign_volume sub that does the actual 
>> check
>>
>> v4 -> v5:
>> * rebased on master
>> * bumped api ver and api age
>> * rephrased "not implemented" message as suggested [0].
>>
>> v3 -> v4:
>> * revert intermediate storage plugin for directory based plugins
>> * add a `die "not supported"` method in Plugin.pm
>> * dir based plugins now call the file_reassign_volume method in
>>    Plugin.pm as the generic file/directory based method
>> * restored old `volume_has_feature` method in Plugin.pm and override it
>>    in directory based plugins to check against the new `reassign` feature
>>    (not too happy about the repetition for each plugin)
>>
>> v2 -> v3:
>> * added feature flags instead of dummy "not implemented" methods in
>>    plugins which do not support it as that would break compatibility with
>>    3rd party plugins.
>>    Had to make $features available outside the `has_features` method in
>>    Plugins.pm in order to be able to individually add features in the
>>    `BaseDirPlugin.pm`.
>> * added the BaseDirPlugin.pm to maintain compat with 3rd party plugins,
>>    this is explained in the commit message
>> * moved the actual renaming from the `reassign_volume` to a dedicated
>>    `rename_volume` method to make this functionality available to other
>>    possible uses in the future.
>> * added support for linked clones ($base)
>>
>>
>> rfc -> v1 -> v2: nothing changed
>>
>> [0] 
>> https://lists.proxmox.com/pipermail/pve-devel/2020-November/046031.html
>>
>>
>>   PVE/Storage.pm                 | 15 +++++++--
>>   PVE/Storage/CIFSPlugin.pm      | 13 ++++++++
>>   PVE/Storage/DirPlugin.pm       | 13 ++++++++
>>   PVE/Storage/GlusterfsPlugin.pm | 13 ++++++++
>>   PVE/Storage/LVMPlugin.pm       | 24 ++++++++++++++
>>   PVE/Storage/LvmThinPlugin.pm   |  1 +
>>   PVE/Storage/NFSPlugin.pm       | 13 ++++++++
>>   PVE/Storage/Plugin.pm          | 60 ++++++++++++++++++++++++++++++++++
>>   PVE/Storage/RBDPlugin.pm       | 31 ++++++++++++++++++
>>   PVE/Storage/ZFSPoolPlugin.pm   | 26 +++++++++++++++
>>   10 files changed, 207 insertions(+), 2 deletions(-)
>>
>> diff --git a/PVE/Storage.pm b/PVE/Storage.pm
>> index 122c3e9..b950c82 100755
>> --- a/PVE/Storage.pm
>> +++ b/PVE/Storage.pm
>> @@ -41,11 +41,11 @@ use PVE::Storage::DRBDPlugin;
>>   use PVE::Storage::PBSPlugin;
>>   # Storage API version. Increment it on changes in storage API 
>> interface.
>> -use constant APIVER => 8;
>> +use constant APIVER => 9;
>>   # Age is the number of versions we're backward compatible with.
>>   # This is like having 'current=APIVER' and age='APIAGE' in libtool,
>>   # see 
>> https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html 
>>
>> -use constant APIAGE => 7;
>> +use constant APIAGE => 8;
>>   # load standard plugins
>>   PVE::Storage::DirPlugin->register();
>> @@ -349,6 +349,7 @@ sub volume_snapshot_needs_fsfreeze {
>>   #            snapshot - taking a snapshot is possible
>>   #            sparseinit - volume is sparsely initialized
>>   #            template - conversion to base image is possible
>> +#            reassign - reassigning disks to other guest is possible
>>   # $snap - check if the feature is supported for a given snapshot
>>   # $running - if the guest owning the volume is running
>>   # $opts - hash with further options:
>> @@ -1843,6 +1844,16 @@ sub complete_volume {
>>       return $res;
>>   }
>> +sub reassign_volume {
>> +    my ($cfg, $volid, $target_vmid) = @_;
>> +
>> +    my ($storeid, $volname) = parse_volume_id($volid);
>> +    my $scfg = storage_config($cfg, $storeid);
>> +    my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
>> +

Check if the storage is enabled and activate it?
And is it necessary to activate the volume for certain storages, e.g. 
LVM (might not be, but did you check)?

>> +    return $plugin->reassign_volume($scfg, $storeid, $volname, 
>> $target_vmid);
>> +}
>> +
>>   # Various io-heavy operations require io/bandwidth limits which can be
>>   # configured on multiple levels: The global defaults in 
>> datacenter.cfg, and
>>   # per-storage overrides. When we want to do a restore from storage A 
>> to storage
>> diff --git a/PVE/Storage/CIFSPlugin.pm b/PVE/Storage/CIFSPlugin.pm
>> index be06cc7..3affa5d 100644
>> --- a/PVE/Storage/CIFSPlugin.pm
>> +++ b/PVE/Storage/CIFSPlugin.pm
>> @@ -293,4 +293,17 @@ sub update_volume_notes {
>>       PVE::Storage::DirPlugin::update_volume_notes($class, @_);
>>   }
>> +sub reassign_volume {
>> +    my ($class, $scfg, $storeid, $volname, $target_vmid) = @_;
>> +    return $class->file_reassign_volume($scfg, $storeid, $volname, 
>> $target_vmid);
>> +}
>> +
>> +sub volume_has_feature {
>> +    my ($class, $scfg, $feature, $storeid, $volname, $snapname, 
>> $running, $opts) = @_;
>> +
>> +    shift @_;
>> +    return $class->file_can_reassign_volume(@_) if $feature eq 
>> 'reassign';
>> +    return $class->SUPER::volume_has_feature(@_);
>> +}
>> +
>>   1;
>> diff --git a/PVE/Storage/DirPlugin.pm b/PVE/Storage/DirPlugin.pm
>> index 2267f11..cfdb575 100644
>> --- a/PVE/Storage/DirPlugin.pm
>> +++ b/PVE/Storage/DirPlugin.pm
>> @@ -156,4 +156,17 @@ sub check_config {
>>       return $opts;
>>   }
>> +sub reassign_volume {
>> +    my ($class, $scfg, $storeid, $volname, $target_vmid) = @_;
>> +    return $class->file_reassign_volume($scfg, $storeid, $volname, 
>> $target_vmid);
>> +}
>> +
>> +sub volume_has_feature {
>> +    my ($class, $scfg, $feature, $storeid, $volname, $snapname, 
>> $running, $opts) = @_;
>> +
>> +    shift @_;
>> +    return $class->file_can_reassign_volume(@_) if $feature eq 
>> 'reassign';
>> +    return $class->SUPER::volume_has_feature(@_);
>> +}
>> +
>>   1;
>> diff --git a/PVE/Storage/GlusterfsPlugin.pm 
>> b/PVE/Storage/GlusterfsPlugin.pm
>> index 2dd414d..8132a3e 100644
>> --- a/PVE/Storage/GlusterfsPlugin.pm
>> +++ b/PVE/Storage/GlusterfsPlugin.pm
>> @@ -348,4 +348,17 @@ sub check_connection {
>>       return defined($server) ? 1 : 0;
>>   }
>> +sub reassign_volume {
>> +    my ($class, $scfg, $storeid, $volname, $target_vmid) = @_;
>> +    return $class->file_reassign_volume($scfg, $storeid, $volname, 
>> $target_vmid);
>> +}
>> +
>> +sub volume_has_feature {
>> +    my ($class, $scfg, $feature, $storeid, $volname, $snapname, 
>> $running, $opts) = @_;
>> +
>> +    shift @_;
>> +    return $class->file_can_reassign_volume(@_) if $feature eq 
>> 'reassign';
>> +    return $class->SUPER::volume_has_feature(@_);
>> +}
>> +
>>   1;
>> diff --git a/PVE/Storage/LVMPlugin.pm b/PVE/Storage/LVMPlugin.pm
>> index df49b76..0d9a691 100644
>> --- a/PVE/Storage/LVMPlugin.pm
>> +++ b/PVE/Storage/LVMPlugin.pm
>> @@ -339,6 +339,13 @@ sub lvcreate {
>>       run_command($cmd, errmsg => "lvcreate '$vg/$name' error");
>>   }
>> +sub lvrename {
>> +    my ($vg, $oldname, $newname) = @_;
>> +
>> +    my $cmd = ['/sbin/lvrename', $vg, $oldname, $newname];
>> +    run_command($cmd, errmsg => "lvrename '${vg}/${oldname}' to 
>> '${newname}' error");
>> +}
>> +
>>   sub alloc_image {
>>       my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
>> @@ -584,6 +591,7 @@ sub volume_has_feature {
>>       my $features = {
>>       copy => { base => 1, current => 1},
>> +    reassign => {current => 1},
>>       };
>>       my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
>> @@ -684,4 +692,20 @@ sub volume_import_write {
>>       input => '<&'.fileno($input_fh));
>>   }
>> +sub reassign_volume {
>> +    my ($class, $scfg, $storeid, $volname, $target_vmid) = @_;
>> +
>> +    $class->cluster_lock_storage($storeid, $scfg->{shared}, undef, sub {
>> +    my $target_volname = $class->find_free_diskname($storeid, $scfg, 
>> $target_vmid);
>> +    return $class->rename_volume($scfg, $storeid, $volname, 
>> $target_volname, $target_vmid);
>> +    });
>> +}
>> +
>> +sub rename_volume {
>> +    my ($class, $scfg, $storeid, $source_volname, $target_volname, 
>> $vmid) = @_;
> 
> Nit: The signature is different than the corresponding one in Plugin.pm. 
> I know you're not using $base here, but maybe add it for consistency.
> 
> That said, why not assemble the new volume ID in the reassign function 
> itself and have the rename function only be concerned with renaming? 
> Then you could drop the $base form the signature altogether.
> 
>> +
>> +    lvrename($scfg->{vgname}, $source_volname, $target_volname);
>> +    return "${storeid}:${target_volname}";
>> +}
>> +
>>   1;
>> diff --git a/PVE/Storage/LvmThinPlugin.pm b/PVE/Storage/LvmThinPlugin.pm
>> index c9e127c..895af8b 100644
>> --- a/PVE/Storage/LvmThinPlugin.pm
>> +++ b/PVE/Storage/LvmThinPlugin.pm
>> @@ -355,6 +355,7 @@ sub volume_has_feature {
>>       template => { current => 1},
>>       copy => { base => 1, current => 1, snap => 1},
>>       sparseinit => { base => 1, current => 1},
>> +    reassign => {current => 1},
>>       };
>>       my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
>> diff --git a/PVE/Storage/NFSPlugin.pm b/PVE/Storage/NFSPlugin.pm
>> index 39bf15a..7217ca2 100644
>> --- a/PVE/Storage/NFSPlugin.pm
>> +++ b/PVE/Storage/NFSPlugin.pm
>> @@ -197,4 +197,17 @@ sub update_volume_notes {
>>       PVE::Storage::DirPlugin::update_volume_notes($class, @_);
>>   }
>> +sub reassign_volume {
>> +    my ($class, $scfg, $storeid, $volname, $target_vmid) = @_;
>> +    return $class->file_reassign_volume($scfg, $storeid, $volname, 
>> $target_vmid);
>> +}
>> +
>> +sub volume_has_feature {
>> +    my ($class, $scfg, $feature, $storeid, $volname, $snapname, 
>> $running, $opts) = @_;
>> +
>> +    shift @_;
>> +    return $class->file_can_reassign_volume(@_) if $feature eq 
>> 'reassign';
>> +    return $class->SUPER::volume_has_feature(@_);
>> +}
>> +
>>   1;
>> diff --git a/PVE/Storage/Plugin.pm b/PVE/Storage/Plugin.pm
>> index d2d8184..c1ea41d 100644
>> --- a/PVE/Storage/Plugin.pm
>> +++ b/PVE/Storage/Plugin.pm
>> @@ -927,6 +927,7 @@ sub storage_can_replicate {
>>       return 0;
>>   }
>> +
> 
> Nit: accidental newline
> 
>>   sub volume_has_feature {
>>       my ($class, $scfg, $feature, $storeid, $volname, $snapname, 
>> $running, $opts) = @_;
>> @@ -1456,4 +1457,63 @@ sub volume_import_formats {
>>       return ();
>>   }
>> +sub reassign_volume {
>> +    my ($class, $scfg, $storeid, $volname, $target_vmid) = @_;
>> +    die "not implemented in storage plugin '$class'\n";
>> +}
>> +
>> +# general reassignment method for file/directory based storages
>> +sub file_reassign_volume {
>> +    my ($class, $scfg, $storeid, $volname, $target_vmid) = @_;
>> +
>> +    my $base;
>> +    my $base_vmid;
>> +    my $format;
>> +    my $source_vmid;
>> +
>> +    (undef, $volname, $source_vmid, $base, $base_vmid, undef, 
>> $format) = $class->parse_volname($volname);
>> +
>> +    # parse_volname strips the directory from volname
>> +    my $source_volname = "${source_vmid}/${volname}";
>> +
>> +    if ($base) {
>> +    $base = "${base_vmid}/${base}/";
>> +    } else {
>> +    $base = '';
>> +    }
>> +
>> +    $class->cluster_lock_storage($storeid, $scfg->{shared}, undef, sub {
>> +    my $target_volname = $class->find_free_diskname($storeid, $scfg, 
>> $target_vmid, $format, 1);
>> +
>> +    return $class->rename_volume($scfg, $storeid, $source_volname, 
>> $target_volname, $target_vmid, $base);
>> +    });
>> +}
>> +
>> +sub rename_volume {
>> +    my ($class, $scfg, $storeid, $source_volname, $target_volname, 
>> $vmid, $base) = @_;
>> +
>> +    my $basedir = $class->get_subdir($scfg, 'images');
>> +    my $imagedir = "${basedir}/${vmid}";
>> +
>> +    mkpath $imagedir;
>> +
>> +    my $old_path = "${basedir}/${source_volname}";
>> +    my $new_path = "${imagedir}/${target_volname}";
>> +
>> +    rename($old_path, $new_path) ||
>> +    die "rename '$old_path' to '$new_path' failed - $!\n";
>> +
>> +    return "${storeid}:${base}${vmid}/${target_volname}";
>> +}
>> +
>> +sub file_can_reassign_volume {
>> +    my ($class, $scfg, $feature, $storeid, $volname, $snapname, 
>> $running, $opts) = @_;
>> +
>> +    my ($vtype, $name, $vmid, $basename, $basevmid, $isBase, $format) =
>> +    $class->parse_volname($volname);
>> +
>> +    return 1 if !$isBase && $format =~ /^raw$|^qcow2$|^vmdk$/;
>> +    return undef;
>> +}
>> +
>>   1;
>> diff --git a/PVE/Storage/RBDPlugin.pm b/PVE/Storage/RBDPlugin.pm
>> index fab6d57..86a9a0d 100644
>> --- a/PVE/Storage/RBDPlugin.pm
>> +++ b/PVE/Storage/RBDPlugin.pm
>> @@ -712,6 +712,7 @@ sub volume_has_feature {
>>       template => { current => 1},
>>       copy => { base => 1, current => 1, snap => 1},
>>       sparseinit => { base => 1, current => 1},
>> +    reassign => {current => 1},
>>       };
>>       my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
>> @@ -728,4 +729,34 @@ sub volume_has_feature {
>>       return undef;
>>   }
>> +sub reassign_volume {
>> +    my ($class, $scfg, $storeid, $volname, $target_vmid) = @_;
>> +
>> +    my $base;;
>> +    (undef, $volname, undef, $base) = $class->parse_volname($volname);
>> +
>> +    if ($base) {
>> +    $base = $base . '/';
>> +    } else {
>> +    $base = '';
>> +    }
>> +
>> +    $class->cluster_lock_storage($storeid, $scfg->{shared}, undef, sub {
>> +    my $target_volname = $class->find_free_diskname($storeid, $scfg, 
>> $target_vmid);
>> +    return $class->rename_volume($scfg, $storeid, $volname, 
>> $target_volname, $target_vmid, $base);
>> +    });
>> +}
>> +
>> +sub rename_volume {
>> +    my ($class, $scfg, $storeid, $source_volname, $target_volname, 
>> $vmid, $base) = @_;
>> +
>> +    my $cmd = $rbd_cmd->($scfg, $storeid, 'rename', $source_volname, 
>> $target_volname);
>> +
>> +    run_rbd_command(
>> +    $cmd,
>> +    errmsg => "could not rename image '${source_volname}' to 
>> '${target_volname}'",
>> +    );
>> +    return "${storeid}:${base}${target_volname}";
>> +}
>> +
>>   1;
>> diff --git a/PVE/Storage/ZFSPoolPlugin.pm b/PVE/Storage/ZFSPoolPlugin.pm
>> index fe65ae4..c63a94b 100644
>> --- a/PVE/Storage/ZFSPoolPlugin.pm
>> +++ b/PVE/Storage/ZFSPoolPlugin.pm
>> @@ -686,6 +686,7 @@ sub volume_has_feature {
>>       copy => { base => 1, current => 1},
>>       sparseinit => { base => 1, current => 1},
>>       replicate => { base => 1, current => 1},
>> +    reassign => {current => 1},
>>       };
>>       my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
>> @@ -788,4 +789,29 @@ sub volume_import_formats {
>>       return $class->volume_export_formats($scfg, $storeid, $volname, 
>> undef, $base_snapshot, $with_snapshots);
>>   }
>> +sub reassign_volume {
>> +    my ($class, $scfg, $storeid, $volname, $target_vmid) = @_;
>> +
>> +    my $base;;
>> +    (undef, $volname, undef, $base) = $class->parse_volname($volname);
>> +
>> +    if ($base) {
>> +    $base = $base . '/';
>> +    } else {
>> +    $base = '';
>> +    }
>> +
>> +    $class->cluster_lock_storage($storeid, $scfg->{shared}, undef, sub {
>> +    my $target_volname = $class->find_free_diskname($storeid, $scfg, 
>> $target_vmid);
>> +    return $class->rename_volume($scfg, $storeid, $volname, 
>> $target_volname, $target_vmid, $base);
>> +    });
>> +}
>> +
>> +sub rename_volume {
>> +    my ($class, $scfg, $storeid, $source_volname, $target_volname, 
>> $vmid, $base) = @_;
>> +
>> +    $class->zfs_request($scfg, 5, 'rename', 
>> "$scfg->{pool}/$source_volname", "$scfg->{pool}/$target_volname");
>> +    return "${storeid}:${base}${target_volname}";
>> +}
>> +
>>   1;
>>
> 
> 
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
> 
>