summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libzfs/libzfs_import.c142
1 files changed, 123 insertions, 19 deletions
diff --git a/lib/libzfs/libzfs_import.c b/lib/libzfs/libzfs_import.c
index 2776ed29c..fa51b6d0d 100644
--- a/lib/libzfs/libzfs_import.c
+++ b/lib/libzfs/libzfs_import.c
@@ -99,6 +99,8 @@ typedef struct pool_list {
name_entry_t *names;
} pool_list_t;
+#define DEV_BYID_PATH "/dev/disk/by-id/"
+
/*
* Linux persistent device strings for vdev labels
*
@@ -106,8 +108,6 @@ typedef struct pool_list {
*/
#ifdef HAVE_LIBUDEV
-#define DEV_BYID_PATH "/dev/disk/by-id/"
-
typedef struct vdev_dev_strs {
char vds_devid[128];
char vds_devphys[128];
@@ -536,7 +536,6 @@ update_vdev_config_dev_strs(nvlist_t *nv)
#endif /* HAVE_LIBUDEV */
-
/*
* Go through and fix up any path and/or devid information for the given vdev
* configuration.
@@ -577,7 +576,6 @@ fix_paths(nvlist_t *nv, name_entry_t *names)
best = NULL;
for (ne = names; ne != NULL; ne = ne->ne_next) {
if (ne->ne_guid == guid) {
-
if (path == NULL) {
best = ne;
break;
@@ -762,6 +760,116 @@ add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
return (0);
}
+static int
+add_path(libzfs_handle_t *hdl, pool_list_t *pools, uint64_t pool_guid,
+ uint64_t vdev_guid, const char *path, int order)
+{
+ nvlist_t *label;
+ uint64_t guid;
+ int error, fd, num_labels;
+
+ fd = open64(path, O_RDONLY);
+ if (fd < 0)
+ return (errno);
+
+ error = zpool_read_label(fd, &label, &num_labels);
+ close(fd);
+
+ if (error || label == NULL)
+ return (ENOENT);
+
+ error = nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_GUID, &guid);
+ if (error || guid != pool_guid) {
+ nvlist_free(label);
+ return (EINVAL);
+ }
+
+ error = nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &guid);
+ if (error || guid != vdev_guid) {
+ nvlist_free(label);
+ return (EINVAL);
+ }
+
+ error = add_config(hdl, pools, path, order, num_labels, label);
+
+ return (error);
+}
+
+static int
+add_configs_from_label_impl(libzfs_handle_t *hdl, pool_list_t *pools,
+ nvlist_t *nvroot, uint64_t pool_guid, uint64_t vdev_guid)
+{
+ char udevpath[MAXPATHLEN];
+ char *path;
+ nvlist_t **child;
+ uint_t c, children;
+ uint64_t guid;
+ int error;
+
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++) {
+ error = add_configs_from_label_impl(hdl, pools,
+ child[c], pool_guid, vdev_guid);
+ if (error)
+ return (error);
+ }
+ return (0);
+ }
+
+ if (nvroot == NULL)
+ return (0);
+
+ error = nvlist_lookup_uint64(nvroot, ZPOOL_CONFIG_GUID, &guid);
+ if ((error != 0) || (guid != vdev_guid))
+ return (0);
+
+ error = nvlist_lookup_string(nvroot, ZPOOL_CONFIG_PATH, &path);
+ if (error == 0)
+ (void) add_path(hdl, pools, pool_guid, vdev_guid, path, 0);
+
+ error = nvlist_lookup_string(nvroot, ZPOOL_CONFIG_DEVID, &path);
+ if (error == 0) {
+ sprintf(udevpath, "%s%s", DEV_BYID_PATH, path);
+ (void) add_path(hdl, pools, pool_guid, vdev_guid, udevpath, 1);
+ }
+
+ return (0);
+}
+
+/*
+ * Given a disk label call add_config() for all known paths to the device
+ * as described by the label itself. The paths are added in the following
+ * priority order: 'path', 'devid', 'devnode'. As these alternate paths are
+ * added the labels are verified to make sure they refer to the same device.
+ */
+static int
+add_configs_from_label(libzfs_handle_t *hdl, pool_list_t *pools,
+ char *devname, int num_labels, nvlist_t *label)
+{
+ nvlist_t *nvroot;
+ uint64_t pool_guid;
+ uint64_t vdev_guid;
+ int error;
+
+ if (nvlist_lookup_nvlist(label, ZPOOL_CONFIG_VDEV_TREE, &nvroot) ||
+ nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_GUID, &pool_guid) ||
+ nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &vdev_guid))
+ return (ENOENT);
+
+ /* Allow devlinks to stabilize so all paths are available. */
+ zpool_label_disk_wait(devname, DISK_LABEL_WAIT);
+
+ /* Add alternate paths as described by the label vdev_tree. */
+ (void) add_configs_from_label_impl(hdl, pools, nvroot,
+ pool_guid, vdev_guid);
+
+ /* Add the device node /dev/sdX path as a last resort. */
+ error = add_config(hdl, pools, devname, 100, num_labels, label);
+
+ return (error);
+}
+
/*
* Returns true if the named pool matches the given GUID.
*/
@@ -1609,9 +1717,7 @@ zpool_find_import_blkid(libzfs_handle_t *hdl, pool_list_t *pools)
blkid_cache cache;
blkid_dev_iterate iter;
blkid_dev dev;
- const char *devname;
- nvlist_t *config;
- int fd, err, num_labels;
+ int err;
err = blkid_get_cache(&cache, NULL);
if (err != 0) {
@@ -1642,25 +1748,23 @@ zpool_find_import_blkid(libzfs_handle_t *hdl, pool_list_t *pools)
}
while (blkid_dev_next(iter, &dev) == 0) {
- devname = blkid_dev_devname(dev);
+ nvlist_t *label;
+ char *devname;
+ int fd, num_labels;
+
+ devname = (char *) blkid_dev_devname(dev);
if ((fd = open64(devname, O_RDONLY)) < 0)
continue;
- err = zpool_read_label(fd, &config, &num_labels);
+ err = zpool_read_label(fd, &label, &num_labels);
(void) close(fd);
- if (err != 0) {
- (void) no_memory(hdl);
- goto err_blkid3;
- }
+ if (err || label == NULL)
+ continue;
- if (config != NULL) {
- err = add_config(hdl, pools, devname, 0,
- num_labels, config);
- if (err != 0)
- goto err_blkid3;
- }
+ add_configs_from_label(hdl, pools, devname, num_labels, label);
}
+ err = 0;
err_blkid3:
blkid_dev_iterate_end(iter);