diff options
author | Chunwei Chen <[email protected]> | 2018-01-26 10:49:46 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2018-01-26 10:49:46 -0800 |
commit | 522db29275b81c18c2bf53a95efa1aedeb13b428 (patch) | |
tree | 3edfce11d4d86d2fcb33e48cf80cbd8603b44b1e /lib/libzfs | |
parent | f55a8757a6be24c36c25e24ab5c30dcddf2ad954 (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.c | 166 |
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; |