From: Philippe Proulx Date: Sat, 13 Sep 2014 01:37:18 +0000 (-0400) Subject: sessiond: Add --extra-kmod-probes option X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=commitdiff_plain;h=c9d424071aa532aa287fa86cfe02edbeded50e7b sessiond: Add --extra-kmod-probes option This patch adds the --extra-kmod-probes option to lttng-sessiond. The LTTNG_EXTRA_KMOD_PROBES environment variable may also be used. The option specifies a list of extra probe kernel modules to be loaded (and unloaded) by lttng-sessiond. The list is appended to either the default list or to the user-supplied --kmod-probes list. This option is especially useful for kernel developers who need the default LTTng kernel probes plus additional probes in order to instrument their custom kernel or module. This becomes easy with --extra-kmod-probes: lttng-sessiond --extra-kmod-probes=custom_subsys,other would load all known and available LTTng kernel probes plus lttng_probe_custom_subsys and lttng_probe_other. Signed-off-by: Philippe Proulx Signed-off-by: David Goulet --- diff --git a/doc/man/lttng-sessiond.8 b/doc/man/lttng-sessiond.8 index 212b743fa..9cd148eac 100644 --- a/doc/man/lttng-sessiond.8 +++ b/doc/man/lttng-sessiond.8 @@ -86,6 +86,12 @@ Specify the kernel modules containing LTTng probes to load by the session daemon Only the component name of the probe needs to be specified, e.g. to load the lttng-probe-irq and lttng-probe-sched use: --kmod-probes="irq, sched". .TP +.BR " --extra-kmod-probes=probe1, probe2, ..." +Specify extra kernel modules containing LTTng probes to be loaded by the session +daemon. The list follows the format of the \fB--kmod-probes\fP option. +This list is appended to the list provided by \fB--kmod-probes\fP or, if +\fB--kmod-probes\fP is missing, to the default list of probes. +.TP .BR "-c, --client-sock=PATH" Specify path for the client unix socket .TP @@ -175,6 +181,8 @@ the timeout of the operating system (this is the default). Specify the path that contains the XML session configuration schema (xsd). .IP "LTTNG_KMOD_PROBES" Specify the kernel modules probes that should be loaded by the session daemon. +.IP "LTTNG_EXTRA_KMOD_PROBES" +Specify extra kernel modules probes that should be loaded by the session daemon. .SH "SEE ALSO" .PP diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index c7fc178cd..2a97c37f6 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -157,6 +157,7 @@ static const struct option long_options[] = { { "config", 1, 0, 'f' }, { "load", 1, 0, 'l' }, { "kmod-probes", 1, 0, 'P' }, + { "extra-kmod-probes", 1, 0, 'e' }, { NULL, 0, 0, 0 } }; @@ -4214,6 +4215,7 @@ static void usage(void) fprintf(stderr, " -f --config Load daemon configuration file\n"); fprintf(stderr, " -l --load PATH Load session configuration\n"); fprintf(stderr, " --kmod-probes Specify kernel module probes to load\n"); + fprintf(stderr, " --extra-kmod-probes Specify extra kernel module probes to load\n"); } /* @@ -4400,6 +4402,14 @@ static int set_option(int opt, const char *arg, const char *optname) ret = -ENOMEM; } break; + case 'e': + free(kmod_extra_probes_list); + kmod_extra_probes_list = strdup(arg); + if (!kmod_extra_probes_list) { + perror("strdup"); + ret = -ENOMEM; + } + break; case 'f': /* This is handled in set_options() thus silent break. */ break; diff --git a/src/bin/lttng-sessiond/modprobe.c b/src/bin/lttng-sessiond/modprobe.c index 968b2650e..d329bb951 100644 --- a/src/bin/lttng-sessiond/modprobe.c +++ b/src/bin/lttng-sessiond/modprobe.c @@ -17,6 +17,7 @@ */ #define _GNU_SOURCE +#include #include #include #include @@ -95,6 +96,7 @@ struct kern_modules_param kern_modules_probes_default[] = { /* dynamic probe modules list */ static struct kern_modules_param *probes; static int nr_probes; +static int probes_capacity; void modprobe_remove_lttng(const struct kern_modules_param *modules, int entries, int required) @@ -122,8 +124,6 @@ void modprobe_remove_lttng(const struct kern_modules_param *modules, DBG("Modprobe removal successful %s", modules[i].name); } - if (probes) - free(probes[i].name); } } @@ -145,14 +145,18 @@ void modprobe_remove_lttng_control(void) */ void modprobe_remove_lttng_data(void) { + int i; + if (probes) { modprobe_remove_lttng(probes, nr_probes, LTTNG_MOD_OPTIONAL); + + for (i = 0; i < nr_probes; ++i) { + free(probes[i].name); + } + free(probes); probes = NULL; - } else - modprobe_remove_lttng(kern_modules_probes_default, - ARRAY_SIZE(kern_modules_probes_default), - LTTNG_MOD_OPTIONAL); + } } /* @@ -274,72 +278,179 @@ int modprobe_lttng_control(void) return ret; } -/* - * Load data kernel module(s). +/** + * Grow global list of probes (double capacity or set it to 1 if + * currently 0 and copy existing data). */ -int modprobe_lttng_data(void) +static int grow_probes(void) { - int i, ret; - int entries = ARRAY_SIZE(kern_modules_probes_default); - char *list, *next; + int i; + struct kern_modules_param *tmp_probes; - /* - * First take command line option, if not available take environment - * variable. - */ - if (kmod_probes_list) { - list = kmod_probes_list; - } else { - list = utils_get_kmod_probes_list(); - } - /* The default is to load ALL probes */ - if (!list) { - return modprobe_lttng(kern_modules_probes_default, entries, - LTTNG_MOD_OPTIONAL); + /* Initialize capacity to 1 if 0. */ + if (probes_capacity == 0) { + probes = zmalloc(sizeof(*probes)); + if (!probes) { + PERROR("malloc probe list"); + return -ENOMEM; + } + + probes_capacity = 1; + return 0; } - /* - * A probe list is available, so use it. - * The number of probes is limited by the number of probes in the - * default list. - */ - probes = zmalloc(sizeof(struct kern_modules_param *) * entries); - if (!probes) { + /* Double size. */ + probes_capacity *= 2; + + tmp_probes = zmalloc(sizeof(*tmp_probes) * probes_capacity); + if (!tmp_probes) { PERROR("malloc probe list"); return -ENOMEM; } - for (i = 0; i < entries; i++) { + for (i = 0; i < nr_probes; ++i) { + /* Move name pointer. */ + tmp_probes[i].name = probes[i].name; + } + + /* Replace probes with larger copy. */ + free(probes); + probes = tmp_probes; + + return 0; +} + +/* + * Appends a comma-separated list of probes to the global list + * of probes. + */ +static int append_list_to_probes(const char *list) +{ + char *next; + int index = nr_probes, ret; + + assert(list); + + char *tmp_list = strdup(list); + if (!tmp_list) { + PERROR("strdup temp list"); + return -ENOMEM; + } + + for (;;) { size_t name_len; + struct kern_modules_param *cur_mod; - next = strtok(list, ","); + next = strtok(tmp_list, ","); if (!next) { - goto out; + break; } - list = NULL; + tmp_list = NULL; /* filter leading spaces */ while (*next == ' ') { next++; } + if (probes_capacity <= nr_probes) { + ret = grow_probes(); + if (ret) { + return ret; + } + } + /* Length 13 is "lttng-probe-" + \0 */ name_len = strlen(next) + 13; - probes[i].name = zmalloc(name_len); - if (!probes[i].name) { + cur_mod = &probes[index]; + cur_mod->name = zmalloc(name_len); + if (!cur_mod->name) { PERROR("malloc probe list"); return -ENOMEM; } - ret = snprintf(probes[i].name, name_len, "lttng-probe-%s", next); + ret = snprintf(cur_mod->name, name_len, "lttng-probe-%s", next); if (ret < 0) { PERROR("snprintf modprobe name"); - goto out; + return -ENOMEM; } + + cur_mod++; + nr_probes++; } -out: - nr_probes = i; + free(tmp_list); + + return 0; +} + +/* + * Load data kernel module(s). + */ +int modprobe_lttng_data(void) +{ + int ret, i; + char *list; + + /* + * Base probes: either from command line option, environment + * variable or default list. + */ + if (kmod_probes_list) { + list = kmod_probes_list; + } else { + list = utils_get_kmod_probes_list(); + } + + if (list) { + /* User-specified probes. */ + ret = append_list_to_probes(list); + + if (ret) { + return ret; + } + } else { + /* Default probes. */ + int def_len = ARRAY_SIZE(kern_modules_probes_default); + probes = zmalloc(sizeof(*probes) * def_len); + + if (!probes) { + PERROR("malloc probe list"); + return -ENOMEM; + } + + nr_probes = probes_capacity = def_len; + + for (i = 0; i < def_len; ++i) { + char* name = strdup(kern_modules_probes_default[i].name); + + if (!name) { + PERROR("strdup probe item"); + return -ENOMEM; + } + + probes[i].name = name; + } + } + + /* + * Extra modules? Append them to current probes list. + */ + if (kmod_extra_probes_list) { + list = kmod_extra_probes_list; + } else { + list = utils_get_extra_kmod_probes_list(); + } + + if (list) { + ret = append_list_to_probes(list); + if (ret) { + return ret; + } + } + + /* + * Load probes modules now. + */ return modprobe_lttng(probes, nr_probes, LTTNG_MOD_OPTIONAL); } diff --git a/src/bin/lttng-sessiond/modprobe.h b/src/bin/lttng-sessiond/modprobe.h index 42e191217..cc4416021 100644 --- a/src/bin/lttng-sessiond/modprobe.h +++ b/src/bin/lttng-sessiond/modprobe.h @@ -25,5 +25,6 @@ int modprobe_lttng_control(void); int modprobe_lttng_data(void); char *kmod_probes_list; +char *kmod_extra_probes_list; #endif /* _MODPROBE_H */ diff --git a/src/common/defaults.h b/src/common/defaults.h index 88f7fe83a..25d7b327b 100644 --- a/src/common/defaults.h +++ b/src/common/defaults.h @@ -94,6 +94,9 @@ /* Default probes list */ #define DEFAULT_LTTNG_KMOD_PROBES "LTTNG_KMOD_PROBES" +/* Default extra probes list */ +#define DEFAULT_LTTNG_EXTRA_KMOD_PROBES "LTTNG_EXTRA_KMOD_PROBES" + /* Default unix socket path */ #define DEFAULT_GLOBAL_CLIENT_UNIX_SOCK DEFAULT_LTTNG_RUNDIR "/client-lttng-sessiond" #define DEFAULT_HOME_CLIENT_UNIX_SOCK DEFAULT_LTTNG_HOME_RUNDIR "/client-lttng-sessiond" diff --git a/src/common/utils.c b/src/common/utils.c index ff6d1c223..1d07cb31c 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -927,7 +927,7 @@ end: /* * Obtain the value of LTTNG_KMOD_PROBES environment variable, if exists. - * Otherwise returns an empty string. + * Otherwise returns NULL. */ LTTNG_HIDDEN char *utils_get_kmod_probes_list(void) @@ -935,6 +935,16 @@ char *utils_get_kmod_probes_list(void) return getenv(DEFAULT_LTTNG_KMOD_PROBES); } +/* + * Obtain the value of LTTNG_EXTRA_KMOD_PROBES environment variable, if + * exists. Otherwise returns NULL. + */ +LTTNG_HIDDEN +char *utils_get_extra_kmod_probes_list(void) +{ + return getenv(DEFAULT_LTTNG_EXTRA_KMOD_PROBES); +} + /* * With the given format, fill dst with the time of len maximum siz. * diff --git a/src/common/utils.h b/src/common/utils.h index bdc0e14f0..537fe0f9e 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -48,6 +48,7 @@ int utils_get_count_order_u32(uint32_t x); char *utils_get_home_dir(void); char *utils_get_user_home_dir(uid_t uid); char *utils_get_kmod_probes_list(void); +char *utils_get_extra_kmod_probes_list(void); size_t utils_get_current_time_str(const char *format, char *dst, size_t len); gid_t utils_get_group_id(const char *name); char *utils_generate_optstring(const struct option *long_options,