From: Lucas De Marchi Date: Tue, 6 Dec 2011 04:26:22 +0000 (-0200) Subject: kmod_config: optimize config files handling X-Git-Tag: v1~84 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b7b7ac298f53db53bebbfeff9dae3e8e4f47724a;p=thirdparty%2Fkmod.git kmod_config: optimize config files handling 1) Allocate less by not sorting the result with qsort. Instead, insert the nodes in the correct order; 2) Do not maintain the whole path in memory, but rely on openat() --- diff --git a/libkmod/libkmod-config.c b/libkmod/libkmod-config.c index 75fdbf15..2859dd47 100644 --- a/libkmod/libkmod-config.c +++ b/libkmod/libkmod-config.c @@ -124,18 +124,26 @@ static void kmod_config_free_blacklist(struct kmod_config *config, config->blacklists = kmod_list_remove(l); } -static int kmod_config_parse(struct kmod_config *config, const char *filename) +/* + * Take an fd and own it. It will be closed on return. filename is used only + * for debug messages + */ +static int kmod_config_parse(struct kmod_config *config, int fd, + const char *filename) { struct kmod_ctx *ctx = config->ctx; char *line; FILE *fp; unsigned int linenum; + int err; - DBG(ctx, "%s\n", filename); - - fp = fopen(filename, "r"); - if (fp == NULL) - return errno; + fp = fdopen(fd, "r"); + if (fp == NULL) { + err = -errno; + ERR(config->ctx, "fd %d: %m", fd); + close(fd); + return err; + } while ((line = getline_wrapped(fp, &linenum)) != NULL) { char *cmd, *saveptr; @@ -198,8 +206,8 @@ void kmod_config_free(struct kmod_config *config) free(config); } -static bool conf_files_filter(struct kmod_ctx *ctx, const char *path, - const char *fn) +static bool conf_files_filter_out(struct kmod_ctx *ctx, const char *path, + const char *fn) { size_t len = strlen(fn); @@ -217,78 +225,84 @@ static bool conf_files_filter(struct kmod_ctx *ctx, const char *path, return 0; } -static int conf_files_list(struct kmod_ctx *ctx, struct kmod_list **list, - const char *path, size_t *n) +static DIR *conf_files_list(struct kmod_ctx *ctx, struct kmod_list **list, + const char *path) { struct stat st; DIR *d; int err; if (stat(path, &st) < 0) - return -ENOENT; + return NULL; if (!S_ISDIR(st.st_mode)) { - *list = kmod_list_append(*list, (void *)path); - *n += 1; - return 0; + *list = kmod_list_append(*list, path); + return NULL; } d = opendir(path); if (d == NULL) { err = errno; ERR(ctx, "%m\n"); - return -errno; + return NULL; } for (;;) { struct dirent ent, *entp; - char *p; + struct kmod_list *l, *tmp; + const char *dname; err = readdir_r(d, &ent, &entp); if (err != 0) { - err = -err; - goto finish; + ERR(ctx, "reading entry %s\n", strerror(-err)); + goto fail_read; } if (entp == NULL) break; - if (conf_files_filter(ctx, path, entp->d_name) == 1) + if (conf_files_filter_out(ctx, path, entp->d_name) == 1) continue; - if (asprintf(&p, "%s/%s", path, entp->d_name) < 0) { - err = -ENOMEM; - goto finish; + /* insert sorted */ + kmod_list_foreach(l, *list) { + if (strcmp(entp->d_name, l->data) < 0) + break; } - DBG(ctx, "%s\n", p); + dname = strdup(entp->d_name); + if (dname == NULL) + goto fail_oom; - *list = kmod_list_append(*list, p); - *n += 1; - } + if (l == NULL) + tmp = kmod_list_append(*list, dname); + else if (l == *list) + tmp = kmod_list_prepend(*list, dname); + else + tmp = kmod_list_insert_before(l, dname); -finish: - closedir(d); - return err; -} + if (tmp == NULL) + goto fail_oom; -static int base_cmp(const void *a, const void *b) -{ - const char *s1, *s2; + if (l == NULL || l == *list) + *list = tmp; + } - s1 = *(char * const *)a; - s2 = *(char * const *)b; + return d; - return strcmp(basename(s1), basename(s2)); +fail_oom: + ERR(ctx, "out of memory while scanning '%s'\n", path); +fail_read: + for (; *list != NULL; *list = kmod_list_remove(*list)) + free((*list)->data); + closedir(d); + return NULL; } int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **p_config) { struct kmod_config *config; - size_t i, n = 0; - const char **files; - int err = 0; - struct kmod_list *list = NULL, *l; + size_t i; *p_config = config = calloc(1, sizeof(struct kmod_config)); if (config == NULL) @@ -296,33 +310,41 @@ int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **p_config) config->ctx = ctx; - for (i = 0; i < ARRAY_SIZE(config_files); i++) - conf_files_list(ctx, &list, config_files[i], &n); + for (i = 0; i < ARRAY_SIZE(config_files); i++) { + struct kmod_list *list = NULL; + DIR *d; + int fd; - files = malloc(sizeof(char *) * n); - if (files == NULL) { - err = -ENOMEM; - goto finish; - } + d = conf_files_list(ctx, &list, config_files[i]); - i = 0; - kmod_list_foreach(l, list) { - files[i] = l->data; - i++; - } + /* there's no entry */ + if (list == NULL) + continue; - qsort(files, n, sizeof(char *), base_cmp); + /* there's only one entry, and it's a file */ + if (d == NULL) { + DBG(ctx, "parsing file '%s'\n", config_files[i]); + list = kmod_list_remove(list); + fd = open(config_files[i], O_RDONLY); + if (fd >= 0) + kmod_config_parse(config, fd, config_files[i]); - for (i = 0; i < n; i++) - kmod_config_parse(config, files[i]); + continue; + } + + /* treat all the entries in that dir */ + for (; list != NULL; list = kmod_list_remove(list)) { + DBG(ctx, "parsing file '%s/%s'\n", config_files[i], + (char *) list->data); + fd = openat(dirfd(d), list->data, O_RDONLY); + if (fd >= 0) + kmod_config_parse(config, fd, list->data); -finish: - free(files); + free(list->data); + } - while (list) { - free(list->data); - list = kmod_list_remove(list); + closedir(d); } - return err; + return 0; }