Implement snapshot commands in lttng-sessiond
[lttng-tools.git] / src / common / ust-consumer / ust-consumer.c
index b558988dcf1a2ba4fcf6b6cabdff46c7166bbf25..8ade3b35f272bfd6a0d77eb42094f8e521cbb026 100644 (file)
@@ -38,6 +38,7 @@
 #include <common/compat/fcntl.h>
 #include <common/consumer-metadata-cache.h>
 #include <common/consumer-timer.h>
+#include <common/utils.h>
 
 #include "ust-consumer.h"
 
@@ -184,21 +185,21 @@ error:
 static int send_stream_to_thread(struct lttng_consumer_stream *stream,
                struct lttng_consumer_local_data *ctx)
 {
-       int ret, stream_pipe;
+       int ret;
+       struct lttng_pipe *stream_pipe;
 
        /* Get the right pipe where the stream will be sent. */
        if (stream->metadata_flag) {
-               stream_pipe = ctx->consumer_metadata_pipe[1];
+               stream_pipe = ctx->consumer_metadata_pipe;
        } else {
-               stream_pipe = ctx->consumer_data_pipe[1];
+               stream_pipe = ctx->consumer_data_pipe;
        }
 
-       do {
-               ret = write(stream_pipe, &stream, sizeof(stream));
-       } while (ret < 0 && errno == EINTR);
+       ret = lttng_pipe_write(stream_pipe, &stream, sizeof(stream));
        if (ret < 0) {
-               PERROR("Consumer write %s stream to pipe %d",
-                               stream->metadata_flag ? "metadata" : "data", stream_pipe);
+               ERR("Consumer write %s stream to pipe %d",
+                               stream->metadata_flag ? "metadata" : "data",
+                               lttng_pipe_get_writefd(stream_pipe));
        }
 
        return ret;
@@ -222,7 +223,9 @@ static int send_stream_to_relayd(struct lttng_consumer_stream *stream)
                pthread_mutex_lock(&relayd->ctrl_sock_mutex);
                /* Add stream on the relayd */
                ret = relayd_add_stream(&relayd->control_sock, stream->name,
-                               stream->chan->pathname, &stream->relayd_stream_id);
+                               stream->chan->pathname, &stream->relayd_stream_id,
+                               stream->chan->tracefile_size,
+                               stream->chan->tracefile_count);
                pthread_mutex_unlock(&relayd->ctrl_sock_mutex);
                if (ret < 0) {
                        goto error;
@@ -275,6 +278,12 @@ static int create_ust_streams(struct lttng_consumer_channel *channel,
                 */
                stream->wait_fd = wait_fd;
 
+               /*
+                * Increment channel refcount since the channel reference has now been
+                * assigned in the allocation process above.
+                */
+               uatomic_inc(&stream->chan->refcount);
+
                /*
                 * Order is important this is why a list is used. On error, the caller
                 * should clean this list.
@@ -385,7 +394,7 @@ static int send_sessiond_channel(int sock,
                struct lttng_consumer_channel *channel,
                struct lttng_consumer_local_data *ctx, int *relayd_error)
 {
-       int ret;
+       int ret, ret_code = LTTNG_OK;
        struct lttng_consumer_stream *stream;
 
        assert(channel);
@@ -394,18 +403,6 @@ static int send_sessiond_channel(int sock,
 
        DBG("UST consumer sending channel %s to sessiond", channel->name);
 
-       /* Send channel to sessiond. */
-       ret = ustctl_send_channel_to_sessiond(sock, channel->uchan);
-       if (ret < 0) {
-               goto error;
-       }
-
-       ret = ustctl_channel_close_wakeup_fd(channel->uchan);
-       if (ret < 0) {
-               goto error;
-       }
-
-       /* The channel was sent successfully to the sessiond at this point. */
        cds_list_for_each_entry(stream, &channel->streams.head, send_node) {
                /* Try to send the stream to the relayd if one is available. */
                ret = send_stream_to_relayd(stream);
@@ -417,9 +414,33 @@ static int send_sessiond_channel(int sock,
                        if (relayd_error) {
                                *relayd_error = 1;
                        }
-                       goto error;
+                       ret_code = LTTNG_ERR_RELAYD_CONNECT_FAIL;
                }
+       }
 
+       /* Inform sessiond that we are about to send channel and streams. */
+       ret = consumer_send_status_msg(sock, ret_code);
+       if (ret < 0 || ret_code != LTTNG_OK) {
+               /*
+                * Either the session daemon is not responding or the relayd died so we
+                * stop now.
+                */
+               goto error;
+       }
+
+       /* Send channel to sessiond. */
+       ret = ustctl_send_channel_to_sessiond(sock, channel->uchan);
+       if (ret < 0) {
+               goto error;
+       }
+
+       ret = ustctl_channel_close_wakeup_fd(channel->uchan);
+       if (ret < 0) {
+               goto error;
+       }
+
+       /* The channel was sent successfully to the sessiond at this point. */
+       cds_list_for_each_entry(stream, &channel->streams.head, send_node) {
                /* Send stream to session daemon. */
                ret = send_sessiond_stream(sock, stream);
                if (ret < 0) {
@@ -438,6 +459,9 @@ static int send_sessiond_channel(int sock,
        return 0;
 
 error:
+       if (ret_code != LTTNG_OK) {
+               ret = -1;
+       }
        return ret;
 }
 
@@ -482,10 +506,6 @@ static int ask_channel(struct lttng_consumer_local_data *ctx, int sock,
 
        channel->wait_fd = ustctl_channel_get_wait_fd(channel->uchan);
 
-       if (ret < 0) {
-               goto error;
-       }
-
        /* Open all streams for this channel. */
        ret = create_ust_streams(channel, ctx);
        if (ret < 0) {
@@ -549,11 +569,16 @@ int lttng_ustconsumer_push_metadata(struct lttng_consumer_channel *metadata,
 
        DBG("UST consumer writing metadata to channel %s", metadata->name);
 
+       if (!metadata->metadata_stream) {
+               ret = 0;
+               goto error;
+       }
+
        assert(target_offset <= metadata->metadata_cache->max_offset);
        ret = ustctl_write_metadata_to_channel(metadata->uchan,
                        metadata_str + target_offset, len);
        if (ret < 0) {
-               ERR("ustctl write metadata fail with ret %d, len %ld", ret, len);
+               ERR("ustctl write metadata fail with ret %d, len %" PRIu64, ret, len);
                goto error;
        }
 
@@ -576,11 +601,12 @@ static int flush_channel(uint64_t chan_key)
        struct lttng_ht *ht;
        struct lttng_ht_iter iter;
 
-       DBG("UST consumer flush channel key %lu", chan_key);
+       DBG("UST consumer flush channel key %" PRIu64, chan_key);
 
+       rcu_read_lock();
        channel = consumer_find_channel(chan_key);
        if (!channel) {
-               ERR("UST consumer flush channel %lu not found", chan_key);
+               ERR("UST consumer flush channel %" PRIu64 " not found", chan_key);
                ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
                goto error;
        }
@@ -588,49 +614,64 @@ static int flush_channel(uint64_t chan_key)
        ht = consumer_data.stream_per_chan_id_ht;
 
        /* For each stream of the channel id, flush it. */
-       rcu_read_lock();
        cds_lfht_for_each_entry_duplicate(ht->ht,
                        ht->hash_fct(&channel->key, lttng_ht_seed), ht->match_fct,
                        &channel->key, &iter.iter, stream, node_channel_id.node) {
                        ustctl_flush_buffer(stream->ustream, 1);
        }
-       rcu_read_unlock();
-
 error:
+       rcu_read_unlock();
        return ret;
 }
 
 /*
  * Close metadata stream wakeup_fd using the given key to retrieve the channel.
+ * RCU read side lock MUST be acquired before calling this function.
  *
  * Return 0 on success else an LTTng error code.
  */
 static int close_metadata(uint64_t chan_key)
 {
-       int ret;
+       int ret = 0;
        struct lttng_consumer_channel *channel;
 
-       DBG("UST consumer close metadata key %lu", chan_key);
+       DBG("UST consumer close metadata key %" PRIu64, chan_key);
 
        channel = consumer_find_channel(chan_key);
        if (!channel) {
-               ERR("UST consumer close metadata %lu not found", chan_key);
+               /*
+                * This is possible if the metadata thread has issue a delete because
+                * the endpoint point of the stream hung up. There is no way the
+                * session daemon can know about it thus use a DBG instead of an actual
+                * error.
+                */
+               DBG("UST consumer close metadata %" PRIu64 " not found", chan_key);
                ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
                goto error;
        }
 
-       ret = ustctl_stream_close_wakeup_fd(channel->metadata_stream->ustream);
-       if (ret < 0) {
-               ERR("UST consumer unable to close fd of metadata (ret: %d)", ret);
-               ret = LTTCOMM_CONSUMERD_ERROR_METADATA;
-               goto error;
+       pthread_mutex_lock(&consumer_data.lock);
+
+       if (cds_lfht_is_node_deleted(&channel->node.node)) {
+               goto error_unlock;
        }
+
        if (channel->switch_timer_enabled == 1) {
                DBG("Deleting timer on metadata channel");
                consumer_timer_switch_stop(channel);
        }
-       consumer_metadata_cache_destroy(channel);
 
+       if (channel->metadata_stream) {
+               ret = ustctl_stream_close_wakeup_fd(channel->metadata_stream->ustream);
+               if (ret < 0) {
+                       ERR("UST consumer unable to close fd of metadata (ret: %d)", ret);
+                       ret = LTTCOMM_CONSUMERD_ERROR_METADATA;
+                       goto error_unlock;
+               }
+       }
+
+error_unlock:
+       pthread_mutex_unlock(&consumer_data.lock);
 error:
        return ret;
 }
@@ -645,13 +686,13 @@ static int setup_metadata(struct lttng_consumer_local_data *ctx, uint64_t key)
        int ret;
        struct lttng_consumer_channel *metadata;
 
-       DBG("UST consumer setup metadata key %lu", key);
+       DBG("UST consumer setup metadata key %" PRIu64, key);
 
        metadata = consumer_find_channel(key);
        if (!metadata) {
                ERR("UST consumer push metadata %" PRIu64 " not found", key);
                ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
-               goto error;
+               goto error_find;
        }
 
        /*
@@ -683,9 +724,17 @@ static int setup_metadata(struct lttng_consumer_local_data *ctx, uint64_t key)
        /* List MUST be empty after or else it could be reused. */
        assert(cds_list_empty(&metadata->streams.head));
 
-       ret = 0;
+       return 0;
 
 error:
+       /*
+        * Delete metadata channel on error. At this point, the metadata stream can
+        * NOT be monitored by the metadata thread thus having the guarantee that
+        * the stream is still in the local stream list of the channel. This call
+        * will make sure to clean that list.
+        */
+       consumer_del_channel(metadata);
+error_find:
        return ret;
 }
 
@@ -698,7 +747,7 @@ int lttng_ustconsumer_recv_metadata(int sock, uint64_t key, uint64_t offset,
        int ret, ret_code = LTTNG_OK;
        char *metadata_str;
 
-       DBG("UST consumer push metadata key %lu of len %lu", key, len);
+       DBG("UST consumer push metadata key %" PRIu64 " of len %" PRIu64, key, len);
 
        metadata_str = zmalloc(len * sizeof(char));
        if (!metadata_str) {
@@ -715,13 +764,33 @@ int lttng_ustconsumer_recv_metadata(int sock, uint64_t key, uint64_t offset,
                goto end_free;
        }
 
+       /*
+        * XXX: The consumer data lock is acquired before calling metadata cache
+        * write which calls push metadata that MUST be protected by the consumer
+        * lock in order to be able to check the validity of the metadata stream of
+        * the channel.
+        *
+        * Note that this will be subject to change to better fine grained locking
+        * and ultimately try to get rid of this global consumer data lock.
+        */
+       pthread_mutex_lock(&consumer_data.lock);
+
        pthread_mutex_lock(&channel->metadata_cache->lock);
        ret = consumer_metadata_cache_write(channel, offset, len, metadata_str);
        if (ret < 0) {
                /* Unable to handle metadata. Notify session daemon. */
                ret_code = LTTCOMM_CONSUMERD_ERROR_METADATA;
+               /*
+                * Skip metadata flush on write error since the offset and len might
+                * not have been updated which could create an infinite loop below when
+                * waiting for the metadata cache to be flushed.
+                */
+               pthread_mutex_unlock(&channel->metadata_cache->lock);
+               pthread_mutex_unlock(&consumer_data.lock);
+               goto end_free;
        }
        pthread_mutex_unlock(&channel->metadata_cache->lock);
+       pthread_mutex_unlock(&consumer_data.lock);
 
        while (consumer_metadata_cache_flushed(channel, offset + len)) {
                DBG("Waiting for metadata to be flushed");
@@ -756,6 +825,9 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
                 * The ret value might 0 meaning an orderly shutdown but this is ok
                 * since the caller handles this.
                 */
+               if (ret > 0) {
+                       ret = -1;
+               }
                return ret;
        }
        if (msg.cmd_type == LTTNG_CONSUMER_STOP) {
@@ -831,6 +903,7 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
                                sizeof(is_data_pending));
                if (ret < 0) {
                        DBG("Error when sending the data pending ret code: %d", ret);
+                       goto error_fatal;
                }
 
                /*
@@ -880,6 +953,12 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
                case LTTNG_UST_CHAN_PER_CPU:
                        channel->type = CONSUMER_CHANNEL_TYPE_DATA;
                        attr.type = LTTNG_UST_CHAN_PER_CPU;
+                       /*
+                        * Set refcount to 1 for owner. Below, we will
+                        * pass ownership to the
+                        * consumer_thread_channel_poll() thread.
+                        */
+                       channel->refcount = 1;
                        break;
                case LTTNG_UST_CHAN_METADATA:
                        channel->type = CONSUMER_CHANNEL_TYPE_METADATA;
@@ -895,17 +974,34 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
                        goto end_channel_error;
                }
 
+               if (msg.u.ask_channel.type == LTTNG_UST_CHAN_METADATA) {
+                       ret = consumer_metadata_cache_allocate(channel);
+                       if (ret < 0) {
+                               ERR("Allocating metadata cache");
+                               goto end_channel_error;
+                       }
+                       consumer_timer_switch_start(channel, attr.switch_timer_interval);
+                       attr.switch_timer_interval = 0;
+               }
+
                /*
                 * Add the channel to the internal state AFTER all streams were created
                 * and successfully sent to session daemon. This way, all streams must
                 * be ready before this channel is visible to the threads.
+                * If add_channel succeeds, ownership of the channel is
+                * passed to consumer_thread_channel_poll().
                 */
                ret = add_channel(channel, ctx);
                if (ret < 0) {
+                       if (msg.u.ask_channel.type == LTTNG_UST_CHAN_METADATA) {
+                               if (channel->switch_timer_enabled == 1) {
+                                       consumer_timer_switch_stop(channel);
+                               }
+                               consumer_metadata_cache_destroy(channel);
+                       }
                        goto end_channel_error;
                }
 
-
                /*
                 * Channel and streams are now created. Inform the session daemon that
                 * everything went well and should wait to receive the channel and
@@ -914,20 +1010,9 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
                ret = consumer_send_status_channel(sock, channel);
                if (ret < 0) {
                        /*
-                        * There is probably a problem on the socket so the poll will get
-                        * it and clean everything up.
+                        * There is probably a problem on the socket.
                         */
-                       goto end_nosignal;
-               }
-
-               if (msg.u.ask_channel.type == LTTNG_UST_CHAN_METADATA) {
-                       ret = consumer_metadata_cache_allocate(channel);
-                       if (ret < 0) {
-                               ERR("Allocating metadata cache");
-                               goto end_channel_error;
-                       }
-                       consumer_timer_switch_start(channel, attr.switch_timer_interval);
-                       attr.switch_timer_interval = 0;
+                       goto error_fatal;
                }
 
                break;
@@ -940,18 +1025,11 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
 
                channel = consumer_find_channel(key);
                if (!channel) {
-                       ERR("UST consumer get channel key %lu not found", key);
+                       ERR("UST consumer get channel key %" PRIu64 " not found", key);
                        ret_code = LTTNG_ERR_UST_CHAN_NOT_FOUND;
                        goto end_msg_sessiond;
                }
 
-               /* Inform sessiond that we are about to send channel and streams. */
-               ret = consumer_send_status_msg(sock, LTTNG_OK);
-               if (ret < 0) {
-                       /* Somehow, the session daemon is not responding anymore. */
-                       goto end_nosignal;
-               }
-
                /* Send everything to sessiond. */
                ret = send_sessiond_channel(sock, channel, ctx, &relayd_err);
                if (ret < 0) {
@@ -959,10 +1037,10 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
                                /*
                                 * We were unable to send to the relayd the stream so avoid
                                 * sending back a fatal error to the thread since this is OK
-                                * and the consumer can continue its work.
+                                * and the consumer can continue its work. The above call
+                                * has sent the error status message to the sessiond.
                                 */
-                               ret_code = LTTNG_ERR_RELAYD_CONNECT_FAIL;
-                               goto end_msg_sessiond;
+                               goto end_nosignal;
                        }
                        /*
                         * The communicaton was broken hence there is a bad state between
@@ -987,17 +1065,13 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
        case LTTNG_CONSUMER_DESTROY_CHANNEL:
        {
                uint64_t key = msg.u.destroy_channel.key;
-               struct lttng_consumer_channel *channel;
-
-               channel = consumer_find_channel(key);
-               if (!channel) {
-                       ERR("UST consumer get channel key %lu not found", key);
-                       ret_code = LTTNG_ERR_UST_CHAN_NOT_FOUND;
-                       goto end_msg_sessiond;
-               }
-
-               destroy_channel(channel);
 
+               /*
+                * Only called if streams have not been sent to stream
+                * manager thread. However, channel has been sent to
+                * channel manager thread.
+                */
+               notify_thread_del_channel(ctx, key);
                goto end_msg_sessiond;
        }
        case LTTNG_CONSUMER_CLOSE_METADATA:
@@ -1030,12 +1104,14 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
                uint64_t offset = msg.u.push_metadata.target_offset;
                struct lttng_consumer_channel *channel;
 
-               DBG("UST consumer push metadata key %lu of len %lu", key, len);
+               DBG("UST consumer push metadata key %" PRIu64 " of len %" PRIu64, key,
+                               len);
 
                channel = consumer_find_channel(key);
                if (!channel) {
-                       ERR("UST consumer push metadata %lu not found", key);
+                       ERR("UST consumer push metadata %" PRIu64 " not found", key);
                        ret_code = LTTNG_ERR_UST_CHAN_NOT_FOUND;
+                       goto end_msg_sessiond;
                }
 
                /* Tell session daemon we are ready to receive the metadata. */
@@ -1047,14 +1123,14 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
 
                /* Wait for more data. */
                if (lttng_consumer_poll_socket(consumer_sockpoll) < 0) {
-                       goto end_nosignal;
+                       goto error_fatal;
                }
 
                ret = lttng_ustconsumer_recv_metadata(sock, key, offset,
                                len, channel);
                if (ret < 0) {
                        /* error receiving from sessiond */
-                       goto end_nosignal;
+                       goto error_fatal;
                } else {
                        ret_code = ret;
                        goto end_msg_sessiond;
@@ -1070,6 +1146,15 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
                }
                goto end_msg_sessiond;
        }
+       case LTTNG_CONSUMER_SNAPSHOT_CHANNEL:
+       {
+               ret = consumer_send_status_msg(sock, ret_code);
+               if (ret < 0) {
+                       /* Somehow, the session daemon is not responding anymore. */
+                       goto end_nosignal;
+               }
+               break;
+       }
        default:
                break;
        }
@@ -1089,7 +1174,10 @@ end_msg_sessiond:
         * the caller because the session daemon socket management is done
         * elsewhere. Returning a negative code or 0 will shutdown the consumer.
         */
-       (void) consumer_send_status_msg(sock, ret_code);
+       ret = consumer_send_status_msg(sock, ret_code);
+       if (ret < 0) {
+               goto error_fatal;
+       }
        rcu_read_unlock();
        return 1;
 end_channel_error:
@@ -1184,6 +1272,10 @@ void lttng_ustconsumer_del_channel(struct lttng_consumer_channel *chan)
        assert(chan);
        assert(chan->uchan);
 
+       if (chan->switch_timer_enabled == 1) {
+               consumer_timer_switch_stop(chan);
+       }
+       consumer_metadata_cache_destroy(chan);
        ustctl_destroy_channel(chan->uchan);
 }
 
@@ -1192,6 +1284,9 @@ void lttng_ustconsumer_del_stream(struct lttng_consumer_stream *stream)
        assert(stream);
        assert(stream->ustream);
 
+       if (stream->chan->switch_timer_enabled == 1) {
+               consumer_timer_switch_stop(stream->chan);
+       }
        ustctl_destroy_stream(stream->ustream);
 }
 
@@ -1271,7 +1366,7 @@ int lttng_ustconsumer_read_subbuffer(struct lttng_consumer_stream *stream,
                 * happen and it is OK with the code flow.
                 */
                DBG("Error writing to tracefile "
-                               "(ret: %zd != len: %lu != subbuf_size: %lu)",
+                               "(ret: %ld != len: %lu != subbuf_size: %lu)",
                                ret, len, subbuf_size);
        }
        err = ustctl_put_next_subbuf(ustream);
@@ -1283,10 +1378,28 @@ end:
 
 /*
  * Called when a stream is created.
+ *
+ * Return 0 on success or else a negative value.
  */
 int lttng_ustconsumer_on_recv_stream(struct lttng_consumer_stream *stream)
 {
-       return lttng_create_output_file(stream);
+       int ret;
+
+       /* Don't create anything if this is set for streaming. */
+       if (stream->net_seq_idx == (uint64_t) -1ULL) {
+               ret = utils_create_stream_file(stream->chan->pathname, stream->name,
+                               stream->chan->tracefile_size, stream->tracefile_count_current,
+                               stream->uid, stream->gid);
+               if (ret < 0) {
+                       goto error;
+               }
+               stream->out_fd = ret;
+               stream->tracefile_size_current = 0;
+       }
+       ret = 0;
+
+error:
+       return ret;
 }
 
 /*
@@ -1412,7 +1525,7 @@ int lttng_ustconsumer_request_metadata(struct lttng_consumer_local_data *ctx,
        ret = lttcomm_recv_unix_sock(ctx->consumer_metadata_socket, &msg,
                        sizeof(msg));
        if (ret != sizeof(msg)) {
-               DBG("Consumer received unexpected message size %d (expects %lu)",
+               DBG("Consumer received unexpected message size %d (expects %zu)",
                        ret, sizeof(msg));
                lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_ERROR_RECV_CMD);
                /*
@@ -1456,7 +1569,13 @@ int lttng_ustconsumer_request_metadata(struct lttng_consumer_local_data *ctx,
 
        ret_code = lttng_ustconsumer_recv_metadata(ctx->consumer_metadata_socket,
                        key, offset, len, channel);
-       (void) consumer_send_status_msg(ctx->consumer_metadata_socket, ret_code);
+       if (ret_code >= 0) {
+               /*
+                * Only send the status msg if the sessiond is alive meaning a positive
+                * ret code.
+                */
+               (void) consumer_send_status_msg(ctx->consumer_metadata_socket, ret_code);
+       }
        ret = 0;
 
 end:
This page took 0.032415 seconds and 4 git commands to generate.