]> granicus.if.org Git - zfs/commitdiff
Check all vdev labels in 'zpool import'
authorBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 20 Mar 2015 22:10:24 +0000 (15:10 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 25 Mar 2015 21:52:52 +0000 (14:52 -0700)
When using 'zpool import' to scan for available pools prefer vdev names
which reference vdevs with more valid labels.  There should be two labels
at the start of the device and two labels at the end of the device.  If
labels are missing then the device has been damaged or is in some other
way incomplete.  Preferring names with fully intact labels helps weed out
bad paths and improves the likelihood of being able to import the pool.

This behavior only applies when scanning /dev/ for valid pools.  If a
cache file exists the pools described by the cache file will be used.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chris Dunlap <cdunlap@llnl.gov>
Closes #3145
Closes #2844
Closes #3107

cmd/mount_zfs/mount_zfs.c
cmd/zpool/zpool_vdev.c
include/libzfs.h
lib/libzfs/libzfs_import.c

index b168f719a5954245fad4f80af6193245fe512172..6cdb668f54c15d15b23b3eb63aa7d7e74b47ead4 100644 (file)
@@ -239,7 +239,7 @@ parse_dataset(char *dataset)
                if (fd < 0)
                        goto out;
 
-               error = zpool_read_label(fd, &config);
+               error = zpool_read_label(fd, &config, NULL);
                (void) close(fd);
                if (error)
                        goto out;
index 93a968dbadc72188377be5a0ed07a3e09a9adcb1..cf6d2bfa56d55d41ef9db1fb236f45db65fd9d99 100644 (file)
@@ -597,7 +597,7 @@ is_spare(nvlist_t *config, const char *path)
        if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0 ||
            !inuse ||
            state != POOL_STATE_SPARE ||
-           zpool_read_label(fd, &label) != 0) {
+           zpool_read_label(fd, &label, NULL) != 0) {
                free(name);
                (void) close(fd);
                return (B_FALSE);
index 108b75f5eb3cb43940a3fb4ea8fdf4dec1202a20..e6a877214a642fd1e8ac1709e46ea79766cf9ab1 100644 (file)
@@ -757,7 +757,7 @@ extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
 /*
  * Label manipulation.
  */
-extern int zpool_read_label(int, nvlist_t **);
+extern int zpool_read_label(int, nvlist_t **, int *);
 extern int zpool_clear_label(int);
 
 /*
index 301b08883629c48fef1f8f9c979709666397ce2f..182168456e0c6e9ad61fd27e812b9d663cf884a1 100644 (file)
@@ -88,6 +88,7 @@ typedef struct name_entry {
        char                    *ne_name;
        uint64_t                ne_guid;
        uint64_t                ne_order;
+       uint64_t                ne_num_labels;
        struct name_entry       *ne_next;
 } name_entry_t;
 
@@ -173,8 +174,23 @@ fix_paths(nvlist_t *nv, name_entry_t *names)
                                break;
                        }
 
-                       if (best == NULL || ne->ne_order < best->ne_order)
+                       if (best == NULL) {
                                best = ne;
+                               continue;
+                       }
+
+                       /* Prefer paths with move vdev labels. */
+                       if (ne->ne_num_labels > best->ne_num_labels) {
+                               best = ne;
+                               continue;
+                       }
+
+                       /* Prefer paths earlier in the search order. */
+                       if (best->ne_num_labels == best->ne_num_labels &&
+                           ne->ne_order < best->ne_order) {
+                               best = ne;
+                               continue;
+                       }
                }
        }
 
@@ -200,7 +216,7 @@ fix_paths(nvlist_t *nv, name_entry_t *names)
  */
 static int
 add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
-    int order, nvlist_t *config)
+    int order, int num_labels, nvlist_t *config)
 {
        uint64_t pool_guid, vdev_guid, top_guid, txg, state;
        pool_entry_t *pe;
@@ -226,6 +242,7 @@ add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
                }
                ne->ne_guid = vdev_guid;
                ne->ne_order = order;
+               ne->ne_num_labels = num_labels;
                ne->ne_next = pl->names;
                pl->names = ne;
                return (0);
@@ -328,6 +345,7 @@ add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
 
        ne->ne_guid = vdev_guid;
        ne->ne_order = order;
+       ne->ne_num_labels = num_labels;
        ne->ne_next = pl->names;
        pl->names = ne;
 
