From 714363d38245d57d5fbb657f67bc069d6f4d8aff Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Wed, 12 Jan 2022 18:18:08 -0500 Subject: [PATCH] Fix: liblttng-ctl comm: lttng_channel is not packed MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Jérémie Galarneau Change-Id: Id5c9aaf3cf8b3d739b71263c02cae8d4d2fedfe3 --- include/lttng/channel-internal.h | 52 +++ src/bin/lttng-sessiond/channel.c | 54 +++ src/bin/lttng-sessiond/channel.h | 3 + src/bin/lttng-sessiond/client.c | 40 +- src/bin/lttng-sessiond/cmd.c | 387 ++++++++++--------- src/bin/lttng-sessiond/cmd.h | 10 +- src/bin/lttng-sessiond/trace-ust.h | 1 + src/common/Makefile.am | 1 + src/common/channel.c | 464 +++++++++++++++++++++++ src/common/sessiond-comm/sessiond-comm.h | 11 +- src/lib/lttng-ctl/lttng-ctl.c | 188 ++++----- 11 files changed, 912 insertions(+), 299 deletions(-) create mode 100644 src/common/channel.c diff --git a/include/lttng/channel-internal.h b/include/lttng/channel-internal.h index 04b19322f..67a4482c7 100644 --- a/include/lttng/channel-internal.h +++ b/include/lttng/channel-internal.h @@ -9,6 +9,11 @@ #define LTTNG_CHANNEL_INTERNAL_H #include +#include +#include + +struct lttng_dynamic_buffer; +struct lttng_buffer_view; struct lttng_channel_extended { uint64_t discarded_events; @@ -17,4 +22,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 */ diff --git a/src/bin/lttng-sessiond/channel.c b/src/bin/lttng-sessiond/channel.c index f346f03a1..a2009bae2 100644 --- a/src/bin/lttng-sessiond/channel.c +++ b/src/bin/lttng-sessiond/channel.c @@ -549,3 +549,57 @@ 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) { + ERR("Failed to create lttng_channel during conversion from ltt_ust_channel to lttng_channel"); + goto end; + } + + if (lttng_strncpy(channel->name, uchan->name, LTTNG_SYMBOL_NAME_LEN)) { + ERR("Failed to set channel name during conversion from ltt_ust_channel to lttng_channel"); + 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_ABI_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; +} diff --git a/src/bin/lttng-sessiond/channel.h b/src/bin/lttng-sessiond/channel.h index b4ff9f4fd..1b6e29bd7 100644 --- a/src/bin/lttng-sessiond/channel.h +++ b/src/bin/lttng-sessiond/channel.h @@ -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 */ diff --git a/src/bin/lttng-sessiond/client.c b/src/bin/lttng-sessiond/client.c index 59421d8e1..bdc5680ee 100644 --- a/src/bin/lttng-sessiond/client.c +++ b/src/bin/lttng-sessiond/client.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -1435,12 +1436,8 @@ 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), - the_kernel_poll_pipe[1]); + ret = cmd_enable_channel( + cmd_ctx, *sock, the_kernel_poll_pipe[1]); break; } case LTTNG_PROCESS_ATTR_TRACKER_ADD_INCLUDE_VALUE: @@ -1958,25 +1955,30 @@ error_add_context: } case LTTNG_LIST_CHANNELS: { - ssize_t payload_size; - struct lttng_channel *channels = NULL; + enum lttng_error_code ret_code; + size_t original_payload_size; + size_t payload_size; + const size_t command_header_size = sizeof(struct lttcomm_list_command_header); - 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; - goto error; + ret = setup_empty_lttng_msg(cmd_ctx); + if (ret) { + ret = LTTNG_ERR_NOMEM; + goto setup_error; } - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, channels, - payload_size); - free(channels); + original_payload_size = cmd_ctx->reply_payload.buffer.size; - if (ret < 0) { - goto setup_error; + ret_code = cmd_list_channels(cmd_ctx->lsm.domain.type, + cmd_ctx->session, &cmd_ctx->reply_payload); + if (ret_code != LTTNG_OK) { + ret = (int) ret_code; + goto error; } + payload_size = cmd_ctx->reply_payload.buffer.size - + command_header_size - original_payload_size; + update_lttng_msg(cmd_ctx, command_header_size, payload_size); + ret = LTTNG_OK; break; } diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index ce468db42..add0a78a8 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -121,6 +121,10 @@ static int cmd_enable_event_internal(struct ltt_session *session, struct lttng_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 @@ -291,118 +295,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_ABI_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 append_extended_info(const char *filter_expression, struct lttng_event_exclusion *exclusion, struct lttng_userspace_probe_location *probe_location, @@ -1360,30 +1252,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; + const struct lttng_domain command_domain = cmd_ctx->lsm.domain; + + 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, &command_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(); @@ -1393,8 +1339,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 */ @@ -1406,8 +1352,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; } @@ -1432,8 +1378,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 @@ -1447,10 +1393,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 { @@ -1480,19 +1427,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; @@ -1501,7 +1448,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 @@ -1512,8 +1459,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 { @@ -1526,12 +1473,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; } @@ -2158,7 +2106,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; } @@ -2297,7 +2246,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; } @@ -3603,67 +3553,138 @@ 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_payload *payload) { - ssize_t nb_chan = 0, payload_size = 0, ret; + int ret = 0; + unsigned int i = 0; + struct lttcomm_list_command_header cmd_header = {}; + size_t cmd_header_offset; + enum lttng_error_code ret_code; + + assert(session); + assert(payload); + + DBG("Listing channels for session %s", session->name); + + cmd_header_offset = payload->buffer.size; + + /* Reserve space for command reply header. */ + ret = lttng_dynamic_buffer_set_size(&payload->buffer, + cmd_header_offset + sizeof(cmd_header)); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } 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; + 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) { + ret_code = LTTNG_ERR_UNK; + 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, &payload->buffer); + if (ret) { + ERR("Failed to serialize lttng_channel: channel name = '%s'", + kchan->channel->name); + ret_code = LTTNG_ERR_UNK; + goto end; + } + + i++; + } } 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; + { + 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; + struct lttng_channel *channel = NULL; + struct lttng_channel_extended *extended; + + channel = trace_ust_channel_to_lttng_channel(uchan); + if (!channel) { + ret = LTTNG_ERR_NOMEM; + break; + } + + 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); + ret_code = LTTNG_ERR_UNK; + break; + } + + extended->discarded_events = discarded_events; + extended->lost_packets = lost_packets; + + ret = lttng_channel_serialize( + channel, &payload->buffer); + if (ret) { + ERR("Failed to serialize lttng_channel: channel name = '%s'", + channel->name); + ret_code = LTTNG_ERR_UNK; + ret = -1; + break; + } + + i++; } + rcu_read_unlock(); break; + } default: - ret = -LTTNG_ERR_UND; - goto end; + break; } - if (nb_chan > 0) { - const size_t channel_size = sizeof(struct lttng_channel) + - sizeof(struct lttng_channel_extended); - struct lttng_channel_extended *channel_exts; - - payload_size = nb_chan * channel_size; - *channels = zmalloc(payload_size); - if (*channels == NULL) { - ret = -LTTNG_ERR_FATAL; - goto end; - } - - 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; - } - } else { - *channels = NULL; + if (i > UINT32_MAX) { + ERR("Channel count would overflow the channel listing command's reply"); + ret_code = LTTNG_ERR_OVERFLOW; + goto end; } - ret = payload_size; + /* Update command reply header. */ + cmd_header.count = (uint32_t) i; + memcpy(payload->buffer.data + cmd_header_offset, &cmd_header, + sizeof(cmd_header)); + ret_code = LTTNG_OK; + end: - return ret; + return ret_code; } /* diff --git a/src/bin/lttng-sessiond/cmd.h b/src/bin/lttng-sessiond/cmd.h index 03f7cc1a4..66897afba 100644 --- a/src/bin/lttng-sessiond/cmd.h +++ b/src/bin/lttng-sessiond/cmd.h @@ -15,6 +15,7 @@ #include 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,9 @@ 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_payload *payload); -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_payload *payload); ssize_t cmd_list_domains(struct ltt_session *session, struct lttng_domain **domains); void cmd_list_lttng_sessions(struct lttng_session *sessions, diff --git a/src/bin/lttng-sessiond/trace-ust.h b/src/bin/lttng-sessiond/trace-ust.h index 64d5105f8..c312dd970 100644 --- a/src/bin/lttng-sessiond/trace-ust.h +++ b/src/bin/lttng-sessiond/trace-ust.h @@ -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_bytecode *filter, diff --git a/src/common/Makefile.am b/src/common/Makefile.am index cb7758b98..3769d5642 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -54,6 +54,7 @@ libcommon_lgpl_la_SOURCES = \ actions/stop-session.c \ actions/rate-policy.c \ buffer-view.h buffer-view.c \ + channel.c \ conditions/buffer-usage.c \ conditions/condition.c \ conditions/event-rule-matches.c \ diff --git a/src/common/channel.c b/src/common/channel.c new file mode 100644 index 000000000..b0078eb9c --- /dev/null +++ b/src/common/channel.c @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2021 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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); +} + +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 = (struct lttng_channel *) zmalloc(sizeof(*channel)); + if (!channel) { + goto end; + } + + *channel = *src; + + if (src->attr.extended.ptr) { + extended = (struct lttng_channel_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. + */ +struct lttng_channel *lttng_channel_create_internal(void) +{ + struct lttng_channel *local_channel = NULL, *ret = NULL; + struct lttng_channel_extended *extended = NULL; + + local_channel = (struct lttng_channel *) zmalloc( + sizeof(struct lttng_channel)); + if (!local_channel) { + goto end; + } + + /* Extended struct */ + extended = (struct lttng_channel_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; +} + +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 = (enum lttng_event_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; +} + +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 = (struct lttng_channel_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; +} + +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 = (const struct lttng_channel *) + 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 = (const struct lttng_channel *) + 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 = (void *) 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; +} + +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; +} diff --git a/src/common/sessiond-comm/sessiond-comm.h b/src/common/sessiond-comm/sessiond-comm.h index 2d6493d8e..a4ea96315 100644 --- a/src/common/sessiond-comm/sessiond-comm.h +++ b/src/common/sessiond-comm/sessiond-comm.h @@ -413,8 +413,7 @@ struct lttcomm_session_msg { } LTTNG_PACKED disable; /* Create channel */ struct { - struct lttng_channel chan; - struct lttng_channel_extended extended; + uint32_t length; } LTTNG_PACKED channel; /* Context */ struct { @@ -560,6 +559,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. diff --git a/src/lib/lttng-ctl/lttng-ctl.c b/src/lib/lttng-ctl/lttng-ctl.c index c20052bf6..92593cfac 100644 --- a/src/lib/lttng-ctl/lttng-ctl.c +++ b/src/lib/lttng-ctl/lttng-ctl.c @@ -1538,10 +1538,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. */ @@ -1552,36 +1551,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) @@ -1605,56 +1594,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) { @@ -1662,6 +1627,31 @@ 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 = + (struct lttng_channel_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); @@ -1672,8 +1662,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; } @@ -2271,12 +2272,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; @@ -2294,31 +2297,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; } - 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]; + if (!cmd_header) { + ret = LTTNG_ERR_UNK; + goto end; + } + + if (cmd_header->count > INT_MAX) { + ret = -LTTNG_ERR_OVERFLOW; + goto end; + } - chan->attr.extended.ptr = extended_at; - extended_at += sizeof(struct lttng_channel_extended); + { + enum lttng_error_code ret_code; + const struct lttng_buffer_view events_view = + lttng_buffer_view_init(reception_buffer, 0, + total_payload_received); + + 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; } @@ -2692,6 +2712,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)); @@ -2708,12 +2729,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) { @@ -2725,12 +2740,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: @@ -2741,12 +2750,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: @@ -2754,6 +2757,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; } -- 2.34.1