aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libzfs
diff options
context:
space:
mode:
authorChunwei Chen <[email protected]>2018-01-26 10:49:46 -0800
committerBrian Behlendorf <[email protected]>2018-01-26 10:49:46 -0800
commit522db29275b81c18c2bf53a95efa1aedeb13b428 (patch)
tree3edfce11d4d86d2fcb33e48cf80cbd8603b44b1e /lib/libzfs
parentf55a8757a6be24c36c25e24ab5c30dcddf2ad954 (diff)
zpool import -d to specify device path
When we know which devices have the pool we are looking for, sometime it's better if we can directly pass those device paths to zpool import instead of letting it to search through all unrelated stuff, which might take a lot of time if you have hundreds of disks. This patch allows option -d <dev_path> to zpool import. You can have multiple pairs of -d <dev_path>, and zpool import will only search through those devices. For example: zpool import -d /dev/sda -d /dev/sdb Reviewed-by: Tony Hutter <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Chunwei Chen <[email protected]> Closes #7077
Diffstat (limited to 'lib/libzfs')
-rw-r--r--lib/libzfs/libzfs_import.c166
1 files changed, 130 insertions, 36 deletions
diff --git a/lib/libzfs/libzfs_import.c b/lib/libzfs/libzfs_import.c
index 6203cd19b..435d91fb8 100644
--- a/lib/libzfs/libzfs_import.c
+++ b/lib/libzfs/libzfs_import.c
@@ -47,6 +47,7 @@
#include <dirent.h>
#include <errno.h>
#include <libintl.h>
+#include <libgen.h>
#ifdef HAVE_LIBUDEV
#include <libudev.h>
#include <sched.h>
@@ -1676,6 +1677,120 @@ zpool_clear_label(int fd)
return (0);
}
+static void
+zpool_find_import_scan_add_slice(libzfs_handle_t *hdl, pthread_mutex_t *lock,
+ avl_tree_t *cache, char *path, const char *name, int order)
+{
+ avl_index_t where;
+ rdsk_node_t *slice;
+
+ slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
+ if (asprintf(&slice->rn_name, "%s/%s", path, name) == -1) {
+ free(slice);
+ return;
+ }
+ slice->rn_vdev_guid = 0;
+ slice->rn_lock = lock;
+ slice->rn_avl = cache;
+ slice->rn_hdl = hdl;
+ slice->rn_order = order + IMPORT_ORDER_SCAN_OFFSET;
+ slice->rn_labelpaths = B_FALSE;
+
+ pthread_mutex_lock(lock);
+ if (avl_find(cache, slice, &where)) {
+ free(slice->rn_name);
+ free(slice);
+ } else {
+ avl_insert(cache, slice, where);
+ }
+ pthread_mutex_unlock(lock);
+}
+
+static int
+zpool_find_import_scan_dir(libzfs_handle_t *hdl, pthread_mutex_t *lock,
+ avl_tree_t *cache, char *dir, int order)
+{
+ int error;
+ char path[MAXPATHLEN];
+ struct dirent64 *dp;
+ DIR *dirp;
+
+ if (realpath(dir, path) == NULL) {
+ error = errno;
+ if (error == ENOENT)
+ return (0);
+
+ zfs_error_aux(hdl, strerror(error));
+ (void) zfs_error_fmt(hdl, EZFS_BADPATH, dgettext(
+ TEXT_DOMAIN, "cannot resolve path '%s'"), dir);
+ return (error);
+ }
+
+ dirp = opendir(path);
+ if (dirp == NULL) {
+ error = errno;
+ zfs_error_aux(hdl, strerror(error));
+ (void) zfs_error_fmt(hdl, EZFS_BADPATH,
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
+ return (error);
+ }
+
+ while ((dp = readdir64(dirp)) != NULL) {
+ const char *name = dp->d_name;
+ if (name[0] == '.' &&
+ (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
+ continue;
+
+ zpool_find_import_scan_add_slice(hdl, lock, cache, path, name,
+ order);
+ }
+
+ (void) closedir(dirp);
+ return (0);
+}
+
+static int
+zpool_find_import_scan_path(libzfs_handle_t *hdl, pthread_mutex_t *lock,
+ avl_tree_t *cache, char *dir, int order)
+{
+ int error = 0;
+ char path[MAXPATHLEN];
+ char *d, *b;
+ char *dpath, *name;
+
+ /*
+ * Seperate the directory part and last part of the
+ * path. We do this so that we can get the realpath of
+ * the directory. We don't get the realpath on the
+ * whole path because if it's a symlink, we want the
+ * path of the symlink not where it points to.
+ */
+ d = zfs_strdup(hdl, dir);
+ b = zfs_strdup(hdl, dir);
+ dpath = dirname(d);
+ name = basename(b);
+
+ if (realpath(dpath, path) == NULL) {
+ error = errno;
+ if (error == ENOENT) {
+ error = 0;
+ goto out;
+ }
+
+ zfs_error_aux(hdl, strerror(error));
+ (void) zfs_error_fmt(hdl, EZFS_BADPATH, dgettext(
+ TEXT_DOMAIN, "cannot resolve path '%s'"), dir);
+ goto out;
+ }
+
+ zpool_find_import_scan_add_slice(hdl, lock, cache, path, name, order);
+
+out:
+ free(b);
+ free(d);
+ return (error);
+}
+
/*
* Scan a list of directories for zfs devices.
*/
@@ -1694,11 +1809,9 @@ zpool_find_import_scan(libzfs_handle_t *hdl, pthread_mutex_t *lock,
offsetof(rdsk_node_t, rn_node));
for (i = 0; i < dirs; i++) {
- char path[MAXPATHLEN];
- struct dirent64 *dp;
- DIR *dirp;
+ struct stat sbuf;
- if (realpath(dir[i], path) == NULL) {
+ if (stat(dir[i], &sbuf) != 0) {
error = errno;
if (error == ENOENT)
continue;
@@ -1709,39 +1822,20 @@ zpool_find_import_scan(libzfs_handle_t *hdl, pthread_mutex_t *lock,
goto error;
}
- dirp = opendir(path);
- if (dirp == NULL) {
- error = errno;
- zfs_error_aux(hdl, strerror(error));
- (void) zfs_error_fmt(hdl, EZFS_BADPATH,
- dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
- goto error;
- }
-
- while ((dp = readdir64(dirp)) != NULL) {
- const char *name = dp->d_name;
- if (name[0] == '.' &&
- (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
- continue;
-
- slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
- error = asprintf(&slice->rn_name, "%s/%s", path, name);
- if (error == -1) {
- free(slice);
- continue;
- }
- slice->rn_vdev_guid = 0;
- slice->rn_lock = lock;
- slice->rn_avl = cache;
- slice->rn_hdl = hdl;
- slice->rn_order = i + IMPORT_ORDER_SCAN_OFFSET;
- slice->rn_labelpaths = B_FALSE;
- pthread_mutex_lock(lock);
- avl_add(cache, slice);
- pthread_mutex_unlock(lock);
+ /*
+ * If dir[i] is a directory, we walk through it and add all
+ * the entry to the cache. If it's not a directory, we just
+ * add it to the cache.
+ */
+ if (S_ISDIR(sbuf.st_mode)) {
+ if ((error = zpool_find_import_scan_dir(hdl, lock,
+ cache, dir[i], i)) != 0)
+ goto error;
+ } else {
+ if ((error = zpool_find_import_scan_path(hdl, lock,
+ cache, dir[i], i)) != 0)
+ goto error;
}
-
- (void) closedir(dirp);
}
*slice_cache = cache;