From fbb9748b6dc509542c4a82960da36d7b03a3a66b Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 14 May 2014 16:26:32 +0200 Subject: [PATCH] Configurable kernel module probes support Create a kernel module probes list and use it to load the specified probes. The probes are selectable by the --kmod-probes command line option to lttng-sessiond or the LTTNG_KMOD_PROBES environment variable. If neither is set all probes are loaded so the current behaviour is not changed. Signed-off-by: Jan Glauber Signed-off-by: David Goulet --- doc/man/lttng-sessiond.8 | 7 ++ src/bin/lttng-sessiond/kern-modules.h | 2 +- src/bin/lttng-sessiond/main.c | 5 ++ src/bin/lttng-sessiond/modprobe.c | 101 ++++++++++++++++++++++---- src/bin/lttng-sessiond/modprobe.h | 2 + src/common/defaults.h | 3 + src/common/utils.c | 10 +++ src/common/utils.h | 1 + 8 files changed, 116 insertions(+), 15 deletions(-) diff --git a/doc/man/lttng-sessiond.8 b/doc/man/lttng-sessiond.8 index e6e37a0f5..8a7e04210 100644 --- a/doc/man/lttng-sessiond.8 +++ b/doc/man/lttng-sessiond.8 @@ -81,6 +81,11 @@ No kernel tracer support .BR " --jul-tcp-port" JUL application registration TCP port (default: 5345) .TP +.BR " --kmod-probes=probe1, probe2, ..." +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 "-c, --client-sock=PATH" Specify path for the client unix socket .TP @@ -153,6 +158,8 @@ parameter: the timeout value, in milliseconds. A value of 0 or -1 uses the timeout of the operating system (this is the default). .IP "LTTNG_SESSION_CONFIG_XSD_PATH" 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. .SH "SEE ALSO" .PP diff --git a/src/bin/lttng-sessiond/kern-modules.h b/src/bin/lttng-sessiond/kern-modules.h index ca09fc3af..26f44578d 100644 --- a/src/bin/lttng-sessiond/kern-modules.h +++ b/src/bin/lttng-sessiond/kern-modules.h @@ -28,7 +28,7 @@ #define KERN_MODULES_MINOR 0 struct kern_modules_param { - const char *name; + char *name; }; #endif /* _KERN_MODULES_H */ diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index eb772fe59..5448259e5 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -155,6 +155,7 @@ static const struct option long_options[] = { { "jul-tcp-port", 1, 0, 'J' }, { "config", 1, 0, 'f' }, { "load", 1, 0, 'l' }, + { "kmod-probes", 1, 0, 'P' }, { NULL, 0, 0, 0 } }; @@ -4132,6 +4133,7 @@ static void usage(void) fprintf(stderr, " --jul-tcp-port JUL application registration TCP port\n"); 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"); } /* @@ -4258,6 +4260,9 @@ static int set_option(int opt, const char *arg, const char *optname) ret = -ENOMEM; } break; + case 'P': /* probe modules list */ + kmod_probes_list = strdup(arg); + 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 2fbc7bd87..3cc67f0b9 100644 --- a/src/bin/lttng-sessiond/modprobe.c +++ b/src/bin/lttng-sessiond/modprobe.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 - David Goulet + * 2014 - Jan Glauber * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2 only, @@ -21,6 +22,7 @@ #include #include +#include #include "modprobe.h" #include "kern-modules.h" @@ -49,7 +51,7 @@ struct kern_modules_param kern_modules_control_opt[] = { }; /* LTTng kernel tracer probe modules list */ -const struct kern_modules_param kern_modules_probes[] = { +struct kern_modules_param kern_modules_probes_default[] = { { "lttng-probe-asoc" }, { "lttng-probe-block" }, { "lttng-probe-btrfs" }, @@ -90,6 +92,10 @@ const struct kern_modules_param kern_modules_probes[] = { { "lttng-probe-writeback" }, }; +/* dynamic probe modules list */ +static struct kern_modules_param *probes; +static int nr_probes; + void modprobe_remove_lttng(const struct kern_modules_param *modules, int entries, int required) { @@ -116,6 +122,8 @@ void modprobe_remove_lttng(const struct kern_modules_param *modules, DBG("Modprobe removal successful %s", modules[i].name); } + if (probes) + free(probes[i].name); } } @@ -125,11 +133,11 @@ void modprobe_remove_lttng(const struct kern_modules_param *modules, void modprobe_remove_lttng_control(void) { modprobe_remove_lttng(kern_modules_control_opt, - ARRAY_SIZE(kern_modules_control_opt), - LTTNG_MOD_OPTIONAL); + ARRAY_SIZE(kern_modules_control_opt), + LTTNG_MOD_OPTIONAL); modprobe_remove_lttng(kern_modules_control_core, - ARRAY_SIZE(kern_modules_control_core), - LTTNG_MOD_REQUIRED); + ARRAY_SIZE(kern_modules_control_core), + LTTNG_MOD_REQUIRED); } /* @@ -137,9 +145,14 @@ void modprobe_remove_lttng_control(void) */ void modprobe_remove_lttng_data(void) { - return modprobe_remove_lttng(kern_modules_probes, - ARRAY_SIZE(kern_modules_probes), - LTTNG_MOD_OPTIONAL); + if (probes) { + modprobe_remove_lttng(probes, nr_probes, LTTNG_MOD_OPTIONAL); + free(probes); + probes = NULL; + } else + modprobe_remove_lttng(kern_modules_probes_default, + ARRAY_SIZE(kern_modules_probes_default), + LTTNG_MOD_OPTIONAL); } /* @@ -151,7 +164,7 @@ void modprobe_remove_lttng_all(void) modprobe_remove_lttng_control(); } -static int modprobe_lttng(const struct kern_modules_param *modules, +static int modprobe_lttng(struct kern_modules_param *modules, int entries, int required) { int ret = 0, i; @@ -195,8 +208,8 @@ int modprobe_lttng_control(void) if (ret != 0) return ret; ret = modprobe_lttng(kern_modules_control_opt, - ARRAY_SIZE(kern_modules_control_opt), - LTTNG_MOD_OPTIONAL); + ARRAY_SIZE(kern_modules_control_opt), + LTTNG_MOD_OPTIONAL); return ret; } @@ -205,7 +218,67 @@ int modprobe_lttng_control(void) */ int modprobe_lttng_data(void) { - return modprobe_lttng(kern_modules_probes, - ARRAY_SIZE(kern_modules_probes), - LTTNG_MOD_OPTIONAL); + int i, ret; + int entries = ARRAY_SIZE(kern_modules_probes_default); + char *list, *next; + + /* + * 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); + } + + /* + * 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) { + PERROR("malloc probe list"); + return -ENOMEM; + } + + for (i = 0; i < entries; i++) { + size_t name_len; + + next = strtok(list, ","); + if (!next) { + goto out; + } + list = NULL; + + /* filter leading spaces */ + while (*next == ' ') { + next++; + } + + /* Length 13 is "lttng-probe-" + \0 */ + name_len = strlen(next) + 13; + + probes[i].name = zmalloc(name_len); + if (!probes[i].name) { + PERROR("malloc probe list"); + return -ENOMEM; + } + + ret = snprintf(probes[i].name, name_len, "lttng-probe-%s", next); + if (ret < 0) { + PERROR("snprintf modprobe name"); + goto out; + } + } + +out: + nr_probes = i; + 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 0c6f5f158..42e191217 100644 --- a/src/bin/lttng-sessiond/modprobe.h +++ b/src/bin/lttng-sessiond/modprobe.h @@ -24,4 +24,6 @@ void modprobe_remove_lttng_data(void); int modprobe_lttng_control(void); int modprobe_lttng_data(void); +char *kmod_probes_list; + #endif /* _MODPROBE_H */ diff --git a/src/common/defaults.h b/src/common/defaults.h index de610644c..b49bf4b33 100644 --- a/src/common/defaults.h +++ b/src/common/defaults.h @@ -90,6 +90,9 @@ #define DEFAULT_LTTNG_SESSIOND_PIDFILE "lttng-sessiond.pid" #define DEFAULT_LTTNG_SESSIOND_JULPORT_FILE "jul.port" +/* Default probes list */ +#define DEFAULT_LTTNG_KMOD_PROBES "LTTNG_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 9821815ba..bf93386c4 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -869,6 +869,16 @@ end: return home_dir; } +/* + * Obtain the value of LTTNG_KMOD_PROBES environment variable, if exists. + * Otherwise returns an empty string. + */ +LTTNG_HIDDEN +char *utils_get_kmod_probes_list(void) +{ + return getenv(DEFAULT_LTTNG_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 b872b5319..cc80a5369 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -47,6 +47,7 @@ int utils_parse_size_suffix(char const * const str, uint64_t * const size); 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); 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, -- 2.34.1