From 91a70d3906fd3614cbfd335f1cedcf2d94950c35 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Fri, 9 Oct 2015 14:54:16 +0000 Subject: nlplug-findfs: avoid lstat syscall wen scanning /sys if possible There are ~10k entries in /sys so we want be fast. Not all filesystems supports dirent filed d_type, (iso9660 for example) so we need use lstat to find directories. However, we know that sysfs supports it, so we can avoid 10k lstat syscalls. This might be noticiable difference on rpi. --- nlplug-findfs.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/nlplug-findfs.c b/nlplug-findfs.c index be112d9..6b2c356 100644 --- a/nlplug-findfs.c +++ b/nlplug-findfs.c @@ -265,6 +265,7 @@ struct recurse_opts { const char *searchname; void (*callback)(const char *, const void *); void *userdata; + int fastdir; /* avoid lstat on sysfs which we know support d_type */ }; /* pathbuf needs hold PATH_MAX chars */ @@ -280,6 +281,7 @@ void recurse_dir(char *pathbuf, struct recurse_opts *opts) struct stat st; size_t pathlen = strlen(pathbuf); size_t namelen = strlen(entry->d_name); + int is_dir; /* d_type is not supported by all filesystems so we need lstat */ @@ -291,12 +293,21 @@ void recurse_dir(char *pathbuf, struct recurse_opts *opts) pathbuf[pathlen] = '/'; strcpy(&pathbuf[pathlen+1], entry->d_name); - if (lstat(pathbuf, &st) < 0) { - dbg("%s: %s", pathbuf, strerror(errno)); - goto next; + if (opts->fastdir) { + /* avoid the lstat syscall for sysfs which we know + support the d_type field. */ + is_dir = entry->d_type & DT_DIR; + } else { + /* some filesystems like iso9660 does not support + the d_type so we use lstat */ + if (lstat(pathbuf, &st) < 0) { + dbg("%s: %s", pathbuf, strerror(errno)); + goto next; + } + is_dir = S_ISDIR(st.st_mode); } - if (S_ISDIR(st.st_mode)) { + if (is_dir) { if (entry->d_name[0] == '.') goto next; } else if (opts->searchname @@ -304,7 +315,7 @@ void recurse_dir(char *pathbuf, struct recurse_opts *opts) goto next; } - if (S_ISDIR(st.st_mode)) + if (is_dir) recurse_dir(pathbuf, opts); else opts->callback(pathbuf, opts->userdata); @@ -376,6 +387,7 @@ static int find_bootrepos(const char *devnode, const char *type, .searchname = ".boot_repository", .callback = bootrepo_cb, .userdata = &repos, + .fastdir = 0, }; @@ -591,6 +603,7 @@ void *trigger_thread(void *data) .searchname = "uevent", .callback = trigger_uevent_cb, .userdata = NULL, + .fastdir = 1, }; char path[PATH_MAX] = "/sys/bus"; -- cgit v1.2.3