On Mon, Jul 27, 2015 at 12:58:29AM +0900, Taeung Song wrote: > This patch consists of functions > which can get, set specific config variables.
I think you'd be better splitting this patch into pieces. I'd like to do it with 3 patches - one for adding default config set (possibly squash/reorder --list-all patch too), next is for adding 'get' functionality, and finally adding 'set' feature. It'll make the reviewer's life little easier. :) Nitpicks below... > For the syntax examples, > > perf config [options] [section.name[=value] ...] > > display key-value pairs of specific config variables > # perf config report.queue-size report.children > > set specific config variables > # perf config report.queue-size=100M report.children=true > > Signed-off-by: Taeung Song <treeze.tae...@gmail.com> > --- [SNIP] > + { > + .section_name = KMEM, > + .name = "default", > + .value = "page", s/page/slab/ > + .type = NULL, > + }, > + { > + .section_name = NULL, > + .name = NULL, > + .value = NULL, > + .type = NULL, > + }, > +}; > + [SNIP] > +static int add_element(struct list_head *head, > + const char *name, const char *value) > +{ > + struct config_element *element_node; > + > + element_node = zalloc(sizeof(*element_node)); Need to check return value here. > + element_node->name = strdup(name); > + if (!element_node->name) { > + pr_err("%s: strdup failed\n", __func__); > + goto out_free; > + } > + if (value) > + element_node->value = (char *)value; > + else > + element_node->value = NULL; > + > + list_add_tail(&element_node->list, head); > + return 0; > + > +out_free: > + free(element_node); > + return -1; > +} > + > static int show_config(const char *key, const char *value, > void *cb __maybe_unused) > { > @@ -45,10 +392,203 @@ static int show_config(const char *key, const char > *value, > return 0; > } > > +static void find_config(struct config_section **section_node, > + struct config_element **element_node, > + const char *section_name, const char *name) > +{ > + *section_node = find_section(section_name); > + > + if (*section_node != NULL) > + *element_node = find_element(name, *section_node); > + else > + *element_node = NULL; > +} > + > +static int show_spec_config(const char *section_name, const char *name, > + char *value __maybe_unused) > +{ > + int i; > + struct config_section *section_node = NULL; > + struct config_element *element_node = NULL; > + char key[BUFSIZ]; > + > + find_config(§ion_node, &element_node, section_name, name); > + > + if (section_node && element_node) { > + scnprintf(key, sizeof(key), "%s.%s", > + section_node->name, element_node->name); > + return show_config(key, element_node->value, NULL); > + } > + > + for (i = 0; default_configsets[i].section_name != NULL; i++) { I'd do this with a local variable: struct default_configset *config = &default_configsets[i]; > + if (!strcmp(default_configsets[i].section_name, section_name) > + && !strcmp(default_configsets[i].name, name)) { Please put the '&&' operator in the above line. > + printf("%s.%s=%s (default)\n", > default_configsets[i].section_name, > + default_configsets[i].name, > default_configsets[i].value); > + return 0; > + } > + } > + > + pr_err("Error: Failed to find the variable.\n"); > + > + return 0; > +} > + > +static char *normalize_value(const char *section_name, const char *name, > const char *value) > +{ > + int i; > + char key[BUFSIZ]; > + char *normalized; > + > + scnprintf(key, sizeof(key), "%s.%s", section_name, name); > + for (i = 0; default_configsets[i].section_name != NULL; i++) { Ditto for default_configsets[i]. > + if (!strcmp(default_configsets[i].section_name, section_name) > + && !strcmp(default_configsets[i].name, name)) { > + normalized = zalloc(BUFSIZ); Instead of always allocating BUFSIZ memory, please use asprintf(). > + if (!default_configsets[i].type) > + scnprintf(normalized, BUFSIZ, "%s", value); > + else if (!strcmp(default_configsets[i].type, TYPE_BOOL)) > + scnprintf(normalized, BUFSIZ, "%s", > + perf_config_bool(key, value) ? "true" > : "false"); > + else if (!strcmp(default_configsets[i].type, > TYPE_ON_OFF)) > + scnprintf(normalized, BUFSIZ, "%s", > + perf_config_bool(key, value) ? "on" : > "off"); > + else if (!strcmp(default_configsets[i].type, TYPE_INT)) > + scnprintf(normalized, BUFSIZ, "%d", > + perf_config_int(key, value)); > + else if (!strcmp(default_configsets[i].type, TYPE_LONG)) > + scnprintf(normalized, BUFSIZ, "%"PRId64, > + perf_config_u64(key, value)); > + else if (!strcmp(default_configsets[i].type, > TYPE_DIRNAME)) > + scnprintf(normalized, BUFSIZ, "%s", > + perf_config_dirname(key, value)); > + return normalized; > + } > + } > + > + normalized = strdup(value); > + if (!normalized) { > + pr_err("%s: strdup failed\n", __func__); > + return NULL; > + } > + > + return normalized; > +} > + > +static int set_config(const char *section_name, const char *name, char > *value) > +{ > + struct config_section *section_node = NULL; > + struct config_element *element_node = NULL; > + > + find_config(§ion_node, &element_node, section_name, name); > + if (value != NULL) { > + value = normalize_value(section_name, name, value); > + > + /* if there isn't existent section, add a new section */ > + if (!section_node) { > + section_node = init_section(section_name); > + if (!section_node) > + return -1; > + list_add_tail(§ion_node->list, §ions); > + } > + /* if nothing to replace, add a new element which contains > key-value pair. */ > + if (!element_node) { > + add_element(§ion_node->element_head, name, value); > + } else { > + if (!element_node->value) > + free(element_node->value); I guess you wanted to check NULL pointer before freeing the old value. It's inverted, but anyway you can skip the check since free() already ignored NULL pointers. > + element_node->value = value; > + } > + } > + > + if (access(config_file_name, W_OK) == -1) { > + pr_err("Error: %s: Can't write to this file or no such file\n", > + config_file_name); Not sure we need to error out in the 'no such file' case. Maybe it's ok to create a new file.. > + return -1; > + } > + > + return perf_configset_write_in_full(config_file_name); > +} > + > +static int collect_current_config(const char *var, const char *value, > + void *cb __maybe_unused) > +{ > + struct config_section *section_node; > + char *key = strdup(var); Who does free the key? > + char *section_name, *name; > + > + if (!key) { > + pr_err("%s: strdup failed\n", __func__); > + return -1; > + } > + > + section_name = strsep(&key, "."); > + name = strsep(&key, "."); > + if (name == NULL) > + return -1; > + > + section_node = find_section(section_name); > + if (!section_node) { > + section_node = init_section(section_name); > + if (!section_node) > + return -1; > + list_add_tail(§ion_node->list, §ions); > + } > + > + return add_element(§ion_node->element_head, name, > + normalize_value(section_name, name, value)); > +} > + > +static int perf_configset_with_option(configset_fn_t fn, const char *var, > char *value) > +{ > + char *section_name; > + char *name; > + const char *last_dot; > + char *key = strdup(var); Ditto. Thanks, Namhyung > + > + if (!key) { > + pr_err("%s: strdup failed\n", __func__); > + return -1; > + } > + last_dot = strchr(key, '.'); > + /* > + * Since "key" actually contains the section name and the real > + * key name separated by a dot, we have to know where the dot is. > + */ > + if (last_dot == NULL || last_dot == key) { > + pr_err("The config variable does not contain a section: %s\n", > key); > + return -1; > + } > + if (!last_dot[1]) { > + pr_err("The config varible does not contain variable name: > %s\n", key); > + return -1; > + } > + > + section_name = strsep(&key, "."); > + name = strsep(&key, "."); > + > + if (!value) { > + /* do nothing */ > + } else if (!strcmp(value, "=")) { > + pr_err("The config variable does not contain a value: %s.%s\n", > + section_name, name); > + return -1; > + } else { > + value++; > + name = strsep(&name, "="); > + } > + > + return fn(section_name, name, value); > + > + pr_err("invalid key: %s\n", var); > + return -1; > +} -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/