X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=226433ead4057a3b1751de9d60e8c6e7aa3f0e09;hp=3625bba0f2d6d1f64049984f5209626d5d1dfcb1;hb=d68c9a04537b683991a7355b812b0af954008cf1;hpb=81f04d5fd1680ff7cf705e19b3cbfc022272bbf3 diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 3625bba0f..226433ead 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -73,10 +73,12 @@ #include "load-session-thread.h" #include "notification-thread.h" #include "notification-thread-commands.h" +#include "rotation-thread.h" #include "syscall.h" #include "agent.h" #include "ht-cleanup.h" #include "sessiond-config.h" +#include "sessiond-timer.h" static const char *help_msg = #ifdef LTTNG_EMBED_HELP @@ -94,6 +96,9 @@ static int lockfile_fd = -1; /* Set to 1 when a SIGUSR1 signal is received. */ static int recv_child_signal; +static struct lttng_kernel_tracer_version kernel_tracer_version; +static struct lttng_kernel_tracer_abi_version kernel_tracer_abi_version; + /* * Consumer daemon specific control data. Every value not initialized here is * set to 0 by the static definition. @@ -103,6 +108,7 @@ static struct consumer_data kconsumer_data = { .err_sock = -1, .cmd_sock = -1, .channel_monitor_pipe = -1, + .channel_rotate_pipe = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, @@ -113,6 +119,7 @@ static struct consumer_data ustconsumer64_data = { .err_sock = -1, .cmd_sock = -1, .channel_monitor_pipe = -1, + .channel_rotate_pipe = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, @@ -123,6 +130,7 @@ static struct consumer_data ustconsumer32_data = { .err_sock = -1, .cmd_sock = -1, .channel_monitor_pipe = -1, + .channel_rotate_pipe = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, @@ -202,6 +210,8 @@ static pthread_t ht_cleanup_thread; static pthread_t agent_reg_thread; static pthread_t load_session_thread; static pthread_t notification_thread; +static pthread_t rotation_thread; +static pthread_t timer_thread; /* * UST registration command queue. This queue is tied with a futex and uses a N @@ -282,6 +292,9 @@ struct load_session_thread_data *load_info; /* Notification thread handle. */ struct notification_thread_handle *notification_thread_handle; +/* Rotation thread handle. */ +struct rotation_thread_handle *rotation_thread_handle; + /* Global hash tables */ struct lttng_ht *agent_apps_ht_by_sock = NULL; @@ -291,7 +304,7 @@ struct lttng_ht *agent_apps_ht_by_sock = NULL; * NR_LTTNG_SESSIOND_READY must match the number of calls to * sessiond_notify_ready(). */ -#define NR_LTTNG_SESSIOND_READY 4 +#define NR_LTTNG_SESSIOND_READY 5 int lttng_sessiond_ready = NR_LTTNG_SESSIOND_READY; int sessiond_check_thread_quit_pipe(int fd, uint32_t events) @@ -468,6 +481,24 @@ static void close_consumer_sockets(void) PERROR("UST consumerd64 channel monitor pipe close"); } } + if (kconsumer_data.channel_rotate_pipe >= 0) { + ret = close(kconsumer_data.channel_rotate_pipe); + if (ret < 0) { + PERROR("kernel consumer channel rotate pipe close"); + } + } + if (ustconsumer32_data.channel_rotate_pipe >= 0) { + ret = close(ustconsumer32_data.channel_rotate_pipe); + if (ret < 0) { + PERROR("UST consumerd32 channel rotate pipe close"); + } + } + if (ustconsumer64_data.channel_rotate_pipe >= 0) { + ret = close(ustconsumer64_data.channel_rotate_pipe); + if (ret < 0) { + PERROR("UST consumerd64 channel rotate pipe close"); + } + } } /* @@ -1263,19 +1294,28 @@ restart: health_code_update(); /* - * Transfer the write-end of the channel monitoring pipe to the - * by issuing a SET_CHANNEL_MONITOR_PIPE command. + * Transfer the write-end of the channel monitoring and rotate pipe + * to the consumer by issuing a SET_CHANNEL_MONITOR_PIPE and + * SET_CHANNEL_ROTATE_PIPE commands. */ cmd_socket_wrapper = consumer_allocate_socket(&consumer_data->cmd_sock); if (!cmd_socket_wrapper) { goto error; } + cmd_socket_wrapper->lock = &consumer_data->lock; ret = consumer_send_channel_monitor_pipe(cmd_socket_wrapper, consumer_data->channel_monitor_pipe); if (ret) { goto error; } + + ret = consumer_send_channel_rotate_pipe(cmd_socket_wrapper, + consumer_data->channel_rotate_pipe); + if (ret) { + goto error; + } + /* Discard the socket wrapper as it is no longer needed. */ consumer_destroy_socket(cmd_socket_wrapper); cmd_socket_wrapper = NULL; @@ -2620,7 +2660,8 @@ static int init_kernel_tracer(void) } /* Validate kernel version */ - ret = kernel_validate_version(kernel_tracer_fd); + ret = kernel_validate_version(kernel_tracer_fd, &kernel_tracer_version, + &kernel_tracer_abi_version); if (ret < 0) { goto error_version; } @@ -2827,20 +2868,6 @@ static int create_kernel_session(struct ltt_session *session) goto error; } - /* Create directory(ies) on local filesystem. */ - if (session->kernel_session->consumer->type == CONSUMER_DST_LOCAL && - strlen(session->kernel_session->consumer->dst.trace_path) > 0) { - ret = run_as_mkdir_recursive( - session->kernel_session->consumer->dst.trace_path, - S_IRWXU | S_IRWXG, session->uid, session->gid); - if (ret < 0) { - if (errno != EEXIST) { - ERR("Trace directory creation error"); - goto error; - } - } - } - session->kernel_session->uid = session->uid; session->kernel_session->gid = session->gid; session->kernel_session->output_traces = session->output_traces; @@ -2876,6 +2903,22 @@ static unsigned int lttng_sessions_count(uid_t uid, gid_t gid) return i; } +/* + * Check if the current kernel tracer supports the session rotation feature. + * Return 1 if it does, 0 otherwise. + */ +static int check_rotate_compatible(void) +{ + int ret = 1; + + if (kernel_tracer_version.major != 2 || kernel_tracer_version.minor < 11) { + DBG("Kernel tracer version is not compatible with the rotation feature"); + ret = 0; + } + + return ret; +} + /* * Process the command requested by the lttng client within the command * context structure. This function make sure that the return structure (llm) @@ -2920,6 +2963,9 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_REGENERATE_STATEDUMP: case LTTNG_REGISTER_TRIGGER: case LTTNG_UNREGISTER_TRIGGER: + case LTTNG_ROTATE_SESSION: + case LTTNG_ROTATION_GET_INFO: + case LTTNG_SESSION_GET_CURRENT_OUTPUT: need_domain = 0; break; default: @@ -2962,6 +3008,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_LIST_SYSCALLS: case LTTNG_LIST_TRACKER_PIDS: case LTTNG_DATA_PENDING: + case LTTNG_ROTATE_SESSION: + case LTTNG_ROTATION_GET_INFO: break; default: /* Setup lttng message with no payload */ @@ -4050,6 +4098,79 @@ error_add_context: notification_thread_handle); break; } + case LTTNG_ROTATE_SESSION: + { + struct lttng_rotate_session_return rotate_return; + + DBG("Client rotate session \"%s\"", cmd_ctx->session->name); + + memset(&rotate_return, 0, sizeof(rotate_return)); + if (cmd_ctx->session->kernel_session && !check_rotate_compatible()) { + DBG("Kernel tracer version is not compatible with the rotation feature"); + ret = LTTNG_ERR_ROTATION_WRONG_VERSION; + goto error; + } + + ret = cmd_rotate_session(cmd_ctx->session, &rotate_return); + if (ret < 0) { + ret = -ret; + goto error; + } + + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &rotate_return, + sizeof(rotate_return)); + if (ret < 0) { + ret = -ret; + goto error; + } + + ret = LTTNG_OK; + break; + } + case LTTNG_ROTATION_GET_INFO: + { + struct lttng_rotation_get_info_return get_info_return; + + memset(&get_info_return, 0, sizeof(get_info_return)); + ret = cmd_rotate_get_info(cmd_ctx->session, &get_info_return, + cmd_ctx->lsm->u.get_rotation_info.rotation_id); + if (ret < 0) { + ret = -ret; + goto error; + } + + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &get_info_return, + sizeof(get_info_return)); + if (ret < 0) { + ret = -ret; + goto error; + } + + ret = LTTNG_OK; + break; + } + case LTTNG_SESSION_GET_CURRENT_OUTPUT: + { + struct lttng_session_get_current_output_return output_return; + + memset(&output_return, 0, sizeof(output_return)); + ret = cmd_session_get_current_output(cmd_ctx->session, + &output_return); + if (ret < 0) { + ret = -ret; + goto error; + } + + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &output_return, + sizeof(output_return)); + if (ret < 0) { + ret = -ret; + goto error; + } + + ret = LTTNG_OK; + break; + } default: ret = LTTNG_ERR_UND; break; @@ -5444,6 +5565,48 @@ end: return ret; } +static +struct rotation_thread_timer_queue *create_rotate_timer_queue(void) +{ + struct rotation_thread_timer_queue *queue = NULL; + + queue = zmalloc(sizeof(struct rotation_thread_timer_queue)); + if (!queue) { + PERROR("Failed to allocate timer rotate queue"); + goto end; + } + + queue->event_pipe = lttng_pipe_open(FD_CLOEXEC | O_NONBLOCK); + CDS_INIT_LIST_HEAD(&queue->list); + pthread_mutex_init(&queue->lock, NULL); + +end: + return queue; +} + +static +void destroy_rotate_timer_queue(struct rotation_thread_timer_queue *queue) +{ + struct sessiond_rotation_timer *node, *tmp_node; + + if (!queue) { + return; + } + + lttng_pipe_destroy(queue->event_pipe); + + pthread_mutex_lock(&queue->lock); + /* Empty wait queue. */ + cds_list_for_each_entry_safe(node, tmp_node, &queue->list, head) { + cds_list_del(&node->head); + free(node); + } + pthread_mutex_unlock(&queue->lock); + + pthread_mutex_destroy(&queue->lock); + free(queue); +} + /* * main */ @@ -5456,6 +5619,14 @@ int main(int argc, char **argv) *ust64_channel_monitor_pipe = NULL, *kernel_channel_monitor_pipe = NULL; bool notification_thread_running = false; + bool rotation_thread_running = false; + bool timer_thread_running = false; + struct lttng_pipe *ust32_channel_rotate_pipe = NULL, + *ust64_channel_rotate_pipe = NULL, + *kernel_channel_rotate_pipe = NULL; + struct timer_thread_parameters timer_thread_ctx; + /* Queue of rotation jobs populated by the sessiond-timer. */ + struct rotation_thread_timer_queue *rotation_timer_queue = NULL; init_kernel_workarounds(); @@ -5466,6 +5637,11 @@ int main(int argc, char **argv) goto exit_set_signal_handler; } + if (sessiond_timer_signal_init()) { + retval = -1; + goto exit_set_signal_handler; + } + page_size = sysconf(_SC_PAGESIZE); if (page_size < 0) { PERROR("sysconf _SC_PAGESIZE"); @@ -5603,6 +5779,19 @@ int main(int argc, char **argv) retval = -1; goto exit_init_data; } + kernel_channel_rotate_pipe = lttng_pipe_open(0); + if (!kernel_channel_rotate_pipe) { + ERR("Failed to create kernel consumer channel rotate pipe"); + retval = -1; + goto exit_init_data; + } + kconsumer_data.channel_rotate_pipe = + lttng_pipe_release_writefd( + kernel_channel_rotate_pipe); + if (kconsumer_data.channel_rotate_pipe < 0) { + retval = -1; + goto exit_init_data; + } } lockfile_fd = create_lockfile(); @@ -5627,6 +5816,30 @@ int main(int argc, char **argv) retval = -1; goto exit_init_data; } + ust32_channel_rotate_pipe = lttng_pipe_open(0); + if (!ust32_channel_rotate_pipe) { + ERR("Failed to create 32-bit user space consumer channel rotate pipe"); + retval = -1; + goto exit_init_data; + } + ustconsumer32_data.channel_rotate_pipe = lttng_pipe_release_writefd( + ust32_channel_rotate_pipe); + if (ustconsumer32_data.channel_rotate_pipe < 0) { + retval = -1; + goto exit_init_data; + } + + /* + * The rotation_timer_queue structure is shared between the sessiond timer + * thread and the rotation thread. The main() keeps the ownership and + * destroys it when both threads have quit. + */ + rotation_timer_queue = create_rotate_timer_queue(); + if (!rotation_timer_queue) { + retval = -1; + goto exit_init_data; + } + timer_thread_ctx.rotation_timer_queue = rotation_timer_queue; ust64_channel_monitor_pipe = lttng_pipe_open(0); if (!ust64_channel_monitor_pipe) { @@ -5640,6 +5853,18 @@ int main(int argc, char **argv) retval = -1; goto exit_init_data; } + ust64_channel_rotate_pipe = lttng_pipe_open(0); + if (!ust64_channel_rotate_pipe) { + ERR("Failed to create 64-bit user space consumer channel rotate pipe"); + retval = -1; + goto exit_init_data; + } + ustconsumer64_data.channel_rotate_pipe = lttng_pipe_release_writefd( + ust64_channel_rotate_pipe); + if (ustconsumer64_data.channel_rotate_pipe < 0) { + retval = -1; + goto exit_init_data; + } /* * See if daemon already exist. @@ -5833,6 +6058,44 @@ int main(int argc, char **argv) } notification_thread_running = true; + /* Create timer thread. */ + ret = pthread_create(&timer_thread, default_pthread_attr(), + sessiond_timer_thread, &timer_thread_ctx); + if (ret) { + errno = ret; + PERROR("pthread_create timer"); + retval = -1; + stop_threads(); + goto exit_notification; + } + timer_thread_running = true; + + /* rotation_thread_data acquires the pipes' read side. */ + rotation_thread_handle = rotation_thread_handle_create( + ust32_channel_rotate_pipe, + ust64_channel_rotate_pipe, + kernel_channel_rotate_pipe, + thread_quit_pipe[0], + rotation_timer_queue); + if (!rotation_thread_handle) { + retval = -1; + ERR("Failed to create rotation thread shared data"); + stop_threads(); + goto exit_rotation; + } + + /* Create rotation thread. */ + ret = pthread_create(&rotation_thread, default_pthread_attr(), + thread_rotation, rotation_thread_handle); + if (ret) { + errno = ret; + PERROR("pthread_create rotation"); + retval = -1; + stop_threads(); + goto exit_rotation; + } + rotation_thread_running = true; + /* Create thread to manage the client socket */ ret = pthread_create(&client_thread, default_pthread_attr(), thread_manage_clients, (void *) NULL); @@ -5999,6 +6262,7 @@ exit_dispatch: } exit_client: +exit_rotation: exit_notification: ret = pthread_join(health_thread, &status); if (ret) { @@ -6048,6 +6312,34 @@ exit_init_data: notification_thread_handle_destroy(notification_thread_handle); } + if (rotation_thread_handle) { + if (rotation_thread_running) { + ret = pthread_join(rotation_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join rotation thread"); + retval = -1; + } + } + rotation_thread_handle_destroy(rotation_thread_handle); + } + + if (timer_thread_running) { + kill(getpid(), LTTNG_SESSIOND_SIG_EXIT); + ret = pthread_join(timer_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join timer thread"); + retval = -1; + } + } + + /* + * After the rotation and timer thread have quit, we can safely destroy + * the rotation_timer_queue. + */ + destroy_rotate_timer_queue(rotation_timer_queue); + rcu_thread_offline(); rcu_unregister_thread(); @@ -6058,6 +6350,9 @@ exit_init_data: lttng_pipe_destroy(ust32_channel_monitor_pipe); lttng_pipe_destroy(ust64_channel_monitor_pipe); lttng_pipe_destroy(kernel_channel_monitor_pipe); + lttng_pipe_destroy(ust32_channel_rotate_pipe); + lttng_pipe_destroy(ust64_channel_rotate_pipe); + lttng_pipe_destroy(kernel_channel_rotate_pipe); exit_ht_cleanup: health_app_destroy(health_sessiond);