[pve-devel] [PATCH storage] zpool: handle race with other zpool imports

Thomas Lamprecht t.lamprecht at proxmox.com
Wed Apr 17 17:00:20 CEST 2019


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





More information about the pve-devel mailing list