summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/mount_zfs/mount_zfs.c2
-rw-r--r--cmd/zpool/zpool_vdev.c2
-rw-r--r--include/libzfs.h2
-rw-r--r--lib/libzfs/libzfs_import.c74
4 files changed, 61 insertions, 19 deletions
diff --git a/cmd/mount_zfs/mount_zfs.c b/cmd/mount_zfs/mount_zfs.c
index b168f719a..6cdb668f5 100644
--- a/cmd/mount_zfs/mount_zfs.c
+++ b/cmd/mount_zfs/mount_zfs.c
@@ -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;
diff --git a/cmd/zpool/zpool_vdev.c b/cmd/zpool/zpool_vdev.c
index 93a968dba..cf6d2bfa5 100644
--- a/cmd/zpool/zpool_vdev.c
+++ b/cmd/zpool/zpool_vdev.c
@@ -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);
diff --git a/include/libzfs.h b/include/libzfs.h
index 108b75f5e..e6a877214 100644
--- a/include/libzfs.h
+++ b/include/libzfs.h
@@ -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);
/*
diff --git a/lib/libzfs/libzfs_import.c b/lib/libzfs/libzfs_import.c
index 301b08883..182168456 100644
--- a/lib/libzfs/libzfs_import.c
+++ b/lib/libzfs/libzfs_import.c
@@ -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);
}