From: Julien Desfossez Date: Wed, 20 Dec 2017 20:43:22 +0000 (-0500) Subject: Rotate timer X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=commitdiff_plain;h=259c267446a63c501298f39a5d2397314b11f729 Rotate timer Allow the user to configure a timer to rotate a session periodically. The user can configure this setting with the API or the new enable-rotation/disable-rotation commands: lttng enable-rotation --timer 10s lttng disable-rotation --timer Signed-off-by: Julien Desfossez Signed-off-by: Jérémie Galarneau --- diff --git a/include/lttng/lttng-error.h b/include/lttng/lttng-error.h index 57f9de05b..1fb773806 100644 --- a/include/lttng/lttng-error.h +++ b/include/lttng/lttng-error.h @@ -149,13 +149,15 @@ enum lttng_error_code { LTTNG_ERR_TRIGGER_EXISTS = 126, /* Trigger already registered. */ LTTNG_ERR_TRIGGER_NOT_FOUND = 127, /* Trigger not found. */ LTTNG_ERR_COMMAND_CANCELLED = 128, /* Command cancelled. */ - LTTNG_ERR_ROTATION_PENDING = 129, /* Rotate already pending for this session. */ - LTTNG_ERR_ROTATION_NOT_AVAILABLE = 130, /* Rotate feature not available for this type of session (e.g: live) */ - LTTNG_ERR_ROTATION_TIMER_IS_SET = 131, /* Rotate timer already setup for this session. */ - LTTNG_ERR_ROTATION_SIZE_IS_SET = 132, /* Rotate size already setup for this session. */ - LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP = 133, /* Already rotated once after a stop. */ - LTTNG_ERR_ROTATION_WRONG_VERSION = 134, /* Rotate not supported by this kernel tracer version */ - LTTNG_ERR_NO_SESSION_OUTPUT = 135, /* Session has no output configured. */ + LTTNG_ERR_ROTATION_PENDING = 129, /* Rotate already pending for this session. */ + LTTNG_ERR_ROTATION_NOT_AVAILABLE = 130, /* Rotate feature not available for this type of session (e.g: live) */ + LTTNG_ERR_ROTATION_TIMER_SET = 131, /* Timer-based rotation schedule already set for this session. */ + LTTNG_ERR_ROTATION_SIZE_SET = 132, /* Size-based rotation schedule already set for this session. */ + LTTNG_ERR_ROTATION_NO_TIMER_SET = 133, /* No timer-based rotation schedule set for this session. */ + LTTNG_ERR_ROTATION_NO_SIZE_SET = 134, /* No size-based rotation schedule set for this session. */ + LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP = 135, /* Already rotated once after a stop. */ + LTTNG_ERR_ROTATION_WRONG_VERSION = 136, /* Session rotation not supported by this kernel tracer version */ + LTTNG_ERR_NO_SESSION_OUTPUT = 137, /* Session has no output configured. */ /* MUST be last element */ LTTNG_ERR_NR, /* Last element */ diff --git a/include/lttng/lttng.h b/include/lttng/lttng.h index 72e8dcf05..1dfac7849 100644 --- a/include/lttng/lttng.h +++ b/include/lttng/lttng.h @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/include/lttng/rotate-internal.h b/include/lttng/rotate-internal.h index 265148376..00a348ff7 100644 --- a/include/lttng/rotate-internal.h +++ b/include/lttng/rotate-internal.h @@ -38,6 +38,18 @@ struct lttng_rotation_immediate_attr { uint64_t rotate_id; }; +/* + * Object used as input parameter to the lttng_rotate_schedule API for + * automatic rotations. + * This is opaque to the public library. + */ +struct lttng_rotation_schedule_attr { + /* Session name to rotate. */ + char session_name[LTTNG_NAME_MAX]; + /* > 0 if a timer is set. */ + uint64_t timer_us; +} LTTNG_PACKED; + /* * Object returned by the rotate session API. * This is opaque to the public library. diff --git a/include/lttng/rotation.h b/include/lttng/rotation.h index 05216fc37..9b797ac11 100644 --- a/include/lttng/rotation.h +++ b/include/lttng/rotation.h @@ -69,17 +69,16 @@ enum lttng_rotation_status { * Input parameter to the lttng_rotate_session command. * * An immediate rotation is performed as soon as possible by the tracers. - * - * The lttng_rotation_immediate_attr object is opaque to the user. Use the - * helper functions below to access it. */ struct lttng_rotation_immediate_attr; +/* + * Input parameter to the lttng_rotate_schedule command. + */ +struct lttng_rotation_schedule_attr; + /* * Handle used to represent a specific rotation. - * - * This object is opaque to the user. Use the helper functions below to access - * it. */ struct lttng_rotation_handle; @@ -90,12 +89,25 @@ struct lttng_rotation_handle; extern struct lttng_rotation_immediate_attr * lttng_rotation_immediate_attr_create(void); +/* + * Return a newly allocated scheduled rotate session descriptor object or NULL + * on error. + */ +extern struct lttng_rotation_schedule_attr * +lttng_rotation_schedule_attr_create(void); + /* * Destroy a given immediate session rotation descriptor object. */ extern void lttng_rotation_immediate_attr_destroy( struct lttng_rotation_immediate_attr *attr); +/* + * Destroy a given scheduled rotate session descriptor object. + */ +extern void lttng_rotation_schedule_attr_destroy( + struct lttng_rotation_schedule_attr *attr); + /* * Set the name of the session to rotate immediately. * @@ -106,6 +118,26 @@ extern enum lttng_rotation_status lttng_rotation_immediate_attr_set_session_name struct lttng_rotation_immediate_attr *attr, const char *session_name); +/* + * Set the name of the session to rotate automatically. + * + * The session_name parameter is copied to the immediate session rotation + * attributes. + */ +extern enum lttng_rotation_status lttng_rotation_schedule_attr_set_session_name( + struct lttng_rotation_schedule_attr *attr, + const char *session_name); + +/* + * Set the timer to periodically rotate the session (µs, -1ULL to disable). + */ +extern enum lttng_rotation_status lttng_rotation_schedule_attr_set_timer_period( + struct lttng_rotation_schedule_attr *attr, uint64_t timer); + +/* + * lttng rotate session handle functions. + */ + /* * Get the current state of the rotation referenced by the handle. * @@ -150,6 +182,12 @@ extern void lttng_rotation_handle_destroy( extern int lttng_rotate_session(struct lttng_rotation_immediate_attr *attr, struct lttng_rotation_handle **rotation_handle); +/* + * Configure a session to rotate periodically or based on the size written. + */ +extern int lttng_rotation_set_schedule( + struct lttng_rotation_schedule_attr *attr); + #ifdef __cplusplus } #endif diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index 5377ad8ee..924ac9231 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -2579,6 +2579,16 @@ int cmd_start_trace(struct ltt_session *session) */ session->rotated_after_last_stop = false; + if (session->rotate_timer_period) { + ret = sessiond_rotate_timer_start(session, + session->rotate_timer_period); + if (ret < 0) { + ERR("Failed to enable rotate timer"); + ret = LTTNG_ERR_UNK; + goto error; + } + } + ret = LTTNG_OK; error: @@ -2655,6 +2665,10 @@ int cmd_stop_trace(struct ltt_session *session) sessiond_timer_rotate_pending_stop(session); } + if (session->rotate_timer_enabled) { + sessiond_rotate_timer_stop(session); + } + if (session->rotate_count > 0 && !session->rotate_pending) { ret = rename_active_chunk(session); if (ret) { @@ -2957,6 +2971,10 @@ int cmd_destroy_session(struct ltt_session *session, int wpipe) sessiond_timer_rotate_pending_stop(session); } + if (session->rotate_timer_enabled) { + sessiond_rotate_timer_stop(session); + } + /* * The rename of the current chunk is performed at stop, but if we rotated * the session after the previous stop command, we need to rename the @@ -4570,7 +4588,7 @@ int cmd_rotate_session(struct ltt_session *session, rotate_return->rotation_id = session->rotate_count; } - DBG("Cmd rotate session %s, rotate_id %" PRIu64 " completed", session->name, + DBG("Cmd rotate session %s, rotate_id %" PRIu64 " sent", session->name, session->rotate_count); ret = LTTNG_OK; @@ -4632,6 +4650,71 @@ end: return ret; } +/* + * Command LTTNG_ROTATION_SET_SCHEDULE from the lttng-ctl library. + * + * Configure the automatic rotation parameters. + * Set to -1ULL to disable them. + * + * Return 0 on success or else an LTTNG_ERR code. + */ +int cmd_rotation_set_schedule(struct ltt_session *session, + uint64_t timer_us, uint64_t size) +{ + int ret; + + assert(session); + + DBG("Cmd rotate set schedule session %s", session->name); + + if (session->live_timer || session->snapshot_mode || + !session->output_traces) { + ret = LTTNG_ERR_ROTATION_NOT_AVAILABLE; + goto end; + } + + /* Trying to override an already active timer. */ + if (timer_us && timer_us != -1ULL && session->rotate_timer_period) { + ret = LTTNG_ERR_ROTATION_TIMER_SET; + goto end; + /* Trying to disable an inactive timer. */ + } else if (timer_us == -1ULL && !session->rotate_timer_period) { + ret = LTTNG_ERR_ROTATION_NO_TIMER_SET; + goto end; + } + + if (timer_us && !session->rotate_timer_period) { + if (timer_us > UINT_MAX) { + ret = LTTNG_ERR_INVALID; + goto end; + } + + session->rotate_timer_period = timer_us; + /* + * Only start the timer if the session is active, otherwise + * it will be started when the session starts. + */ + if (session->active) { + ret = sessiond_rotate_timer_start(session, timer_us); + if (ret) { + ERR("Failed to enable rotate timer"); + ret = LTTNG_ERR_UNK; + goto end; + } + } + } else if (timer_us == -1ULL && session->rotate_timer_period > 0) { + sessiond_rotate_timer_stop(session); + session->rotate_timer_period = 0; + } + + ret = LTTNG_OK; + + goto end; + +end: + return ret; +} + /* * Command ROTATE_GET_CURRENT_PATH from the lttng-ctl library. * diff --git a/src/bin/lttng-sessiond/cmd.h b/src/bin/lttng-sessiond/cmd.h index 49e9992cc..25c4ad506 100644 --- a/src/bin/lttng-sessiond/cmd.h +++ b/src/bin/lttng-sessiond/cmd.h @@ -125,5 +125,7 @@ int cmd_rotate_get_info(struct ltt_session *session, uint64_t rotate_id); int cmd_session_get_current_output(struct ltt_session *session, struct lttng_session_get_current_output_return *output_return); +int cmd_rotation_set_schedule(struct ltt_session *session, uint64_t timer_us, + uint64_t size); #endif /* CMD_H */ diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 226433ead..5e4148fb6 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -2966,6 +2966,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_ROTATE_SESSION: case LTTNG_ROTATION_GET_INFO: case LTTNG_SESSION_GET_CURRENT_OUTPUT: + case LTTNG_ROTATION_SET_SCHEDULE: need_domain = 0; break; default: @@ -3701,6 +3702,20 @@ error_add_context: } case LTTNG_START_TRACE: { + /* + * On the first start, if we have a kernel session and we have + * enabled time or size-based rotations, we have to make sure + * the kernel tracer supports it. + */ + if (!cmd_ctx->session->has_been_started && \ + cmd_ctx->session->kernel_session && \ + (cmd_ctx->session->rotate_timer_period || \ + cmd_ctx->session->rotate_size) && \ + !check_rotate_compatible()) { + DBG("Kernel tracer version is not compatible with the rotation feature"); + ret = LTTNG_ERR_ROTATION_WRONG_VERSION; + goto error; + } ret = cmd_start_trace(cmd_ctx->session); break; } @@ -4171,6 +4186,25 @@ error_add_context: ret = LTTNG_OK; break; } + case LTTNG_ROTATION_SET_SCHEDULE: + { + if (cmd_ctx->session->kernel_session && !check_rotate_compatible()) { + DBG("Kernel tracer version does not support session rotations"); + ret = LTTNG_ERR_ROTATION_WRONG_VERSION; + goto error; + } + + ret = cmd_rotation_set_schedule(cmd_ctx->session, + cmd_ctx->lsm->u.rotate_setup.timer_us, + cmd_ctx->lsm->u.rotate_setup.size); + if (ret < 0) { + ret = -ret; + goto error; + } + + ret = LTTNG_OK; + break; + } default: ret = LTTNG_ERR_UND; break; diff --git a/src/bin/lttng-sessiond/rotation-thread.c b/src/bin/lttng-sessiond/rotation-thread.c index 9e599e489..ecccc7bb0 100644 --- a/src/bin/lttng-sessiond/rotation-thread.c +++ b/src/bin/lttng-sessiond/rotation-thread.c @@ -435,6 +435,48 @@ end: return ret; } +/* + * Process the rotate_timer, called with session lock held. + */ +static +int rotate_timer(struct ltt_session *session) +{ + int ret; + + /* + * Complete _at most_ one scheduled rotation on a stopped session. + */ + if (!session->active && session->rotate_timer_enabled && + session->rotated_after_last_stop) { + ret = 0; + goto end; + } + + /* Ignore this timer if a rotation is already in progress. */ + if (session->rotate_pending || session->rotate_pending_relay) { + ret = 0; + goto end; + } + + DBG("[rotation-thread] Rotate timer on session %s", session->name); + + ret = cmd_rotate_session(session, NULL); + if (ret == -LTTNG_ERR_ROTATION_PENDING) { + DBG("Scheduled rotation aborted since a rotation is already in progress"); + ret = 0; + goto end; + } else if (ret != LTTNG_OK) { + ERR("[rotation-thread] Automatic time-triggered rotation failed with error code %i", ret); + ret = -1; + goto end; + } + + ret = 0; + +end: + return ret; +} + static int handle_rotate_timer_pipe(uint32_t revents, struct rotation_thread_handle *handle, @@ -504,6 +546,8 @@ int handle_rotate_timer_pipe(uint32_t revents, if (timer_data->signal == LTTNG_SESSIOND_SIG_ROTATE_PENDING) { ret = rotate_pending_relay_timer(session); + } else if (timer_data->signal == LTTNG_SESSIOND_SIG_ROTATE_TIMER) { + ret = rotate_timer(session); } else { ERR("Unknown signal in rotate timer %d", timer_data->signal); ret = -1; diff --git a/src/bin/lttng-sessiond/session.c b/src/bin/lttng-sessiond/session.c index 0f62ab49f..39c5611d7 100644 --- a/src/bin/lttng-sessiond/session.c +++ b/src/bin/lttng-sessiond/session.c @@ -403,6 +403,7 @@ int session_create(char *name, uid_t uid, gid_t gid) new_session->rotate_pending = false; new_session->rotate_pending_relay = false; new_session->rotate_relay_pending_timer_enabled = false; + new_session->rotate_timer = false; /* Add new session to the session list */ session_lock_list(); diff --git a/src/bin/lttng-sessiond/session.h b/src/bin/lttng-sessiond/session.h index 3c9bc1824..e00e51cc6 100644 --- a/src/bin/lttng-sessiond/session.h +++ b/src/bin/lttng-sessiond/session.h @@ -173,6 +173,12 @@ struct ltt_session { */ bool rotate_relay_pending_timer_enabled; timer_t rotate_relay_pending_timer; + /* Timer to periodically rotate a session. */ + bool rotate_timer_enabled; + timer_t rotate_timer; + uint64_t rotate_timer_period; + /* Value for size-based rotation, 0 if disabled. */ + uint64_t rotate_size; /* * Keep a state if this session was rotated after the last stop command. * We only allow one rotation after a stop. At destroy, we also need to diff --git a/src/bin/lttng-sessiond/sessiond-timer.c b/src/bin/lttng-sessiond/sessiond-timer.c index ba8373bb9..38cfdc660 100644 --- a/src/bin/lttng-sessiond/sessiond-timer.c +++ b/src/bin/lttng-sessiond/sessiond-timer.c @@ -55,6 +55,10 @@ void setmask(sigset_t *mask) if (ret) { PERROR("sigaddset switch"); } + ret = sigaddset(mask, LTTNG_SESSIOND_SIG_ROTATE_TIMER); + if (ret) { + PERROR("sigaddset switch"); + } } /* @@ -212,7 +216,7 @@ int sessiond_timer_rotate_pending_start(struct ltt_session *session, * Stop and delete the channel's live timer. * Called with session and session_list locks held. */ -void sessiond_timer_rotate_pending_stop(struct ltt_session *session) +int sessiond_timer_rotate_pending_stop(struct ltt_session *session) { int ret; @@ -223,9 +227,55 @@ void sessiond_timer_rotate_pending_stop(struct ltt_session *session) LTTNG_SESSIOND_SIG_ROTATE_PENDING); if (ret == -1) { ERR("Failed to stop rotate_pending timer"); + } else { + session->rotate_relay_pending_timer_enabled = false; + } + return ret; +} + +int sessiond_rotate_timer_start(struct ltt_session *session, + unsigned int interval_us) +{ + int ret; + + DBG("Enabling rotation timer on session \"%s\" (%ui µs)", session->name, + interval_us); + ret = session_timer_start(&session->rotate_timer, session, interval_us, + LTTNG_SESSIOND_SIG_ROTATE_TIMER, false); + if (ret < 0) { + goto end; + } + session->rotate_timer_enabled = true; +end: + return ret; +} + +/* + * Stop and delete the channel's live timer. + */ +int sessiond_rotate_timer_stop(struct ltt_session *session) +{ + int ret = 0; + + assert(session); + + if (!session->rotate_timer_enabled) { + goto end; + } + + DBG("Disabling rotation timer on session %s", session->name); + ret = session_timer_stop(&session->rotate_timer, + LTTNG_SESSIOND_SIG_ROTATE_TIMER); + if (ret < 0) { + ERR("Failed to stop rotate timer of session \"%s\"", + session->name); + goto end; } - session->rotate_relay_pending_timer_enabled = false; + session->rotate_timer_enabled = false; + ret = 0; +end: + return ret; } /* @@ -339,12 +389,32 @@ end: static void relay_rotation_pending_timer(struct timer_thread_parameters *ctx, int sig, siginfo_t *si) +{ + struct ltt_session *session = si->si_value.sival_ptr; + + assert(session); + + (void) enqueue_timer_rotate_job(ctx, session, + LTTNG_SESSIOND_SIG_ROTATE_PENDING); +} + +/* + * Handle the LTTNG_SESSIOND_SIG_ROTATE_TIMER timer. Add the session ID to + * the rotation_timer_queue so the rotation thread can trigger a new rotation + * on that session. + */ +static +void rotate_timer(struct timer_thread_parameters *ctx, int sig, siginfo_t *si) { int ret; + /* + * The session cannot be freed/destroyed while we are running this + * signal handler. + */ struct ltt_session *session = si->si_value.sival_ptr; assert(session); - ret = enqueue_timer_rotate_job(ctx, session, LTTNG_SESSIOND_SIG_ROTATE_PENDING); + ret = enqueue_timer_rotate_job(ctx, session, LTTNG_SESSIOND_SIG_ROTATE_TIMER); if (ret) { PERROR("wakeup rotate pipe"); } @@ -397,6 +467,8 @@ void *sessiond_timer_thread(void *data) goto end; } else if (signr == LTTNG_SESSIOND_SIG_ROTATE_PENDING) { relay_rotation_pending_timer(ctx, info.si_signo, &info); + } else if (signr == LTTNG_SESSIOND_SIG_ROTATE_TIMER) { + rotate_timer(ctx, info.si_signo, &info); } else { ERR("Unexpected signal %d\n", info.si_signo); } diff --git a/src/bin/lttng-sessiond/sessiond-timer.h b/src/bin/lttng-sessiond/sessiond-timer.h index 5c84f3830..523d87852 100644 --- a/src/bin/lttng-sessiond/sessiond-timer.h +++ b/src/bin/lttng-sessiond/sessiond-timer.h @@ -25,6 +25,7 @@ #define LTTNG_SESSIOND_SIG_TEARDOWN SIGRTMIN + 10 #define LTTNG_SESSIOND_SIG_EXIT SIGRTMIN + 11 #define LTTNG_SESSIOND_SIG_ROTATE_PENDING SIGRTMIN + 12 +#define LTTNG_SESSIOND_SIG_ROTATE_TIMER SIGRTMIN + 13 #define CLOCKID CLOCK_MONOTONIC @@ -55,8 +56,12 @@ struct sessiond_rotation_timer { void *sessiond_timer_thread(void *data); int sessiond_timer_signal_init(void); -int sessiond_timer_rotate_pending_start(struct ltt_session *session, unsigned int - interval_us); -void sessiond_timer_rotate_pending_stop(struct ltt_session *session); +int sessiond_timer_rotate_pending_start(struct ltt_session *session, + unsigned int interval_us); +int sessiond_timer_rotate_pending_stop(struct ltt_session *session); + +int sessiond_rotate_timer_start(struct ltt_session *session, + unsigned int interval_us); +int sessiond_rotate_timer_stop(struct ltt_session *session); #endif /* SESSIOND_TIMER_H */ diff --git a/src/bin/lttng/Makefile.am b/src/bin/lttng/Makefile.am index b56ba2be8..b0e1247d2 100644 --- a/src/bin/lttng/Makefile.am +++ b/src/bin/lttng/Makefile.am @@ -24,6 +24,8 @@ lttng_SOURCES = command.h conf.c conf.h commands/start.c \ commands/regenerate.c \ commands/help.c \ commands/rotate.c \ + commands/enable_rotation.c \ + commands/disable_rotation.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 32d54d224..6b20847f2 100644 --- a/src/bin/lttng/command.h +++ b/src/bin/lttng/command.h @@ -84,6 +84,8 @@ DECL_COMMAND(untrack); DECL_COMMAND(metadata); DECL_COMMAND(regenerate); DECL_COMMAND(rotate); +DECL_COMMAND(enable_rotation); +DECL_COMMAND(disable_rotation); extern int cmd_help(int argc, const char **argv, const struct cmd_struct commands[]); diff --git a/src/bin/lttng/commands/disable_rotation.c b/src/bin/lttng/commands/disable_rotation.c new file mode 100644 index 000000000..b0de06d9f --- /dev/null +++ b/src/bin/lttng/commands/disable_rotation.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2017 - 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 + +#include +#include + +#include "../command.h" +#include + +static char *opt_session_name; +static struct mi_writer *writer; + +enum { + OPT_HELP = 1, + OPT_LIST_OPTIONS, + OPT_TIMER, +}; + +static struct poptOption long_options[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, + {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL}, + {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0}, + {"timer", 0, POPT_ARG_NONE, 0, OPT_TIMER, 0, 0}, + {0, 0, 0, 0, 0, 0, 0} +}; + +static int setup_rotate(char *session_name, uint64_t timer) +{ + int ret = 0; + struct lttng_rotation_schedule_attr *attr = NULL; + + attr = lttng_rotation_schedule_attr_create(); + if (!attr) { + goto error; + } + + if (lttng_opt_mi) { + /* Open rotation_schedule element */ + ret = mi_lttng_writer_open_element(writer, + config_element_rotation_schedule); + if (ret) { + goto error; + } + } + + ret = lttng_rotation_schedule_attr_set_session_name(attr, session_name); + if (ret < 0) { + goto error; + } + + if (lttng_opt_mi) { + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_session_name, session_name); + if (ret) { + goto error; + } + } + + if (timer == -1ULL) { + lttng_rotation_schedule_attr_set_timer_period(attr, timer); + MSG("Disabling rotation timer on session %s", session_name); + } + + ret = lttng_rotation_set_schedule(attr); + if (ret) { + ERR("%s", lttng_strerror(ret)); + if (lttng_opt_mi) { + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_rotate_status, "error"); + if (ret) { + goto end; + } + /* Close rotation_schedule element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto end; + } + } + goto error; + } + + if (lttng_opt_mi) { + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_rotate_status, "success"); + if (ret) { + goto end; + } + + /* Close rotation_schedule element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto end; + } + } + + ret = 0; + goto end; + +error: + ret = -1; +end: + return ret; +} + +/* + * cmd_disable_rotation + * + * The 'enable-rotation ' first level command + */ +int cmd_disable_rotation(int argc, const char **argv) +{ + int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1; + int popt_ret; + static poptContext pc; + char *session_name = NULL; + bool free_session_name = false; + uint64_t timer = 0; + + pc = poptGetContext(NULL, argc, argv, long_options, 0); + popt_ret = poptReadDefaultConfig(pc, 0); + if (popt_ret) { + ret = CMD_ERROR; + ERR("poptReadDefaultConfig"); + goto end; + } + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_HELP: + SHOW_HELP(); + goto end; + case OPT_LIST_OPTIONS: + list_cmd_options(stdout, long_options); + goto end; + case OPT_TIMER: + timer = -1ULL; + break; + default: + ret = CMD_UNDEFINED; + goto end; + } + } + + if (opt_session_name == NULL) { + session_name = get_session_name(); + if (session_name == NULL) { + goto end; + } + free_session_name = true; + } else { + session_name = opt_session_name; + } + + /* Mi check */ + if (lttng_opt_mi) { + writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); + if (!writer) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + /* Open command element */ + ret = mi_lttng_writer_command_open(writer, + mi_lttng_element_command_disable_rotation); + if (ret) { + ret = CMD_ERROR; + goto end; + } + + /* Open output element */ + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_command_output); + if (ret) { + ret = CMD_ERROR; + goto end; + } + } + + /* No config options, just rotate the session now */ + if (timer == 0) { + ERR("No timer given"); + success = 0; + command_ret = -1; + } else { + command_ret = setup_rotate(session_name, timer); + } + + if (command_ret) { + ERR("%s", lttng_strerror(command_ret)); + success = 0; + } + + /* Mi closing */ + if (lttng_opt_mi) { + /* Close output element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto end; + } + + /* Success ? */ + ret = mi_lttng_writer_write_element_bool(writer, + mi_lttng_element_command_success, success); + if (ret) { + ret = CMD_ERROR; + goto end; + } + + /* Command element close */ + ret = mi_lttng_writer_command_close(writer); + if (ret) { + ret = CMD_ERROR; + goto end; + } + } + +end: + /* Mi clean-up */ + if (writer && mi_lttng_writer_destroy(writer)) { + /* Preserve original error code */ + ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL; + } + + /* Overwrite ret if an error occurred with start_tracing */ + ret = command_ret ? command_ret : ret; + poptFreeContext(pc); + if (free_session_name) { + free(session_name); + } + return ret; +} diff --git a/src/bin/lttng/commands/enable_rotation.c b/src/bin/lttng/commands/enable_rotation.c new file mode 100644 index 000000000..a746f016f --- /dev/null +++ b/src/bin/lttng/commands/enable_rotation.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2017 - 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 + +#include +#include +#include + +#include "../command.h" +#include + +static char *opt_session_name; +static struct mi_writer *writer; + +enum { + OPT_HELP = 1, + OPT_LIST_OPTIONS, + OPT_TIMER, +}; + +static struct poptOption long_options[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, + {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL}, + {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0}, + {"timer", 0, POPT_ARG_INT, 0, OPT_TIMER, 0, 0}, + {0, 0, 0, 0, 0, 0, 0} +}; + +static int setup_rotate(char *session_name, uint64_t timer) +{ + int ret = 0; + struct lttng_rotation_schedule_attr *attr = NULL; + + attr = lttng_rotation_schedule_attr_create(); + if (!attr) { + goto error; + } + + ret = lttng_rotation_schedule_attr_set_session_name(attr, session_name); + if (ret < 0) { + goto error; + } + + if (lttng_opt_mi) { + /* Open rotation_schedule element */ + ret = mi_lttng_writer_open_element(writer, + config_element_rotation_schedule); + if (ret) { + goto error; + } + + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_session_name, session_name); + if (ret) { + goto error; + } + } + + if (timer) { + lttng_rotation_schedule_attr_set_timer_period(attr, timer); + MSG("Configuring session %s to rotate every %" PRIu64 " us", + session_name, timer); + if (lttng_opt_mi) { + ret = mi_lttng_writer_write_element_unsigned_int(writer, + config_element_rotation_timer_interval, timer); + if (ret) { + goto end; + } + } + } + + ret = lttng_rotation_set_schedule(attr); + if (ret) { + ERR("%s", lttng_strerror(ret)); + if (lttng_opt_mi) { + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_rotate_status, "error"); + if (ret) { + goto end; + } + /* Close rotation_schedule element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto end; + } + } + goto error; + } + + if (lttng_opt_mi) { + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_rotate_status, "success"); + if (ret) { + goto end; + } + + /* Close rotation_schedule element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto end; + } + } + + ret = 0; + goto end; + +error: + ret = -1; +end: + return ret; +} + +/* + * cmd_enable_rotation + * + * The 'enable-rotation ' first level command + */ +int cmd_enable_rotation(int argc, const char **argv) +{ + int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1; + int popt_ret; + static poptContext pc; + char *session_name = NULL; + char *opt_arg = NULL; + uint64_t timer = 0; + bool free_session_name = false; + + pc = poptGetContext(NULL, argc, argv, long_options, 0); + popt_ret = poptReadDefaultConfig(pc, 0); + if (popt_ret) { + ret = CMD_ERROR; + ERR("poptReadDefaultConfig"); + goto end; + } + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_HELP: + SHOW_HELP(); + goto end; + case OPT_LIST_OPTIONS: + list_cmd_options(stdout, long_options); + goto end; + case OPT_TIMER: + errno = 0; + opt_arg = poptGetOptArg(pc); + if (errno != 0 || !isdigit(opt_arg[0])) { + ERR("Wrong value for --timer option: %s", opt_arg); + ret = CMD_ERROR; + goto end; + } + if (utils_parse_time_suffix(opt_arg, &timer) < 0 || timer == 0) { + ERR("Wrong value for --timer option: %s", opt_arg); + ret = CMD_ERROR; + goto end; + } + DBG("Rotation timer set to %" PRIu64, timer); + break; + default: + ret = CMD_UNDEFINED; + goto end; + } + } + + if (opt_session_name == NULL) { + session_name = get_session_name(); + if (session_name == NULL) { + goto end; + } + free_session_name = true; + } else { + session_name = opt_session_name; + } + + /* Mi check */ + if (lttng_opt_mi) { + writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); + if (!writer) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + /* Open command element */ + ret = mi_lttng_writer_command_open(writer, + mi_lttng_element_command_enable_rotation); + if (ret) { + ret = CMD_ERROR; + goto end; + } + + /* Open output element */ + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_command_output); + if (ret) { + ret = CMD_ERROR; + goto end; + } + } + + /* No config options, just rotate the session now */ + if (timer == 0) { + ERR("No timer given"); + success = 0; + command_ret = -1; + } else { + command_ret = setup_rotate(session_name, timer); + } + + if (command_ret) { + ERR("%s", lttng_strerror(command_ret)); + success = 0; + } + + /* Mi closing */ + if (lttng_opt_mi) { + /* Close output element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto end; + } + /* Success ? */ + ret = mi_lttng_writer_write_element_bool(writer, + mi_lttng_element_command_success, success); + if (ret) { + ret = CMD_ERROR; + goto end; + } + + /* Command element close */ + ret = mi_lttng_writer_command_close(writer); + if (ret) { + ret = CMD_ERROR; + goto end; + } + } + +end: + /* Mi clean-up */ + if (writer && mi_lttng_writer_destroy(writer)) { + /* Preserve original error code */ + ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL; + } + + /* Overwrite ret if an error occurred with start_tracing */ + ret = command_ret ? command_ret : ret; + poptFreeContext(pc); + if (free_session_name) { + free(session_name); + } + return ret; +} diff --git a/src/bin/lttng/lttng.c b/src/bin/lttng/lttng.c index c0f5a05ca..d905af9a6 100644 --- a/src/bin/lttng/lttng.c +++ b/src/bin/lttng/lttng.c @@ -86,6 +86,8 @@ static struct cmd_struct commands[] = { { "metadata", cmd_metadata}, { "regenerate", cmd_regenerate}, { "rotate", cmd_rotate}, + { "enable-rotation", cmd_enable_rotation}, + { "disable-rotation", cmd_disable_rotation}, { "save", cmd_save}, { "set-session", cmd_set_session}, { "snapshot", cmd_snapshot}, diff --git a/src/common/config/config-session-abi.h b/src/common/config/config-session-abi.h index 5f91109cc..65589f83e 100644 --- a/src/common/config/config-session-abi.h +++ b/src/common/config/config-session-abi.h @@ -80,6 +80,8 @@ extern const char * const config_element_pid_tracker; extern const char * const config_element_trackers; extern const char * const config_element_targets; extern const char * const config_element_target_pid; +extern const char * const config_element_rotation_timer_interval; +extern const char * const config_element_rotation_schedule; extern const char * const config_domain_type_kernel; extern const char * const config_domain_type_ust; diff --git a/src/common/config/session-config.c b/src/common/config/session-config.c index 783a74a3f..4d5045f09 100644 --- a/src/common/config/session-config.c +++ b/src/common/config/session-config.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "session-config.h" #include "config-internal.h" @@ -131,6 +132,9 @@ const char * const config_element_trackers = "trackers"; const char * const config_element_targets = "targets"; const char * const config_element_target_pid = "pid_target"; +LTTNG_HIDDEN const char * const config_element_rotation_timer_interval = "rotation_schedule_timer_period"; +LTTNG_HIDDEN const char * const config_element_rotation_schedule = "rotation_schedule"; + const char * const config_domain_type_kernel = "KERNEL"; const char * const config_domain_type_ust = "UST"; const char * const config_domain_type_jul = "JUL"; @@ -2513,7 +2517,8 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, const struct config_load_session_override_attr *overrides) { int ret, started = -1, snapshot_mode = -1; - uint64_t live_timer_interval = UINT64_MAX; + uint64_t live_timer_interval = UINT64_MAX, + rotation_timer_interval = 0; xmlChar *name = NULL; xmlChar *shm_path = NULL; xmlNodePtr domains_node = NULL; @@ -2571,7 +2576,9 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, shm_path = node_content; } else { - /* attributes, snapshot_mode or live_timer_interval */ + /* + * attributes, snapshot_mode, live_timer_interval, rotation_size, + * rotation_timer_interval. */ xmlNodePtr attributes_child = xmlFirstElementChild(node); @@ -2591,7 +2598,8 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; goto error; } - } else { + } else if (!strcmp((const char *) attributes_child->name, + config_element_live_timer_interval)) { /* live_timer_interval */ xmlChar *timer_interval_content = xmlNodeGetContent(attributes_child); @@ -2607,6 +2615,23 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, goto error; } } + if (!strcmp((const char *) attributes_child->name, + config_element_rotation_timer_interval)) { + /* rotation_timer_interval */ + xmlChar *timer_interval_content = + xmlNodeGetContent(attributes_child); + if (!timer_interval_content) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } + + ret = parse_uint(timer_interval_content, &rotation_timer_interval); + free(timer_interval_content); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto error; + } + } } } @@ -2744,6 +2769,26 @@ domain_init_error: } } + if (rotation_timer_interval) { + struct lttng_rotation_schedule_attr *rotation_attr = lttng_rotation_schedule_attr_create(); + + if (!rotation_attr) { + goto error; + } + ret = lttng_rotation_schedule_attr_set_session_name(rotation_attr, (const char *) name); + if (ret) { + lttng_rotation_schedule_attr_destroy(rotation_attr); + goto error; + } + lttng_rotation_schedule_attr_set_timer_period(rotation_attr, + rotation_timer_interval); + ret = lttng_rotation_set_schedule(rotation_attr); + lttng_rotation_schedule_attr_destroy(rotation_attr); + if (ret) { + goto error; + } + } + if (started) { ret = lttng_start_tracing((const char *) name); if (ret) { diff --git a/src/common/config/session.xsd b/src/common/config/session.xsd index 83f04bc53..7f4592f1e 100644 --- a/src/common/config/session.xsd +++ b/src/common/config/session.xsd @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> +elementFormDefault="qualified" version="2.11"> @@ -275,10 +275,11 @@ by its signed 32-bit representation when converted to msec. - - - - + + + + + diff --git a/src/common/error.c b/src/common/error.c index 1e161c9bd..69ba785d1 100644 --- a/src/common/error.c +++ b/src/common/error.c @@ -192,10 +192,12 @@ static const char *error_string_array[] = { [ ERROR_INDEX(LTTNG_ERR_COMMAND_CANCELLED) ] = "Command cancelled", [ ERROR_INDEX(LTTNG_ERR_ROTATION_PENDING) ] = "Rotation already pending for this session", [ ERROR_INDEX(LTTNG_ERR_ROTATION_NOT_AVAILABLE) ] = "Rotation feature not available for this session's creation mode", - [ ERROR_INDEX(LTTNG_ERR_ROTATION_TIMER_IS_SET) ] = "Automatic rotation schedule with a timer condition already set for this session", - [ ERROR_INDEX(LTTNG_ERR_ROTATION_SIZE_IS_SET) ] = "Automatic rotation schedule with a size threshold condition already set for this session", + [ ERROR_INDEX(LTTNG_ERR_ROTATION_TIMER_SET) ] = "Automatic timer-based rotation schedule already set for this session", + [ ERROR_INDEX(LTTNG_ERR_ROTATION_SIZE_SET) ] = "Automatic size-based rotation schedule already set for this session", + [ ERROR_INDEX(LTTNG_ERR_ROTATION_NO_TIMER_SET) ] = "No automatic timer-based rotation schedule set for this session", + [ ERROR_INDEX(LTTNG_ERR_ROTATION_NO_SIZE_SET) ] = "No automatic size-based rotation schedule set for this session", [ ERROR_INDEX(LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP) ] = "Session was already rotated once since it became inactive", - [ ERROR_INDEX(LTTNG_ERR_ROTATION_WRONG_VERSION) ] = "Rotation feature is not supported by this kernel tracer version", + [ ERROR_INDEX(LTTNG_ERR_ROTATION_WRONG_VERSION) ] = "Session rotation is not supported by this kernel tracer version", [ ERROR_INDEX(LTTNG_ERR_NO_SESSION_OUTPUT) ] = "Session has no output", /* Last element */ diff --git a/src/common/mi-lttng.c b/src/common/mi-lttng.c index 21cf78693..bc0778d2f 100644 --- a/src/common/mi-lttng.c +++ b/src/common/mi-lttng.c @@ -75,6 +75,8 @@ const char * const mi_lttng_element_command_track = "track"; const char * const mi_lttng_element_command_untrack = "untrack"; const char * const mi_lttng_element_command_version = "version"; const char * const mi_lttng_element_command_rotate = "rotate"; +const char * const mi_lttng_element_command_enable_rotation = "enable-rotation"; +const char * const mi_lttng_element_command_disable_rotation = "disable-rotation"; /* Strings related to version command */ const char * const mi_lttng_element_version = "version"; @@ -186,6 +188,7 @@ LTTNG_HIDDEN const char * const mi_lttng_element_session_name = "session_name"; LTTNG_HIDDEN const char * const mi_lttng_element_rotation = "rotation"; LTTNG_HIDDEN const char * const mi_lttng_element_rotations = "rotations"; LTTNG_HIDDEN const char * const mi_lttng_element_rotate_status = "status"; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule = "rotation_schedule"; /* Deprecated symbols preserved for ABI compatibility. */ const char * const mi_lttng_context_type_perf_counter; diff --git a/src/common/mi-lttng.h b/src/common/mi-lttng.h index b74d30086..4b26b6254 100644 --- a/src/common/mi-lttng.h +++ b/src/common/mi-lttng.h @@ -81,6 +81,8 @@ extern const char * const mi_lttng_element_command_track; extern const char * const mi_lttng_element_command_untrack; extern const char * const mi_lttng_element_command_version; extern const char * const mi_lttng_element_command_rotate; +extern const char * const mi_lttng_element_command_enable_rotation; +extern const char * const mi_lttng_element_command_disable_rotation; /* Strings related to version command */ extern const char * const mi_lttng_element_version; @@ -192,6 +194,7 @@ LTTNG_HIDDEN const char * const mi_lttng_element_session_name; LTTNG_HIDDEN const char * const mi_lttng_element_rotation; LTTNG_HIDDEN const char * const mi_lttng_element_rotations; LTTNG_HIDDEN const char * const mi_lttng_element_rotate_status; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule; /* Utility string function */ const char *mi_lttng_loglevel_string(int value, enum lttng_domain_type domain); diff --git a/src/common/sessiond-comm/sessiond-comm.h b/src/common/sessiond-comm/sessiond-comm.h index 5b7cc089e..48daec06a 100644 --- a/src/common/sessiond-comm/sessiond-comm.h +++ b/src/common/sessiond-comm/sessiond-comm.h @@ -103,6 +103,7 @@ enum lttcomm_sessiond_command { LTTNG_UNREGISTER_TRIGGER = 44, LTTNG_ROTATE_SESSION = 45, LTTNG_ROTATION_GET_INFO = 46, + LTTNG_ROTATION_SET_SCHEDULE = 47, LTTNG_SESSION_GET_CURRENT_OUTPUT = 48, }; @@ -336,6 +337,10 @@ struct lttcomm_session_msg { struct { uint64_t rotation_id; } LTTNG_PACKED get_rotation_info; + struct { + uint64_t timer_us; + uint64_t size; + } LTTNG_PACKED rotate_setup; } u; } LTTNG_PACKED; diff --git a/src/lib/lttng-ctl/rotate.c b/src/lib/lttng-ctl/rotate.c index 413215932..d0e127497 100644 --- a/src/lib/lttng-ctl/rotate.c +++ b/src/lib/lttng-ctl/rotate.c @@ -32,12 +32,25 @@ struct lttng_rotation_immediate_attr *lttng_rotation_immediate_attr_create(void) return zmalloc(sizeof(struct lttng_rotation_immediate_attr)); } +struct lttng_rotation_schedule_attr *lttng_rotation_schedule_attr_create(void) +{ + return zmalloc(sizeof(struct lttng_rotation_schedule_attr)); +} + void lttng_rotation_immediate_attr_destroy( struct lttng_rotation_immediate_attr *attr) { free(attr); } +void lttng_rotation_schedule_attr_destroy(struct lttng_rotation_schedule_attr *attr) +{ + if (attr) { + free(attr); + attr = NULL; + } +} + enum lttng_rotation_status lttng_rotation_immediate_attr_set_session_name( struct lttng_rotation_immediate_attr *attr, const char *session_name) @@ -97,6 +110,45 @@ end: } +enum lttng_rotation_status lttng_rotation_schedule_attr_set_session_name( + struct lttng_rotation_schedule_attr *attr, + const char *session_name) +{ + enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK; + int ret; + + if (!attr || !session_name) { + status = LTTNG_ROTATION_STATUS_INVALID; + goto error; + } + + ret = lttng_strncpy(attr->session_name, session_name, + sizeof(attr->session_name)); + if (ret) { + status = LTTNG_ROTATION_STATUS_INVALID; + goto error; + } + +error: + return status; +} + +enum lttng_rotation_status lttng_rotation_schedule_attr_set_timer_period( + struct lttng_rotation_schedule_attr *attr, + uint64_t timer) +{ + enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK; + + if (!attr) { + status = LTTNG_ROTATION_STATUS_INVALID; + goto end; + } + + attr->timer_us = timer; +end: + return status; +} + enum lttng_rotation_status lttng_rotation_handle_get_state( struct lttng_rotation_handle *rotation_handle, enum lttng_rotation_state *state) @@ -251,3 +303,29 @@ end: free(rotate_return); return ret; } + +/* + * Configure the automatic rotate parameters. + */ +int lttng_rotation_set_schedule( + struct lttng_rotation_schedule_attr *attr) +{ + struct lttcomm_session_msg lsm; + int ret; + + if (!attr) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + memset(&lsm, 0, sizeof(lsm)); + lsm.cmd_type = LTTNG_ROTATION_SET_SCHEDULE; + lttng_ctl_copy_string(lsm.session.name, attr->session_name, + sizeof(lsm.session.name)); + lsm.u.rotate_setup.timer_us = attr->timer_us; + + ret = lttng_ctl_ask_sessiond(&lsm, NULL); + +end: + return ret; +}