+ ret = modprobe_lttng(kern_modules_control_core,
+ ARRAY_SIZE(kern_modules_control_core),
+ LTTNG_MOD_REQUIRED);
+ if (ret != 0)
+ return ret;
+ ret = modprobe_lttng(kern_modules_control_opt,
+ ARRAY_SIZE(kern_modules_control_opt),
+ LTTNG_MOD_OPTIONAL);
+ return ret;
+}
+
+/**
+ * Grow global list of probes (double capacity or set it to 1 if
+ * currently 0 and copy existing data).
+ */
+static int grow_probes(void)
+{
+ int i;
+ struct kern_modules_param *tmp_probes;
+
+ /* 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;
+ }
+
+ /* 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 < 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;
+ char *tmp_list;
+
+ assert(list);
+
+ 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(tmp_list, ",");
+ if (!next) {
+ break;
+ }
+ tmp_list = NULL;
+
+ /* filter leading spaces */
+ while (*next == ' ') {
+ next++;
+ }
+
+ if (probes_capacity <= nr_probes) {
+ ret = grow_probes();
+ if (ret) {
+ goto error;
+ }
+ }
+
+ /* Length 13 is "lttng-probe-" + \0 */
+ name_len = strlen(next) + 13;
+
+ cur_mod = &probes[index];
+ cur_mod->name = zmalloc(name_len);
+ if (!cur_mod->name) {
+ PERROR("malloc probe list");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = snprintf(cur_mod->name, name_len, "lttng-probe-%s", next);
+ if (ret < 0) {
+ PERROR("snprintf modprobe name");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ cur_mod++;
+ nr_probes++;
+ }
+
+ free(tmp_list);
+ return 0;
+
+error:
+ free(tmp_list);
+ free_probes();
+ return ret;
+}
+
+/*
+ * 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");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ probes[i].name = name;
+ }