diff options
author | jwadams <none@none> | 2008-04-08 11:10:49 -0700 |
---|---|---|
committer | jwadams <none@none> | 2008-04-08 11:10:49 -0700 |
commit | 842c5645dc246ff7fd786d8a6f56644d79705e18 (patch) | |
tree | 62525ec2d7049376b413fc5ef30173583ebd96ad /usr/src/lib/libzfs/common/libzfs_import.c | |
parent | dbe3f931a78f2d36a72003f6b51bf1fdc3aa035e (diff) | |
download | illumos-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.c | 60 |
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); |