+ ret = -1;
+ goto end;
+end_msg_sessiond:
+ /*
+ * The returned value here is not useful since either way we'll return 1 to
+ * the caller because the session daemon socket management is done
+ * elsewhere. Returning a negative code or 0 will shutdown the consumer.
+ */
+ ret = consumer_send_status_msg(sock, ret_code);
+ if (ret < 0) {
+ goto error_fatal;
+ }
+ ret = 1;
+end:
+ health_code_update();
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Populate index values of a kernel stream. Values are set in big endian order.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int get_index_values(struct ctf_packet_index *index, int infd)
+{
+ int ret;
+ uint64_t packet_size, content_size, timestamp_begin, timestamp_end,
+ events_discarded, stream_id, stream_instance_id,
+ packet_seq_num;
+
+ ret = kernctl_get_timestamp_begin(infd, ×tamp_begin);
+ if (ret < 0) {
+ PERROR("kernctl_get_timestamp_begin");
+ goto error;
+ }
+
+ ret = kernctl_get_timestamp_end(infd, ×tamp_end);
+ if (ret < 0) {
+ PERROR("kernctl_get_timestamp_end");
+ goto error;
+ }
+
+ ret = kernctl_get_events_discarded(infd, &events_discarded);
+ if (ret < 0) {
+ PERROR("kernctl_get_events_discarded");
+ goto error;
+ }
+
+ ret = kernctl_get_content_size(infd, &content_size);
+ if (ret < 0) {
+ PERROR("kernctl_get_content_size");
+ goto error;
+ }
+
+ ret = kernctl_get_packet_size(infd, &packet_size);
+ if (ret < 0) {
+ PERROR("kernctl_get_packet_size");
+ goto error;
+ }
+
+ ret = kernctl_get_stream_id(infd, &stream_id);
+ if (ret < 0) {
+ PERROR("kernctl_get_stream_id");
+ goto error;
+ }
+
+ ret = kernctl_get_instance_id(infd, &stream_instance_id);
+ if (ret < 0) {
+ if (ret == -ENOTTY) {
+ /* Command not implemented by lttng-modules. */
+ stream_instance_id = -1ULL;
+ } else {
+ PERROR("kernctl_get_instance_id");
+ goto error;
+ }
+ }
+
+ ret = kernctl_get_sequence_number(infd, &packet_seq_num);
+ if (ret < 0) {
+ if (ret == -ENOTTY) {
+ /* Command not implemented by lttng-modules. */
+ packet_seq_num = -1ULL;
+ ret = 0;
+ } else {
+ PERROR("kernctl_get_sequence_number");
+ goto error;
+ }
+ }
+ index->packet_seq_num = htobe64(index->packet_seq_num);
+
+ *index = (typeof(*index)) {
+ .offset = index->offset,
+ .packet_size = htobe64(packet_size),
+ .content_size = htobe64(content_size),
+ .timestamp_begin = htobe64(timestamp_begin),
+ .timestamp_end = htobe64(timestamp_end),
+ .events_discarded = htobe64(events_discarded),
+ .stream_id = htobe64(stream_id),
+ .stream_instance_id = htobe64(stream_instance_id),
+ .packet_seq_num = htobe64(packet_seq_num),
+ };
+
+error:
+ return ret;
+}
+/*
+ * Sync metadata meaning request them to the session daemon and snapshot to the
+ * metadata thread can consumer them.
+ *
+ * Metadata stream lock MUST be acquired.
+ *
+ * Return 0 if new metadatda is available, EAGAIN if the metadata stream
+ * is empty or a negative value on error.
+ */
+int lttng_kconsumer_sync_metadata(struct lttng_consumer_stream *metadata)
+{
+ int ret;
+
+ assert(metadata);
+
+ ret = kernctl_buffer_flush(metadata->wait_fd);
+ if (ret < 0) {
+ ERR("Failed to flush kernel stream");
+ goto end;
+ }
+
+ ret = kernctl_snapshot(metadata->wait_fd);
+ if (ret < 0) {
+ if (ret != -EAGAIN) {
+ ERR("Sync metadata, taking kernel snapshot failed.");
+ goto end;
+ }
+ DBG("Sync metadata, no new kernel metadata");
+ /* No new metadata, exit. */
+ ret = ENODATA;
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+static
+int update_stream_stats(struct lttng_consumer_stream *stream)
+{
+ int ret;
+ uint64_t seq, discarded;
+
+ ret = kernctl_get_sequence_number(stream->wait_fd, &seq);
+ if (ret < 0) {
+ if (ret == -ENOTTY) {
+ /* Command not implemented by lttng-modules. */
+ seq = -1ULL;
+ } else {
+ PERROR("kernctl_get_sequence_number");
+ goto end;
+ }
+ }
+
+ /*
+ * Start the sequence when we extract the first packet in case we don't
+ * start at 0 (for example if a consumer is not connected to the
+ * session immediately after the beginning).
+ */
+ if (stream->last_sequence_number == -1ULL) {
+ stream->last_sequence_number = seq;
+ } else if (seq > stream->last_sequence_number) {
+ stream->chan->lost_packets += seq -
+ stream->last_sequence_number - 1;
+ } else {
+ /* seq <= last_sequence_number */
+ ERR("Sequence number inconsistent : prev = %" PRIu64
+ ", current = %" PRIu64,
+ stream->last_sequence_number, seq);
+ ret = -1;
+ goto end;
+ }
+ stream->last_sequence_number = seq;
+
+ ret = kernctl_get_events_discarded(stream->wait_fd, &discarded);
+ if (ret < 0) {
+ PERROR("kernctl_get_events_discarded");
+ goto end;
+ }
+ if (discarded < stream->last_discarded_events) {
+ /*
+ * Overflow has occurred. We assume only one wrap-around
+ * has occurred.
+ */
+ stream->chan->discarded_events += (1ULL << (CAA_BITS_PER_LONG - 1)) -
+ stream->last_discarded_events + discarded;
+ } else {
+ stream->chan->discarded_events += discarded -
+ stream->last_discarded_events;
+ }
+ stream->last_discarded_events = discarded;
+ ret = 0;
+
+end:
+ return ret;
+}
+
+/*
+ * Check if the local version of the metadata stream matches with the version
+ * of the metadata stream in the kernel. If it was updated, set the reset flag
+ * on the stream.
+ */
+static
+int metadata_stream_check_version(int infd, struct lttng_consumer_stream *stream)
+{
+ int ret;
+ uint64_t cur_version;
+
+ ret = kernctl_get_metadata_version(infd, &cur_version);
+ if (ret < 0) {
+ if (ret == -ENOTTY) {
+ /*
+ * LTTng-modules does not implement this
+ * command.
+ */
+ ret = 0;
+ goto end;
+ }
+ ERR("Failed to get the metadata version");
+ goto end;
+ }
+
+ if (stream->metadata_version == cur_version) {
+ ret = 0;
+ goto end;
+ }
+
+ DBG("New metadata version detected");
+ stream->metadata_version = cur_version;
+ stream->reset_metadata_flag = 1;
+ ret = 0;
+
+end:
+ return ret;