summaryrefslogtreecommitdiff
path: root/usr/src/lib/libzfs/common/libzfs_import.c
diff options
context:
space:
mode:
authorjwadams <none@none>2008-04-08 11:10:49 -0700
committerjwadams <none@none>2008-04-08 11:10:49 -0700
commit842c5645dc246ff7fd786d8a6f56644d79705e18 (patch)
tree62525ec2d7049376b413fc5ef30173583ebd96ad /usr/src/lib/libzfs/common/libzfs_import.c
parentdbe3f931a78f2d36a72003f6b51bf1fdc3aa035e (diff)
downloadillumos-joyent-842c5645dc246ff7fd786d8a6f56644d79705e18.tar.gz
6682366 zpool_find_import() is inefficient.
Diffstat (limited to 'usr/src/lib/libzfs/common/libzfs_import.c')
-rw-r--r--usr/src/lib/libzfs/common/libzfs_import.c60
1 files changed, 40 insertions, 20 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs_import.c b/usr/src/lib/libzfs/common/libzfs_import.c
index c96711ea2f..96f1c21beb 100644
--- a/usr/src/lib/libzfs/common/libzfs_import.c
+++ b/usr/src/lib/libzfs/common/libzfs_import.c
@@ -783,6 +783,8 @@ zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv,
DIR *dirp = NULL;
struct dirent64 *dp;
char path[MAXPATHLEN];
+ char *end;
+ size_t pathleft;
struct stat64 statbuf;
nvlist_t *ret = NULL, *config;
static char *default_dir = "/dev/dsk";
@@ -793,7 +795,6 @@ zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv,
config_entry_t *ce, *cenext;
name_entry_t *ne, *nenext;
-
if (argc == 0) {
argc = 1;
argv = &default_dir;
@@ -805,18 +806,37 @@ zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv,
* and toplevel GUID.
*/
for (i = 0; i < argc; i++) {
- if (argv[i][0] != '/') {
+ char *rdsk;
+ int dfd;
+
+ /* use realpath to normalize the path */
+ if (realpath(argv[i], path) == 0) {
(void) zfs_error_fmt(hdl, EZFS_BADPATH,
dgettext(TEXT_DOMAIN, "cannot open '%s'"),
argv[i]);
goto error;
}
+ end = &path[strlen(path)];
+ *end++ = '/';
+ *end = 0;
+ pathleft = &path[sizeof (path)] - end;
+
+ /*
+ * Using raw devices instead of block devices when we're
+ * reading the labels skips a bunch of slow operations during
+ * close(2) processing, so we replace /dev/dsk with /dev/rdsk.
+ */
+ if (strcmp(path, "/dev/dsk/") == 0)
+ rdsk = "/dev/rdsk/";
+ else
+ rdsk = path;
- if ((dirp = opendir(argv[i])) == NULL) {
+ if ((dfd = open64(rdsk, O_RDONLY)) < 0 ||
+ (dirp = fdopendir(dfd)) == NULL) {
zfs_error_aux(hdl, strerror(errno));
(void) zfs_error_fmt(hdl, EZFS_BADPATH,
dgettext(TEXT_DOMAIN, "cannot open '%s'"),
- argv[i]);
+ rdsk);
goto error;
}
@@ -824,28 +844,25 @@ zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv,
* This is not MT-safe, but we have no MT consumers of libzfs
*/
while ((dp = readdir64(dirp)) != NULL) {
-
- (void) snprintf(path, sizeof (path), "%s/%s",
- argv[i], dp->d_name);
-
- if (stat64(path, &statbuf) != 0)
+ const char *name = dp->d_name;
+ if (name[0] == '.' &&
+ (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
continue;
- /*
- * Ignore directories (which includes "." and "..").
- */
- if (S_ISDIR(statbuf.st_mode))
+ if ((fd = openat64(dfd, name, O_RDONLY)) < 0)
continue;
/*
- * Ignore special (non-character or non-block) files.
+ * Ignore failed stats. We only want regular
+ * files, character devs and block devs.
*/
- if (!S_ISREG(statbuf.st_mode) &&
- !S_ISBLK(statbuf.st_mode))
- continue;
-
- if ((fd = open64(path, O_RDONLY)) < 0)
+ if (fstat64(fd, &statbuf) != 0 ||
+ (!S_ISREG(statbuf.st_mode) &&
+ !S_ISCHR(statbuf.st_mode) &&
+ !S_ISBLK(statbuf.st_mode))) {
+ (void) close(fd);
continue;
+ }
if ((zpool_read_label(fd, &config)) != 0) {
(void) close(fd);
@@ -855,9 +872,12 @@ zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv,
(void) close(fd);
- if (config != NULL)
+ if (config != NULL) {
+ /* use the non-raw path for the config */
+ (void) strlcpy(end, name, pathleft);
if (add_config(hdl, &pools, path, config) != 0)
goto error;
+ }
}
(void) closedir(dirp);