#include "channel.h"
#include "consumer.h"
#include "event.h"
+#include "health.h"
#include "kernel.h"
#include "kernel-consumer.h"
#include "lttng-sessiond.h"
/*
* 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.
- *
- * This value should be incremented atomically for safety purposes and future
- * possible concurrent access.
+ * to send to. It must be accessed with the relayd_net_seq_idx_lock
+ * held.
*/
-static unsigned int relayd_net_seq_idx;
+static pthread_mutex_t relayd_net_seq_idx_lock = PTHREAD_MUTEX_INITIALIZER;
+static uint64_t relayd_net_seq_idx;
/*
* Create a session path used by list_lttng_sessions for the case that the
* Do we have a UST url set. If yes, this means we have both kernel and UST
* to print.
*/
- if (strlen(tmp_uurl) > 0) {
+ if (*tmp_uurl != '\0') {
ret = snprintf(dst, size, "[K]: %s [data: %d] -- [U]: %s [data: %d]",
tmp_urls, kdata_port, tmp_uurl, udata_port);
} else {
int dport;
- if (kuri) {
+ if (kuri || (!kuri && !uuri)) {
dport = kdata_port;
} else {
/* No kernel URI, use the UST port. */
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) {
strncpy(channels[i].name, uchan->name, LTTNG_SYMBOL_NAME_LEN);
}
i++;
}
+ rcu_read_unlock();
break;
}
default:
case LTTNG_KERNEL_TRACEPOINT:
(*events)[i].type = LTTNG_EVENT_TRACEPOINT;
break;
- case LTTNG_KERNEL_KPROBE:
case LTTNG_KERNEL_KRETPROBE:
+ (*events)[i].type = LTTNG_EVENT_FUNCTION;
+ memcpy(&(*events)[i].attr.probe, &event->event->u.kprobe,
+ sizeof(struct lttng_kernel_kprobe));
+ break;
+ case LTTNG_KERNEL_KPROBE:
(*events)[i].type = LTTNG_EVENT_PROBE;
memcpy(&(*events)[i].attr.probe, &event->event->u.kprobe,
sizeof(struct lttng_kernel_kprobe));
case LTTNG_DST_IPV6:
DBG2("Setting network URI to consumer");
+ if (consumer->type == CONSUMER_DST_NET) {
+ if ((uri->stype == LTTNG_STREAM_CONTROL &&
+ consumer->dst.net.control_isset) ||
+ (uri->stype == LTTNG_STREAM_DATA &&
+ consumer->dst.net.data_isset)) {
+ ret = LTTNG_ERR_URL_EXIST;
+ goto error;
+ }
+ } else {
+ memset(&consumer->dst.net, 0, sizeof(consumer->dst.net));
+ }
+
+ consumer->type = CONSUMER_DST_NET;
+
/* Set URI into consumer output object */
ret = consumer_set_network_uri(consumer, uri);
if (ret < 0) {
- ret = LTTNG_ERR_FATAL;
+ ret = -ret;
goto error;
} else if (ret == 1) {
/*
break;
}
+ ret = LTTNG_OK;
+
error:
return ret;
}
assert(session);
+ rcu_read_lock();
+
if (session->consumer_fds_sent == 0 && session->consumer != NULL) {
cds_lfht_for_each_entry(session->consumer->socks->ht, &iter.iter,
socket, node.node) {
assert(socket->fd >= 0);
pthread_mutex_lock(socket->lock);
- ret = kernel_consumer_send_session(socket->fd, session);
+ ret = kernel_consumer_send_session(socket, session);
pthread_mutex_unlock(socket->lock);
if (ret < 0) {
ret = LTTNG_ERR_KERN_CONSUMER_FAIL;
}
error:
+ rcu_read_unlock();
return ret;
}
* On success, the relayd_sock pointer is set to the created socket.
* Else, it's stays untouched and a lttcomm error code is returned.
*/
-static int create_connect_relayd(struct consumer_output *output,
- const char *session_name, struct lttng_uri *uri,
- struct lttcomm_sock **relayd_sock)
+static int create_connect_relayd(struct lttng_uri *uri,
+ struct lttcomm_relayd_sock **relayd_sock)
{
int ret;
- struct lttcomm_sock *sock;
+ struct lttcomm_relayd_sock *rsock;
- /* Create socket object from URI */
- sock = lttcomm_alloc_sock_from_uri(uri);
- if (sock == NULL) {
+ rsock = lttcomm_alloc_relayd_sock(uri, RELAYD_VERSION_COMM_MAJOR,
+ RELAYD_VERSION_COMM_MINOR);
+ if (!rsock) {
ret = LTTNG_ERR_FATAL;
goto error;
}
- ret = lttcomm_create_sock(sock);
- if (ret < 0) {
- ret = LTTNG_ERR_FATAL;
- goto error;
- }
-
- /* Connect to relayd so we can proceed with a session creation. */
- ret = relayd_connect(sock);
+ /*
+ * Connect to relayd so we can proceed with a session creation. This call
+ * can possibly block for an arbitrary amount of time to set the health
+ * state to be in poll execution.
+ */
+ health_poll_entry();
+ ret = relayd_connect(rsock);
+ health_poll_exit();
if (ret < 0) {
ERR("Unable to reach lttng-relayd");
ret = LTTNG_ERR_RELAYD_CONNECT_FAIL;
DBG3("Creating relayd stream socket from URI");
/* Check relayd version */
- ret = relayd_version_check(sock, RELAYD_VERSION_COMM_MAJOR,
- RELAYD_VERSION_COMM_MINOR);
+ ret = relayd_version_check(rsock);
if (ret < 0) {
ret = LTTNG_ERR_RELAYD_VERSION_FAIL;
goto close_sock;
goto close_sock;
}
- *relayd_sock = sock;
+ *relayd_sock = rsock;
return LTTNG_OK;
close_sock:
- if (sock) {
- (void) relayd_close(sock);
- }
+ /* The returned value is not useful since we are on an error path. */
+ (void) relayd_close(rsock);
free_sock:
- if (sock) {
- lttcomm_destroy_sock(sock);
- }
+ free(rsock);
error:
return ret;
}
*/
static int send_consumer_relayd_socket(int domain, struct ltt_session *session,
struct lttng_uri *relayd_uri, struct consumer_output *consumer,
- int consumer_fd)
+ struct consumer_socket *consumer_sock)
{
int ret;
- struct lttcomm_sock *sock = NULL;
-
- /* Set the network sequence index if not set. */
- if (consumer->net_seq_index == -1) {
- /*
- * Increment net_seq_idx because we are about to transfer the
- * new relayd socket to the consumer.
- */
- uatomic_inc(&relayd_net_seq_idx);
- /* Assign unique key so the consumer can match streams */
- uatomic_set(&consumer->net_seq_index,
- uatomic_read(&relayd_net_seq_idx));
- }
+ struct lttcomm_relayd_sock *rsock = NULL;
/* Connect to relayd and make version check if uri is the control. */
- ret = create_connect_relayd(consumer, session->name, relayd_uri, &sock);
+ ret = create_connect_relayd(relayd_uri, &rsock);
if (ret != LTTNG_OK) {
- goto close_sock;
+ goto error;
}
+ assert(rsock);
/* If the control socket is connected, network session is ready */
if (relayd_uri->stype == LTTNG_STREAM_CONTROL) {
session->net_handle = 1;
}
+ /* Set the network sequence index if not set. */
+ if (consumer->net_seq_index == (uint64_t) -1ULL) {
+ pthread_mutex_lock(&relayd_net_seq_idx_lock);
+ /*
+ * Increment net_seq_idx because we are about to transfer the
+ * new relayd socket to the consumer.
+ * Assign unique key so the consumer can match streams.
+ */
+ consumer->net_seq_index = ++relayd_net_seq_idx;
+ pthread_mutex_unlock(&relayd_net_seq_idx_lock);
+ }
+
/* Send relayd socket to consumer. */
- ret = consumer_send_relayd_socket(consumer_fd, sock,
- consumer, relayd_uri->stype);
+ ret = consumer_send_relayd_socket(consumer_sock, rsock, consumer,
+ relayd_uri->stype, session->id);
if (ret < 0) {
ret = LTTNG_ERR_ENABLE_CONSUMER_FAIL;
goto close_sock;
/* Flag that the corresponding socket was sent. */
if (relayd_uri->stype == LTTNG_STREAM_CONTROL) {
- consumer->dst.net.control_sock_sent = 1;
+ consumer_sock->control_sock_sent = 1;
} else if (relayd_uri->stype == LTTNG_STREAM_DATA) {
- consumer->dst.net.data_sock_sent = 1;
+ consumer_sock->data_sock_sent = 1;
}
ret = LTTNG_OK;
*/
close_sock:
- if (sock) {
- (void) relayd_close(sock);
- lttcomm_destroy_sock(sock);
- }
+ (void) relayd_close(rsock);
+ free(rsock);
+error:
+ if (ret != LTTNG_OK) {
+ /*
+ * The consumer output for this session should not be used anymore
+ * since the relayd connection failed thus making any tracing or/and
+ * streaming not usable.
+ */
+ consumer->enabled = 0;
+ }
return ret;
}
* session.
*/
static int send_consumer_relayd_sockets(int domain,
- struct ltt_session *session, struct consumer_output *consumer, int fd)
+ struct ltt_session *session, struct consumer_output *consumer,
+ struct consumer_socket *sock)
{
int ret = LTTNG_OK;
assert(consumer);
/* Sending control relayd socket. */
- if (!consumer->dst.net.control_sock_sent) {
+ if (!sock->control_sock_sent) {
ret = send_consumer_relayd_socket(domain, session,
- &consumer->dst.net.control, consumer, fd);
+ &consumer->dst.net.control, consumer, sock);
if (ret != LTTNG_OK) {
goto error;
}
}
/* Sending data relayd socket. */
- if (!consumer->dst.net.data_sock_sent) {
+ if (!sock->data_sock_sent) {
ret = send_consumer_relayd_socket(domain, session,
- &consumer->dst.net.data, consumer, fd);
+ &consumer->dst.net.data, consumer, sock);
if (ret != LTTNG_OK) {
goto error;
}
* the relayd and send them to the right domain consumer. Consumer type MUST be
* network.
*/
-static int setup_relayd(struct ltt_session *session)
+int cmd_setup_relayd(struct ltt_session *session)
{
int ret = LTTNG_OK;
struct ltt_ust_session *usess;
usess = session->ust_session;
ksess = session->kernel_session;
- DBG2("Setting relayd for session %s", session->name);
+ DBG("Setting relayd for session %s", session->name);
+
+ rcu_read_lock();
if (usess && usess->consumer && usess->consumer->type == CONSUMER_DST_NET
&& usess->consumer->enabled) {
pthread_mutex_lock(socket->lock);
ret = send_consumer_relayd_sockets(LTTNG_DOMAIN_UST, session,
- usess->consumer, socket->fd);
+ usess->consumer, socket);
pthread_mutex_unlock(socket->lock);
if (ret != LTTNG_OK) {
goto error;
pthread_mutex_lock(socket->lock);
ret = send_consumer_relayd_sockets(LTTNG_DOMAIN_KERNEL, session,
- ksess->consumer, socket->fd);
+ ksess->consumer, socket);
pthread_mutex_unlock(socket->lock);
if (ret != LTTNG_OK) {
goto error;
}
error:
+ rcu_read_unlock();
return ret;
}
/* Setup kernel consumer socket and send fds to it */
ret = init_kernel_tracing(ksess);
- if (ret < 0) {
+ if (ret != 0) {
ret = LTTNG_ERR_KERN_START_FAIL;
goto error;
}
usess = session->ust_session;
+ rcu_read_lock();
+
switch (domain) {
case LTTNG_DOMAIN_KERNEL:
{
goto error;
}
- ret = channel_ust_disable(usess, domain, uchan);
+ ret = channel_ust_disable(usess, uchan);
if (ret != LTTNG_OK) {
goto error;
}
ret = LTTNG_OK;
error:
+ rcu_read_unlock();
return ret;
}
* The wpipe arguments is used as a notifier for the kernel thread.
*/
int cmd_enable_channel(struct ltt_session *session,
- int domain, struct lttng_channel *attr, int wpipe)
+ struct lttng_domain *domain, struct lttng_channel *attr, int wpipe)
{
int ret;
struct ltt_ust_session *usess = session->ust_session;
assert(session);
assert(attr);
+ assert(domain);
DBG("Enabling channel %s for session %s", attr->name, session->name);
- switch (domain) {
+ /*
+ * Don't try to enable a channel if the session has been started at
+ * some point in time before. The tracer does not allow it.
+ */
+ if (session->started) {
+ ret = LTTNG_ERR_TRACE_ALREADY_STARTED;
+ goto error;
+ }
+
+ rcu_read_lock();
+
+ switch (domain->type) {
case LTTNG_DOMAIN_KERNEL:
{
struct ltt_kernel_channel *kchan;
}
kernel_wait_quiescent(kernel_tracer_fd);
-
- /*
- * If the session was previously started, start as well this newly
- * created kernel session so the events/channels enabled *after* the
- * start actually work.
- */
- if (session->started && !session->kernel_session->started) {
- ret = start_kernel_session(session->kernel_session, wpipe);
- if (ret != LTTNG_OK) {
- goto error;
- }
- }
break;
}
case LTTNG_DOMAIN_UST:
uchan = trace_ust_find_channel_by_name(chan_ht, attr->name);
if (uchan == NULL) {
- ret = channel_ust_create(usess, domain, attr);
+ ret = channel_ust_create(usess, attr, domain->buf_type);
} else {
- ret = channel_ust_enable(usess, domain, uchan);
- }
-
- /* Start the UST session if the session was already started. */
- if (session->started && !usess->start_trace) {
- ret = ust_app_start_trace_all(usess);
- if (ret < 0) {
- ret = LTTNG_ERR_UST_START_FAIL;
- goto error;
- }
- ret = LTTNG_OK;
- usess->start_trace = 1;
+ ret = channel_ust_enable(usess, uchan);
}
break;
}
-#if 0
- case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
- case LTTNG_DOMAIN_UST_EXEC_NAME:
- case LTTNG_DOMAIN_UST_PID:
-#endif
default:
ret = LTTNG_ERR_UNKNOWN_DOMAIN;
goto error;
}
error:
+ rcu_read_unlock();
return ret;
}
{
int ret;
+ rcu_read_lock();
+
switch (domain) {
case LTTNG_DOMAIN_KERNEL:
{
goto error;
}
- ret = event_kernel_disable_tracepoint(ksess, kchan, event_name);
+ ret = event_kernel_disable_tracepoint(kchan, event_name);
if (ret != LTTNG_OK) {
goto error;
}
goto error;
}
- ret = event_ust_disable_tracepoint(usess, domain, uchan, event_name);
+ ret = event_ust_disable_tracepoint(usess, uchan, event_name);
if (ret != LTTNG_OK) {
goto error;
}
ret = LTTNG_OK;
error:
+ rcu_read_unlock();
return ret;
}
{
int ret;
+ rcu_read_lock();
+
switch (domain) {
case LTTNG_DOMAIN_KERNEL:
{
goto error;
}
- ret = event_kernel_disable_all(ksess, kchan);
+ ret = event_kernel_disable_all(kchan);
if (ret != LTTNG_OK) {
goto error;
}
goto error;
}
- ret = event_ust_disable_all_tracepoints(usess, domain, uchan);
+ ret = event_ust_disable_all_tracepoints(usess, uchan);
if (ret != 0) {
goto error;
}
ret = LTTNG_OK;
error:
+ rcu_read_unlock();
return ret;
}
int cmd_add_context(struct ltt_session *session, int domain,
char *channel_name, struct lttng_event_context *ctx, int kwpipe)
{
- int ret;
+ int ret, chan_kern_created = 0, chan_ust_created = 0;
switch (domain) {
case LTTNG_DOMAIN_KERNEL:
if (ret != LTTNG_OK) {
goto error;
}
+ chan_kern_created = 1;
}
/* Add kernel context to kernel tracer */
if (chan_count == 0) {
struct lttng_channel *attr;
/* Create default channel */
- attr = channel_new_default_attr(domain);
+ attr = channel_new_default_attr(domain, usess->buffer_type);
if (attr == NULL) {
ret = LTTNG_ERR_FATAL;
goto error;
}
- ret = channel_ust_create(usess, domain, attr);
+ ret = channel_ust_create(usess, attr, usess->buffer_type);
if (ret != LTTNG_OK) {
free(attr);
goto error;
}
free(attr);
+ chan_ust_created = 1;
}
ret = context_ust_add(usess, domain, ctx, channel_name);
goto error;
}
- ret = LTTNG_OK;
+ return LTTNG_OK;
error:
+ if (chan_kern_created) {
+ struct ltt_kernel_channel *kchan =
+ trace_kernel_get_channel_by_name(DEFAULT_CHANNEL_NAME,
+ session->kernel_session);
+ /* Created previously, this should NOT fail. */
+ assert(kchan);
+ kernel_destroy_channel(kchan);
+ }
+
+ if (chan_ust_created) {
+ struct ltt_ust_channel *uchan =
+ trace_ust_find_channel_by_name(
+ session->ust_session->domain_global.channels,
+ DEFAULT_CHANNEL_NAME);
+ /* Created previously, this should NOT fail. */
+ assert(uchan);
+ /* Remove from the channel list of the session. */
+ trace_ust_delete_channel(session->ust_session->domain_global.channels,
+ uchan);
+ trace_ust_destroy_channel(uchan);
+ }
return ret;
}
/*
* Command LTTNG_ENABLE_EVENT processed by the client thread.
*/
-int cmd_enable_event(struct ltt_session *session, int domain,
+int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain,
char *channel_name, struct lttng_event *event,
struct lttng_filter_bytecode *filter, int wpipe)
{
- int ret;
+ int ret, channel_created = 0;
struct lttng_channel *attr;
assert(session);
assert(event);
assert(channel_name);
- switch (domain) {
+ rcu_read_lock();
+
+ switch (domain->type) {
case LTTNG_DOMAIN_KERNEL:
{
struct ltt_kernel_channel *kchan;
kchan = trace_kernel_get_channel_by_name(channel_name,
session->kernel_session);
if (kchan == NULL) {
- attr = channel_new_default_attr(domain);
+ attr = channel_new_default_attr(LTTNG_DOMAIN_KERNEL,
+ LTTNG_BUFFER_GLOBAL);
if (attr == NULL) {
ret = LTTNG_ERR_FATAL;
goto error;
goto error;
}
free(attr);
+
+ channel_created = 1;
}
/* Get the newly created kernel channel pointer */
goto error;
}
- ret = event_kernel_enable_tracepoint(session->kernel_session, kchan,
- event);
+ ret = event_kernel_enable_tracepoint(kchan, event);
if (ret != LTTNG_OK) {
+ if (channel_created) {
+ /* Let's not leak a useless channel. */
+ kernel_destroy_channel(kchan);
+ }
goto error;
}
channel_name);
if (uchan == NULL) {
/* Create default channel */
- attr = channel_new_default_attr(domain);
+ attr = channel_new_default_attr(LTTNG_DOMAIN_UST,
+ usess->buffer_type);
if (attr == NULL) {
ret = LTTNG_ERR_FATAL;
goto error;
}
/* At this point, the session and channel exist on the tracer */
- ret = event_ust_enable_tracepoint(usess, domain, uchan, event, filter);
+ ret = event_ust_enable_tracepoint(usess, uchan, event, filter);
if (ret != LTTNG_OK) {
goto error;
}
ret = LTTNG_OK;
error:
+ rcu_read_unlock();
return ret;
}
/*
* Command LTTNG_ENABLE_ALL_EVENT processed by the client thread.
*/
-int cmd_enable_event_all(struct ltt_session *session, int domain,
- char *channel_name, int event_type,
+int cmd_enable_event_all(struct ltt_session *session,
+ struct lttng_domain *domain, char *channel_name, int event_type,
struct lttng_filter_bytecode *filter, int wpipe)
{
int ret;
assert(session);
assert(channel_name);
- switch (domain) {
+ rcu_read_lock();
+
+ switch (domain->type) {
case LTTNG_DOMAIN_KERNEL:
{
struct ltt_kernel_channel *kchan;
session->kernel_session);
if (kchan == NULL) {
/* Create default channel */
- attr = channel_new_default_attr(domain);
+ attr = channel_new_default_attr(LTTNG_DOMAIN_KERNEL,
+ LTTNG_BUFFER_GLOBAL);
if (attr == NULL) {
ret = LTTNG_ERR_FATAL;
goto error;
switch (event_type) {
case LTTNG_EVENT_SYSCALL:
- ret = event_kernel_enable_all_syscalls(session->kernel_session,
- kchan, kernel_tracer_fd);
+ ret = event_kernel_enable_all_syscalls(kchan, kernel_tracer_fd);
break;
case LTTNG_EVENT_TRACEPOINT:
/*
* This call enables all LTTNG_KERNEL_TRACEPOINTS and
* events already registered to the channel.
*/
- ret = event_kernel_enable_all_tracepoints(session->kernel_session,
- kchan, kernel_tracer_fd);
+ ret = event_kernel_enable_all_tracepoints(kchan, kernel_tracer_fd);
break;
case LTTNG_EVENT_ALL:
/* Enable syscalls and tracepoints */
- ret = event_kernel_enable_all(session->kernel_session,
- kchan, kernel_tracer_fd);
+ ret = event_kernel_enable_all(kchan, kernel_tracer_fd);
break;
default:
ret = LTTNG_ERR_KERN_ENABLE_FAIL;
/* Manage return value */
if (ret != LTTNG_OK) {
+ /*
+ * On error, cmd_enable_channel call will take care of destroying
+ * the created channel if it was needed.
+ */
goto error;
}
channel_name);
if (uchan == NULL) {
/* Create default channel */
- attr = channel_new_default_attr(domain);
+ attr = channel_new_default_attr(LTTNG_DOMAIN_UST,
+ usess->buffer_type);
if (attr == NULL) {
ret = LTTNG_ERR_FATAL;
goto error;
switch (event_type) {
case LTTNG_EVENT_ALL:
case LTTNG_EVENT_TRACEPOINT:
- ret = event_ust_enable_all_tracepoints(usess, domain, uchan,
- filter);
+ ret = event_ust_enable_all_tracepoints(usess, uchan, filter);
if (ret != LTTNG_OK) {
goto error;
}
ret = LTTNG_OK;
error:
+ rcu_read_unlock();
return ret;
}
session->enabled = 1;
- ret = setup_relayd(session);
- if (ret != LTTNG_OK) {
- ERR("Error setting up relayd for session %s", session->name);
- goto error;
- }
-
/* Kernel tracing */
if (ksession != NULL) {
ret = start_kernel_session(ksession, kernel_tracer_fd);
session->enabled = 0;
/* Kernel tracer */
- if (ksession) {
+ if (ksession && ksession->started) {
DBG("Stop kernel tracing");
/* Flush metadata if exist */
ksession->started = 0;
}
- if (usess) {
+ if (usess && usess->start_trace) {
usess->start_trace = 0;
ret = ust_app_stop_trace_all(usess);
}
}
- session->started = 0;
-
ret = LTTNG_OK;
error:
case LTTNG_DOMAIN_KERNEL:
/* Code flow error if we don't have a kernel session here. */
assert(ksess);
-
- /* Create consumer output if none exists */
- consumer = ksess->tmp_consumer;
- if (consumer == NULL) {
- consumer = consumer_copy_output(ksess->consumer);
- if (consumer == NULL) {
- ret = LTTNG_ERR_FATAL;
- goto error;
- }
- /* Trash the consumer subdir, we are about to set a new one. */
- memset(consumer->subdir, 0, sizeof(consumer->subdir));
- ksess->tmp_consumer = consumer;
- }
-
+ assert(ksess->consumer);
+ consumer = ksess->consumer;
break;
case LTTNG_DOMAIN_UST:
/* Code flow error if we don't have a kernel session here. */
assert(usess);
-
- /* Create consumer output if none exists */
- consumer = usess->tmp_consumer;
- if (consumer == NULL) {
- consumer = consumer_copy_output(usess->consumer);
- if (consumer == NULL) {
- ret = LTTNG_ERR_FATAL;
- goto error;
- }
- /* Trash the consumer subdir, we are about to set a new one. */
- memset(consumer->subdir, 0, sizeof(consumer->subdir));
- usess->tmp_consumer = consumer;
- }
-
+ assert(usess->consumer);
+ consumer = usess->consumer;
break;
}
for (i = 0; i < nb_uri; i++) {
- struct consumer_socket *socket;
- struct lttng_ht_iter iter;
-
ret = add_uri_to_consumer(consumer, &uris[i], domain, session->name);
- if (ret < 0) {
+ if (ret != LTTNG_OK) {
goto error;
}
-
- /*
- * Don't send relayd socket if URI is NOT remote or if the relayd
- * socket for the session was already sent.
- */
- if (uris[i].dtype == LTTNG_DST_PATH ||
- (uris[i].stype == LTTNG_STREAM_CONTROL &&
- consumer->dst.net.control_sock_sent) ||
- (uris[i].stype == LTTNG_STREAM_DATA &&
- consumer->dst.net.data_sock_sent)) {
- continue;
- }
-
- /* Try to send relayd URI to the consumer if exist. */
- rcu_read_lock();
- cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter,
- socket, node.node) {
-
- /* A socket in the HT should never have a negative fd */
- assert(socket->fd >= 0);
-
- pthread_mutex_lock(socket->lock);
- ret = send_consumer_relayd_socket(domain, session, &uris[i],
- consumer, socket->fd);
- pthread_mutex_unlock(socket->lock);
- if (ret != LTTNG_OK) {
- rcu_read_unlock();
- goto error;
- }
- }
- rcu_read_unlock();
}
/* All good! */
size_t nb_uri, lttng_sock_cred *creds)
{
int ret;
- char *path = NULL;
struct ltt_session *session;
assert(name);
+ /* No URIs is not possible. */
+ if (uris == NULL) {
+ ret = LTTNG_ERR_SESSION_FAIL;
+ goto session_error;
+ }
+
/*
* Verify if the session already exist
*
}
/* Create tracing session in the registry */
- ret = session_create(name, path, LTTNG_SOCK_GET_UID_CRED(creds),
+ ret = session_create(name, LTTNG_SOCK_GET_UID_CRED(creds),
LTTNG_SOCK_GET_GID_CRED(creds));
if (ret != LTTNG_OK) {
goto session_error;
goto consumer_error;
}
- /*
- * This means that the lttng_create_session call was called with the _path_
- * argument set to NULL.
- */
- if (uris == NULL) {
- /*
- * At this point, we'll skip the consumer URI setup and create a
- * session with a NULL path which will flag the session to NOT spawn a
- * consumer.
- */
- DBG("Create session %s with NO uri, skipping consumer setup", name);
- goto end;
- }
-
- session->start_consumer = 1;
-
ret = cmd_set_consumer_uri(0, session, nb_uri, uris);
if (ret != LTTNG_OK) {
goto consumer_error;
session->consumer->enabled = 1;
-end:
return LTTNG_OK;
consumer_error:
const char *sock_path, struct consumer_data *cdata)
{
int ret, sock;
- struct consumer_socket *socket;
+ struct consumer_socket *socket = NULL;
assert(session);
assert(cdata);
goto error;
}
- ret = LTTNG_OK;
+ return LTTNG_OK;
error:
+ if (socket) {
+ consumer_destroy_socket(socket);
+ }
return ret;
}
if (session->ust_session != NULL) {
(*domains)[index].type = LTTNG_DOMAIN_UST;
+ (*domains)[index].buf_type = session->ust_session->buffer_type;
index++;
}
(ksess && ksess->consumer->type == CONSUMER_DST_NET) ||
(usess && usess->consumer->type == CONSUMER_DST_NET)) {
ret = build_network_session_path(sessions[i].path,
- sizeof(session[i].path), session);
+ sizeof(sessions[i].path), session);
} else {
- ret = snprintf(sessions[i].path, sizeof(session[i].path), "%s",
+ ret = snprintf(sessions[i].path, sizeof(sessions[i].path), "%s",
session->consumer->dst.trace_path);
}
if (ret < 0) {
}
}
-/*
- * Command LTTNG_DISABLE_CONSUMER processed by the client thread.
- */
-int cmd_disable_consumer(int domain, struct ltt_session *session)
-{
- int ret;
- struct ltt_kernel_session *ksess = session->kernel_session;
- struct ltt_ust_session *usess = session->ust_session;
- struct consumer_output *consumer;
-
- assert(session);
-
- if (session->enabled) {
- /* Can't disable consumer on an already started session */
- ret = LTTNG_ERR_TRACE_ALREADY_STARTED;
- goto error;
- }
-
- if (!session->start_consumer) {
- ret = LTTNG_ERR_NO_CONSUMER;
- goto error;
- }
-
- switch (domain) {
- case 0:
- DBG("Disable tracing session %s consumer", session->name);
- consumer = session->consumer;
- break;
- case LTTNG_DOMAIN_KERNEL:
- /* Code flow error if we don't have a kernel session here. */
- assert(ksess);
-
- DBG("Disabling kernel consumer");
- consumer = ksess->consumer;
-
- break;
- case LTTNG_DOMAIN_UST:
- /* Code flow error if we don't have a UST session here. */
- assert(usess);
-
- DBG("Disabling UST consumer");
- consumer = usess->consumer;
-
- break;
- default:
- ret = LTTNG_ERR_UNKNOWN_DOMAIN;
- goto error;
- }
-
- if (consumer) {
- consumer->enabled = 0;
- /* Success at this point */
- ret = LTTNG_OK;
- } else {
- ret = LTTNG_ERR_NO_CONSUMER;
- }
-
-error:
- return ret;
-}
-
-/*
- * Command LTTNG_ENABLE_CONSUMER processed by the client thread.
- */
-int cmd_enable_consumer(int domain, struct ltt_session *session)
-{
- int ret;
- struct ltt_kernel_session *ksess = session->kernel_session;
- struct ltt_ust_session *usess = session->ust_session;
- struct consumer_output *consumer = NULL;
-
- assert(session);
-
- /* Can't enable consumer after session started. */
- if (session->enabled) {
- ret = LTTNG_ERR_TRACE_ALREADY_STARTED;
- goto error;
- }
-
- switch (domain) {
- case 0:
- assert(session->consumer);
- consumer = session->consumer;
- break;
- case LTTNG_DOMAIN_KERNEL:
- /* Code flow error if we don't have a kernel session here. */
- assert(ksess);
-
- /*
- * Check if we have already sent fds to the consumer. In that case,
- * the enable-consumer command can't be used because a start trace
- * had previously occured.
- */
- if (ksess->consumer_fds_sent) {
- ret = LTTNG_ERR_ENABLE_CONSUMER_FAIL;
- goto error;
- }
-
- consumer = ksess->tmp_consumer;
- if (consumer == NULL) {
- ret = LTTNG_OK;
- /* No temp. consumer output exists. Using the current one. */
- DBG3("No temporary consumer. Using default");
- consumer = ksess->consumer;
- goto error;
- }
-
- switch (consumer->type) {
- case CONSUMER_DST_LOCAL:
- DBG2("Consumer output is local. Creating directory(ies)");
-
- /* Create directory(ies) */
- ret = run_as_mkdir_recursive(consumer->dst.trace_path,
- S_IRWXU | S_IRWXG, session->uid, session->gid);
- if (ret < 0) {
- if (ret != -EEXIST) {
- ERR("Trace directory creation error");
- ret = LTTNG_ERR_FATAL;
- goto error;
- }
- }
- break;
- case CONSUMER_DST_NET:
- DBG2("Consumer output is network. Validating URIs");
- /* Validate if we have both control and data path set. */
- if (!consumer->dst.net.control_isset) {
- ret = LTTNG_ERR_URL_CTRL_MISS;
- goto error;
- }
-
- if (!consumer->dst.net.data_isset) {
- ret = LTTNG_ERR_URL_DATA_MISS;
- goto error;
- }
-
- /* Check established network session state */
- if (session->net_handle == 0) {
- ret = LTTNG_ERR_ENABLE_CONSUMER_FAIL;
- ERR("Session network handle is not set on enable-consumer");
- goto error;
- }
-
- break;
- }
-
- /*
- * @session-lock
- * This is race free for now since the session lock is acquired before
- * ending up in this function. No other threads can access this kernel
- * session without this lock hence freeing the consumer output object
- * is valid.
- */
- rcu_read_lock();
- /* Destroy current consumer. We are about to replace it */
- consumer_destroy_output(ksess->consumer);
- rcu_read_unlock();
- ksess->consumer = consumer;
- ksess->tmp_consumer = NULL;
-
- break;
- case LTTNG_DOMAIN_UST:
- /* Code flow error if we don't have a UST session here. */
- assert(usess);
-
- /*
- * Check if we have already sent fds to the consumer. In that case,
- * the enable-consumer command can't be used because a start trace
- * had previously occured.
- */
- if (usess->start_trace) {
- ret = LTTNG_ERR_ENABLE_CONSUMER_FAIL;
- goto error;
- }
-
- consumer = usess->tmp_consumer;
- if (consumer == NULL) {
- ret = LTTNG_OK;
- /* No temp. consumer output exists. Using the current one. */
- DBG3("No temporary consumer. Using default");
- consumer = usess->consumer;
- goto error;
- }
-
- switch (consumer->type) {
- case CONSUMER_DST_LOCAL:
- DBG2("Consumer output is local. Creating directory(ies)");
-
- /* Create directory(ies) */
- ret = run_as_mkdir_recursive(consumer->dst.trace_path,
- S_IRWXU | S_IRWXG, session->uid, session->gid);
- if (ret < 0) {
- if (ret != -EEXIST) {
- ERR("Trace directory creation error");
- ret = LTTNG_ERR_FATAL;
- goto error;
- }
- }
- break;
- case CONSUMER_DST_NET:
- DBG2("Consumer output is network. Validating URIs");
- /* Validate if we have both control and data path set. */
- if (!consumer->dst.net.control_isset) {
- ret = LTTNG_ERR_URL_CTRL_MISS;
- goto error;
- }
-
- if (!consumer->dst.net.data_isset) {
- ret = LTTNG_ERR_URL_DATA_MISS;
- goto error;
- }
-
- /* Check established network session state */
- if (session->net_handle == 0) {
- ret = LTTNG_ERR_ENABLE_CONSUMER_FAIL;
- DBG2("Session network handle is not set on enable-consumer");
- goto error;
- }
-
- if (consumer->net_seq_index == -1) {
- ret = LTTNG_ERR_ENABLE_CONSUMER_FAIL;
- DBG2("Network index is not set on the consumer");
- goto error;
- }
-
- break;
- }
-
- /*
- * @session-lock
- * This is race free for now since the session lock is acquired before
- * ending up in this function. No other threads can access this kernel
- * session without this lock hence freeing the consumer output object
- * is valid.
- */
- rcu_read_lock();
- /* Destroy current consumer. We are about to replace it */
- consumer_destroy_output(usess->consumer);
- rcu_read_unlock();
- usess->consumer = consumer;
- usess->tmp_consumer = NULL;
-
- break;
- }
-
- session->start_consumer = 1;
-
- /* Enable it */
- if (consumer) {
- consumer->enabled = 1;
- /* Success at this point */
- ret = LTTNG_OK;
- } else {
- /* Should not really happend... */
- ret = LTTNG_ERR_NO_CONSUMER;
- }
-
-error:
- return ret;
-}
-
/*
* Command LTTNG_DATA_PENDING returning 0 if the data is NOT pending meaning
* ready for trace analysis (or anykind of reader) or else 1 for pending data.
void cmd_init(void)
{
/*
- * Set network sequence index to 1 for streams to match a relayd socket on
- * the consumer side.
+ * Set network sequence index to 1 for streams to match a relayd
+ * socket on the consumer side.
*/
- uatomic_set(&relayd_net_seq_idx, 1);
+ pthread_mutex_lock(&relayd_net_seq_idx_lock);
+ relayd_net_seq_idx = 1;
+ pthread_mutex_unlock(&relayd_net_seq_idx_lock);
DBG("Command subsystem initialized");
}