X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fcmd.cpp;h=0b74920556d59230a5bf2a87adcef42590dd1627;hb=139a8d250fb18f8ffc95b0936f7285f7b484b72f;hp=4ddff45b4160e711391501fd67d02165aa0c0b32;hpb=7966af5763c4aaca39df9bbfa9277ff15715c720;p=lttng-tools.git diff --git a/src/bin/lttng-sessiond/cmd.cpp b/src/bin/lttng-sessiond/cmd.cpp index 4ddff45b4..0b7492055 100644 --- a/src/bin/lttng-sessiond/cmd.cpp +++ b/src/bin/lttng-sessiond/cmd.cpp @@ -15,64 +15,70 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include #include -#include +#include #include -#include +#include #include -#include -#include +#include +#include +#include #include -#include +#include #include -#include -#include -#include +#include +#include +#include #include -#include -#include - -#include "agent-thread.h" -#include "agent.h" -#include "buffer-registry.h" -#include "channel.h" -#include "cmd.h" -#include "consumer.h" -#include "event-notifier-error-accounting.h" -#include "event.h" -#include "health-sessiond.h" -#include "kernel-consumer.h" -#include "kernel.h" -#include "lttng-sessiond.h" -#include "lttng-syscall.h" -#include "notification-thread-commands.h" -#include "notification-thread.h" -#include "rotate.h" -#include "rotation-thread.h" -#include "session.h" -#include "timer.h" -#include "tracker.h" -#include "utils.h" +#include +#include + +#include "agent-thread.hpp" +#include "agent.hpp" +#include "buffer-registry.hpp" +#include "channel.hpp" +#include "cmd.hpp" +#include "consumer.hpp" +#include "event-notifier-error-accounting.hpp" +#include "event.hpp" +#include "health-sessiond.hpp" +#include "kernel-consumer.hpp" +#include "kernel.hpp" +#include "lttng-sessiond.hpp" +#include "lttng-syscall.hpp" +#include "notification-thread-commands.hpp" +#include "notification-thread.hpp" +#include "rotate.hpp" +#include "rotation-thread.hpp" +#include "session.hpp" +#include "timer.hpp" +#include "tracker.hpp" +#include "utils.hpp" /* Sleep for 100ms between each check for the shm path's deletion. */ #define SESSION_DESTROY_SHM_PATH_CHECK_DELAY_US 100000 +namespace lsu = lttng::sessiond::ust; + +static enum lttng_error_code wait_on_path(void *path); + +namespace { struct cmd_destroy_session_reply_context { int reply_sock_fd; bool implicit_rotation_on_destroy; @@ -83,15 +89,13 @@ struct cmd_destroy_session_reply_context { enum lttng_error_code destruction_status; }; -static enum lttng_error_code wait_on_path(void *path); - /* * Command completion handler that is used by the destroy command * when a session that has a non-default shm_path is being destroyed. * * See comment in cmd_destroy_session() for the rationale. */ -static struct destroy_completion_handler { +struct destroy_completion_handler { struct cmd_completion_handler handler; char shm_path[member_sizeof(struct ltt_session, shm_path)]; } destroy_completion_handler = { @@ -102,17 +106,17 @@ static struct destroy_completion_handler { .shm_path = { 0 }, }; -static struct cmd_completion_handler *current_completion_handler; - /* * Used to keep a unique index for each relayd socket created where this value * is associated with streams on the consumer so it can match the right relayd * to send to. It must be accessed with the relayd_net_seq_idx_lock * held. */ -static pthread_mutex_t relayd_net_seq_idx_lock = PTHREAD_MUTEX_INITIALIZER; -static uint64_t relayd_net_seq_idx; +pthread_mutex_t relayd_net_seq_idx_lock = PTHREAD_MUTEX_INITIALIZER; +uint64_t relayd_net_seq_idx; +} /* namespace */ +static struct cmd_completion_handler *current_completion_handler; static int validate_ust_event_name(const char *); static int cmd_enable_event_internal(struct ltt_session *session, const struct lttng_domain *domain, @@ -121,6 +125,11 @@ static int cmd_enable_event_internal(struct ltt_session *session, struct lttng_bytecode *filter, struct lttng_event_exclusion *exclusion, int wpipe); +static enum lttng_error_code 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,262 +300,96 @@ 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. - */ - abort(); - 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, - struct lttng_payload *payload) -{ - int ret = 0; - size_t filter_len = 0; - size_t nb_exclusions = 0; - size_t userspace_probe_location_len = 0; - struct lttcomm_event_extended_header extended_header = {}; - struct lttcomm_event_extended_header *p_extended_header; - const size_t original_payload_size = payload->buffer.size; - - ret = lttng_dynamic_buffer_append(&payload->buffer, &extended_header, - sizeof(extended_header)); - if (ret) { - goto end; - } - - if (filter_expression) { - filter_len = strlen(filter_expression) + 1; - ret = lttng_dynamic_buffer_append(&payload->buffer, - filter_expression, filter_len); - if (ret) { - goto end; - } - } - - if (exclusion) { - const size_t len = exclusion->count * LTTNG_SYMBOL_NAME_LEN; - - nb_exclusions = exclusion->count; - - ret = lttng_dynamic_buffer_append( - &payload->buffer, &exclusion->names, len); - if (ret) { - goto end; - } - } - - if (probe_location) { - const size_t size_before_probe = payload->buffer.size; - - ret = lttng_userspace_probe_location_serialize(probe_location, - payload); - if (ret < 0) { - ret = -1; - goto end; - } - - userspace_probe_location_len = - payload->buffer.size - size_before_probe; - } - - /* Set header fields */ - p_extended_header = (struct lttcomm_event_extended_header *) - (payload->buffer.data + original_payload_size); - - p_extended_header->filter_len = filter_len; - p_extended_header->nb_exclusions = nb_exclusions; - p_extended_header->userspace_probe_location_len = - userspace_probe_location_len; - - ret = 0; -end: - return ret; -} - /* * Create a list of agent domain events. * * Return number of events in list on success or else a negative value. */ -static int list_lttng_agent_events(struct agent *agt, - struct lttng_payload *payload) +static enum lttng_error_code list_lttng_agent_events( + struct agent *agt, struct lttng_payload *reply_payload, + unsigned int *nb_events) { - int nb_events = 0, ret = 0; - const struct agent_event *agent_event; + enum lttng_error_code ret_code; + int ret = 0; + unsigned int local_nb_events = 0; + struct agent_event *event; struct lttng_ht_iter iter; + unsigned long agent_event_count; - LTTNG_ASSERT(agt); + assert(agt); + assert(reply_payload); DBG3("Listing agent events"); rcu_read_lock(); - cds_lfht_for_each_entry ( - agt->events->ht, &iter.iter, agent_event, node.node) { - struct lttng_event event {}; + agent_event_count = lttng_ht_get_count(agt->events); + if (agent_event_count == 0) { + /* Early exit. */ + goto end; + } - event.loglevel_type = agent_event->loglevel_type; - event.loglevel = agent_event->loglevel_value; - event.enabled = AGENT_EVENT_IS_ENABLED(agent_event); + if (agent_event_count > UINT_MAX) { + ret_code = LTTNG_ERR_OVERFLOW; + goto error; + } - ret = lttng_strncpy(event.name, agent_event->name, sizeof(event.name)); - if (ret) { - /* Internal error, invalid name. */ - ERR("Invalid event name while listing agent events: '%s' exceeds the maximal allowed length of %zu bytes", - agent_event->name, sizeof(event.name)); - ret = -LTTNG_ERR_UNK; - goto end; - } + local_nb_events = (unsigned int) agent_event_count; - ret = lttng_dynamic_buffer_append( - &payload->buffer, &event, sizeof(event)); - if (ret) { - ERR("Failed to append event to payload"); - ret = -LTTNG_ERR_NOMEM; - goto end; + cds_lfht_for_each_entry(agt->events->ht, &iter.iter, event, node.node) { + struct lttng_event *tmp_event = lttng_event_create(); + + if (!tmp_event) { + ret_code = LTTNG_ERR_NOMEM; + goto error; } - nb_events++; - } + if (lttng_strncpy(tmp_event->name, event->name, sizeof(tmp_event->name))) { + lttng_event_destroy(tmp_event); + ret_code = LTTNG_ERR_FATAL; + goto error; + } + + tmp_event->name[sizeof(tmp_event->name) - 1] = '\0'; + tmp_event->enabled = !!event->enabled_count; + tmp_event->loglevel = event->loglevel_value; + tmp_event->loglevel_type = event->loglevel_type; - cds_lfht_for_each_entry ( - agt->events->ht, &iter.iter, agent_event, node.node) { - /* Append extended info. */ - ret = append_extended_info(agent_event->filter_expression, NULL, - NULL, payload); + ret = lttng_event_serialize(tmp_event, 0, NULL, + event->filter_expression, 0, NULL, reply_payload); + lttng_event_destroy(tmp_event); if (ret) { - ERR("Failed to append extended event info to payload"); - ret = -LTTNG_ERR_NOMEM; - goto end; + ret_code = LTTNG_ERR_FATAL; + goto error; } } - ret = nb_events; end: + ret_code = LTTNG_OK; + *nb_events = local_nb_events; +error: rcu_read_unlock(); - return ret; + return ret_code; } /* * Create a list of ust global domain events. */ -static int list_lttng_ust_global_events(char *channel_name, +static enum lttng_error_code list_lttng_ust_global_events(char *channel_name, struct ltt_ust_domain_global *ust_global, - struct lttng_payload *payload) + struct lttng_payload *reply_payload, + unsigned int *nb_events) { - int ret = 0; - unsigned int nb_events = 0; + enum lttng_error_code ret_code; + int ret; struct lttng_ht_iter iter; - const struct lttng_ht_node_str *node; - const struct ltt_ust_channel *uchan; - const struct ltt_ust_event *uevent; + struct lttng_ht_node_str *node; + struct ltt_ust_channel *uchan; + struct ltt_ust_event *uevent; + unsigned long channel_event_count; + unsigned int local_nb_events = 0; + + assert(reply_payload); + assert(nb_events); DBG("Listing UST global events for channel %s", channel_name); @@ -555,158 +398,184 @@ static int list_lttng_ust_global_events(char *channel_name, lttng_ht_lookup(ust_global->channels, (void *) channel_name, &iter); node = lttng_ht_iter_get_node_str(&iter); if (node == NULL) { - ret = LTTNG_ERR_UST_CHAN_NOT_FOUND; - goto end; + ret_code = LTTNG_ERR_UST_CHAN_NOT_FOUND; + goto error; } uchan = caa_container_of(&node->node, struct ltt_ust_channel, node.node); - DBG3("Listing UST global events"); + channel_event_count = lttng_ht_get_count(uchan->events); + if (channel_event_count == 0) { + /* Early exit. */ + ret_code = LTTNG_OK; + goto end; + } + + if (channel_event_count > UINT_MAX) { + ret_code = LTTNG_ERR_OVERFLOW; + goto error; + } + + local_nb_events = (unsigned int) channel_event_count; + + DBG3("Listing UST global %d events", *nb_events); cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent, node.node) { - struct lttng_event event = {}; + struct lttng_event *tmp_event = NULL; if (uevent->internal) { + /* This event should remain hidden from clients */ + local_nb_events--; continue; } - ret = lttng_strncpy(event.name, uevent->attr.name, sizeof(event.name)); - if (ret) { - /* Internal error, invalid name. */ - ERR("Invalid event name while listing user space tracer events: '%s' exceeds the maximal allowed length of %zu bytes", - uevent->attr.name, sizeof(event.name)); - ret = -LTTNG_ERR_UNK; - goto end; + tmp_event = lttng_event_create(); + if (!tmp_event) { + ret_code = LTTNG_ERR_NOMEM; + goto error; } - event.enabled = uevent->enabled; + if (lttng_strncpy(tmp_event->name, uevent->attr.name, + LTTNG_SYMBOL_NAME_LEN)) { + ret_code = LTTNG_ERR_FATAL; + lttng_event_destroy(tmp_event); + goto error; + } + + tmp_event->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; + tmp_event->enabled = uevent->enabled; switch (uevent->attr.instrumentation) { case LTTNG_UST_ABI_TRACEPOINT: - event.type = LTTNG_EVENT_TRACEPOINT; + tmp_event->type = LTTNG_EVENT_TRACEPOINT; break; case LTTNG_UST_ABI_PROBE: - event.type = LTTNG_EVENT_PROBE; + tmp_event->type = LTTNG_EVENT_PROBE; break; case LTTNG_UST_ABI_FUNCTION: - event.type = LTTNG_EVENT_FUNCTION; + tmp_event->type = LTTNG_EVENT_FUNCTION; break; } - event.loglevel = uevent->attr.loglevel; + tmp_event->loglevel = uevent->attr.loglevel; switch (uevent->attr.loglevel_type) { case LTTNG_UST_ABI_LOGLEVEL_ALL: - event.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; + tmp_event->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; break; case LTTNG_UST_ABI_LOGLEVEL_RANGE: - event.loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE; + tmp_event->loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE; break; case LTTNG_UST_ABI_LOGLEVEL_SINGLE: - event.loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE; + tmp_event->loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE; break; } - if (uevent->filter) { - event.filter = 1; + tmp_event->filter = 1; } - if (uevent->exclusion) { - event.exclusion = 1; + tmp_event->exclusion = 1; } - ret = lttng_dynamic_buffer_append(&payload->buffer, &event, sizeof(event)); - if (ret) { - ERR("Failed to append event to payload"); - ret = -LTTNG_ERR_NOMEM; - goto end; - } - - nb_events++; - } - - cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent, node.node) { - /* Append extended info. */ - ret = append_extended_info(uevent->filter_expression, - uevent->exclusion, NULL, payload); + /* + * We do not care about the filter bytecode and the fd from the + * userspace_probe_location. + */ + ret = lttng_event_serialize(tmp_event, uevent->exclusion ? uevent->exclusion->count : 0, + uevent->exclusion ? (char **) uevent->exclusion ->names : NULL, + uevent->filter_expression, 0, NULL, reply_payload); + lttng_event_destroy(tmp_event); if (ret) { - ERR("Failed to append extended event info to payload"); - ret = -LTTNG_ERR_FATAL; - goto end; + ret_code = LTTNG_ERR_FATAL; + goto error; } } - ret = nb_events; end: + /* nb_events is already set at this point. */ + ret_code = LTTNG_OK; + *nb_events = local_nb_events; +error: rcu_read_unlock(); - return ret; + return ret_code; } /* * Fill lttng_event array of all kernel events in the channel. */ -static int list_lttng_kernel_events(char *channel_name, +static enum lttng_error_code list_lttng_kernel_events(char *channel_name, struct ltt_kernel_session *kernel_session, - struct lttng_payload *payload) + struct lttng_payload *reply_payload, + unsigned int *nb_events) { + enum lttng_error_code ret_code; int ret; - unsigned int nb_event; - const struct ltt_kernel_event *kevent; - const struct ltt_kernel_channel *kchan; + struct ltt_kernel_event *event; + struct ltt_kernel_channel *kchan; + + assert(reply_payload); kchan = trace_kernel_get_channel_by_name(channel_name, kernel_session); if (kchan == NULL) { - ret = LTTNG_ERR_KERN_CHAN_NOT_FOUND; - goto error; + ret_code = LTTNG_ERR_KERN_CHAN_NOT_FOUND; + goto end; } - nb_event = kchan->event_count; + *nb_events = kchan->event_count; DBG("Listing events for channel %s", kchan->channel->name); + if (*nb_events == 0) { + ret_code = LTTNG_OK; + goto end; + } + /* Kernel channels */ - cds_list_for_each_entry(kevent, &kchan->events_list.head , list) { - struct lttng_event event = {}; + cds_list_for_each_entry(event, &kchan->events_list.head , list) { + struct lttng_event *tmp_event = lttng_event_create(); - ret = lttng_strncpy(event.name, kevent->event->name, sizeof(event.name)); - if (ret) { - /* Internal error, invalid name. */ - ERR("Invalid event name while listing kernel events: '%s' exceeds the maximal allowed length of %zu bytes", - kevent->event->name, - sizeof(event.name)); - ret = -LTTNG_ERR_UNK; + if (!tmp_event) { + ret_code = LTTNG_ERR_NOMEM; goto end; } - event.enabled = kevent->enabled; - event.filter = (unsigned char) !!kevent->filter_expression; + if (lttng_strncpy(tmp_event->name, event->event->name, LTTNG_SYMBOL_NAME_LEN)) { + lttng_event_destroy(tmp_event); + ret_code = LTTNG_ERR_FATAL; + goto end; + + } - switch (kevent->event->instrumentation) { + tmp_event->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; + tmp_event->enabled = event->enabled; + tmp_event->filter = (unsigned char) !!event->filter_expression; + + switch (event->event->instrumentation) { case LTTNG_KERNEL_ABI_TRACEPOINT: - event.type = LTTNG_EVENT_TRACEPOINT; + tmp_event->type = LTTNG_EVENT_TRACEPOINT; break; case LTTNG_KERNEL_ABI_KRETPROBE: - event.type = LTTNG_EVENT_FUNCTION; - memcpy(&event.attr.probe, &kevent->event->u.kprobe, + tmp_event->type = LTTNG_EVENT_FUNCTION; + memcpy(&tmp_event->attr.probe, &event->event->u.kprobe, sizeof(struct lttng_kernel_abi_kprobe)); break; case LTTNG_KERNEL_ABI_KPROBE: - event.type = LTTNG_EVENT_PROBE; - memcpy(&event.attr.probe, &kevent->event->u.kprobe, + tmp_event->type = LTTNG_EVENT_PROBE; + memcpy(&tmp_event->attr.probe, &event->event->u.kprobe, sizeof(struct lttng_kernel_abi_kprobe)); break; case LTTNG_KERNEL_ABI_UPROBE: - event.type = LTTNG_EVENT_USERSPACE_PROBE; + tmp_event->type = LTTNG_EVENT_USERSPACE_PROBE; break; case LTTNG_KERNEL_ABI_FUNCTION: - event.type = LTTNG_EVENT_FUNCTION; - memcpy(&event.attr.ftrace, &kevent->event->u.ftrace, + tmp_event->type = LTTNG_EVENT_FUNCTION; + memcpy(&(tmp_event->attr.ftrace), &event->event->u.ftrace, sizeof(struct lttng_kernel_abi_function)); break; case LTTNG_KERNEL_ABI_NOOP: - event.type = LTTNG_EVENT_NOOP; + tmp_event->type = LTTNG_EVENT_NOOP; break; case LTTNG_KERNEL_ABI_SYSCALL: - event.type = LTTNG_EVENT_SYSCALL; + tmp_event->type = LTTNG_EVENT_SYSCALL; break; case LTTNG_KERNEL_ABI_ALL: /* fall-through. */ @@ -715,30 +584,40 @@ static int list_lttng_kernel_events(char *channel_name, break; } - ret = lttng_dynamic_buffer_append( - &payload->buffer, &event, sizeof(event)); - if (ret) { - ERR("Failed to append event to payload"); - ret = -LTTNG_ERR_NOMEM; - goto end; + if (event->userspace_probe_location) { + struct lttng_userspace_probe_location *location_copy = + lttng_userspace_probe_location_copy( + event->userspace_probe_location); + + if (!location_copy) { + lttng_event_destroy(tmp_event); + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + ret = lttng_event_set_userspace_probe_location( + tmp_event, location_copy); + if (ret) { + lttng_event_destroy(tmp_event); + lttng_userspace_probe_location_destroy( + location_copy); + ret_code = LTTNG_ERR_INVALID; + goto end; + } } - } - cds_list_for_each_entry(kevent, &kchan->events_list.head , list) { - /* Append extended info. */ - ret = append_extended_info(kevent->filter_expression, NULL, - kevent->userspace_probe_location, payload); + ret = lttng_event_serialize(tmp_event, 0, NULL, + event->filter_expression, 0, NULL, reply_payload); + lttng_event_destroy(tmp_event); if (ret) { - DBG("Error appending extended info message"); - ret = -LTTNG_ERR_FATAL; - goto error; + ret_code = LTTNG_ERR_FATAL; + goto end; } } + ret_code = LTTNG_OK; end: - return nb_event; -error: - return ret; + return ret_code; } /* @@ -1050,7 +929,6 @@ relayd_comm_error: * Returns LTTNG_OK, or an LTTng error code on failure. */ static enum lttng_error_code send_consumer_relayd_sockets( - enum lttng_domain_type domain, unsigned int session_id, struct consumer_output *consumer, struct consumer_socket *sock, const char *session_name, const char *hostname, const char *base_path, int session_live_timer, @@ -1131,7 +1009,7 @@ int cmd_setup_relayd(struct ltt_session *session) cds_lfht_for_each_entry(usess->consumer->socks->ht, &iter.iter, socket, node.node) { pthread_mutex_lock(socket->lock); - ret = send_consumer_relayd_sockets(LTTNG_DOMAIN_UST, session->id, + ret = send_consumer_relayd_sockets(session->id, usess->consumer, socket, session->name, session->hostname, session->base_path, @@ -1159,7 +1037,7 @@ int cmd_setup_relayd(struct ltt_session *session) cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter, socket, node.node) { pthread_mutex_lock(socket->lock); - ret = send_consumer_relayd_sockets(LTTNG_DOMAIN_KERNEL, session->id, + ret = send_consumer_relayd_sockets(session->id, ksess->consumer, socket, session->name, session->hostname, session->base_path, @@ -1360,30 +1238,85 @@ 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 enum lttng_error_code cmd_enable_channel_internal( + struct ltt_session *session, + const struct lttng_domain *domain, + const struct lttng_channel *_attr, + int wpipe) +{ + enum lttng_error_code ret_code; 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; LTTNG_ASSERT(session); LTTNG_ASSERT(_attr); LTTNG_ASSERT(domain); - attr = *_attr; - len = lttng_strnlen(attr.name, sizeof(attr.name)); + attr = lttng_channel_copy(_attr); + if (!attr) { + ret_code = 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) { - ret = LTTNG_ERR_INVALID_CHANNEL_NAME; + if (attr->name[0] == '.' || + memchr(attr->name, '/', len) != NULL) { + ret_code = 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 +1326,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 +1339,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; } @@ -1418,12 +1351,12 @@ int cmd_enable_channel(struct ltt_session *session, case LTTNG_DOMAIN_PYTHON: if (!agent_tracing_is_enabled()) { DBG("Attempted to enable a channel in an agent domain but the agent thread is not running"); - ret = LTTNG_ERR_AGENT_TRACING_DISABLED; + ret_code = LTTNG_ERR_AGENT_TRACING_DISABLED; goto error; } break; default: - ret = LTTNG_ERR_UNKNOWN_DOMAIN; + ret_code = LTTNG_ERR_UNKNOWN_DOMAIN; goto error; } @@ -1432,32 +1365,33 @@ 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 * some point in time before. The tracer does not allow it. */ if (session->has_been_started) { - ret = LTTNG_ERR_TRACE_ALREADY_STARTED; + ret_code = LTTNG_ERR_TRACE_ALREADY_STARTED; goto error; } 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_code = channel_kernel_create( + session->kernel_session, attr, wpipe); + if (attr->name[0] != '\0') { session->kernel_session->has_non_default_channel = 1; } } else { - ret = channel_kernel_enable(session->kernel_session, kchan); + ret_code = channel_kernel_enable(session->kernel_session, kchan); } - if (ret != LTTNG_OK) { + if (ret_code != LTTNG_OK) { goto error; } @@ -1480,59 +1414,60 @@ 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; + ret_code = 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; + ret_code = 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; + ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME; goto error; } } 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 * some point in time before. The tracer does not allow it. */ if (session->has_been_started) { - ret = LTTNG_ERR_TRACE_ALREADY_STARTED; + ret_code = LTTNG_ERR_TRACE_ALREADY_STARTED; goto error; } - ret = channel_ust_create(usess, &attr, domain->buf_type); - if (attr.name[0] != '\0') { + ret_code = channel_ust_create(usess, attr, domain->buf_type); + if (attr->name[0] != '\0') { usess->has_non_default_channel = 1; } } else { - ret = channel_ust_enable(usess, uchan); + ret_code = channel_ust_enable(usess, uchan); } break; } default: - ret = LTTNG_ERR_UNKNOWN_DOMAIN; + ret_code = LTTNG_ERR_UNKNOWN_DOMAIN; goto error; } - if (ret == LTTNG_OK && attr.attr.output != LTTNG_EVENT_MMAP) { + if (ret_code == LTTNG_OK && attr->attr.output != LTTNG_EVENT_MMAP) { session->has_non_mmap_channel = true; } error: rcu_read_unlock(); end: - return ret; + lttng_channel_destroy(attr); + return ret_code; } enum lttng_error_code cmd_process_attr_tracker_get_tracking_policy( @@ -1743,15 +1678,33 @@ end: /* * Command LTTNG_DISABLE_EVENT processed by the client thread. */ -int cmd_disable_event(struct ltt_session *session, - enum lttng_domain_type domain, const char *channel_name, - const struct lttng_event *event) +int cmd_disable_event(struct command_ctx *cmd_ctx, + struct lttng_event *event, + char *filter_expression, + struct lttng_bytecode *bytecode, + struct lttng_event_exclusion *exclusion) { int ret; const char *event_name; + const struct ltt_session *session = cmd_ctx->session; + const char *channel_name = cmd_ctx->lsm.u.disable.channel_name; + const enum lttng_domain_type domain = cmd_ctx->lsm.domain.type; DBG("Disable event command for event \'%s\'", event->name); + /* + * Filter and exclusions are simply not handled by the + * disable event command at this time. + * + * FIXME + */ + (void) filter_expression; + (void) exclusion; + + /* Ignore the presence of filter or exclusion for the event */ + event->filter = 0; + event->exclusion = 0; + event_name = event->name; /* Error out on unhandled search criteria */ @@ -1914,33 +1867,33 @@ int cmd_disable_event(struct ltt_session *session, error_unlock: rcu_read_unlock(); error: + free(exclusion); + free(bytecode); + free(filter_expression); return ret; } /* * Command LTTNG_ADD_CONTEXT processed by the client thread. */ -int cmd_add_context(struct ltt_session *session, enum lttng_domain_type domain, - char *channel_name, const struct lttng_event_context *ctx, int kwpipe) +int cmd_add_context(struct command_ctx *cmd_ctx, + const struct lttng_event_context *event_context, int kwpipe) { int ret, chan_kern_created = 0, chan_ust_created = 0; - char *app_ctx_provider_name = NULL, *app_ctx_name = NULL; + const enum lttng_domain_type domain = cmd_ctx->lsm.domain.type; + const struct ltt_session *session = cmd_ctx->session; + const char *channel_name = cmd_ctx->lsm.u.context.channel_name; /* * Don't try to add a context if the session has been started at * some point in time before. The tracer does not allow it and would * result in a corrupted trace. */ - if (session->has_been_started) { + if (cmd_ctx->session->has_been_started) { ret = LTTNG_ERR_TRACE_ALREADY_STARTED; goto end; } - if (ctx->ctx == LTTNG_EVENT_CONTEXT_APP_CONTEXT) { - app_ctx_provider_name = ctx->u.app_ctx.provider_name; - app_ctx_name = ctx->u.app_ctx.ctx_name; - } - switch (domain) { case LTTNG_DOMAIN_KERNEL: LTTNG_ASSERT(session->kernel_session); @@ -1954,7 +1907,8 @@ int cmd_add_context(struct ltt_session *session, enum lttng_domain_type domain, chan_kern_created = 1; } /* Add kernel context to kernel tracer */ - ret = context_kernel_add(session->kernel_session, ctx, channel_name); + ret = context_kernel_add(session->kernel_session, + event_context, channel_name); if (ret != LTTNG_OK) { goto error; } @@ -1980,8 +1934,8 @@ int cmd_add_context(struct ltt_session *session, enum lttng_domain_type domain, ret = LTTNG_ERR_UST_CHAN_NOT_FOUND; goto error; } - /* break is _not_ missing here. */ } + /* fall through */ case LTTNG_DOMAIN_UST: { struct ltt_ust_session *usess = session->ust_session; @@ -2008,11 +1962,8 @@ int cmd_add_context(struct ltt_session *session, enum lttng_domain_type domain, chan_ust_created = 1; } - ret = context_ust_add(usess, domain, ctx, channel_name); - free(app_ctx_provider_name); - free(app_ctx_name); - app_ctx_name = NULL; - app_ctx_provider_name = NULL; + ret = context_ust_add(usess, domain, event_context, + channel_name); if (ret != LTTNG_OK) { goto error; } @@ -2049,8 +2000,6 @@ error: trace_ust_destroy_channel(uchan); } end: - free(app_ctx_provider_name); - free(app_ctx_name); return ret; } @@ -2158,7 +2107,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; } @@ -2193,7 +2143,7 @@ static int _cmd_enable_event(struct ltt_session *session, } } if (filter) { - filter_a = (lttng_bytecode *) zmalloc(sizeof(*filter_a) + filter->len); + filter_a = zmalloc(sizeof(*filter_a) + filter->len); if (!filter_a) { free(filter_expression_a); ret = LTTNG_ERR_FATAL; @@ -2297,7 +2247,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; } @@ -2420,7 +2371,7 @@ static int _cmd_enable_event(struct ltt_session *session, struct lttng_bytecode) + filter->len; - filter_copy = (lttng_bytecode *) zmalloc(filter_size); + filter_copy = zmalloc(filter_size); if (!filter_copy) { ret = LTTNG_ERR_NOMEM; goto error; @@ -2489,16 +2440,35 @@ error: * Command LTTNG_ENABLE_EVENT processed by the client thread. * We own filter, exclusion, and filter_expression. */ -int cmd_enable_event(struct ltt_session *session, - const struct lttng_domain *domain, - char *channel_name, struct lttng_event *event, +int cmd_enable_event(struct command_ctx *cmd_ctx, + struct lttng_event *event, char *filter_expression, - struct lttng_bytecode *filter, struct lttng_event_exclusion *exclusion, + struct lttng_bytecode *bytecode, int wpipe) { - return _cmd_enable_event(session, domain, channel_name, event, - filter_expression, filter, exclusion, wpipe, false); + int ret; + /* + * Copied to ensure proper alignment since 'lsm' is a packed structure. + */ + const lttng_domain command_domain = cmd_ctx->lsm.domain; + + /* + * The ownership of the following parameters is transferred to + * _cmd_enable_event: + * + * - filter_expression, + * - bytecode, + * - exclusion + */ + ret = _cmd_enable_event(cmd_ctx->session, + &command_domain, + cmd_ctx->lsm.u.enable.channel_name, event, + filter_expression, bytecode, exclusion, wpipe, false); + filter_expression = NULL; + bytecode = NULL; + exclusion = NULL; + return ret; } /* @@ -2521,81 +2491,204 @@ static int cmd_enable_event_internal(struct ltt_session *session, /* * Command LTTNG_LIST_TRACEPOINTS processed by the client thread. */ -ssize_t cmd_list_tracepoints(enum lttng_domain_type domain, - struct lttng_event **events) +enum lttng_error_code cmd_list_tracepoints(enum lttng_domain_type domain, + struct lttng_payload *reply_payload) { + enum lttng_error_code ret_code; int ret; - ssize_t nb_events = 0; + ssize_t i, nb_events = 0; + struct lttng_event *events = NULL; + struct lttcomm_list_command_header reply_command_header = {}; + size_t reply_command_header_offset; + + assert(reply_payload); + + /* Reserve space for command reply header. */ + reply_command_header_offset = reply_payload->buffer.size; + ret = lttng_dynamic_buffer_set_size(&reply_payload->buffer, + reply_command_header_offset + + sizeof(struct lttcomm_list_command_header)); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto error; + } switch (domain) { case LTTNG_DOMAIN_KERNEL: - nb_events = kernel_list_events(events); + nb_events = kernel_list_events(&events); if (nb_events < 0) { - ret = LTTNG_ERR_KERN_LIST_FAIL; + ret_code = LTTNG_ERR_KERN_LIST_FAIL; goto error; } break; case LTTNG_DOMAIN_UST: - nb_events = ust_app_list_events(events); + nb_events = ust_app_list_events(&events); if (nb_events < 0) { - ret = LTTNG_ERR_UST_LIST_FAIL; + ret_code = LTTNG_ERR_UST_LIST_FAIL; goto error; } break; case LTTNG_DOMAIN_LOG4J: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_PYTHON: - nb_events = agent_list_events(events, domain); + nb_events = agent_list_events(&events, domain); if (nb_events < 0) { - ret = LTTNG_ERR_UST_LIST_FAIL; + ret_code = LTTNG_ERR_UST_LIST_FAIL; goto error; } break; default: - ret = LTTNG_ERR_UND; + ret_code = LTTNG_ERR_UND; + goto error; + } + + for (i = 0; i < nb_events; i++) { + ret = lttng_event_serialize(&events[i], 0, NULL, NULL, 0, NULL, + reply_payload); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto error; + } + } + + if (nb_events > UINT32_MAX) { + ERR("Tracepoint count would overflow the tracepoint listing command's reply"); + ret_code = LTTNG_ERR_OVERFLOW; goto error; } - return nb_events; + /* Update command reply header. */ + reply_command_header.count = (uint32_t) nb_events; + memcpy(reply_payload->buffer.data + reply_command_header_offset, &reply_command_header, + sizeof(reply_command_header)); + ret_code = LTTNG_OK; error: - /* Return negative value to differentiate return code */ - return -ret; + free(events); + return ret_code; } /* * Command LTTNG_LIST_TRACEPOINT_FIELDS processed by the client thread. */ -ssize_t cmd_list_tracepoint_fields(enum lttng_domain_type domain, - struct lttng_event_field **fields) +enum lttng_error_code cmd_list_tracepoint_fields(enum lttng_domain_type domain, + struct lttng_payload *reply) { + enum lttng_error_code ret_code; int ret; - ssize_t nb_fields = 0; + unsigned int i, nb_fields; + struct lttng_event_field *fields = NULL; + struct lttcomm_list_command_header reply_command_header = {}; + size_t reply_command_header_offset; + + assert(reply); + + /* Reserve space for command reply header. */ + reply_command_header_offset = reply->buffer.size; + ret = lttng_dynamic_buffer_set_size(&reply->buffer, + reply_command_header_offset + + sizeof(struct lttcomm_list_command_header)); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto error; + } switch (domain) { case LTTNG_DOMAIN_UST: - nb_fields = ust_app_list_event_fields(fields); - if (nb_fields < 0) { - ret = LTTNG_ERR_UST_LIST_FAIL; + ret = ust_app_list_event_fields(&fields); + if (ret < 0) { + ret_code = LTTNG_ERR_UST_LIST_FAIL; goto error; } + break; case LTTNG_DOMAIN_KERNEL: default: /* fall-through */ - ret = LTTNG_ERR_UND; + ret_code = LTTNG_ERR_UND; + goto error; + } + + nb_fields = ret; + + for (i = 0; i < nb_fields; i++) { + ret = lttng_event_field_serialize(&fields[i], reply); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto error; + } + } + + if (nb_fields > UINT32_MAX) { + ERR("Tracepoint field count would overflow the tracepoint field listing command's reply"); + ret_code = LTTNG_ERR_OVERFLOW; goto error; } - return nb_fields; + /* Update command reply header. */ + reply_command_header.count = (uint32_t) nb_fields; + + memcpy(reply->buffer.data + reply_command_header_offset, &reply_command_header, + sizeof(reply_command_header)); + + ret_code = LTTNG_OK; error: - /* Return negative value to differentiate return code */ - return -ret; + free(fields); + return ret_code; } -ssize_t cmd_list_syscalls(struct lttng_event **events) +enum lttng_error_code cmd_list_syscalls( + struct lttng_payload *reply_payload) { - return syscall_table_list(events); + enum lttng_error_code ret_code; + ssize_t nb_events, i; + int ret; + struct lttng_event *events = NULL; + struct lttcomm_list_command_header reply_command_header = {}; + size_t reply_command_header_offset; + + assert(reply_payload); + + /* Reserve space for command reply header. */ + reply_command_header_offset = reply_payload->buffer.size; + ret = lttng_dynamic_buffer_set_size(&reply_payload->buffer, + reply_command_header_offset + + sizeof(struct lttcomm_list_command_header)); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + nb_events = syscall_table_list(&events); + if (nb_events < 0) { + ret_code = (enum lttng_error_code) -nb_events; + goto end; + } + + for (i = 0; i < nb_events; i++) { + ret = lttng_event_serialize(&events[i], 0, NULL, NULL, 0, NULL, + reply_payload); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + } + + if (nb_events > UINT32_MAX) { + ERR("Syscall count would overflow the syscall listing command's reply"); + ret_code = LTTNG_ERR_OVERFLOW; + goto end; + } + + /* Update command reply header. */ + reply_command_header.count = (uint32_t) nb_events; + memcpy(reply_payload->buffer.data + reply_command_header_offset, &reply_command_header, + sizeof(reply_command_header)); + + ret_code = LTTNG_OK; +end: + free(events); + return ret_code; } /* @@ -2737,7 +2830,7 @@ int cmd_start_trace(struct ltt_session *session) */ session->rotated_after_last_stop = false; - if (session->rotate_timer_period) { + if (session->rotate_timer_period && !session->rotation_schedule_timer_enabled) { int int_ret = timer_session_rotation_schedule_timer_start( session, session->rotate_timer_period); @@ -2782,7 +2875,7 @@ int cmd_stop_trace(struct ltt_session *session) ksession = session->kernel_session; usess = session->ust_session; - /* Session is not active. Skip everythong and inform the client. */ + /* Session is not active. Skip everything and inform the client. */ if (!session->active) { ret = LTTNG_ERR_TRACE_ALREADY_STOPPED; goto error; @@ -3043,6 +3136,28 @@ enum lttng_error_code cmd_create_session_from_descriptor( goto end; } + ret_code = notification_thread_command_add_session(the_notification_thread_handle, + new_session->id, new_session->name, new_session->uid, new_session->gid); + if (ret_code != LTTNG_OK) { + goto end; + } + + /* Announce the session's destruction to the notification thread when it is destroyed. */ + ret = session_add_destroy_notifier( + new_session, + [](const struct ltt_session *session, + void *user_data __attribute__((unused))) { + (void) notification_thread_command_remove_session( + the_notification_thread_handle, session->id); + }, + NULL); + if (ret) { + PERROR("Failed to add notification thread command to session's destroy notifiers: session name = %s", + new_session->name); + ret = LTTNG_ERR_NOMEM; + goto end; + } + if (!session_name) { ret = lttng_session_descriptor_set_session_name(descriptor, new_session->name); @@ -3207,6 +3322,7 @@ void cmd_destroy_session_reply(const struct ltt_session *session, .cmd_header_size = sizeof(struct lttcomm_session_destroy_command_header), .data_size = 0, + .fd_count = 0, }; size_t payload_size_before_location; @@ -3289,11 +3405,12 @@ int cmd_destroy_session(struct ltt_session *session, struct cmd_destroy_session_reply_context *reply_context = NULL; if (sock_fd) { - reply_context = (cmd_destroy_session_reply_context *) zmalloc(sizeof(*reply_context)); + reply_context = zmalloc(); if (!reply_context) { ret = LTTNG_ERR_NOMEM; goto end; } + reply_context->reply_sock_fd = *sock_fd; } @@ -3492,12 +3609,13 @@ int cmd_register_consumer(struct ltt_session *session, goto error; } - socket->lock = (pthread_mutex_t *) zmalloc(sizeof(pthread_mutex_t)); + socket->lock = zmalloc(); if (socket->lock == NULL) { PERROR("zmalloc pthread mutex"); ret = LTTNG_ERR_FATAL; goto error; } + pthread_mutex_init(socket->lock, NULL); socket->registered = 1; @@ -3560,7 +3678,7 @@ ssize_t cmd_list_domains(struct ltt_session *session, goto end; } - *domains = (lttng_domain *) zmalloc(nb_dom * sizeof(struct lttng_domain)); + *domains = calloc(nb_dom); if (*domains == NULL) { ret = LTTNG_ERR_FATAL; goto error; @@ -3603,102 +3721,183 @@ 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_code = LTTNG_ERR_NOMEM; + 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); + ret_code = LTTNG_ERR_UNK; + goto end; + } + + 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); + lttng_channel_destroy(channel); + ret_code = LTTNG_ERR_UNK; + goto end; + } + + lttng_channel_destroy(channel); + 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 = (lttng_channel *) zmalloc(payload_size); - if (*channels == NULL) { - ret = -LTTNG_ERR_FATAL; - goto end; - } - - channel_exts = (lttng_channel_extended *) - (((char *) *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; } /* * Command LTTNG_LIST_EVENTS processed by the client thread. */ -ssize_t cmd_list_events(enum lttng_domain_type domain, - struct ltt_session *session, char *channel_name, - struct lttng_payload *payload) +enum lttng_error_code cmd_list_events(enum lttng_domain_type domain, + struct ltt_session *session, + char *channel_name, + struct lttng_payload *reply_payload) { - int ret = 0; - ssize_t nb_events = 0; - struct lttcomm_event_command_header cmd_header = {}; - const size_t cmd_header_offset = payload->buffer.size; + int buffer_resize_ret; + enum lttng_error_code ret_code = LTTNG_OK; + struct lttcomm_list_command_header reply_command_header = {}; + size_t reply_command_header_offset; + unsigned int nb_events = 0; - ret = lttng_dynamic_buffer_append( - &payload->buffer, &cmd_header, sizeof(cmd_header)); - if (ret) { - ret = LTTNG_ERR_NOMEM; - goto error; + assert(reply_payload); + + /* Reserve space for command reply header. */ + reply_command_header_offset = reply_payload->buffer.size; + buffer_resize_ret = lttng_dynamic_buffer_set_size(&reply_payload->buffer, + reply_command_header_offset + + sizeof(struct lttcomm_list_command_header)); + if (buffer_resize_ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; } switch (domain) { case LTTNG_DOMAIN_KERNEL: if (session->kernel_session != NULL) { - nb_events = list_lttng_kernel_events(channel_name, - session->kernel_session, payload); + ret_code = list_lttng_kernel_events(channel_name, + session->kernel_session, reply_payload, &nb_events); } + break; case LTTNG_DOMAIN_UST: { if (session->ust_session != NULL) { - nb_events = list_lttng_ust_global_events(channel_name, + ret_code = list_lttng_ust_global_events(channel_name, &session->ust_session->domain_global, - payload); + reply_payload, &nb_events); } + break; } case LTTNG_DOMAIN_LOG4J: @@ -3712,27 +3911,32 @@ ssize_t cmd_list_events(enum lttng_domain_type domain, cds_lfht_for_each_entry(session->ust_session->agents->ht, &iter.iter, agt, node.node) { if (agt->domain == domain) { - nb_events = list_lttng_agent_events( - agt, payload); + ret_code = list_lttng_agent_events( + agt, reply_payload, &nb_events); break; } } + rcu_read_unlock(); } break; default: - ret = LTTNG_ERR_UND; - goto error; + ret_code = LTTNG_ERR_UND; + break; } - ((struct lttcomm_event_command_header *) (payload->buffer.data + - cmd_header_offset))->nb_events = (uint32_t) nb_events; + if (nb_events > UINT32_MAX) { + ret_code = LTTNG_ERR_OVERFLOW; + goto end; + } - return nb_events; + /* Update command reply header. */ + reply_command_header.count = (uint32_t) nb_events; + memcpy(reply_payload->buffer.data + reply_command_header_offset, &reply_command_header, + sizeof(reply_command_header)); -error: - /* Return negative value to differentiate return code */ - return -ret; +end: + return ret_code; } /* @@ -4016,7 +4220,7 @@ ssize_t cmd_snapshot_list_outputs(struct ltt_session *session, goto end; } - list = (lttng_snapshot_output *) zmalloc(session->snapshot.nb_output * sizeof(*list)); + list = calloc(session->snapshot.nb_output); if (!list) { ret = -LTTNG_ERR_NOMEM; goto end; @@ -4116,99 +4320,6 @@ end: return ret; } -static -int clear_metadata_file(int fd) -{ - int ret; - off_t lseek_ret; - - lseek_ret = lseek(fd, 0, SEEK_SET); - if (lseek_ret < 0) { - PERROR("lseek"); - ret = -1; - goto end; - } - - ret = ftruncate(fd, 0); - if (ret < 0) { - PERROR("ftruncate"); - goto end; - } - -end: - return ret; -} - -static -int ust_regenerate_metadata(struct ltt_ust_session *usess) -{ - int ret = 0; - struct buffer_reg_uid *uid_reg = NULL; - struct buffer_reg_session *session_reg = NULL; - - rcu_read_lock(); - cds_list_for_each_entry(uid_reg, &usess->buffer_reg_uid_list, lnode) { - struct ust_registry_session *registry; - struct ust_registry_channel *chan; - struct lttng_ht_iter iter_chan; - - session_reg = uid_reg->registry; - registry = session_reg->reg.ust; - - pthread_mutex_lock(®istry->lock); - registry->metadata_len_sent = 0; - memset(registry->metadata, 0, registry->metadata_alloc_len); - registry->metadata_len = 0; - registry->metadata_version++; - if (registry->metadata_fd > 0) { - /* Clear the metadata file's content. */ - ret = clear_metadata_file(registry->metadata_fd); - if (ret) { - pthread_mutex_unlock(®istry->lock); - goto end; - } - } - - ret = ust_metadata_session_statedump(registry, NULL, - registry->major, registry->minor); - if (ret) { - pthread_mutex_unlock(®istry->lock); - ERR("Failed to generate session metadata (err = %d)", - ret); - goto end; - } - cds_lfht_for_each_entry(registry->channels->ht, &iter_chan.iter, - chan, node.node) { - struct ust_registry_event *event; - struct lttng_ht_iter iter_event; - - ret = ust_metadata_channel_statedump(registry, chan); - if (ret) { - pthread_mutex_unlock(®istry->lock); - ERR("Failed to generate channel metadata " - "(err = %d)", ret); - goto end; - } - cds_lfht_for_each_entry(chan->ht->ht, &iter_event.iter, - event, node.node) { - ret = ust_metadata_event_statedump(registry, - chan, event); - if (ret) { - pthread_mutex_unlock(®istry->lock); - ERR("Failed to generate event metadata " - "(err = %d)", ret); - goto end; - } - } - } - pthread_mutex_unlock(®istry->lock); - } - -end: - rcu_read_unlock(); - return ret; -} - /* * Command LTTNG_REGENERATE_METADATA from the lttng-ctl library. * @@ -4239,7 +4350,7 @@ int cmd_regenerate_metadata(struct ltt_session *session) } if (session->ust_session) { - ret = ust_regenerate_metadata(session->ust_session); + ret = trace_ust_regenerate_metadata(session->ust_session); if (ret < 0) { ERR("Failed to regenerate the UST metadata"); goto end; @@ -4871,7 +4982,7 @@ static enum lttng_error_code set_relayd_for_snapshot( cds_lfht_for_each_entry(output->socks->ht, &iter.iter, socket, node.node) { pthread_mutex_lock(socket->lock); - status = send_consumer_relayd_sockets(LTTNG_DOMAIN_NONE, session->id, + status = send_consumer_relayd_sockets(session->id, output, socket, session->name, session->hostname, base_path, @@ -4900,7 +5011,7 @@ static enum lttng_error_code record_kernel_snapshot( struct ltt_kernel_session *ksess, const struct consumer_output *output, const struct ltt_session *session, - int wait, uint64_t nb_packets_per_stream) + uint64_t nb_packets_per_stream) { enum lttng_error_code status; @@ -4909,7 +5020,7 @@ static enum lttng_error_code record_kernel_snapshot( LTTNG_ASSERT(session); status = kernel_snapshot_record( - ksess, output, wait, nb_packets_per_stream); + ksess, output, nb_packets_per_stream); return status; } @@ -4921,7 +5032,7 @@ static enum lttng_error_code record_kernel_snapshot( static enum lttng_error_code record_ust_snapshot(struct ltt_ust_session *usess, const struct consumer_output *output, const struct ltt_session *session, - int wait, uint64_t nb_packets_per_stream) + uint64_t nb_packets_per_stream) { enum lttng_error_code status; @@ -4930,7 +5041,7 @@ static enum lttng_error_code record_ust_snapshot(struct ltt_ust_session *usess, LTTNG_ASSERT(session); status = ust_app_snapshot_record( - usess, output, wait, nb_packets_per_stream); + usess, output, nb_packets_per_stream); return status; } @@ -5024,7 +5135,7 @@ int64_t get_session_nb_packets_per_stream(const struct ltt_session *session, static enum lttng_error_code snapshot_record(struct ltt_session *session, - const struct snapshot_output *snapshot_output, int wait) + const struct snapshot_output *snapshot_output) { int64_t nb_packets_per_stream; char snapshot_chunk_name[LTTNG_NAME_MAX]; @@ -5144,7 +5255,7 @@ enum lttng_error_code snapshot_record(struct ltt_session *session, if (session->kernel_session) { ret_code = record_kernel_snapshot(session->kernel_session, snapshot_kernel_consumer_output, session, - wait, nb_packets_per_stream); + nb_packets_per_stream); if (ret_code != LTTNG_OK) { goto error_close_trace_chunk; } @@ -5153,7 +5264,7 @@ enum lttng_error_code snapshot_record(struct ltt_session *session, if (session->ust_session) { ret_code = record_ust_snapshot(session->ust_session, snapshot_ust_consumer_output, session, - wait, nb_packets_per_stream); + nb_packets_per_stream); if (ret_code != LTTNG_OK) { goto error_close_trace_chunk; } @@ -5176,6 +5287,9 @@ error_close_trace_chunk: session->name); ret_code = LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER; } + + lttng_trace_chunk_put(snapshot_trace_chunk); + snapshot_trace_chunk = NULL; error: if (original_ust_consumer_output) { session->ust_session->consumer = original_ust_consumer_output; @@ -5198,7 +5312,8 @@ error: * Return LTTNG_OK on success or else a LTTNG_ERR code. */ int cmd_snapshot_record(struct ltt_session *session, - const struct lttng_snapshot_output *output, int wait) + const struct lttng_snapshot_output *output, + int wait __attribute__((unused))) { enum lttng_error_code cmd_ret = LTTNG_OK; int ret; @@ -5260,7 +5375,7 @@ int cmd_snapshot_record(struct ltt_session *session, /* Use the global datetime */ memcpy(tmp_output->datetime, datetime, sizeof(datetime)); - cmd_ret = snapshot_record(session, tmp_output, wait); + cmd_ret = snapshot_record(session, tmp_output); if (cmd_ret != LTTNG_OK) { goto error; } @@ -5300,7 +5415,7 @@ int cmd_snapshot_record(struct ltt_session *session, } } - cmd_ret = snapshot_record(session, &output_copy, wait); + cmd_ret = snapshot_record(session, &output_copy); if (cmd_ret != LTTNG_OK) { rcu_read_unlock(); goto error; @@ -5516,8 +5631,7 @@ int cmd_rotate_session(struct ltt_session *session, chunk_being_archived = NULL; if (!quiet_rotation) { ret = notification_thread_command_session_rotation_ongoing( - the_notification_thread_handle, session->name, - session->uid, session->gid, + the_notification_thread_handle, session->id, ongoing_rotation_chunk_id); if (ret != LTTNG_OK) { ERR("Failed to notify notification thread that a session rotation is ongoing for session %s",