sessiond: Add --extra-kmod-probes option
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Sat, 13 Sep 2014 01:37:18 +0000 (21:37 -0400)
committerDavid Goulet <dgoulet@efficios.com>
Fri, 19 Sep 2014 16:08:17 +0000 (12:08 -0400)
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 <eeppeliteloop@gmail.com>
Signed-off-by: David Goulet <dgoulet@efficios.com>
doc/man/lttng-sessiond.8
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/modprobe.c
src/bin/lttng-sessiond/modprobe.h
src/common/defaults.h
src/common/utils.c
src/common/utils.h

index 212b743fa9d0cd46d91d85db79b00e208c442638..9cd148eac18ae2c6586e02b7ad1bf663188554c7 100644 (file)
@@ -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
index c7fc178cdf09820809f14c218ac236f989439317..2a97c37f6859988360dd283d514429cc8a7f59c8 100644 (file)
@@ -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;
index 968b2650e05c9685fc04b3e56e29bb5fb87cd1ae..d329bb9514905570a1c3a25c36c5a9672d4bf353 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #define _GNU_SOURCE
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/wait.h>
@@ -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);
 }
index 42e191217ee8f6d054e7f6412788cdd0760b2fc2..cc4416021c32250472cbd8a3347533e92f2fe2da 100644 (file)
@@ -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 */
index 88f7fe83a9a91598a9edb1f56136061ffab592d8..25d7b327b02799f2ce8dc39ed05a8ad64271bad4 100644 (file)
@@ -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"
index ff6d1c22337200e69e24807b1c871530ce6ea09e..1d07cb31cc01511aedb781124de609277410075d 100644 (file)
@@ -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.
  *
index bdc0e14f063f0565dbcebd78578250cc7bc41736..537fe0f9e6cf1017cafbe7cbd43fa5f054291a3e 100644 (file)
@@ -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,
This page took 0.034279 seconds and 5 git commands to generate.