[pve-devel] applied: [PATCH storage] zpool: handle race with other zpool imports
Fabian Grünbichler
f.gruenbichler at proxmox.com
Thu Apr 18 10:08:33 CEST 2019
On Wed, Apr 17, 2019 at 03:00:20PM +0000, Thomas Lamprecht wrote:
> The underlying issue is that a zpool can get imported only once, so
> we first check if it's in `zpool list`, and thus imported, and only
> if it does not shows up there we try to import it.
>
> But, this can race with either:
> * parallel running activate_storage call, through CLI/API/daemon
> * a zpool import from an admin (a bit unlikely, but hey that's the
> thing with race conditions ;))
>
> So refactor the "is pool imported" check into a closure, and call it
> addditionally if the import failed, and silent the error if the pool
> is now listed, and thus imported. This makes it a little bit nicer to
> read too, IMO.
>
> Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
> ---
> PVE/Storage/ZFSPoolPlugin.pm | 29 ++++++++++++++++-------------
> 1 file changed, 16 insertions(+), 13 deletions(-)
>
> diff --git a/PVE/Storage/ZFSPoolPlugin.pm b/PVE/Storage/ZFSPoolPlugin.pm
> index 047a06e..2e9c4c7 100644
> --- a/PVE/Storage/ZFSPoolPlugin.pm
> +++ b/PVE/Storage/ZFSPoolPlugin.pm
> @@ -516,20 +516,23 @@ sub activate_storage {
> my $pool = $scfg->{pool};
> $pool =~ s!/.*$!!;
>
> - my @param = ('-o', 'name', '-H', "$pool");
> - my $res;
> - eval {
> - $res = $class->zfs_request($scfg, undef, 'zpool_list', @param);
> - };
> - my $err = $@;
> - if ($err || !defined($res) || $res !~ $pool) {
> - eval {
> - @param = ('-d', '/dev/disk/by-id/', '-o', 'cachefile=none', "$pool");
> - $class->zfs_request($scfg, undef, 'zpool_import', @param);
> - };
> + my $pool_imported = sub {
> + my @param = ('-o', 'name', '-H', "$pool");
> + my $res = eval { $class->zfs_request($scfg, undef, 'zpool_list', @param) };
> if ($@) {
> - warn "$err\n";
> - die "could not activate storage '$storeid', $@\n";
> + warn "$@\n";
> + return undef;
> + }
> + return defined($res) && $res =~ m/$pool/;
> + };
> +
> + if (!$pool_imported->()) {
> + # import can only be done if not yet imported!
> + my @param = ('-d', '/dev/disk/by-id/', '-o', 'cachefile=none', "$pool");
> + eval { $class->zfs_request($scfg, undef, 'zpool_import', @param) };
> + if (my $err = $@) {
> + # just could've raced with another import, so recheck if it is imported
> + die "could not activate storage '$storeid', $@\n" if !$pool_imported->();
> }
> }
> return 1;
> --
> 2.20.1
thanks!
More information about the pve-devel
mailing list