return stream;
}
-static void steal_stream_key(int key, struct lttng_ht *ht)
+static void steal_stream_key(uint64_t key, struct lttng_ht *ht)
{
struct lttng_consumer_stream *stream;
rcu_read_lock();
stream = find_stream(key, ht);
if (stream) {
- stream->key = -1ULL;
+ stream->key = (uint64_t) -1ULL;
/*
* We don't want the lookup to match, but we still need
* to iterate on this stream when iterating over the hash table. Just
* change the node key.
*/
- stream->node.key = -1ULL;
+ stream->node.key = (uint64_t) -1ULL;
}
rcu_read_unlock();
}
cds_list_for_each_entry_safe(stream, stmp, &channel->streams.head,
send_node) {
cds_list_del(&stream->send_node);
- lttng_ustconsumer_del_stream(stream);
- free(stream);
+ /*
+ * Once a stream is added to this list, the buffers were created so
+ * we have a guarantee that this call will succeed.
+ */
+ consumer_stream_destroy(stream, NULL);
}
lttng_ustconsumer_del_channel(channel);
break;
goto end;
}
- /* Empty no monitor streams list. */
- if (!channel->monitor) {
- struct lttng_consumer_stream *stream, *stmp;
-
- /*
- * So, these streams are not visible to any data thread. This is why we
- * close and free them because they were never added to any data
- * structure apart from this one.
- */
- cds_list_for_each_entry_safe(stream, stmp,
- &channel->stream_no_monitor_list.head, no_monitor_node) {
- cds_list_del(&stream->no_monitor_node);
- /* Close everything in that stream. */
- consumer_stream_close(stream);
- /* Free the ressource. */
- consumer_stream_free(stream);
- }
- }
-
rcu_read_lock();
iter.iter.node = &channel->node.node;
ret = lttng_ht_del(consumer_data.channel_ht, &iter);
* It's atomically set without having the stream mutex locked which is fine
* because we handle the write/read race with a pipe wakeup for each thread.
*/
-static void update_endpoint_status_by_netidx(int net_seq_idx,
+static void update_endpoint_status_by_netidx(uint64_t net_seq_idx,
enum consumer_endpoint_status status)
{
struct lttng_ht_iter iter;
struct lttng_consumer_stream *stream;
- DBG("Consumer set delete flag on stream by idx %d", net_seq_idx);
+ DBG("Consumer set delete flag on stream by idx %" PRIu64, net_seq_idx);
rcu_read_lock();
static void cleanup_relayd(struct consumer_relayd_sock_pair *relayd,
struct lttng_consumer_local_data *ctx)
{
- int netidx;
+ uint64_t netidx;
assert(relayd);
* Allocate and return a consumer relayd socket.
*/
struct consumer_relayd_sock_pair *consumer_allocate_relayd_sock_pair(
- int net_seq_idx)
+ uint64_t net_seq_idx)
{
struct consumer_relayd_sock_pair *obj = NULL;
- /* Negative net sequence index is a failure */
- if (net_seq_idx < 0) {
+ /* net sequence index of -1 is a failure */
+ if (net_seq_idx == (uint64_t) -1ULL) {
goto error;
}
return relayd;
}
+/*
+ * Find a relayd and send the stream
+ *
+ * Returns 0 on success, < 0 on error
+ */
+int consumer_send_relayd_stream(struct lttng_consumer_stream *stream,
+ char *path)
+{
+ int ret = 0;
+ struct consumer_relayd_sock_pair *relayd;
+
+ assert(stream);
+ assert(stream->net_seq_idx != -1ULL);
+ assert(path);
+
+ /* The stream is not metadata. Get relayd reference if exists. */
+ rcu_read_lock();
+ relayd = consumer_find_relayd(stream->net_seq_idx);
+ if (relayd != NULL) {
+ /* Add stream on the relayd */
+ pthread_mutex_lock(&relayd->ctrl_sock_mutex);
+ ret = relayd_add_stream(&relayd->control_sock, stream->name,
+ path, &stream->relayd_stream_id,
+ stream->chan->tracefile_size, stream->chan->tracefile_count);
+ pthread_mutex_unlock(&relayd->ctrl_sock_mutex);
+ if (ret < 0) {
+ goto end;
+ }
+ uatomic_inc(&relayd->refcount);
+ } else {
+ ERR("Stream %" PRIu64 " relayd ID %" PRIu64 " unknown. Can't send it.",
+ stream->key, stream->net_seq_idx);
+ ret = -1;
+ goto end;
+ }
+
+ DBG("Stream %s with key %" PRIu64 " sent to relayd id %" PRIu64,
+ stream->name, stream->key, stream->net_seq_idx);
+
+end:
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Find a relayd and close the stream
+ */
+void close_relayd_stream(struct lttng_consumer_stream *stream)
+{
+ struct consumer_relayd_sock_pair *relayd;
+
+ /* The stream is not metadata. Get relayd reference if exists. */
+ rcu_read_lock();
+ relayd = consumer_find_relayd(stream->net_seq_idx);
+ if (relayd) {
+ consumer_stream_relayd_close(stream, relayd);
+ }
+ rcu_read_unlock();
+}
+
/*
* Handle stream for relayd transmission if the stream applies for network
* streaming where the net sequence index is set.
enum lttng_event_output output,
uint64_t tracefile_size,
uint64_t tracefile_count,
+ uint64_t session_id_per_pid,
unsigned int monitor)
{
struct lttng_consumer_channel *channel;
channel->key = key;
channel->refcount = 0;
channel->session_id = session_id;
+ channel->session_id_per_pid = session_id_per_pid;
channel->uid = uid;
channel->gid = gid;
channel->relayd_id = relayd_id;
channel->refcount = 1;
}
- switch (output) {
- case LTTNG_EVENT_SPLICE:
- channel->output = CONSUMER_CHANNEL_SPLICE;
- break;
- case LTTNG_EVENT_MMAP:
- channel->output = CONSUMER_CHANNEL_MMAP;
- break;
- default:
- ERR("Allocate channel output unknown %d", output);
- free(channel);
- channel = NULL;
- goto end;
- }
-
strncpy(channel->pathname, pathname, sizeof(channel->pathname));
channel->pathname[sizeof(channel->pathname) - 1] = '\0';
channel->wait_fd = -1;
CDS_INIT_LIST_HEAD(&channel->streams.head);
- CDS_INIT_LIST_HEAD(&channel->stream_no_monitor_list.head);
DBG("Allocated channel (key %" PRIu64 ")", channel->key)
pthread_mutex_unlock(&consumer_data.lock);
if (!ret && channel->wait_fd != -1 &&
- channel->metadata_stream == NULL) {
+ channel->type == CONSUMER_CHANNEL_TYPE_DATA) {
notify_channel_pipe(ctx, channel, -1, CONSUMER_CHANNEL_ADD);
}
return ret;
rcu_read_lock();
/* Flag that the current stream if set for network streaming. */
- if (stream->net_seq_idx != -1) {
+ if (stream->net_seq_idx != (uint64_t) -1ULL) {
relayd = consumer_find_relayd(stream->net_seq_idx);
if (relayd == NULL) {
goto end;
rcu_read_lock();
/* Flag that the current stream if set for network streaming. */
- if (stream->net_seq_idx != -1) {
+ if (stream->net_seq_idx != (uint64_t) -1ULL) {
relayd = consumer_find_relayd(stream->net_seq_idx);
if (relayd == NULL) {
goto end;
lttng_poll_del(&events, chan->wait_fd);
ret = lttng_ht_del(channel_ht, &iter);
assert(ret == 0);
- assert(cds_list_empty(&chan->streams.head));
consumer_close_channel_streams(chan);
/* Release our own refcount */
* This will create a relayd socket pair and add it to the relayd hash table.
* The caller MUST acquire a RCU read side lock before calling it.
*/
-int consumer_add_relayd_socket(int net_seq_idx, int sock_type,
+int consumer_add_relayd_socket(uint64_t net_seq_idx, int sock_type,
struct lttng_consumer_local_data *ctx, int sock,
struct pollfd *consumer_sockpoll,
struct lttcomm_relayd_sock *relayd_sock, unsigned int sessiond_id)
assert(ctx);
assert(relayd_sock);
- DBG("Consumer adding relayd socket (idx: %d)", net_seq_idx);
+ DBG("Consumer adding relayd socket (idx: %" PRIu64 ")", net_seq_idx);
/* Get relayd reference if exists. */
relayd = consumer_find_relayd(net_seq_idx);
if (relayd == NULL) {
+ assert(sock_type == LTTNG_STREAM_CONTROL);
/* Not found. Allocate one. */
relayd = consumer_allocate_relayd_sock_pair(net_seq_idx);
if (relayd == NULL) {
- ret_code = LTTCOMM_CONSUMERD_ENOMEM;
ret = -ENOMEM;
+ ret_code = LTTCOMM_CONSUMERD_ENOMEM;
+ goto error;
} else {
relayd->sessiond_session_id = (uint64_t) sessiond_id;
relayd_created = 1;
* we can notify the session daemon and continue our work without
* killing everything.
*/
+ } else {
+ /*
+ * relayd key should never be found for control socket.
+ */
+ assert(sock_type != LTTNG_STREAM_CONTROL);
}
/* First send a status message before receiving the fds. */
- ret = consumer_send_status_msg(sock, ret_code);
- if (ret < 0 || ret_code != LTTNG_OK) {
+ ret = consumer_send_status_msg(sock, LTTNG_OK);
+ if (ret < 0) {
/* Somehow, the session daemon is not responding anymore. */
- goto error;
+ lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_FATAL);
+ goto error_nosignal;
}
/* Poll on consumer socket. */
if (lttng_consumer_poll_socket(consumer_sockpoll) < 0) {
lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_POLL_ERROR);
ret = -EINTR;
- goto error;
+ goto error_nosignal;
}
/* Get relayd socket from session daemon */
ret = lttcomm_recv_fds_unix_sock(sock, &fd, 1);
if (ret != sizeof(fd)) {
- ret_code = LTTCOMM_CONSUMERD_ERROR_RECV_FD;
ret = -1;
fd = -1; /* Just in case it gets set with an invalid value. */
* issue when reaching the fd limit.
*/
lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_ERROR_RECV_FD);
-
- /*
- * This code path MUST continue to the consumer send status message so
- * we can send the error to the thread expecting a reply. The above
- * call will make everything stop.
- */
- }
-
- /* We have the fds without error. Send status back. */
- ret = consumer_send_status_msg(sock, ret_code);
- if (ret < 0 || ret_code != LTTNG_OK) {
- /* Somehow, the session daemon is not responding anymore. */
+ ret_code = LTTCOMM_CONSUMERD_ERROR_RECV_FD;
goto error;
}
/* Copy received lttcomm socket */
lttcomm_copy_sock(&relayd->control_sock.sock, &relayd_sock->sock);
ret = lttcomm_create_sock(&relayd->control_sock.sock);
- /* Immediately try to close the created socket if valid. */
- if (relayd->control_sock.sock.fd >= 0) {
- if (close(relayd->control_sock.sock.fd)) {
- PERROR("close relayd control socket");
- }
- }
/* Handle create_sock error. */
if (ret < 0) {
+ ret_code = LTTCOMM_CONSUMERD_ENOMEM;
goto error;
}
+ /*
+ * Close the socket created internally by
+ * lttcomm_create_sock, so we can replace it by the one
+ * received from sessiond.
+ */
+ if (close(relayd->control_sock.sock.fd)) {
+ PERROR("close");
+ }
/* Assign new file descriptor */
relayd->control_sock.sock.fd = fd;
*/
(void) relayd_close(&relayd->control_sock);
(void) relayd_close(&relayd->data_sock);
+ ret_code = LTTCOMM_CONSUMERD_RELAYD_FAIL;
goto error;
}
/* Copy received lttcomm socket */
lttcomm_copy_sock(&relayd->data_sock.sock, &relayd_sock->sock);
ret = lttcomm_create_sock(&relayd->data_sock.sock);
- /* Immediately try to close the created socket if valid. */
- if (relayd->data_sock.sock.fd >= 0) {
- if (close(relayd->data_sock.sock.fd)) {
- PERROR("close relayd data socket");
- }
- }
/* Handle create_sock error. */
if (ret < 0) {
+ ret_code = LTTCOMM_CONSUMERD_ENOMEM;
goto error;
}
+ /*
+ * Close the socket created internally by
+ * lttcomm_create_sock, so we can replace it by the one
+ * received from sessiond.
+ */
+ if (close(relayd->data_sock.sock.fd)) {
+ PERROR("close");
+ }
/* Assign new file descriptor */
relayd->data_sock.sock.fd = fd;
default:
ERR("Unknown relayd socket type (%d)", sock_type);
ret = -1;
+ ret_code = LTTCOMM_CONSUMERD_FATAL;
goto error;
}
sock_type == LTTNG_STREAM_CONTROL ? "control" : "data",
relayd->net_seq_idx, fd);
+ /* We successfully added the socket. Send status back. */
+ ret = consumer_send_status_msg(sock, ret_code);
+ if (ret < 0) {
+ /* Somehow, the session daemon is not responding anymore. */
+ lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_FATAL);
+ goto error_nosignal;
+ }
+
/*
* Add relayd socket pair to consumer data hashtable. If object already
* exists or on error, the function gracefully returns.
return 0;
error:
+ if (consumer_send_status_msg(sock, ret_code) < 0) {
+ lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_FATAL);
+ }
+
+error_nosignal:
/* Close received socket if valid. */
if (fd >= 0) {
if (close(fd)) {