Command to regenerate the metadata file when the session is running.
This allows the user to regenerate the metadata after a major NTP
correction and that way update the clock offset from epoch in the
metadata.
Works for kernel and UST per-uid session local or remote (not live).
Signed-off-by: Julien Desfossez <jdesfossez@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
.RE
.PP
+.PP
+\fBmetadata\fP [OPTIONS] ACTION
+.RS
+Metadata command for a LTTng session.
+
+.B OPTIONS:
+
+.TP
+.BR "\-h, \-\-help"
+Show summary of possible options and commands.
+.TP
+.BR "\-\-list-options"
+Simple listing of options
+
+.PP
+.B ACTION:
+
+.TP
+\fBregenerate\fP [-s <NAME>]
+Regenerate the metadata of a session. This allows the user to regenerate the
+metadata after a major NTP correction and that way update the clock offset from
+epoch in the metadata. Only works on kernel, UST per-uid and non-live sessions.
+.RE
+.PP
+
.PP
\fBsave\fP [OPTIONS] [SESSION]
.RS
LTTNG_ERR_PID_NOT_TRACKED = 115, /* PID not tracked */
LTTNG_ERR_INVALID_CHANNEL_DOMAIN = 116, /* Invalid channel domain */
LTTNG_ERR_OVERFLOW = 117, /* Overflow occured. */
+ LTTNG_ERR_SESSION_NOT_STARTED = 118, /* Session not started */
+ LTTNG_ERR_LIVE_SESSION = 119, /* Live session unsupported */
+ LTTNG_ERR_PER_PID_SESSION = 120, /* Per-PID sessions unsupported */
/* MUST be last element */
LTTNG_ERR_NR, /* Last element */
*/
extern int lttng_data_pending(const char *session_name);
+/*
+ * Trigger the regeneration of the metadata for a session.
+ * The new metadata overwrite the previous one locally or remotely (through
+ * the lttng-relayd). Only kernel, per-uid and non-live sessions are supported.
+ * Return 0 on success, a negative LTTng error code on error.
+ */
+extern int lttng_metadata_regenerate(const char *session_name);
+
#ifdef __cplusplus
}
#endif
return ret;
}
+/*
+ * relay_reset_metadata: reset a metadata stream
+ */
+static
+int relay_reset_metadata(struct lttcomm_relayd_hdr *recv_hdr,
+ struct relay_connection *conn)
+{
+ int ret, send_ret;
+ struct relay_session *session = conn->session;
+ struct lttcomm_relayd_reset_metadata stream_info;
+ struct lttcomm_relayd_generic_reply reply;
+ struct relay_stream *stream;
+
+ DBG("Reset metadata received");
+
+ if (!session || conn->version_check_done == 0) {
+ ERR("Trying to reset a metadata stream before version check");
+ ret = -1;
+ goto end_no_session;
+ }
+
+ ret = conn->sock->ops->recvmsg(conn->sock, &stream_info,
+ sizeof(struct lttcomm_relayd_reset_metadata), 0);
+ if (ret < sizeof(struct lttcomm_relayd_reset_metadata)) {
+ if (ret == 0) {
+ /* Orderly shutdown. Not necessary to print an error. */
+ DBG("Socket %d did an orderly shutdown", conn->sock->fd);
+ } else {
+ ERR("Relay didn't receive valid reset_metadata struct "
+ "size : %d", ret);
+ }
+ ret = -1;
+ goto end_no_session;
+ }
+ DBG("Update metadata to version %" PRIu64, be64toh(stream_info.version));
+
+ /* Unsupported for live sessions for now. */
+ if (session->live_timer != 0) {
+ ret = -1;
+ goto end;
+ }
+
+ stream = stream_get_by_id(be64toh(stream_info.stream_id));
+ if (!stream) {
+ ret = -1;
+ goto end;
+ }
+ pthread_mutex_lock(&stream->lock);
+ if (!stream->is_metadata) {
+ ret = -1;
+ goto end_unlock;
+ }
+
+ ret = utils_rotate_stream_file(stream->path_name, stream->channel_name,
+ 0, 0, -1, -1, stream->stream_fd->fd, NULL,
+ &stream->stream_fd->fd);
+ if (ret < 0) {
+ ERR("Failed to rotate metadata file %s of channel %s",
+ stream->path_name, stream->channel_name);
+ goto end_unlock;
+ }
+
+end_unlock:
+ pthread_mutex_unlock(&stream->lock);
+ stream_put(stream);
+
+end:
+ memset(&reply, 0, sizeof(reply));
+ if (ret < 0) {
+ reply.ret_code = htobe32(LTTNG_ERR_UNK);
+ } else {
+ reply.ret_code = htobe32(LTTNG_OK);
+ }
+ send_ret = conn->sock->ops->sendmsg(conn->sock, &reply,
+ sizeof(struct lttcomm_relayd_generic_reply), 0);
+ if (send_ret < 0) {
+ ERR("Relay sending reset metadata reply");
+ ret = send_ret;
+ }
+
+end_no_session:
+ return ret;
+}
+
/*
* relay_unknown_command: send -1 if received unknown command
*/
case RELAYD_STREAMS_SENT:
ret = relay_streams_sent(recv_hdr, conn);
break;
+ case RELAYD_RESET_METADATA:
+ ret = relay_reset_metadata(recv_hdr, conn);
+ break;
case RELAYD_UPDATE_SYNC_INFO:
default:
ERR("Received unknown command (%u)", be32toh(recv_hdr->cmd));
#include <common/relayd/relayd.h>
#include <common/utils.h>
#include <common/compat/string.h>
+#include <common/kernel-ctl/kernel-ctl.h>
#include "channel.h"
#include "consumer.h"
#include "utils.h"
#include "syscall.h"
#include "agent.h"
+#include "buffer-registry.h"
#include "cmd.h"
return ret;
}
+/*
+ * Check if we can regenerate the metadata for this session.
+ * Only kernel, UST per-uid and non-live sessions are supported.
+ *
+ * Return 0 if the metadata can be generated, a LTTNG_ERR code otherwise.
+ */
+static
+int check_metadata_regenerate_support(struct ltt_session *session)
+{
+ int ret;
+
+ assert(session);
+
+ if (session->live_timer != 0) {
+ ret = LTTNG_ERR_LIVE_SESSION;
+ goto end;
+ }
+ if (!session->active) {
+ ret = LTTNG_ERR_SESSION_NOT_STARTED;
+ goto end;
+ }
+ if (session->ust_session) {
+ switch (session->ust_session->buffer_type) {
+ case LTTNG_BUFFER_PER_UID:
+ break;
+ case LTTNG_BUFFER_PER_PID:
+ ret = LTTNG_ERR_PER_PID_SESSION;
+ goto end;
+ default:
+ assert(0);
+ ret = LTTNG_ERR_UNK;
+ goto end;
+ }
+ }
+ if (session->consumer->type == CONSUMER_DST_NET &&
+ session->consumer->relay_minor_version < 8) {
+ ret = LTTNG_ERR_RELAYD_VERSION_FAIL;
+ goto end;
+ }
+ ret = 0;
+
+end:
+ return ret;
+}
+
+static
+int ust_metadata_regenerate(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++;
+ 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_METADATA_REGENERATE from the lttng-ctl library.
+ *
+ * Ask the consumer to truncate the existing metadata file(s) and
+ * then regenerate the metadata. Live and per-pid sessions are not
+ * supported and return an error.
+ *
+ * Return 0 on success or else a LTTNG_ERR code.
+ */
+int cmd_metadata_regenerate(struct ltt_session *session)
+{
+ int ret;
+
+ assert(session);
+
+ ret = check_metadata_regenerate_support(session);
+ if (ret) {
+ goto end;
+ }
+
+ if (session->kernel_session) {
+ ret = kernctl_session_metadata_regenerate(
+ session->kernel_session->fd);
+ if (ret < 0) {
+ ERR("Failed to regenerate the kernel metadata");
+ goto end;
+ }
+ }
+
+ if (session->ust_session) {
+ ret = ust_metadata_regenerate(session->ust_session);
+ if (ret < 0) {
+ ERR("Failed to regenerate the UST metadata");
+ goto end;
+ }
+ }
+ DBG("Cmd metadata regenerate for session %s", session->name);
+ ret = LTTNG_OK;
+
+end:
+ return ret;
+}
+
+
/*
* Send relayd sockets from snapshot output to consumer. Ignore request if the
* snapshot output is *not* set with a remote destination.
int cmd_set_session_shm_path(struct ltt_session *session,
const char *shm_path);
+int cmd_metadata_regenerate(struct ltt_session *session);
#endif /* CMD_H */
*/
int consumer_push_metadata(struct consumer_socket *socket,
uint64_t metadata_key, char *metadata_str, size_t len,
- size_t target_offset)
+ size_t target_offset, uint64_t version)
{
int ret;
struct lttcomm_consumer_msg msg;
msg.u.push_metadata.key = metadata_key;
msg.u.push_metadata.target_offset = target_offset;
msg.u.push_metadata.len = len;
+ msg.u.push_metadata.version = version;
health_code_update();
ret = consumer_send_msg(socket, &msg);
uint64_t metadata_key);
int consumer_push_metadata(struct consumer_socket *socket,
uint64_t metadata_key, char *metadata_str, size_t len,
- size_t target_offset);
+ size_t target_offset, uint64_t version);
int consumer_flush_channel(struct consumer_socket *socket, uint64_t key);
int consumer_get_discarded_events(uint64_t session_id, uint64_t channel_key,
struct consumer_output *consumer, uint64_t *discarded);
case LTTNG_SNAPSHOT_RECORD:
case LTTNG_SAVE_SESSION:
case LTTNG_SET_SESSION_SHM_PATH:
+ case LTTNG_METADATA_REGENERATE:
need_domain = 0;
break;
default:
cmd_ctx->lsm->u.set_shm_path.shm_path);
break;
}
+ case LTTNG_METADATA_REGENERATE:
+ {
+ ret = cmd_metadata_regenerate(cmd_ctx->session);
+ break;
+ }
default:
ret = LTTNG_ERR_UND;
break;
char *metadata_str = NULL;
size_t len, offset, new_metadata_len_sent;
ssize_t ret_val;
- uint64_t metadata_key;
+ uint64_t metadata_key, metadata_version;
assert(registry);
assert(socket);
offset = registry->metadata_len_sent;
len = registry->metadata_len - registry->metadata_len_sent;
new_metadata_len_sent = registry->metadata_len;
+ metadata_version = registry->metadata_version;
if (len == 0) {
DBG3("No metadata to push for metadata key %" PRIu64,
registry->metadata_key);
* different bidirectionnal communication sockets.
*/
ret = consumer_push_metadata(socket, metadata_key,
- metadata_str, len, offset);
+ metadata_str, len, offset, metadata_version);
pthread_mutex_lock(®istry->lock);
if (ret < 0) {
/*
size_t metadata_len, metadata_alloc_len;
/* Length of bytes sent to the consumer. */
size_t metadata_len_sent;
+ /* Current version of the metadata. */
+ uint64_t metadata_version;
char root_shm_path[PATH_MAX];
char shm_path[PATH_MAX];
commands/load.c \
commands/track-untrack.c \
commands/status.c \
+ commands/metadata.c \
utils.c utils.h lttng.c
lttng_LDADD = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la \
DECL_COMMAND(load);
DECL_COMMAND(track);
DECL_COMMAND(untrack);
+DECL_COMMAND(metadata);
#endif /* _LTTNG_CMD_H */
--- /dev/null
+/*
+ * Copyright (C) 2015 - Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _LGPL_SOURCE
+#include <assert.h>
+#include <ctype.h>
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+
+static char *opt_session_name;
+static char *session_name = NULL;
+
+static int metadata_regenerate(int argc, const char **argv);
+
+enum {
+ OPT_HELP = 1,
+ OPT_LIST_OPTIONS,
+ OPT_LIST_COMMANDS,
+};
+
+static struct poptOption long_options[] = {
+ /* { longName, shortName, argInfo, argPtr, value, descrip, argDesc, } */
+ { "help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0, },
+ { "session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
+ { "list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, 0, 0, },
+ { "list-commands", 0, POPT_ARG_NONE, NULL, OPT_LIST_COMMANDS},
+ { 0, 0, 0, 0, 0, 0, 0, },
+};
+
+static struct cmd_struct actions[] = {
+ { "regenerate", metadata_regenerate },
+ { NULL, NULL } /* Array closure */
+};
+
+/*
+ * usage
+ */
+static void usage(FILE *ofp)
+{
+ fprintf(ofp, "usage: lttng metadata [OPTION] ACTION\n");
+ fprintf(ofp, "\n");
+ fprintf(ofp, "Actions:\n");
+ fprintf(ofp, " regenerate\n");
+ fprintf(ofp, " Regenerate and overwrite the metadata of the session.\n");
+ fprintf(ofp, "Options:\n");
+ fprintf(ofp, " -h, --help Show this help.\n");
+ fprintf(ofp, " --list-options Simple listing of options.\n");
+ fprintf(ofp, " -s, --session NAME Apply to session name.\n");
+ fprintf(ofp, "\n");
+}
+
+/*
+ * Count and return the number of arguments in argv.
+ */
+static int count_arguments(const char **argv)
+{
+ int i = 0;
+
+ assert(argv);
+
+ while (argv[i] != NULL) {
+ i++;
+ }
+
+ return i;
+}
+
+static int metadata_regenerate(int argc, const char **argv)
+{
+ int ret;
+
+ ret = lttng_metadata_regenerate(session_name);
+ if (ret == 0) {
+ MSG("Metadata successfully regenerated for session %s", session_name);
+ }
+ return ret;
+}
+
+static int handle_command(const char **argv)
+{
+ struct cmd_struct *cmd;
+ int ret = CMD_SUCCESS, i = 0, argc, command_ret = CMD_SUCCESS;
+
+ if (argv == NULL) {
+ usage(stderr);
+ command_ret = CMD_ERROR;
+ goto end;
+ }
+
+ argc = count_arguments(argv);
+
+ cmd = &actions[i];
+ while (cmd->func != NULL) {
+ /* Find command */
+ if (strcmp(argv[0], cmd->name) == 0) {
+ command_ret = cmd->func(argc, argv);
+ goto end;
+ }
+
+ cmd = &actions[i++];
+ }
+
+ ret = CMD_UNDEFINED;
+
+end:
+ /* Overwrite ret if an error occurred in cmd->func() */
+ ret = command_ret ? command_ret : ret;
+ return ret;
+}
+
+/*
+ * Metadata command handling.
+ */
+int cmd_metadata(int argc, const char **argv)
+{
+ int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
+ static poptContext pc;
+
+ if (argc < 1) {
+ usage(stderr);
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ pc = poptGetContext(NULL, argc, argv, long_options, 0);
+ poptReadDefaultConfig(pc, 0);
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case OPT_HELP:
+ usage(stdout);
+ goto end;
+ case OPT_LIST_OPTIONS:
+ list_cmd_options(stdout, long_options);
+ goto end;
+ case OPT_LIST_COMMANDS:
+ list_commands(actions, stdout);
+ goto end;
+ default:
+ usage(stderr);
+ ret = CMD_UNDEFINED;
+ goto end;
+ }
+ }
+
+ if (!opt_session_name) {
+ session_name = get_session_name();
+ if (session_name == NULL) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+ } else {
+ session_name = opt_session_name;
+ }
+
+ command_ret = handle_command(poptGetArgs(pc));
+ if (command_ret) {
+ switch (-command_ret) {
+ default:
+ ERR("%s", lttng_strerror(command_ret));
+ break;
+ }
+ }
+
+end:
+ if (!opt_session_name) {
+ free(session_name);
+ }
+
+ /* Overwrite ret if an error occurred during handle_command() */
+ ret = command_ret ? command_ret : ret;
+
+ poptFreeContext(pc);
+ return ret;
+}
{ "load", cmd_load},
{ "track", cmd_track},
{ "untrack", cmd_untrack},
+ { "metadata", cmd_metadata},
{ NULL, NULL} /* Array closure */
};
fprintf(ofp, " load Load session configuration\n");
fprintf(ofp, " track Track specific system resources\n");
fprintf(ofp, " untrack Untrack specific system resources\n");
+ fprintf(ofp, " metadata Regenerate the metadata of a session\n");
fprintf(ofp, "\n");
fprintf(ofp, "Each command also has its own -h, --help option.\n");
fprintf(ofp, "\n");
return ret;
}
+/*
+ * Reset the metadata cache.
+ */
+static
+void metadata_cache_reset(struct consumer_metadata_cache *cache)
+{
+ memset(cache->data, 0, cache->cache_alloc_size);
+ cache->max_offset = 0;
+}
+
+/*
+ * Check if the metadata cache version changed.
+ * If it did, reset the metadata cache.
+ * The metadata cache lock MUST be held.
+ *
+ * Returns 0 on success, a negative value on error.
+ */
+static
+int metadata_cache_check_version(struct consumer_metadata_cache *cache,
+ struct lttng_consumer_channel *channel, uint64_t version)
+{
+ int ret = 0;
+
+ if (cache->version == version) {
+ goto end;
+ }
+
+ DBG("Metadata cache version update to %" PRIu64, version);
+ metadata_cache_reset(cache);
+ cache->version = version;
+
+end:
+ return ret;
+}
+
/*
* Write metadata to the cache, extend the cache if necessary. We support
* overlapping updates, but they need to be contiguous. Send the
* Return 0 on success, a negative value on error.
*/
int consumer_metadata_cache_write(struct lttng_consumer_channel *channel,
- unsigned int offset, unsigned int len, char *data)
+ unsigned int offset, unsigned int len, uint64_t version,
+ char *data)
{
int ret = 0;
int size_ret;
assert(channel->metadata_cache);
cache = channel->metadata_cache;
+
+ ret = metadata_cache_check_version(cache, channel, version);
+ if (ret < 0) {
+ goto end;
+ }
+
DBG("Writing %u bytes from offset %u in metadata cache", len, offset);
if (offset + len > cache->cache_alloc_size) {
struct consumer_metadata_cache {
char *data;
uint64_t cache_alloc_size;
+ /*
+ * Current version of the metadata cache.
+ */
+ uint64_t version;
/*
* The upper-limit of data written inside the buffer.
*
};
int consumer_metadata_cache_write(struct lttng_consumer_channel *channel,
- unsigned int offset, unsigned int len, char *data);
+ unsigned int offset, unsigned int len, uint64_t version,
+ char *data);
int consumer_metadata_cache_allocate(struct lttng_consumer_channel *channel);
void consumer_metadata_cache_destroy(struct lttng_consumer_channel *channel);
int consumer_metadata_cache_flushed(struct lttng_consumer_channel *channel,
if (stream->metadata_flag) {
/* Metadata requires the control socket. */
pthread_mutex_lock(&relayd->ctrl_sock_mutex);
+ if (stream->reset_metadata_flag) {
+ ret = relayd_reset_metadata(&relayd->control_sock,
+ stream->relayd_stream_id,
+ stream->metadata_version);
+ if (ret < 0) {
+ relayd_hang_up = 1;
+ goto write_error;
+ }
+ stream->reset_metadata_flag = 0;
+ }
netlen += sizeof(struct lttcomm_relayd_metadata_payload);
}
/* No streaming, we have to set the len with the full padding */
len += padding;
+ if (stream->metadata_flag && stream->reset_metadata_flag) {
+ ret = utils_truncate_stream_file(stream->out_fd, 0);
+ if (ret < 0) {
+ ERR("Reset metadata file");
+ goto end;
+ }
+ stream->reset_metadata_flag = 0;
+ }
+
/*
* Check if we need to change the tracefile before writing the packet.
*/
*/
pthread_mutex_lock(&relayd->ctrl_sock_mutex);
+ if (stream->reset_metadata_flag) {
+ ret = relayd_reset_metadata(&relayd->control_sock,
+ stream->relayd_stream_id,
+ stream->metadata_version);
+ if (ret < 0) {
+ relayd_hang_up = 1;
+ goto write_error;
+ }
+ stream->reset_metadata_flag = 0;
+ }
ret = write_relayd_metadata_id(splice_pipe[1], stream, relayd,
padding);
if (ret < 0) {
/* No streaming, we have to set the len with the full padding */
len += padding;
+ if (stream->metadata_flag && stream->reset_metadata_flag) {
+ ret = utils_truncate_stream_file(stream->out_fd, 0);
+ if (ret < 0) {
+ ERR("Reset metadata file");
+ goto end;
+ }
+ stream->reset_metadata_flag = 0;
+ }
/*
* Check if we need to change the tracefile before writing the packet.
*/
/* Identify if the stream is the metadata */
unsigned int metadata_flag;
+ /*
+ * Last known metadata version, reset the metadata file in case
+ * of change.
+ */
+ uint64_t metadata_version;
/* Used when the stream is set for network streaming */
uint64_t relayd_stream_id;
/*
/* Indicate if the stream still has some data to be read. */
unsigned int has_data:1;
+ /*
+ * Inform the consumer or relay to reset the metadata
+ * file before writing in it (regeneration).
+ */
+ unsigned int reset_metadata_flag:1;
};
/*
[ ERROR_INDEX(LTTNG_ERR_PID_NOT_TRACKED) ] = "PID not tracked",
[ ERROR_INDEX(LTTNG_ERR_INVALID_CHANNEL_DOMAIN) ] = "Invalid channel domain",
[ ERROR_INDEX(LTTNG_ERR_OVERFLOW) ] = "Overflow occured",
+ [ ERROR_INDEX(LTTNG_ERR_SESSION_NOT_STARTED) ] = "Session not started",
+ [ ERROR_INDEX(LTTNG_ERR_LIVE_SESSION) ] = "Live sessions are not supported",
+ [ ERROR_INDEX(LTTNG_ERR_PER_PID_SESSION) ] = "Per-PID tracing sessions are not supported",
/* Last element */
[ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code"
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) {
+ 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;
+}
+
/*
* Consume data on a file descriptor and write it on a trace file.
*/
}
} else {
write_index = 0;
+ ret = metadata_stream_check_version(infd, stream);
+ if (ret < 0) {
+ goto end;
+ }
}
switch (stream->chan->output) {
return ioctl(fd, LTTNG_KERNEL_SESSION_LIST_TRACKER_PIDS);
}
+int kernctl_session_metadata_regenerate(int fd)
+{
+ return ioctl(fd, LTTNG_KERNEL_SESSION_METADATA_REGEN);
+}
+
int kernctl_create_stream(int fd)
{
return compat_ioctl_no_arg(fd, LTTNG_KERNEL_OLD_STREAM,
return ioctl(fd, RING_BUFFER_FLUSH);
}
+/* returns the version of the metadata. */
+int kernctl_get_metadata_version(int fd, uint64_t *version)
+{
+ return ioctl(fd, RING_BUFFER_GET_METADATA_VERSION, version);
+}
+
/* Buffer operations */
int kernctl_untrack_pid(int fd, int pid);
int kernctl_list_tracker_pids(int fd);
+int kernctl_session_metadata_regenerate(int fd);
+
/* Buffer operations */
/* For mmap mode, readable without "get" operation */
int kernctl_put_subbuf(int fd);
int kernctl_buffer_flush(int fd);
+int kernctl_get_metadata_version(int fd, uint64_t *version);
/* index */
int kernctl_get_timestamp_begin(int fd, uint64_t *timestamp_begin);
#define RING_BUFFER_GET_MMAP_READ_OFFSET _IOR(0xF6, 0x0B, unsigned long)
/* flush the current sub-buffer */
#define RING_BUFFER_FLUSH _IO(0xF6, 0x0C)
+/* Get the current version of the metadata cache (after a get_next). */
+#define RING_BUFFER_GET_METADATA_VERSION _IOR(0xF6, 0x0D, uint64_t)
/* returns the timestamp begin of the current sub-buffer */
#define LTTNG_RING_BUFFER_GET_TIMESTAMP_BEGIN _IOR(0xF6, 0x20, uint64_t)
#define LTTNG_KERNEL_SESSION_UNTRACK_PID \
_IOR(0xF6, 0x59, int32_t)
#define LTTNG_KERNEL_SESSION_LIST_TRACKER_PIDS _IO(0xF6, 0x58)
+#define LTTNG_KERNEL_SESSION_METADATA_REGEN _IO(0xF6, 0x59)
/* Channel FD ioctl */
#define LTTNG_KERNEL_STREAM _IO(0xF6, 0x62)
error:
return ret;
}
+
+/*
+ * Ask the relay to reset the metadata trace file (regeneration).
+ */
+int relayd_reset_metadata(struct lttcomm_relayd_sock *rsock,
+ uint64_t stream_id, uint64_t version)
+{
+ int ret;
+ struct lttcomm_relayd_reset_metadata msg;
+ struct lttcomm_relayd_generic_reply reply;
+
+ /* Code flow error. Safety net. */
+ assert(rsock);
+
+ /* Should have been prevented by the sessiond. */
+ if (rsock->minor < 8) {
+ ERR("Metadata regeneration unsupported before 2.8");
+ ret = -1;
+ goto error;
+ }
+
+ DBG("Relayd reset metadata stream id %" PRIu64, stream_id);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.stream_id = htobe64(stream_id);
+ msg.version = htobe64(version);
+
+ /* Send command */
+ ret = send_command(rsock, RELAYD_RESET_METADATA, (void *) &msg, sizeof(msg), 0);
+ if (ret < 0) {
+ goto error;
+ }
+
+ /* Receive response */
+ ret = recv_reply(rsock, (void *) &reply, sizeof(reply));
+ if (ret < 0) {
+ goto error;
+ }
+
+ reply.ret_code = be32toh(reply.ret_code);
+
+ /* Return session id or negative ret code. */
+ if (reply.ret_code != LTTNG_OK) {
+ ret = -1;
+ ERR("Relayd reset metadata replied error %d", reply.ret_code);
+ } else {
+ /* Success */
+ ret = 0;
+ }
+
+ DBG("Relayd reset metadata stream id %" PRIu64 " successfully", stream_id);
+
+error:
+ return ret;
+}
int relayd_send_index(struct lttcomm_relayd_sock *rsock,
struct ctf_packet_index *index, uint64_t relay_stream_id,
uint64_t net_seq_num);
+int relayd_reset_metadata(struct lttcomm_relayd_sock *rsock,
+ uint64_t stream_id, uint64_t version);
#endif /* _RELAYD_H */
uint32_t snapshot;
} LTTNG_PACKED;
+/*
+ * Used to ask the relay to reset the metadata trace file (regeneration).
+ * Send the new version of the metadata (starts at 0).
+ */
+struct lttcomm_relayd_reset_metadata {
+ uint64_t stream_id;
+ uint64_t version;
+} LTTNG_PACKED;
+
#endif /* _RELAYD_COMM */
LTTNG_UNTRACK_PID = 33,
LTTNG_LIST_TRACKER_PIDS = 34,
LTTNG_SET_SESSION_SHM_PATH = 40,
+ LTTNG_METADATA_REGENERATE = 41,
};
enum lttcomm_relayd_command {
RELAYD_LIST_SESSIONS = 15,
/* All streams of the channel have been sent to the relayd (2.4+). */
RELAYD_STREAMS_SENT = 16,
+ /* Ask the relay to reset the metadata trace file (2.8+) */
+ RELAYD_RESET_METADATA = 17,
};
/*
uint64_t key; /* Metadata channel key. */
uint64_t target_offset; /* Offset in the consumer */
uint64_t len; /* Length of metadata to be received. */
+ uint64_t version; /* Version of the metadata. */
} LTTNG_PACKED push_metadata;
struct {
uint64_t key; /* Metadata channel key. */
uint64_t session_id;
uint64_t channel_key;
} LTTNG_PACKED lost_packets;
+ struct {
+ uint64_t session_id;
+ } LTTNG_PACKED metadata_regenerate;
} u;
} LTTNG_PACKED;
* complete.
*/
int lttng_ustconsumer_recv_metadata(int sock, uint64_t key, uint64_t offset,
- uint64_t len, struct lttng_consumer_channel *channel,
- int timer, int wait)
+ uint64_t len, uint64_t version,
+ struct lttng_consumer_channel *channel, int timer, int wait)
{
int ret, ret_code = LTTCOMM_CONSUMERD_SUCCESS;
char *metadata_str;
health_code_update();
pthread_mutex_lock(&channel->metadata_cache->lock);
- ret = consumer_metadata_cache_write(channel, offset, len, metadata_str);
+ ret = consumer_metadata_cache_write(channel, offset, len, version,
+ metadata_str);
if (ret < 0) {
/* Unable to handle metadata. Notify session daemon. */
ret_code = LTTCOMM_CONSUMERD_ERROR_METADATA;
uint64_t len = msg.u.push_metadata.len;
uint64_t key = msg.u.push_metadata.key;
uint64_t offset = msg.u.push_metadata.target_offset;
+ uint64_t version = msg.u.push_metadata.version;
struct lttng_consumer_channel *channel;
DBG("UST consumer push metadata key %" PRIu64 " of len %" PRIu64, key,
health_code_update();
ret = lttng_ustconsumer_recv_metadata(sock, key, offset,
- len, channel, 0, 1);
+ len, version, channel, 0, 1);
if (ret < 0) {
/* error receiving from sessiond */
goto error_fatal;
return ret;
}
+static
+void metadata_stream_reset_cache(struct lttng_consumer_stream *stream,
+ struct consumer_metadata_cache *cache)
+{
+ DBG("Metadata stream update to version %" PRIu64,
+ cache->version);
+ stream->ust_metadata_pushed = 0;
+ stream->metadata_version = cache->version;
+ stream->reset_metadata_flag = 1;
+}
+
+/*
+ * Check if the version of the metadata stream and metadata cache match.
+ * If the cache got updated, reset the metadata stream.
+ * The stream lock and metadata cache lock MUST be held.
+ * Return 0 on success, a negative value on error.
+ */
+static
+int metadata_stream_check_version(struct lttng_consumer_stream *stream)
+{
+ int ret = 0;
+ struct consumer_metadata_cache *cache = stream->chan->metadata_cache;
+
+ if (cache->version == stream->metadata_version) {
+ goto end;
+ }
+ metadata_stream_reset_cache(stream, cache);
+
+end:
+ return ret;
+}
+
/*
* Write up to one packet from the metadata cache to the channel.
*
int ret;
pthread_mutex_lock(&stream->chan->metadata_cache->lock);
+ ret = metadata_stream_check_version(stream);
+ if (ret < 0) {
+ goto end;
+ }
if (stream->chan->metadata_cache->max_offset
== stream->ust_metadata_pushed) {
ret = 0;
struct lttcomm_metadata_request_msg request;
struct lttcomm_consumer_msg msg;
enum lttcomm_return_code ret_code = LTTCOMM_CONSUMERD_SUCCESS;
- uint64_t len, key, offset;
+ uint64_t len, key, offset, version;
int ret;
assert(channel);
len = msg.u.push_metadata.len;
key = msg.u.push_metadata.key;
offset = msg.u.push_metadata.target_offset;
+ version = msg.u.push_metadata.version;
assert(key == channel->key);
if (len == 0) {
health_code_update();
ret = lttng_ustconsumer_recv_metadata(ctx->consumer_metadata_socket,
- key, offset, len, channel, timer, wait);
+ key, offset, len, version, channel, timer, wait);
if (ret >= 0) {
/*
* Only send the status msg if the sessiond is alive meaning a positive
void lttng_ustconsumer_close_metadata(struct lttng_consumer_channel *metadata);
void lttng_ustconsumer_close_stream_wakeup(struct lttng_consumer_stream *stream);
int lttng_ustconsumer_recv_metadata(int sock, uint64_t key, uint64_t offset,
- uint64_t len, struct lttng_consumer_channel *channel,
- int timer, int wait);
+ uint64_t len, uint64_t version,
+ struct lttng_consumer_channel *channel, int timer, int wait);
int lttng_ustconsumer_request_metadata(struct lttng_consumer_local_data *ctx,
struct lttng_consumer_channel *channel, int timer, int wait);
int lttng_ustconsumer_sync_metadata(struct lttng_consumer_local_data *ctx,
}
static inline
int lttng_ustconsumer_recv_metadata(int sock, uint64_t key, uint64_t offset,
- uint64_t len, struct lttng_consumer_channel *channel,
- int timer)
+ uint64_t len, uint64_t version,
+ struct lttng_consumer_channel *channel, int timer)
{
return -ENOSYS;
}
{
int ret;
- assert(new_count);
assert(stream_fd);
ret = close(out_fd);
* Unlinking the old file rather than overwriting it
* achieves this.
*/
- *new_count = (*new_count + 1) % count;
- ret = utils_unlink_stream_file(path_name, file_name,
- size, *new_count, uid, gid, 0);
+ if (new_count) {
+ *new_count = (*new_count + 1) % count;
+ }
+ ret = utils_unlink_stream_file(path_name, file_name, size,
+ new_count ? *new_count : 0, uid, gid, 0);
if (ret < 0 && errno != ENOENT) {
goto error;
}
} else {
- (*new_count)++;
+ if (new_count) {
+ (*new_count)++;
+ }
}
- ret = utils_create_stream_file(path_name, file_name, size, *new_count,
- uid, gid, 0);
+ ret = utils_create_stream_file(path_name, file_name, size,
+ new_count ? *new_count : 0, uid, gid, 0);
if (ret < 0) {
goto error;
}
}
return ret;
}
+
+LTTNG_HIDDEN
+int utils_truncate_stream_file(int fd, off_t length)
+{
+ int ret;
+
+ ret = ftruncate(fd, length);
+ if (ret < 0) {
+ PERROR("ftruncate");
+ goto end;
+ }
+ ret = lseek(fd, length, SEEK_SET);
+ if (ret < 0) {
+ PERROR("lseek");
+ goto end;
+ }
+
+end:
+ return ret;
+}
size_t opt_count);
int utils_create_lock_file(const char *filepath);
int utils_recursive_rmdir(const char *path);
+int utils_truncate_stream_file(int fd, off_t length);
#endif /* _COMMON_UTILS_H */
return 0;
}
+/*
+ * Regenerate the metadata for a session.
+ * Return 0 on success, a negative error code on error.
+ */
+int lttng_metadata_regenerate(const char *session_name)
+{
+ int ret;
+ struct lttcomm_session_msg lsm;
+
+ if (!session_name) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_METADATA_REGENERATE;
+
+ lttng_ctl_copy_string(lsm.session.name, session_name,
+ sizeof(lsm.session.name));
+
+ ret = lttng_ctl_ask_sessiond(&lsm, NULL);
+ if (ret < 0) {
+ goto end;
+ }
+
+ ret = 0;
+end:
+ return ret;
+}
+
/*
* lib constructor.
*/