]> granicus.if.org Git - zfs/commitdiff
Fix 'zpool import' detection issue
authorBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 14 Nov 2016 17:40:18 +0000 (09:40 -0800)
committerGitHub <noreply@github.com>
Mon, 14 Nov 2016 17:40:18 +0000 (09:40 -0800)
Before adding the entry to the configuration verify that the
device can be opened exclusively.  This ensures that as long
as multipathd is running the underlying multipath devices, which
otherwise appear identical to their /dev/mapper counterpart,
are pruned from the configuration.

Failure to do so can result in a result in the vdev appearing
as UNAVAIL when the vdev path provided to the kernel can't be
opened exclusively.

This check would normally be performed in zpool_open_func()
but placing it there would result in false positives because
it is called concurrently for many devices.

Reviewed-by: Olaf Faaland <faaland1@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #5387

lib/libzfs/libzfs_import.c

index e23232792fe225ead21b76637ab6328fe1a0a59b..fe783a3a39f065c4ab2d6b0dde378190da1e1f87 100644 (file)
@@ -1912,6 +1912,7 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
                if (slice->rn_config != NULL) {
                        nvlist_t *config = slice->rn_config;
                        boolean_t matched = B_TRUE;
+                       int fd;
 
                        if (iarg->poolname != NULL) {
                                char *pname;
@@ -1929,9 +1930,21 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
                        if (!matched) {
                                nvlist_free(config);
                        } else {
-                               add_config(hdl, &pools,
-                                   slice->rn_name, slice->rn_order,
-                                   slice->rn_num_labels, config);
+                               /*
+                                * Verify all remaining entries can be opened
+                                * exclusively. This will prune all underlying
+                                * multipath devices which otherwise could
+                                * result in the vdev appearing as UNAVAIL.
+                                */
+                               fd = open(slice->rn_name, O_RDONLY | O_EXCL);
+                               if (fd >= 0) {
+                                       close(fd);
+                                       add_config(hdl, &pools,
+                                           slice->rn_name, slice->rn_order,
+                                           slice->rn_num_labels, config);
+                               } else {
+                                       nvlist_free(config);
+                               }
                        }
                }
                free(slice->rn_name);