From 93ec662e687dc15a3601704a1e0c96c51ad228c9 Mon Sep 17 00:00:00 2001 From: Julien Desfossez Date: Fri, 7 Aug 2015 16:06:49 -0400 Subject: [PATCH] Command metadata regenerate MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Jérémie Galarneau --- doc/man/lttng.1 | 25 +++ include/lttng/lttng-error.h | 3 + include/lttng/lttng.h | 8 + src/bin/lttng-relayd/main.c | 87 ++++++++ src/bin/lttng-sessiond/cmd.c | 152 ++++++++++++++ src/bin/lttng-sessiond/cmd.h | 1 + src/bin/lttng-sessiond/consumer.c | 3 +- src/bin/lttng-sessiond/consumer.h | 2 +- src/bin/lttng-sessiond/main.c | 6 + src/bin/lttng-sessiond/ust-app.c | 5 +- src/bin/lttng-sessiond/ust-registry.h | 2 + src/bin/lttng/Makefile.am | 1 + src/bin/lttng/command.h | 1 + src/bin/lttng/commands/metadata.c | 196 ++++++++++++++++++ src/bin/lttng/lttng.c | 2 + src/common/consumer/consumer-metadata-cache.c | 44 +++- src/common/consumer/consumer-metadata-cache.h | 7 +- src/common/consumer/consumer.c | 37 ++++ src/common/consumer/consumer.h | 10 + src/common/error.c | 3 + src/common/kernel-consumer/kernel-consumer.c | 35 ++++ src/common/kernel-ctl/kernel-ctl.c | 11 + src/common/kernel-ctl/kernel-ctl.h | 3 + src/common/kernel-ctl/kernel-ioctl.h | 3 + src/common/relayd/relayd.c | 55 +++++ src/common/relayd/relayd.h | 2 + src/common/sessiond-comm/relayd.h | 9 + src/common/sessiond-comm/sessiond-comm.h | 7 + src/common/ust-consumer/ust-consumer.c | 51 ++++- src/common/ust-consumer/ust-consumer.h | 8 +- src/common/utils.c | 37 +++- src/common/utils.h | 1 + src/lib/lttng-ctl/lttng-ctl.c | 30 +++ 33 files changed, 824 insertions(+), 23 deletions(-) create mode 100644 src/bin/lttng/commands/metadata.c diff --git a/doc/man/lttng.1 b/doc/man/lttng.1 index 7aef3d57a..bd2776114 100644 --- a/doc/man/lttng.1 +++ b/doc/man/lttng.1 @@ -848,6 +848,31 @@ already exists. .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 ] +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 diff --git a/include/lttng/lttng-error.h b/include/lttng/lttng-error.h index 1030bdfc3..b55d9478c 100644 --- a/include/lttng/lttng-error.h +++ b/include/lttng/lttng-error.h @@ -138,6 +138,9 @@ enum lttng_error_code { 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 */ diff --git a/include/lttng/lttng.h b/include/lttng/lttng.h index c5be66128..2088864d2 100644 --- a/include/lttng/lttng.h +++ b/include/lttng/lttng.h @@ -159,6 +159,14 @@ extern int lttng_set_consumer_url(struct lttng_handle *handle, */ 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 diff --git a/src/bin/lttng-relayd/main.c b/src/bin/lttng-relayd/main.c index e4ded2b86..cc5009940 100644 --- a/src/bin/lttng-relayd/main.c +++ b/src/bin/lttng-relayd/main.c @@ -1330,6 +1330,90 @@ end_no_session: 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 */ @@ -2060,6 +2144,9 @@ static int relay_process_control(struct lttcomm_relayd_hdr *recv_hdr, 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)); diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index 1ee0c98f9..9af6d9d4a 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "channel.h" #include "consumer.h" @@ -39,6 +40,7 @@ #include "utils.h" #include "syscall.h" #include "agent.h" +#include "buffer-registry.h" #include "cmd.h" @@ -3372,6 +3374,156 @@ error: 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. diff --git a/src/bin/lttng-sessiond/cmd.h b/src/bin/lttng-sessiond/cmd.h index e9c9054ea..a220e3a45 100644 --- a/src/bin/lttng-sessiond/cmd.h +++ b/src/bin/lttng-sessiond/cmd.h @@ -110,5 +110,6 @@ int cmd_snapshot_record(struct ltt_session *session, 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 */ diff --git a/src/bin/lttng-sessiond/consumer.c b/src/bin/lttng-sessiond/consumer.c index 395657066..bd019dd31 100644 --- a/src/bin/lttng-sessiond/consumer.c +++ b/src/bin/lttng-sessiond/consumer.c @@ -1259,7 +1259,7 @@ end: */ 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; @@ -1275,6 +1275,7 @@ int consumer_push_metadata(struct consumer_socket *socket, 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); diff --git a/src/bin/lttng-sessiond/consumer.h b/src/bin/lttng-sessiond/consumer.h index 18d989809..75a40f8ae 100644 --- a/src/bin/lttng-sessiond/consumer.h +++ b/src/bin/lttng-sessiond/consumer.h @@ -282,7 +282,7 @@ int consumer_setup_metadata(struct consumer_socket *socket, 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); diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index dbd99cc63..65f598b60 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -3039,6 +3039,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_SNAPSHOT_RECORD: case LTTNG_SAVE_SESSION: case LTTNG_SET_SESSION_SHM_PATH: + case LTTNG_METADATA_REGENERATE: need_domain = 0; break; default: @@ -4143,6 +4144,11 @@ error_add_context: 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; diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c index 9b634facc..9a766e4ab 100644 --- a/src/bin/lttng-sessiond/ust-app.c +++ b/src/bin/lttng-sessiond/ust-app.c @@ -551,7 +551,7 @@ ssize_t ust_app_push_metadata(struct ust_registry_session *registry, 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); @@ -581,6 +581,7 @@ ssize_t ust_app_push_metadata(struct ust_registry_session *registry, 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); @@ -617,7 +618,7 @@ push_data: * 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) { /* diff --git a/src/bin/lttng-sessiond/ust-registry.h b/src/bin/lttng-sessiond/ust-registry.h index 77b9a8666..34db29ea1 100644 --- a/src/bin/lttng-sessiond/ust-registry.h +++ b/src/bin/lttng-sessiond/ust-registry.h @@ -68,6 +68,8 @@ struct ust_registry_session { 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]; diff --git a/src/bin/lttng/Makefile.am b/src/bin/lttng/Makefile.am index 7cf329ee2..93a563ff5 100644 --- a/src/bin/lttng/Makefile.am +++ b/src/bin/lttng/Makefile.am @@ -17,6 +17,7 @@ lttng_SOURCES = command.h conf.c conf.h commands/start.c \ 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 \ diff --git a/src/bin/lttng/command.h b/src/bin/lttng/command.h index fc6f01c1c..451e30f79 100644 --- a/src/bin/lttng/command.h +++ b/src/bin/lttng/command.h @@ -64,5 +64,6 @@ DECL_COMMAND(save); DECL_COMMAND(load); DECL_COMMAND(track); DECL_COMMAND(untrack); +DECL_COMMAND(metadata); #endif /* _LTTNG_CMD_H */ diff --git a/src/bin/lttng/commands/metadata.c b/src/bin/lttng/commands/metadata.c new file mode 100644 index 000000000..20c577e53 --- /dev/null +++ b/src/bin/lttng/commands/metadata.c @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2015 - Julien Desfossez + * + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#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; +} diff --git a/src/bin/lttng/lttng.c b/src/bin/lttng/lttng.c index d4dbe2697..86f5b0c24 100644 --- a/src/bin/lttng/lttng.c +++ b/src/bin/lttng/lttng.c @@ -84,6 +84,7 @@ static struct cmd_struct commands[] = { { "load", cmd_load}, { "track", cmd_track}, { "untrack", cmd_untrack}, + { "metadata", cmd_metadata}, { NULL, NULL} /* Array closure */ }; @@ -128,6 +129,7 @@ static void usage(FILE *ofp) 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"); diff --git a/src/common/consumer/consumer-metadata-cache.c b/src/common/consumer/consumer-metadata-cache.c index 48257c299..3211ec1e8 100644 --- a/src/common/consumer/consumer-metadata-cache.c +++ b/src/common/consumer/consumer-metadata-cache.c @@ -70,6 +70,41 @@ end: 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 @@ -79,7 +114,8 @@ end: * 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; @@ -89,6 +125,12 @@ int consumer_metadata_cache_write(struct lttng_consumer_channel *channel, 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) { diff --git a/src/common/consumer/consumer-metadata-cache.h b/src/common/consumer/consumer-metadata-cache.h index 8ce7f30b1..7dcf6976f 100644 --- a/src/common/consumer/consumer-metadata-cache.h +++ b/src/common/consumer/consumer-metadata-cache.h @@ -24,6 +24,10 @@ 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. * @@ -42,7 +46,8 @@ struct consumer_metadata_cache { }; 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, diff --git a/src/common/consumer/consumer.c b/src/common/consumer/consumer.c index 7911a5b4e..d57271c3a 100644 --- a/src/common/consumer/consumer.c +++ b/src/common/consumer/consumer.c @@ -1556,6 +1556,16 @@ ssize_t lttng_consumer_on_read_subbuffer_mmap( 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); } @@ -1579,6 +1589,15 @@ ssize_t lttng_consumer_on_read_subbuffer_mmap( /* 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. */ @@ -1744,6 +1763,16 @@ ssize_t lttng_consumer_on_read_subbuffer_splice( */ 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) { @@ -1767,6 +1796,14 @@ ssize_t lttng_consumer_on_read_subbuffer_splice( /* 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. */ diff --git a/src/common/consumer/consumer.h b/src/common/consumer/consumer.h index 3af7db913..59764e105 100644 --- a/src/common/consumer/consumer.h +++ b/src/common/consumer/consumer.h @@ -292,6 +292,11 @@ struct lttng_consumer_stream { /* 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; /* @@ -382,6 +387,11 @@ struct lttng_consumer_stream { /* 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; }; /* diff --git a/src/common/error.c b/src/common/error.c index c3fde51d4..9232894ff 100644 --- a/src/common/error.c +++ b/src/common/error.c @@ -170,6 +170,9 @@ static const char *error_string_array[] = { [ 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" diff --git a/src/common/kernel-consumer/kernel-consumer.c b/src/common/kernel-consumer/kernel-consumer.c index e5c0c2e83..9e3540426 100644 --- a/src/common/kernel-consumer/kernel-consumer.c +++ b/src/common/kernel-consumer/kernel-consumer.c @@ -1202,6 +1202,37 @@ 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) { + 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. */ @@ -1272,6 +1303,10 @@ ssize_t lttng_kconsumer_read_subbuffer(struct lttng_consumer_stream *stream, } } else { write_index = 0; + ret = metadata_stream_check_version(infd, stream); + if (ret < 0) { + goto end; + } } switch (stream->chan->output) { diff --git a/src/common/kernel-ctl/kernel-ctl.c b/src/common/kernel-ctl/kernel-ctl.c index dd228773b..1ddf4e81d 100644 --- a/src/common/kernel-ctl/kernel-ctl.c +++ b/src/common/kernel-ctl/kernel-ctl.c @@ -209,6 +209,11 @@ int kernctl_list_tracker_pids(int fd) 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, @@ -406,6 +411,12 @@ int kernctl_buffer_flush(int fd) 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 */ diff --git a/src/common/kernel-ctl/kernel-ctl.h b/src/common/kernel-ctl/kernel-ctl.h index 929488841..6736937d0 100644 --- a/src/common/kernel-ctl/kernel-ctl.h +++ b/src/common/kernel-ctl/kernel-ctl.h @@ -65,6 +65,8 @@ int kernctl_track_pid(int fd, int pid); 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 */ @@ -90,6 +92,7 @@ int kernctl_get_subbuf(int fd, unsigned long *pos); 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); diff --git a/src/common/kernel-ctl/kernel-ioctl.h b/src/common/kernel-ctl/kernel-ioctl.h index b37605bb1..f5e866b88 100644 --- a/src/common/kernel-ctl/kernel-ioctl.h +++ b/src/common/kernel-ctl/kernel-ioctl.h @@ -49,6 +49,8 @@ #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) @@ -126,6 +128,7 @@ #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) diff --git a/src/common/relayd/relayd.c b/src/common/relayd/relayd.c index 60b7ee849..acf6c38e7 100644 --- a/src/common/relayd/relayd.c +++ b/src/common/relayd/relayd.c @@ -882,3 +882,58 @@ int relayd_send_index(struct lttcomm_relayd_sock *rsock, 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; +} diff --git a/src/common/relayd/relayd.h b/src/common/relayd/relayd.h index 9890efb87..f090a0db6 100644 --- a/src/common/relayd/relayd.h +++ b/src/common/relayd/relayd.h @@ -49,5 +49,7 @@ int relayd_end_data_pending(struct lttcomm_relayd_sock *sock, uint64_t id, 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 */ diff --git a/src/common/sessiond-comm/relayd.h b/src/common/sessiond-comm/relayd.h index 358123273..1fc48c442 100644 --- a/src/common/sessiond-comm/relayd.h +++ b/src/common/sessiond-comm/relayd.h @@ -173,4 +173,13 @@ struct lttcomm_relayd_create_session_2_4 { 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 */ diff --git a/src/common/sessiond-comm/sessiond-comm.h b/src/common/sessiond-comm/sessiond-comm.h index a60fc4506..344ba508d 100644 --- a/src/common/sessiond-comm/sessiond-comm.h +++ b/src/common/sessiond-comm/sessiond-comm.h @@ -94,6 +94,7 @@ enum lttcomm_sessiond_command { LTTNG_UNTRACK_PID = 33, LTTNG_LIST_TRACKER_PIDS = 34, LTTNG_SET_SESSION_SHM_PATH = 40, + LTTNG_METADATA_REGENERATE = 41, }; enum lttcomm_relayd_command { @@ -115,6 +116,8 @@ 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, }; /* @@ -486,6 +489,7 @@ struct lttcomm_consumer_msg { 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. */ @@ -517,6 +521,9 @@ struct lttcomm_consumer_msg { uint64_t session_id; uint64_t channel_key; } LTTNG_PACKED lost_packets; + struct { + uint64_t session_id; + } LTTNG_PACKED metadata_regenerate; } u; } LTTNG_PACKED; diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c index 5686fbd09..fe7445b7f 100644 --- a/src/common/ust-consumer/ust-consumer.c +++ b/src/common/ust-consumer/ust-consumer.c @@ -1197,8 +1197,8 @@ error: * 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; @@ -1225,7 +1225,8 @@ int lttng_ustconsumer_recv_metadata(int sock, uint64_t key, uint64_t offset, 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; @@ -1587,6 +1588,7 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, 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, @@ -1637,7 +1639,7 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, 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; @@ -2097,6 +2099,38 @@ error: 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. * @@ -2110,6 +2144,10 @@ int commit_one_metadata_packet(struct lttng_consumer_stream *stream) 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; @@ -2693,7 +2731,7 @@ int lttng_ustconsumer_request_metadata(struct lttng_consumer_local_data *ctx, 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); @@ -2773,6 +2811,7 @@ int lttng_ustconsumer_request_metadata(struct lttng_consumer_local_data *ctx, 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) { @@ -2795,7 +2834,7 @@ int lttng_ustconsumer_request_metadata(struct lttng_consumer_local_data *ctx, 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 diff --git a/src/common/ust-consumer/ust-consumer.h b/src/common/ust-consumer/ust-consumer.h index f933e90dc..67b5bb511 100644 --- a/src/common/ust-consumer/ust-consumer.h +++ b/src/common/ust-consumer/ust-consumer.h @@ -57,8 +57,8 @@ void lttng_ustconsumer_close_all_metadata(struct lttng_ht *ht); 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, @@ -185,8 +185,8 @@ void lttng_ustconsumer_close_stream_wakeup(struct lttng_consumer_stream *stream) } 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; } diff --git a/src/common/utils.c b/src/common/utils.c index 6e7726714..d71d92446 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -843,7 +843,6 @@ int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size, { int ret; - assert(new_count); assert(stream_fd); ret = close(out_fd); @@ -866,18 +865,22 @@ int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size, * 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; } @@ -1322,3 +1325,23 @@ end: } 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; +} diff --git a/src/common/utils.h b/src/common/utils.h index 4f82ebd44..5272d54a6 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -58,5 +58,6 @@ char *utils_generate_optstring(const struct option *long_options, 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 */ diff --git a/src/lib/lttng-ctl/lttng-ctl.c b/src/lib/lttng-ctl/lttng-ctl.c index fe0527d42..61396eb46 100644 --- a/src/lib/lttng-ctl/lttng-ctl.c +++ b/src/lib/lttng-ctl/lttng-ctl.c @@ -2374,6 +2374,36 @@ int lttng_list_tracker_pids(struct lttng_handle *handle, 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. */ -- 2.34.1