@@ -843,15 +861,17 @@ label_offset(uint64_t size, int l)
 
 /*
  * Given a file descriptor, read the label information and return an nvlist
- * describing the configuration, if there is one.
+ * describing the configuration, if there is one.  The number of valid
+ * labels found will be returned in num_labels when non-NULL.
  */
 int
-zpool_read_label(int fd, nvlist_t **config)
+zpool_read_label(int fd, nvlist_t **config, int *num_labels)
 {
        struct stat64 statbuf;
-       int l;
+       int l, count = 0;
        vdev_label_t *label;
-       uint64_t state, txg, size;
+       nvlist_t *expected_config = NULL;
+       uint64_t expected_guid = 0, size;
 
        *config = NULL;
 
@@ -863,6 +883,8 @@ zpool_read_label(int fd, nvlist_t **config)
                return (-1);
 
        for (l = 0; l < VDEV_LABELS; l++) {
+               uint64_t state, guid, txg;
+
                if (pread64(fd, label, sizeof (vdev_label_t),
                    label_offset(size, l)) != sizeof (vdev_label_t))
                        continue;
@@ -871,6 +893,12 @@ zpool_read_label(int fd, nvlist_t **config)
                    sizeof (label->vl_vdev_phys.vp_nvlist), config, 0) != 0)
                        continue;
 
+               if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_GUID,
+                   &guid) != 0 || guid == 0) {
+                       nvlist_free(*config);
+                       continue;
+               }
+
                if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_STATE,
                    &state) != 0 || state > POOL_STATE_L2CACHE) {
                        nvlist_free(*config);
@@ -884,12 +912,24 @@ zpool_read_label(int fd, nvlist_t **config)
                        continue;
                }
 
-               free(label);
-               return (0);
+               if (expected_guid) {
+                       if (expected_guid == guid)
+                               count++;
+
+                       nvlist_free(*config);
+               } else {
+                       expected_config = *config;
+                       expected_guid = guid;
+                       count++;
+               }
        }
 
+       if (num_labels != NULL)
+               *num_labels = count;
+
        free(label);
-       *config = NULL;
+       *config = expected_config;
+
        return (0);
 }
 
@@ -937,7 +977,7 @@ zpool_find_import_blkid(libzfs_handle_t *hdl, pool_list_t *pools)
        blkid_dev dev;
        const char *devname;
        nvlist_t *config;
-       int fd, err;
+       int fd, err, num_labels;
 
        err = blkid_get_cache(&cache, NULL);
        if (err != 0) {
@@ -972,7 +1012,7 @@ zpool_find_import_blkid(libzfs_handle_t *hdl, pool_list_t *pools)
                if ((fd = open64(devname, O_RDONLY)) < 0)
                        continue;
 
-               err = zpool_read_label(fd, &config);
+               err = zpool_read_label(fd, &config, &num_labels);
                (void) close(fd);
 
                if (err != 0) {
@@ -981,7 +1021,8 @@ zpool_find_import_blkid(libzfs_handle_t *hdl, pool_list_t *pools)
                }
 
                if (config != NULL) {
-                       err = add_config(hdl, pools, devname, 0, config);
+                       err = add_config(hdl, pools, devname, 0,
+                           num_labels, config);
                        if (err != 0)
                                goto err_blkid3;
                }
@@ -1017,7 +1058,7 @@ zpool_default_import_path[DEFAULT_IMPORT_PATH_SIZE] = {
 static nvlist_t *
 zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
 {
-       int i, dirs = iarg->paths;
+       int i, num_labels, dirs = iarg->paths;
        DIR *dirp = NULL;
        struct dirent64 *dp;
        char path[MAXPATHLEN];
@@ -1143,7 +1184,7 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
                        if ((fd = openat64(dfd, name, O_RDONLY)) < 0)
                                continue;
 
-                       if ((zpool_read_label(fd, &config)) != 0) {
+                       if ((zpool_read_label(fd, &config, &num_labels))) {
                                (void) close(fd);
                                (void) no_memory(hdl);
                                goto error;
@@ -1177,7 +1218,8 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
                                }
                                /* use the non-raw path for the config */
                                (void) strlcpy(end, name, pathleft);
-                               if (add_config(hdl, &pools, path, i+1, config))
+                               if (add_config(hdl, &pools, path, i+1,
+                                   num_labels, config))
                                        goto error;
                        }
                }
@@ -1461,7 +1503,7 @@ zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr,
 
        *inuse = B_FALSE;
 
-       if (zpool_read_label(fd, &config) != 0) {
+       if (zpool_read_label(fd, &config, NULL) != 0) {
                (void) no_memory(hdl);
                return (-1);
        }