Fix: liblttng-ctl comm: lttng_channel is not packed
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Wed, 12 Jan 2022 23:18:08 +0000 (18:18 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 28 Feb 2022 22:12:15 +0000 (17:12 -0500)
Observed issue
==============

The size of the struct differs between bitness for x86-64 and x86
leading to serialization/deserialization problem across client
(liblttng-ctl) and lttng-sessiond.

sizeof(struct lttng_channel):

  x86: 608
  x86-64: 624

The struct cannot be marked as LTTNG_PACKED since it is part of the API.

Solution
========

Adopt a similar pattern to the new API with a "serialize" &
"create_from_buffer" approach. The only particularity is that we need to
flatten the channels on listing.

Most of the complexity is moved to `src/common/channel.c`

Known drawbacks
=========

None.

Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I59b0e92286e36c4f183d2950417cb180d4efc200

include/lttng/channel-internal.h
src/bin/lttng-sessiond/channel.c
src/bin/lttng-sessiond/channel.h
src/bin/lttng-sessiond/client.c
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/cmd.h
src/bin/lttng-sessiond/trace-ust.h
src/common/Makefile.am
src/common/channel.c [new file with mode: 0644]
src/common/sessiond-comm/sessiond-comm.h
src/lib/lttng-ctl/lttng-ctl.c

index 04b19322f96ea35f1340b6e5d6f74ac569ca3246..2e9590836da63c71f1e8837d7236353453188094 100644 (file)
@@ -9,6 +9,10 @@
 #define LTTNG_CHANNEL_INTERNAL_H
 
 #include <common/macros.h>
+#include <lttng/channel.h>
+
+struct lttng_dynamic_buffer;
+struct lttng_buffer_view;
 
 struct lttng_channel_extended {
        uint64_t discarded_events;
@@ -17,4 +21,51 @@ struct lttng_channel_extended {
        int64_t blocking_timeout;
 } LTTNG_PACKED;
 
+struct lttng_channel_comm {
+       /* Includes terminator `\0`. */
+       uint32_t name_len;
+       uint8_t enabled;
+
+       /* attr */
+       int8_t overwrite;
+       uint64_t subbuf_size;
+       uint64_t num_subbuf;
+       uint32_t switch_timer_interval;
+       uint32_t read_timer_interval;
+       uint8_t output;
+       uint64_t tracefile_size;
+       uint64_t tracefile_count;
+       uint32_t live_timer_interval;
+
+       /* Extended struct */
+       uint64_t discarded_events;
+       uint64_t lost_packets;
+       uint64_t monitor_timer_interval;
+       int64_t blocking_timeout;
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+struct lttng_channel *lttng_channel_create_internal(void);
+
+LTTNG_HIDDEN
+struct lttng_channel *lttng_channel_copy(const struct lttng_channel *src);
+
+LTTNG_HIDDEN
+ssize_t lttng_channel_create_from_buffer(const struct lttng_buffer_view *view,
+               struct lttng_channel **event);
+
+LTTNG_HIDDEN
+int lttng_channel_serialize(struct lttng_channel *channel,
+               struct lttng_dynamic_buffer *buf);
+
+LTTNG_HIDDEN
+void lttng_channel_set_default_extended_attr(struct lttng_domain *domain,
+               struct lttng_channel_extended *extended_attr);
+
+LTTNG_HIDDEN
+enum lttng_error_code lttng_channels_create_and_flatten_from_buffer(
+               const struct lttng_buffer_view *view,
+               unsigned int count,
+               struct lttng_channel **channels);
+
 #endif /* LTTNG_CHANNEL_INTERNAL_H */
index e2596ce58ebbc4caa8269513991349e378dffb79..365b24a59a7c6eb110c9b1bcdc663cbbf72c2fdd 100644 (file)
@@ -544,3 +544,56 @@ end:
 error:
        return ret;
 }
+
+struct lttng_channel *trace_ust_channel_to_lttng_channel(
+               const struct ltt_ust_channel *uchan)
+{
+       struct lttng_channel *channel = NULL, *ret = NULL;
+
+       channel = lttng_channel_create_internal();
+       if (!channel) {
+               goto end;
+       }
+
+       if (lttng_strncpy(channel->name, uchan->name, LTTNG_SYMBOL_NAME_LEN)) {
+               goto end;
+       }
+
+       channel->attr.overwrite = uchan->attr.overwrite;
+       channel->attr.subbuf_size = uchan->attr.subbuf_size;
+       channel->attr.num_subbuf = uchan->attr.num_subbuf;
+       channel->attr.switch_timer_interval = uchan->attr.switch_timer_interval;
+       channel->attr.read_timer_interval = uchan->attr.read_timer_interval;
+       channel->enabled = uchan->enabled;
+       channel->attr.tracefile_size = uchan->tracefile_size;
+       channel->attr.tracefile_count = uchan->tracefile_count;
+
+       /*
+        * Map enum lttng_ust_output to enum lttng_event_output.
+        */
+       switch (uchan->attr.output) {
+       case LTTNG_UST_MMAP:
+               channel->attr.output = LTTNG_EVENT_MMAP;
+               break;
+       default:
+               /*
+                * LTTNG_UST_MMAP is the only supported UST
+                * output mode.
+                */
+               abort();
+               break;
+       }
+
+       lttng_channel_set_blocking_timeout(
+                       channel, uchan->attr.u.s.blocking_timeout);
+       lttng_channel_set_monitor_timer_interval(
+                       channel, uchan->monitor_timer_interval);
+
+       ret = channel;
+       channel = NULL;
+
+end:
+       lttng_channel_destroy(channel);
+
+       return ret;
+}
index b4ff9f4fda0a2387c1b2dcde6c4f74b99977bbab..1b6e29bd758a77b0087de202cfa06f45cb7c861c 100644 (file)
@@ -31,4 +31,7 @@ int channel_ust_enable(struct ltt_ust_session *usess,
 int channel_ust_disable(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan);
 
+struct lttng_channel *trace_ust_channel_to_lttng_channel(
+               const struct ltt_ust_channel *uchan);
+
 #endif /* _LTT_CHANNEL_H */
index be907ebe38b6f877edf78c3bbbf574977f3b90a7..5e95a59f0fabf2c6874a01d276a7357945d137c2 100644 (file)
@@ -23,6 +23,7 @@
 #include <pthread.h>
 #include <signal.h>
 #include <stddef.h>
+#include <stdint.h>
 #include <sys/stat.h>
 
 #include "client.h"
@@ -716,6 +717,9 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
        int ret = LTTNG_OK;
        int need_tracing_session = 1;
        int need_domain;
+       struct lttng_dynamic_buffer payload;
+
+       lttng_dynamic_buffer_init(&payload);
 
        DBG("Processing client command %d", cmd_ctx->lsm->cmd_type);
 
@@ -1195,12 +1199,7 @@ error_add_context:
        }
        case LTTNG_ENABLE_CHANNEL:
        {
-               cmd_ctx->lsm->u.channel.chan.attr.extended.ptr =
-                               (struct lttng_channel_extended *) &cmd_ctx->lsm->u.channel.extended;
-               ret = cmd_enable_channel(cmd_ctx->session,
-                               ALIGNED_CONST_PTR(cmd_ctx->lsm->domain),
-                               ALIGNED_CONST_PTR(cmd_ctx->lsm->u.channel.chan),
-                               kernel_poll_pipe[1]);
+               ret = cmd_enable_channel(cmd_ctx, *sock, kernel_poll_pipe[1]);
                break;
        }
        case LTTNG_PROCESS_ATTR_TRACKER_ADD_INCLUDE_VALUE:
@@ -1706,20 +1705,20 @@ error_add_context:
        }
        case LTTNG_LIST_CHANNELS:
        {
-               ssize_t payload_size;
-               struct lttng_channel *channels = NULL;
+               uint32_t nb_channel;
+               enum lttng_error_code ret_code;
+               struct lttcomm_list_command_header cmd_header = { 0 };
 
-               payload_size = cmd_list_channels(cmd_ctx->lsm->domain.type,
-                               cmd_ctx->session, &channels);
-               if (payload_size < 0) {
-                       /* Return value is a negative lttng_error_code. */
-                       ret = -payload_size;
+               ret_code = cmd_list_channels(cmd_ctx->lsm->domain.type,
+                               cmd_ctx->session, &payload, &nb_channel);
+               if (ret_code != LTTNG_OK) {
+                       ret = (int) ret_code;
                        goto error;
                }
 
-               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, channels,
-                       payload_size);
-               free(channels);
+               cmd_header.count = nb_channel;
+               ret = setup_lttng_msg(cmd_ctx, payload.data, payload.size,
+                               &cmd_header, sizeof(cmd_header));
 
                if (ret < 0) {
                        goto setup_error;
@@ -2108,6 +2107,7 @@ setup_error:
        }
 init_setup_error:
        assert(!rcu_read_ongoing());
+       lttng_dynamic_buffer_reset(&payload);
        return ret;
 }
 
index 655e4727d1b967b35ed2cbf81eb0f56e06b4bb76..01dc3bb7486471844ec358d6dfba5dee25e3f424 100644 (file)
@@ -111,6 +111,10 @@ static int cmd_enable_event_internal(struct ltt_session *session,
                struct lttng_filter_bytecode *filter,
                struct lttng_event_exclusion *exclusion,
                int wpipe);
+static int cmd_enable_channel_internal(struct ltt_session *session,
+               const struct lttng_domain *domain,
+               const struct lttng_channel *_attr,
+               int wpipe);
 
 /*
  * Create a session path used by list_lttng_sessions for the case that the
@@ -281,118 +285,6 @@ end:
        return ret;
 }
 
-/*
- * Fill lttng_channel array of all channels.
- */
-static ssize_t list_lttng_channels(enum lttng_domain_type domain,
-               struct ltt_session *session, struct lttng_channel *channels,
-               struct lttng_channel_extended *chan_exts)
-{
-       int i = 0, ret = 0;
-       struct ltt_kernel_channel *kchan;
-
-       DBG("Listing channels for session %s", session->name);
-
-       switch (domain) {
-       case LTTNG_DOMAIN_KERNEL:
-               /* Kernel channels */
-               if (session->kernel_session != NULL) {
-                       cds_list_for_each_entry(kchan,
-                                       &session->kernel_session->channel_list.head, list) {
-                               uint64_t discarded_events, lost_packets;
-                               struct lttng_channel_extended *extended;
-
-                               extended = (struct lttng_channel_extended *)
-                                               kchan->channel->attr.extended.ptr;
-
-                               ret = get_kernel_runtime_stats(session, kchan,
-                                               &discarded_events, &lost_packets);
-                               if (ret < 0) {
-                                       goto end;
-                               }
-                               /* Copy lttng_channel struct to array */
-                               memcpy(&channels[i], kchan->channel, sizeof(struct lttng_channel));
-                               channels[i].enabled = kchan->enabled;
-                               chan_exts[i].discarded_events =
-                                               discarded_events;
-                               chan_exts[i].lost_packets = lost_packets;
-                               chan_exts[i].monitor_timer_interval =
-                                               extended->monitor_timer_interval;
-                               chan_exts[i].blocking_timeout = 0;
-                               i++;
-                       }
-               }
-               break;
-       case LTTNG_DOMAIN_UST:
-       {
-               struct lttng_ht_iter iter;
-               struct ltt_ust_channel *uchan;
-
-               rcu_read_lock();
-               cds_lfht_for_each_entry(session->ust_session->domain_global.channels->ht,
-                               &iter.iter, uchan, node.node) {
-                       uint64_t discarded_events = 0, lost_packets = 0;
-
-                       if (lttng_strncpy(channels[i].name, uchan->name,
-                                       LTTNG_SYMBOL_NAME_LEN)) {
-                               break;
-                       }
-                       channels[i].attr.overwrite = uchan->attr.overwrite;
-                       channels[i].attr.subbuf_size = uchan->attr.subbuf_size;
-                       channels[i].attr.num_subbuf = uchan->attr.num_subbuf;
-                       channels[i].attr.switch_timer_interval =
-                               uchan->attr.switch_timer_interval;
-                       channels[i].attr.read_timer_interval =
-                               uchan->attr.read_timer_interval;
-                       channels[i].enabled = uchan->enabled;
-                       channels[i].attr.tracefile_size = uchan->tracefile_size;
-                       channels[i].attr.tracefile_count = uchan->tracefile_count;
-
-                       /*
-                        * Map enum lttng_ust_output to enum lttng_event_output.
-                        */
-                       switch (uchan->attr.output) {
-                       case LTTNG_UST_MMAP:
-                               channels[i].attr.output = LTTNG_EVENT_MMAP;
-                               break;
-                       default:
-                               /*
-                                * LTTNG_UST_MMAP is the only supported UST
-                                * output mode.
-                                */
-                               assert(0);
-                               break;
-                       }
-
-                       chan_exts[i].monitor_timer_interval =
-                                       uchan->monitor_timer_interval;
-                       chan_exts[i].blocking_timeout =
-                               uchan->attr.u.s.blocking_timeout;
-
-                       ret = get_ust_runtime_stats(session, uchan,
-                                       &discarded_events, &lost_packets);
-                       if (ret < 0) {
-                               break;
-                       }
-                       chan_exts[i].discarded_events = discarded_events;
-                       chan_exts[i].lost_packets = lost_packets;
-                       i++;
-               }
-               rcu_read_unlock();
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       if (ret < 0) {
-               return -LTTNG_ERR_FATAL;
-       } else {
-               return LTTNG_OK;
-       }
-}
-
 static int increment_extended_len(const char *filter_expression,
                struct lttng_event_exclusion *exclusion,
                const struct lttng_userspace_probe_location *probe_location,
@@ -1434,30 +1326,84 @@ error:
  *
  * The wpipe arguments is used as a notifier for the kernel thread.
  */
-int cmd_enable_channel(struct ltt_session *session,
-               const struct lttng_domain *domain, const struct lttng_channel *_attr, int wpipe)
+int cmd_enable_channel(struct command_ctx *cmd_ctx, int sock, int wpipe)
+{
+       int ret;
+       size_t channel_len;
+       ssize_t sock_recv_len;
+       struct lttng_channel *channel = NULL;
+       struct lttng_buffer_view view;
+       struct lttng_dynamic_buffer channel_buffer;
+
+       lttng_dynamic_buffer_init(&channel_buffer);
+       channel_len = (size_t) cmd_ctx->lsm->u.channel.length;
+       ret = lttng_dynamic_buffer_set_size(&channel_buffer, channel_len);
+       if (ret) {
+               ret = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       sock_recv_len = lttcomm_recv_unix_sock(sock, channel_buffer.data,
+                       channel_len);
+       if (sock_recv_len < 0 || sock_recv_len != channel_len) {
+               ERR("Failed to receive \"enable channel\" command payload");
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       view = lttng_buffer_view_from_dynamic_buffer(&channel_buffer, 0, channel_len);
+       if (!lttng_buffer_view_is_valid(&view)) {
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       if (lttng_channel_create_from_buffer(&view, &channel) != channel_len) {
+               ERR("Invalid channel payload received in \"enable channel\" command");
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = cmd_enable_channel_internal(cmd_ctx->session,
+                       ALIGNED_CONST_PTR(cmd_ctx->lsm->domain), channel,
+                       wpipe);
+
+end:
+       lttng_dynamic_buffer_reset(&channel_buffer);
+       lttng_channel_destroy(channel);
+       return ret;
+}
+
+static int cmd_enable_channel_internal(struct ltt_session *session,
+               const struct lttng_domain *domain,
+               const struct lttng_channel *_attr,
+               int wpipe)
 {
        int ret;
        struct ltt_ust_session *usess = session->ust_session;
        struct lttng_ht *chan_ht;
        size_t len;
-       struct lttng_channel attr;
+       struct lttng_channel *attr = NULL;
 
        assert(session);
        assert(_attr);
        assert(domain);
 
-       attr = *_attr;
-       len = lttng_strnlen(attr.name, sizeof(attr.name));
+       attr = lttng_channel_copy(_attr);
+       if (!attr) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       len = lttng_strnlen(attr->name, sizeof(attr->name));
 
        /* Validate channel name */
-       if (attr.name[0] == '.' ||
-               memchr(attr.name, '/', len) != NULL) {
+       if (attr->name[0] == '.' ||
+               memchr(attr->name, '/', len) != NULL) {
                ret = LTTNG_ERR_INVALID_CHANNEL_NAME;
                goto end;
        }
 
-       DBG("Enabling channel %s for session %s", attr.name, session->name);
+       DBG("Enabling channel %s for session %s", attr->name, session->name);
 
        rcu_read_lock();
 
@@ -1467,8 +1413,8 @@ int cmd_enable_channel(struct ltt_session *session,
         * beacons for inactive streams.
         */
        if (session->live_timer > 0) {
-               attr.attr.live_timer_interval = session->live_timer;
-               attr.attr.switch_timer_interval = 0;
+               attr->attr.live_timer_interval = session->live_timer;
+               attr->attr.switch_timer_interval = 0;
        }
 
        /* Check for feature support */
@@ -1480,8 +1426,8 @@ int cmd_enable_channel(struct ltt_session *session,
                        WARN("Kernel tracer does not support buffer monitoring. "
                                        "Setting the monitor interval timer to 0 "
                                        "(disabled) for channel '%s' of session '%s'",
-                                       attr.name, session->name);
-                       lttng_channel_set_monitor_timer_interval(&attr, 0);
+                                       attr->name, session->name);
+                       lttng_channel_set_monitor_timer_interval(attr, 0);
                }
                break;
        }
@@ -1506,8 +1452,8 @@ int cmd_enable_channel(struct ltt_session *session,
        {
                struct ltt_kernel_channel *kchan;
 
-               kchan = trace_kernel_get_channel_by_name(attr.name,
-                               session->kernel_session);
+               kchan = trace_kernel_get_channel_by_name(
+                               attr->name, session->kernel_session);
                if (kchan == NULL) {
                        /*
                         * Don't try to create a channel if the session has been started at
@@ -1521,10 +1467,11 @@ int cmd_enable_channel(struct ltt_session *session,
                        if (session->snapshot.nb_output > 0 ||
                                        session->snapshot_mode) {
                                /* Enforce mmap output for snapshot sessions. */
-                               attr.attr.output = LTTNG_EVENT_MMAP;
+                               attr->attr.output = LTTNG_EVENT_MMAP;
                        }
-                       ret = channel_kernel_create(session->kernel_session, &attr, wpipe);
-                       if (attr.name[0] != '\0') {
+                       ret = channel_kernel_create(
+                                       session->kernel_session, attr, wpipe);
+                       if (attr->name[0] != '\0') {
                                session->kernel_session->has_non_default_channel = 1;
                        }
                } else {
@@ -1554,19 +1501,19 @@ int cmd_enable_channel(struct ltt_session *session,
                 * adhered to.
                 */
                if (domain->type == LTTNG_DOMAIN_JUL) {
-                       if (strncmp(attr.name, DEFAULT_JUL_CHANNEL_NAME,
+                       if (strncmp(attr->name, DEFAULT_JUL_CHANNEL_NAME,
                                        LTTNG_SYMBOL_NAME_LEN)) {
                                ret = LTTNG_ERR_INVALID_CHANNEL_NAME;
                                goto error;
                        }
                } else if (domain->type == LTTNG_DOMAIN_LOG4J) {
-                       if (strncmp(attr.name, DEFAULT_LOG4J_CHANNEL_NAME,
+                       if (strncmp(attr->name, DEFAULT_LOG4J_CHANNEL_NAME,
                                        LTTNG_SYMBOL_NAME_LEN)) {
                                ret = LTTNG_ERR_INVALID_CHANNEL_NAME;
                                goto error;
                        }
                } else if (domain->type == LTTNG_DOMAIN_PYTHON) {
-                       if (strncmp(attr.name, DEFAULT_PYTHON_CHANNEL_NAME,
+                       if (strncmp(attr->name, DEFAULT_PYTHON_CHANNEL_NAME,
                                        LTTNG_SYMBOL_NAME_LEN)) {
                                ret = LTTNG_ERR_INVALID_CHANNEL_NAME;
                                goto error;
@@ -1575,7 +1522,7 @@ int cmd_enable_channel(struct ltt_session *session,
 
                chan_ht = usess->domain_global.channels;
 
-               uchan = trace_ust_find_channel_by_name(chan_ht, attr.name);
+               uchan = trace_ust_find_channel_by_name(chan_ht, attr->name);
                if (uchan == NULL) {
                        /*
                         * Don't try to create a channel if the session has been started at
@@ -1586,8 +1533,8 @@ int cmd_enable_channel(struct ltt_session *session,
                                goto error;
                        }
 
-                       ret = channel_ust_create(usess, &attr, domain->buf_type);
-                       if (attr.name[0] != '\0') {
+                       ret = channel_ust_create(usess, attr, domain->buf_type);
+                       if (attr->name[0] != '\0') {
                                usess->has_non_default_channel = 1;
                        }
                } else {
@@ -1600,12 +1547,13 @@ int cmd_enable_channel(struct ltt_session *session,
                goto error;
        }
 
-       if (ret == LTTNG_OK && attr.attr.output != LTTNG_EVENT_MMAP) {
+       if (ret == LTTNG_OK && attr->attr.output != LTTNG_EVENT_MMAP) {
                session->has_non_mmap_channel = true;
        }
 error:
        rcu_read_unlock();
 end:
+       lttng_channel_destroy(attr);
        return ret;
 }
 
@@ -2232,7 +2180,8 @@ static int _cmd_enable_event(struct ltt_session *session,
                                goto error;
                        }
 
-                       ret = cmd_enable_channel(session, domain, attr, wpipe);
+                       ret = cmd_enable_channel_internal(
+                                       session, domain, attr, wpipe);
                        if (ret != LTTNG_OK) {
                                goto error;
                        }
@@ -2371,7 +2320,8 @@ static int _cmd_enable_event(struct ltt_session *session,
                                goto error;
                        }
 
-                       ret = cmd_enable_channel(session, domain, attr, wpipe);
+                       ret = cmd_enable_channel_internal(
+                                       session, domain, attr, wpipe);
                        if (ret != LTTNG_OK) {
                                goto error;
                        }
@@ -3665,67 +3615,113 @@ error:
 /*
  * Command LTTNG_LIST_CHANNELS processed by the client thread.
  */
-ssize_t cmd_list_channels(enum lttng_domain_type domain,
-               struct ltt_session *session, struct lttng_channel **channels)
+enum lttng_error_code cmd_list_channels(enum lttng_domain_type domain,
+               struct ltt_session *session,
+               struct lttng_dynamic_buffer *buffer,
+               uint32_t *nb_channel)
 {
-       ssize_t nb_chan = 0, payload_size = 0, ret;
+       int ret = 0;
+       uint32_t i = 0;
+
+       assert(session);
+       assert(buffer);
+       assert(nb_channel);
+
+       DBG("Listing channels for session %s", session->name);
 
        switch (domain) {
        case LTTNG_DOMAIN_KERNEL:
+       {
+               /* Kernel channels */
+               struct ltt_kernel_channel *kchan;
                if (session->kernel_session != NULL) {
-                       nb_chan = session->kernel_session->channel_count;
-               }
-               DBG3("Number of kernel channels %zd", nb_chan);
-               if (nb_chan <= 0) {
-                       ret = -LTTNG_ERR_KERN_CHAN_NOT_FOUND;
-                       goto end;
-               }
-               break;
-       case LTTNG_DOMAIN_UST:
-               if (session->ust_session != NULL) {
-                       rcu_read_lock();
-                       nb_chan = lttng_ht_get_count(
-                               session->ust_session->domain_global.channels);
-                       rcu_read_unlock();
-               }
-               DBG3("Number of UST global channels %zd", nb_chan);
-               if (nb_chan < 0) {
-                       ret = -LTTNG_ERR_UST_CHAN_NOT_FOUND;
-                       goto end;
+                       cds_list_for_each_entry(kchan,
+                                       &session->kernel_session->channel_list.head, list) {
+                               uint64_t discarded_events, lost_packets;
+                               struct lttng_channel_extended *extended;
+
+                               extended = (struct lttng_channel_extended *)
+                                               kchan->channel->attr.extended.ptr;
+
+                               ret = get_kernel_runtime_stats(session, kchan,
+                                               &discarded_events, &lost_packets);
+                               if (ret < 0) {
+                                       goto end;
+                               }
+
+                               /*
+                                * Update the discarded_events and lost_packets
+                                * count for the channel
+                                */
+                               extended->discarded_events = discarded_events;
+                               extended->lost_packets = lost_packets;
+
+                               ret = lttng_channel_serialize(
+                                               kchan->channel, buffer);
+                               if (ret) {
+                                       ret = -1;
+                                       goto end;
+                               }
+
+                               i++;
+                       }
                }
                break;
-       default:
-               ret = -LTTNG_ERR_UND;
-               goto end;
        }
+       case LTTNG_DOMAIN_UST:
+       {
+               struct lttng_ht_iter iter;
+               struct ltt_ust_channel *uchan;
 
-       if (nb_chan > 0) {
-               const size_t channel_size = sizeof(struct lttng_channel) +
-                       sizeof(struct lttng_channel_extended);
-               struct lttng_channel_extended *channel_exts;
+               rcu_read_lock();
+               cds_lfht_for_each_entry(session->ust_session->domain_global.channels->ht,
+                               &iter.iter, uchan, node.node) {
+                       uint64_t discarded_events = 0, lost_packets = 0;
+                       struct lttng_channel *channel = NULL;
+                       struct lttng_channel_extended *extended;
 
-               payload_size = nb_chan * channel_size;
-               *channels = zmalloc(payload_size);
-               if (*channels == NULL) {
-                       ret = -LTTNG_ERR_FATAL;
-                       goto end;
-               }
+                       channel = trace_ust_channel_to_lttng_channel(uchan);
+                       if (!channel) {
+                               ret = -1;
+                               break;
+                       }
 
-               channel_exts = ((void *) *channels) +
-                               (nb_chan * sizeof(struct lttng_channel));
-               ret = list_lttng_channels(domain, session, *channels, channel_exts);
-               if (ret != LTTNG_OK) {
-                       free(*channels);
-                       *channels = NULL;
-                       goto end;
+                       extended = (struct lttng_channel_extended *)
+                                                  channel->attr.extended.ptr;
+
+                       ret = get_ust_runtime_stats(session, uchan,
+                                       &discarded_events, &lost_packets);
+                       if (ret < 0) {
+                               lttng_channel_destroy(channel);
+                               break;
+                       }
+
+                       extended->discarded_events = discarded_events;
+                       extended->lost_packets = lost_packets;
+
+                       ret = lttng_channel_serialize(channel, buffer);
+                       if (ret) {
+                               ret = -1;
+                               break;
+                       }
+
+                       i++;
                }
-       } else {
-               *channels = NULL;
+               rcu_read_unlock();
+               break;
+       }
+       default:
+               break;
        }
 
-       ret = payload_size;
 end:
-       return ret;
+       if (ret < 0) {
+               *nb_channel = 0;
+               return LTTNG_ERR_FATAL;
+       } else {
+               *nb_channel = i;
+               return LTTNG_OK;
+       }
 }
 
 /*
index 1be746031146962372c0d465de19e4adeb3753f4..65e3846c83b5d877690b99a6d4c3a03dd883da7c 100644 (file)
@@ -15,6 +15,7 @@
 #include <common/tracker.h>
 
 struct notification_thread_handle;
+struct lttng_dynamic_buffer;
 
 /*
  * A callback (and associated user data) that should be run after a command
@@ -46,9 +47,7 @@ int cmd_destroy_session(struct ltt_session *session,
 /* Channel commands */
 int cmd_disable_channel(struct ltt_session *session,
                enum lttng_domain_type domain, char *channel_name);
-int cmd_enable_channel(struct ltt_session *session,
-               const struct lttng_domain *domain, const struct lttng_channel *attr,
-               int wpipe);
+int cmd_enable_channel(struct command_ctx *cmd_ctx, int sock, int wpipe);
 
 /* Process attribute tracker commands */
 enum lttng_error_code cmd_process_attr_tracker_get_tracking_policy(
@@ -112,8 +111,10 @@ ssize_t cmd_list_domains(struct ltt_session *session,
 ssize_t cmd_list_events(enum lttng_domain_type domain,
                struct ltt_session *session, char *channel_name,
                struct lttng_event **events, size_t *total_size);
-ssize_t cmd_list_channels(enum lttng_domain_type domain,
-               struct ltt_session *session, struct lttng_channel **channels);
+enum lttng_error_code cmd_list_channels(enum lttng_domain_type domain,
+               struct ltt_session *session,
+               struct lttng_dynamic_buffer *buffer,
+               uint32_t *nb_channel);
 ssize_t cmd_list_domains(struct ltt_session *session,
                struct lttng_domain **domains);
 void cmd_list_lttng_sessions(struct lttng_session *sessions,
index 960ba57d5f8f97ca22cecac28a5982a380aa026f..f0e35b8bd0c62968a90571b6a110019d23ec6222 100644 (file)
@@ -196,6 +196,7 @@ struct agent *trace_ust_find_agent(struct ltt_ust_session *session,
 struct ltt_ust_session *trace_ust_create_session(uint64_t session_id);
 struct ltt_ust_channel *trace_ust_create_channel(struct lttng_channel *attr,
                enum lttng_domain_type domain);
+
 enum lttng_error_code trace_ust_create_event(struct lttng_event *ev,
                char *filter_expression,
                struct lttng_filter_bytecode *filter,
index ca9c70d806c5277fed567c5a8c2efcbb941bf62a..8b698c92174b5d941a81be4c546e8fca64d1c78f 100644 (file)
@@ -33,6 +33,7 @@ libcommon_lgpl_la_SOURCES = \
        action.c \
        buffer-view.h buffer-view.c \
        buffer-usage.c \
+       channel.c \
        credentials.h \
        condition.c \
        defaults.c \
diff --git a/src/common/channel.c b/src/common/channel.c
new file mode 100644 (file)
index 0000000..4a237e4
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2021 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <common/macros.h>
+#include <lttng/channel.h>
+#include <lttng/constant.h>
+#include <lttng/channel-internal.h>
+#include <lttng/userspace-probe-internal.h>
+#include <common/dynamic-buffer.h>
+#include <common/error.h>
+#include <assert.h>
+#include <string.h>
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/dynamic-array.h>
+#include <common/buffer-view.h>
+
+static enum lttng_error_code flatten_lttng_channels(
+               struct lttng_dynamic_pointer_array *channels,
+               struct lttng_channel **flattened_channels);
+
+static enum lttng_error_code channel_list_create_from_buffer(
+               const struct lttng_buffer_view *buffer,
+               uint32_t count,
+               struct lttng_dynamic_pointer_array *channel_list);
+
+static void channel_list_destructor(void *ptr)
+{
+       struct lttng_channel *element = (struct lttng_channel *) ptr;
+
+       lttng_channel_destroy(element);
+}
+
+LTTNG_HIDDEN
+struct lttng_channel *lttng_channel_copy(const struct lttng_channel *src)
+{
+       struct lttng_channel_extended *extended = NULL;
+       struct lttng_channel *channel = NULL, *ret = NULL;
+
+       channel = zmalloc(sizeof(*channel));
+       if (!channel) {
+               goto end;
+       }
+
+       memcpy(channel, src, sizeof(*channel));
+
+       if (src->attr.extended.ptr) {
+               extended = zmalloc(sizeof(*extended));
+               if (!extended) {
+                       goto end;
+               }
+               memcpy(extended, src->attr.extended.ptr, sizeof(*extended));
+               channel->attr.extended.ptr = extended;
+               extended = NULL;
+       }
+
+       ret = channel;
+       channel = NULL;
+end:
+       free(channel);
+       free(extended);
+       return ret;
+}
+
+/*
+ * The channel object is NOT populated.
+ */
+LTTNG_HIDDEN
+struct lttng_channel *lttng_channel_create_internal(void)
+{
+       struct lttng_channel *local_channel = NULL, *ret = NULL;
+       struct lttng_channel_extended *extended = NULL;
+
+       local_channel = zmalloc(sizeof(struct lttng_channel));
+       if (!local_channel) {
+               goto end;
+       }
+
+       /* Extended struct */
+       extended = zmalloc(sizeof(*extended));
+       if (!extended) {
+               goto end;
+       }
+
+       local_channel->attr.extended.ptr = extended;
+       extended = NULL;
+
+       ret = local_channel;
+       local_channel = NULL;
+end:
+       free(extended);
+       free(local_channel);
+       return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_channel_create_from_buffer(const struct lttng_buffer_view *view,
+               struct lttng_channel **channel)
+{
+       ssize_t ret, offset = 0;
+       struct lttng_channel *local_channel = NULL;
+       const struct lttng_channel_comm *channel_comm;
+       struct lttng_channel_extended *extended = NULL;
+
+       assert(channel);
+
+       if (!view || !channel) {
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Create an 'internal' channel since `lttng_create_channel` requires a
+        * domain and we cannot infer the domain from the payload.
+        */
+       local_channel = lttng_channel_create_internal();
+       if (!local_channel) {
+               ret = -1;
+               goto end;
+       }
+
+       extended = (typeof(extended)) local_channel->attr.extended.ptr;
+
+       /* lttng_trigger_comm header */
+       {
+               const struct lttng_buffer_view comm_view =
+                               lttng_buffer_view_from_view(view, offset,
+                                               sizeof(*channel_comm));
+
+               if (!lttng_buffer_view_is_valid(&comm_view)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               channel_comm = (const struct lttng_channel_comm *)
+                                              comm_view.data;
+               offset += sizeof(*channel_comm);
+       }
+
+       {
+               const char *name;
+               const struct lttng_buffer_view name_view =
+                               lttng_buffer_view_from_view(view, offset,
+                                               channel_comm->name_len);
+
+               if (channel_comm->name_len > LTTNG_SYMBOL_NAME_LEN - 1) {
+                       ret = -1;
+                       goto end;
+               }
+
+               name = name_view.data;
+               if (!lttng_buffer_view_contains_string(
+                                   &name_view, name, channel_comm->name_len)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               strcpy(local_channel->name, name);
+               offset += channel_comm->name_len;
+       }
+
+       /* Populate the channel */
+       local_channel->enabled = channel_comm->enabled;
+
+       /* attr */
+       local_channel->attr.overwrite = channel_comm->overwrite;
+       local_channel->attr.subbuf_size = channel_comm->subbuf_size;
+       local_channel->attr.num_subbuf = channel_comm->num_subbuf;
+       local_channel->attr.switch_timer_interval =
+                       channel_comm->switch_timer_interval;
+       local_channel->attr.read_timer_interval =
+                       channel_comm->read_timer_interval;
+       local_channel->attr.output = channel_comm->output;
+       local_channel->attr.tracefile_size = channel_comm->tracefile_size;
+       local_channel->attr.tracefile_count = channel_comm->tracefile_count;
+       local_channel->attr.live_timer_interval =
+                       channel_comm->live_timer_interval;
+
+       extended->discarded_events = channel_comm->discarded_events;
+       extended->lost_packets = channel_comm->lost_packets;
+       extended->monitor_timer_interval = channel_comm->monitor_timer_interval;
+       extended->blocking_timeout = channel_comm->blocking_timeout;
+
+       *channel = local_channel;
+       local_channel = NULL;
+
+       ret = offset;
+end:
+       lttng_channel_destroy(local_channel);
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_channel_serialize(
+               struct lttng_channel *channel, struct lttng_dynamic_buffer *buf)
+{
+       int ret;
+       size_t name_len;
+       struct lttng_channel_comm channel_comm = { 0 };
+       struct lttng_channel_extended *extended;
+
+       assert(channel);
+       assert(buf);
+
+       extended = channel->attr.extended.ptr;
+
+       name_len = lttng_strnlen(channel->name, LTTNG_SYMBOL_NAME_LEN);
+       if (name_len == LTTNG_SYMBOL_NAME_LEN) {
+               /* channel name is not NULL-terminated. */
+               ret = -1;
+               goto end;
+       }
+
+       /* Include string termination. */
+       name_len += 1;
+
+       /* Base field */
+       channel_comm.name_len = (uint32_t) name_len;
+       channel_comm.enabled = channel->enabled;
+
+       /* attr */
+       channel_comm.overwrite = channel->attr.overwrite;
+       channel_comm.subbuf_size = channel->attr.subbuf_size;
+       channel_comm.num_subbuf = channel->attr.num_subbuf;
+       channel_comm.switch_timer_interval =
+                       channel->attr.switch_timer_interval;
+       channel_comm.read_timer_interval = channel->attr.read_timer_interval;
+       channel_comm.output = channel->attr.output;
+       channel_comm.tracefile_size = channel->attr.tracefile_size;
+       channel_comm.tracefile_count = channel->attr.tracefile_count;
+       channel_comm.live_timer_interval = channel->attr.live_timer_interval;
+
+       /* Extended struct */
+       channel_comm.discarded_events = extended->discarded_events;
+       channel_comm.lost_packets = extended->lost_packets;
+       channel_comm.monitor_timer_interval = extended->monitor_timer_interval;
+       channel_comm.blocking_timeout = extended->blocking_timeout;
+
+       /* Header */
+       ret = lttng_dynamic_buffer_append(
+                       buf, &channel_comm, sizeof(channel_comm));
+       if (ret) {
+               goto end;
+       }
+
+       /* channel name */
+       ret = lttng_dynamic_buffer_append(buf, channel->name, name_len);
+       if (ret) {
+               goto end;
+       }
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+void lttng_channel_set_default_extended_attr(struct lttng_domain *domain,
+               struct lttng_channel_extended *extended_attr)
+{
+       assert(domain);
+       assert(extended_attr);
+
+       memset(extended_attr, 0, sizeof(*extended_attr));
+
+       switch (domain->type) {
+       case LTTNG_DOMAIN_KERNEL:
+               extended_attr->monitor_timer_interval =
+                               DEFAULT_KERNEL_CHANNEL_MONITOR_TIMER;
+               extended_attr->blocking_timeout =
+                               DEFAULT_KERNEL_CHANNEL_BLOCKING_TIMEOUT;
+               break;
+       case LTTNG_DOMAIN_UST:
+               switch (domain->buf_type) {
+               case LTTNG_BUFFER_PER_UID:
+                       extended_attr->monitor_timer_interval =
+                                       DEFAULT_UST_UID_CHANNEL_MONITOR_TIMER;
+                       extended_attr->blocking_timeout =
+                                       DEFAULT_UST_UID_CHANNEL_BLOCKING_TIMEOUT;
+                       break;
+               case LTTNG_BUFFER_PER_PID:
+               default:
+                       if (extended_attr) {
+                               extended_attr->monitor_timer_interval =
+                                               DEFAULT_UST_PID_CHANNEL_MONITOR_TIMER;
+                               extended_attr->blocking_timeout =
+                                               DEFAULT_UST_PID_CHANNEL_BLOCKING_TIMEOUT;
+                       }
+                       break;
+               }
+       default:
+               /* Default behavior: leave set to 0. */
+               break;
+       }
+}
+
+static enum lttng_error_code channel_list_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               unsigned int count,
+               struct lttng_dynamic_pointer_array *channel_list)
+{
+       enum lttng_error_code ret_code;
+       int ret, i;
+       int offset = 0;
+
+       assert(view);
+       assert(channel_list);
+
+       for (i = 0; i < count; i++) {
+               ssize_t channel_size;
+               struct lttng_channel *channel = NULL;
+               const struct lttng_buffer_view channel_view =
+                               lttng_buffer_view_from_view(view, offset, -1);
+
+               channel_size = lttng_channel_create_from_buffer(
+                               &channel_view, &channel);
+               if (channel_size < 0) {
+                       ret_code = LTTNG_ERR_INVALID;
+                       goto end;
+               }
+
+               /* Lifetime and management of the object is now bound to the array. */
+               ret = lttng_dynamic_pointer_array_add_pointer(channel_list, channel);
+               if (ret) {
+                       lttng_channel_destroy(channel);
+                       ret_code = LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+               offset += channel_size;
+       }
+
+       if (view->size != offset) {
+               ret_code = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret_code = LTTNG_OK;
+
+end:
+       return ret_code;
+}
+
+static enum lttng_error_code flatten_lttng_channels(struct lttng_dynamic_pointer_array *channels,
+               struct lttng_channel **flattened_channels)
+{
+       enum lttng_error_code ret_code;
+       int ret, i;
+       size_t storage_req = 0;
+       struct lttng_dynamic_buffer local_flattened_channels;
+       int nb_channels;
+
+       assert(channels);
+       assert(flattened_channels);
+
+       lttng_dynamic_buffer_init(&local_flattened_channels);
+       nb_channels = lttng_dynamic_pointer_array_get_count(channels);
+
+       storage_req += sizeof(struct lttng_channel) * nb_channels;
+       storage_req += sizeof(struct lttng_channel_extended) * nb_channels;
+
+       /*
+        * We must ensure that "local_flattened_channels" is never resized so as
+        * to preserve the validity of the flattened objects.
+        */
+       ret = lttng_dynamic_buffer_set_capacity(
+                       &local_flattened_channels, storage_req);
+       if (ret) {
+               ret_code = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /* Start by laying the struct lttng_channel */
+       for (i = 0; i < nb_channels; i++) {
+               const struct lttng_channel *element =
+                               lttng_dynamic_pointer_array_get_pointer(
+                                               channels, i);
+
+               if (!element) {
+                       ret_code = LTTNG_ERR_FATAL;
+                       goto end;
+               }
+               ret = lttng_dynamic_buffer_append(&local_flattened_channels,
+                               element, sizeof(struct lttng_channel));
+               if (ret) {
+                       ret_code = LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+       }
+
+       /* Flatten the extended data */
+       for (i = 0; i < nb_channels; i++) {
+               const struct lttng_channel *element =
+                               lttng_dynamic_pointer_array_get_pointer(
+                                               channels, i);
+               /*
+                * Sample the location of the flattened channel we are about
+                * to modify
+                */
+                struct lttng_channel *channel = (struct lttng_channel *)
+                       (local_flattened_channels.data + (sizeof(struct lttng_channel) * i));
+               /*
+                * Sample the location of the extended attributes we are about
+                * to add.
+                */
+               struct lttng_channel_extended *channel_extended =
+                       (struct lttng_channel_extended *)
+                               (local_flattened_channels.data + local_flattened_channels.size);
+
+               if (!element) {
+                       ret_code = LTTNG_ERR_FATAL;
+                       goto end;
+               }
+
+               ret = lttng_dynamic_buffer_append(&local_flattened_channels,
+                               element->attr.extended.ptr,
+                               sizeof(struct lttng_channel_extended));
+               if (ret) {
+                       ret_code = LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /*
+                * Update the flattened lttng_channel object with its flattened
+                * extended object location.
+                */
+               channel->attr.extended.ptr = channel_extended;
+       }
+
+       /* Don't reset local_flattened_channels buffer as we return its content. */
+       *flattened_channels = (struct lttng_channel *) local_flattened_channels.data;
+       lttng_dynamic_buffer_init(&local_flattened_channels);
+       ret_code = LTTNG_OK;
+end:
+       lttng_dynamic_buffer_reset(&local_flattened_channels);
+       return ret_code;
+}
+
+LTTNG_HIDDEN
+enum lttng_error_code lttng_channels_create_and_flatten_from_buffer(
+               const struct lttng_buffer_view *view,
+               uint32_t count,
+               struct lttng_channel **channels)
+{
+       enum lttng_error_code ret_code;
+       struct lttng_dynamic_pointer_array local_channels;
+
+       lttng_dynamic_pointer_array_init(&local_channels, channel_list_destructor);
+
+       /* Deserialize the channels */
+       {
+               const struct lttng_buffer_view channels_view =
+                               lttng_buffer_view_from_view(view, 0, -1);
+
+               ret_code = channel_list_create_from_buffer(
+                               &channels_view, count, &local_channels);
+               if (ret_code != LTTNG_OK) {
+                       goto end;
+               }
+       }
+
+       ret_code = flatten_lttng_channels(&local_channels, channels);
+
+end:
+       lttng_dynamic_pointer_array_reset(&local_channels);
+       return ret_code;
+}
index b9ab05bcb26e3e34b7c765dd93094ad8846541c7..0d3e374b3d30ac30fea6394eb8b272158abec3c9 100644 (file)
@@ -311,9 +311,7 @@ struct lttcomm_session_msg {
                } LTTNG_PACKED disable;
                /* Create channel */
                struct {
-                       struct lttng_channel chan LTTNG_PACKED;
-                       /* struct lttng_channel_extended is already packed. */
-                       struct lttng_channel_extended extended;
+                       uint32_t length;
                } LTTNG_PACKED channel;
                /* Context */
                struct {
@@ -453,6 +451,14 @@ struct lttcomm_event_command_header {
        uint32_t nb_events;
 } LTTNG_PACKED;
 
+/*
+ * Listing command header.
+ */
+struct lttcomm_list_command_header {
+       /* Number of elements */
+       uint32_t count;
+} LTTNG_PACKED;
+
 /*
  * Event extended info header. This is the structure preceding each
  * extended info data.
index 5cdc2b011d2f0af23c7e1d15d87d032c34e93304..622a2bd04d1c72b3f4d88b659bd4f4eb541494fd 100644 (file)
@@ -1509,10 +1509,9 @@ end:
 struct lttng_channel *lttng_channel_create(struct lttng_domain *domain)
 {
        struct lttng_channel *channel = NULL;
-       struct lttng_channel_extended *extended = NULL;
 
        if (!domain) {
-               goto error;
+               goto end;
        }
 
        /* Validate domain. */
@@ -1523,36 +1522,26 @@ struct lttng_channel *lttng_channel_create(struct lttng_domain *domain)
                case LTTNG_BUFFER_PER_PID:
                        break;
                default:
-                       goto error;
+                       goto end;
                }
                break;
        case LTTNG_DOMAIN_KERNEL:
                if (domain->buf_type != LTTNG_BUFFER_GLOBAL) {
-                       goto error;
+                       goto end;
                }
                break;
        default:
-               goto error;
+               goto end;
        }
 
-       channel = zmalloc(sizeof(*channel));
+       channel = lttng_channel_create_internal();
        if (!channel) {
-               goto error;
-       }
-
-       extended = zmalloc(sizeof(*extended));
-       if (!extended) {
-               goto error;
+               goto end;
        }
 
-       channel->attr.extended.ptr = extended;
-
        lttng_channel_set_default_attr(domain, &channel->attr);
+end:
        return channel;
-error:
-       free(channel);
-       free(extended);
-       return NULL;
 }
 
 void lttng_channel_destroy(struct lttng_channel *channel)
@@ -1576,56 +1565,32 @@ int lttng_enable_channel(struct lttng_handle *handle,
 {
        enum lttng_error_code ret_code;
        int ret;
+       struct lttng_dynamic_buffer buffer;
        struct lttcomm_session_msg lsm;
        uint64_t total_buffer_size_needed_per_cpu = 0;
+       struct lttng_channel *channel = NULL;
+
+       lttng_dynamic_buffer_init(&buffer);
 
        /* NULL arguments are forbidden. No default values. */
        if (handle == NULL || in_chan == NULL) {
-               return -LTTNG_ERR_INVALID;
-       }
-
-       memset(&lsm, 0, sizeof(lsm));
-       memcpy(&lsm.u.channel.chan, in_chan, sizeof(lsm.u.channel.chan));
-       lsm.u.channel.chan.attr.extended.ptr = NULL;
-
-       if (!in_chan->attr.extended.ptr) {
-               struct lttng_channel *channel;
-               struct lttng_channel_extended *extended;
-
-               channel = lttng_channel_create(&handle->domain);
-               if (!channel) {
-                       return -LTTNG_ERR_NOMEM;
-               }
-
-               /*
-                * Create a new channel in order to use default extended
-                * attribute values.
-                */
-               extended = (struct lttng_channel_extended *)
-                               channel->attr.extended.ptr;
-               memcpy(&lsm.u.channel.extended, extended, sizeof(*extended));
-               lttng_channel_destroy(channel);
-       } else {
-               struct lttng_channel_extended *extended;
-
-               extended = (struct lttng_channel_extended *)
-                               in_chan->attr.extended.ptr;
-               memcpy(&lsm.u.channel.extended, extended, sizeof(*extended));
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
        }
 
        /*
         * Verify that the amount of memory required to create the requested
         * buffer is available on the system at the moment.
         */
-       if (lsm.u.channel.chan.attr.num_subbuf >
-                       UINT64_MAX / lsm.u.channel.chan.attr.subbuf_size) {
+       if (in_chan->attr.num_subbuf >
+                       UINT64_MAX / in_chan->attr.subbuf_size) {
                /* Overflow */
                ret = -LTTNG_ERR_OVERFLOW;
                goto end;
        }
 
-       total_buffer_size_needed_per_cpu = lsm.u.channel.chan.attr.num_subbuf *
-               lsm.u.channel.chan.attr.subbuf_size;
+       total_buffer_size_needed_per_cpu =
+                       in_chan->attr.num_subbuf * in_chan->attr.subbuf_size;
        ret_code = check_enough_available_memory(
                        total_buffer_size_needed_per_cpu);
        if (ret_code != LTTNG_OK) {
@@ -1633,6 +1598,30 @@ int lttng_enable_channel(struct lttng_handle *handle,
                goto end;
        }
 
+       /* Copy the channel for easier manipulation. */
+       channel = lttng_channel_copy(in_chan);
+       if (!channel) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /* Populate the channel extended attribute if necessary. */
+       if (!channel->attr.extended.ptr) {
+               struct lttng_channel_extended *extended =
+                               zmalloc(sizeof(*extended));
+
+               if (!extended) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+               lttng_channel_set_default_extended_attr(
+                               &handle->domain, extended);
+               channel->attr.extended.ptr = extended;
+       }
+
+       /* Prepare the payload */
+       memset(&lsm, 0, sizeof(lsm));
+
        lsm.cmd_type = LTTNG_ENABLE_CHANNEL;
        COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
 
@@ -1643,8 +1632,19 @@ int lttng_enable_channel(struct lttng_handle *handle,
                goto end;
        }
 
-       ret = lttng_ctl_ask_sessiond(&lsm, NULL);
+       ret = lttng_channel_serialize(channel, &buffer);
+       if (ret) {
+               ret = -LTTNG_ERR_FATAL;
+               goto end;
+       }
+
+       lsm.u.channel.length = buffer.size;
+
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(
+                       &lsm, buffer.data, buffer.size, NULL);
 end:
+       lttng_channel_destroy(channel);
+       lttng_dynamic_buffer_reset(&buffer);
        return ret;
 }
 
@@ -2242,12 +2242,14 @@ error:
 int lttng_list_channels(struct lttng_handle *handle,
                struct lttng_channel **channels)
 {
-       int ret;
-       size_t channel_count, i;
-       const size_t channel_size = sizeof(struct lttng_channel) +
-                       sizeof(struct lttng_channel_extended);
+       int ret, total_payload_received;
        struct lttcomm_session_msg lsm;
-       void *extended_at;
+       char *reception_buffer = NULL;
+       size_t cmd_header_len = 0;
+       struct lttcomm_list_command_header *cmd_header = NULL;
+       struct lttng_dynamic_buffer tmp_buffer;
+
+       lttng_dynamic_buffer_init(&tmp_buffer);
 
        if (handle == NULL) {
                ret = -LTTNG_ERR_INVALID;
@@ -2265,31 +2267,48 @@ int lttng_list_channels(struct lttng_handle *handle,
 
        COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
 
-       ret = lttng_ctl_ask_sessiond(&lsm, (void**) channels);
+       ret = lttng_ctl_ask_sessiond_fds_varlen(&lsm, NULL, 0, NULL, 0,
+                       (void **) &reception_buffer, (void **) &cmd_header,
+                       &cmd_header_len);
        if (ret < 0) {
                goto end;
        }
 
-       if (ret % channel_size) {
-               ret = -LTTNG_ERR_UNK;
-               free(*channels);
-               *channels = NULL;
+       total_payload_received = ret;
+
+       if (cmd_header_len != sizeof(*cmd_header)) {
+               ret = -LTTNG_ERR_FATAL;
+               goto end;
+       }
+
+       if (!cmd_header) {
+               ret = LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       if (cmd_header->count > INT_MAX) {
+               ret = -LTTNG_ERR_OVERFLOW;
                goto end;
        }
-       channel_count = (size_t) ret / channel_size;
 
-       /* Set extended info pointers */
-       extended_at = ((void *) *channels) +
-                       channel_count * sizeof(struct lttng_channel);
-       for (i = 0; i < channel_count; i++) {
-               struct lttng_channel *chan = &(*channels)[i];
+       {
+               enum lttng_error_code ret_code;
+               const struct lttng_buffer_view events_view =
+                               lttng_buffer_view_init(reception_buffer, 0,
+                                               total_payload_received);
 
-               chan->attr.extended.ptr = extended_at;
-               extended_at += sizeof(struct lttng_channel_extended);
+               ret_code = lttng_channels_create_and_flatten_from_buffer(
+                               &events_view, cmd_header->count, channels);
+               if (ret_code != LTTNG_OK) {
+                       ret = -ret_code;
+                       goto end;
+               }
        }
 
-       ret = (int) channel_count;
+       ret = (int) cmd_header->count;
 end:
+       free(cmd_header);
+       free(reception_buffer);
        return ret;
 }
 
@@ -2598,6 +2617,7 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain,
                return;
        }
 
+       /* Save the pointer for later use */
        extended = (struct lttng_channel_extended *) attr->extended.ptr;
        memset(attr, 0, sizeof(struct lttng_channel_attr));
 
@@ -2614,12 +2634,6 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain,
                attr->subbuf_size = default_get_kernel_channel_subbuf_size();
                attr->num_subbuf = DEFAULT_KERNEL_CHANNEL_SUBBUF_NUM;
                attr->output = DEFAULT_KERNEL_CHANNEL_OUTPUT;
-               if (extended) {
-                       extended->monitor_timer_interval =
-                                       DEFAULT_KERNEL_CHANNEL_MONITOR_TIMER;
-                       extended->blocking_timeout =
-                                       DEFAULT_KERNEL_CHANNEL_BLOCKING_TIMEOUT;
-               }
                break;
        case LTTNG_DOMAIN_UST:
                switch (domain->buf_type) {
@@ -2631,12 +2645,6 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain,
                                        DEFAULT_UST_UID_CHANNEL_SWITCH_TIMER;
                        attr->read_timer_interval =
                                        DEFAULT_UST_UID_CHANNEL_READ_TIMER;
-                       if (extended) {
-                               extended->monitor_timer_interval =
-                                               DEFAULT_UST_UID_CHANNEL_MONITOR_TIMER;
-                               extended->blocking_timeout =
-                                               DEFAULT_UST_UID_CHANNEL_BLOCKING_TIMEOUT;
-                       }
                        break;
                case LTTNG_BUFFER_PER_PID:
                default:
@@ -2647,12 +2655,6 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain,
                                        DEFAULT_UST_PID_CHANNEL_SWITCH_TIMER;
                        attr->read_timer_interval =
                                        DEFAULT_UST_PID_CHANNEL_READ_TIMER;
-                       if (extended) {
-                               extended->monitor_timer_interval =
-                                               DEFAULT_UST_PID_CHANNEL_MONITOR_TIMER;
-                               extended->blocking_timeout =
-                                               DEFAULT_UST_PID_CHANNEL_BLOCKING_TIMEOUT;
-                       }
                        break;
                }
        default:
@@ -2660,6 +2662,11 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain,
                break;
        }
 
+       if (extended) {
+               lttng_channel_set_default_extended_attr(domain, extended);
+       }
+
+       /* Reassign the extended pointer. */
        attr->extended.ptr = extended;
 }
 
This page took 0.047046 seconds and 4 git commands to generate.