X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=61ddf905cc37f716393a0b3e7a148456fcd2025e;hp=f40c52487004f9d28b70a3ce735e1deaf4c94e5f;hb=022d91ba14053d6093a6d6a1af02a345c6fd42d2;hpb=4282f9a3d51a8db6a6cc602f11d42ee9a5a0c686 diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index f40c52487..61ddf905c 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -67,7 +67,9 @@ #include "health-sessiond.h" #include "testpoint.h" #include "ust-thread.h" -#include "jul-thread.h" +#include "agent-thread.h" +#include "save.h" +#include "load-session-thread.h" #define CONSUMERD_FILE "lttng-consumerd" @@ -79,10 +81,11 @@ static int opt_sig_parent; static int opt_verbose_consumer; static int opt_daemon, opt_background; static int opt_no_kernel; -static int is_root; /* Set to 1 if the daemon is running as root */ +static char *opt_load_session_path; static pid_t ppid; /* Parent PID for --sig-parent option */ static pid_t child_ppid; /* Internal parent PID use with daemonize. */ static char *rundir; +static int lockfile_fd = -1; /* Set to 1 when a SIGUSR1 signal is received. */ static int recv_child_signal; @@ -152,6 +155,8 @@ static const struct option long_options[] = { { "pidfile", 1, 0, 'p' }, { "jul-tcp-port", 1, 0, 'J' }, { "config", 1, 0, 'f' }, + { "load", 1, 0, 'l' }, + { "kmod-probes", 1, 0, 'P' }, { NULL, 0, 0, 0 } }; @@ -199,14 +204,17 @@ static pthread_t kernel_thread; static pthread_t dispatch_thread; static pthread_t health_thread; static pthread_t ht_cleanup_thread; -static pthread_t jul_reg_thread; +static pthread_t agent_reg_thread; +static pthread_t load_session_thread; /* * UST registration command queue. This queue is tied with a futex and uses a N * wakers / 1 waiter implemented and detailed in futex.c/.h * - * The thread_manage_apps and thread_dispatch_ust_registration interact with - * this queue and the wait/wake scheme. + * The thread_registration_apps and thread_dispatch_ust_registration uses this + * queue along with the wait/wake scheme. The thread_manage_apps receives down + * the line new application socket and monitors it for any I/O error or clean + * close that triggers an unregistration of the application. */ static struct ust_cmd_queue ust_cmd_queue; @@ -281,22 +289,28 @@ long page_size; /* Application health monitoring */ struct health_app *health_sessiond; -/* JUL TCP port for registration. Used by the JUL thread. */ -unsigned int jul_tcp_port = DEFAULT_JUL_TCP_PORT; +/* Agent TCP port for registration. Used by the agent thread. */ +unsigned int agent_tcp_port = DEFAULT_AGENT_TCP_PORT; + +/* Am I root or not. */ +int is_root; /* Set to 1 if the daemon is running as root */ const char * const config_section_name = "sessiond"; +/* Load session thread information to operate. */ +struct load_session_thread_data *load_info; + /* * Whether sessiond is ready for commands/health check requests. * NR_LTTNG_SESSIOND_READY must match the number of calls to - * lttng_sessiond_notify_ready(). + * sessiond_notify_ready(). */ -#define NR_LTTNG_SESSIOND_READY 2 +#define NR_LTTNG_SESSIOND_READY 3 int lttng_sessiond_ready = NR_LTTNG_SESSIOND_READY; /* Notify parents that we are ready for cmd and health check */ -static -void lttng_sessiond_notify_ready(void) +LTTNG_HIDDEN +void sessiond_notify_ready(void) { if (uatomic_sub_return(<tng_sessiond_ready, 1) == 0) { /* @@ -498,6 +512,27 @@ static void close_consumer_sockets(void) } } +/* + * Generate the full lock file path using the rundir. + * + * Return the snprintf() return value thus a negative value is an error. + */ +static int generate_lock_file_path(char *path, size_t len) +{ + int ret; + + assert(path); + assert(rundir); + + /* Build lockfile path from rundir. */ + ret = snprintf(path, len, "%s/" DEFAULT_LTTNG_SESSIOND_LOCKFILE, rundir); + if (ret < 0) { + PERROR("snprintf lockfile path"); + } + + return ret; +} + /* * Cleanup the daemon */ @@ -536,7 +571,7 @@ static void cleanup(void) (void) unlink(path); snprintf(path, PATH_MAX, "%s/%s", rundir, - DEFAULT_LTTNG_SESSIOND_JULPORT_FILE); + DEFAULT_LTTNG_SESSIOND_AGENTPORT_FILE); DBG("Removing %s", path); (void) unlink(path); @@ -579,14 +614,6 @@ static void cleanup(void) DBG("Removing directory %s", path); (void) rmdir(path); - /* - * We do NOT rmdir rundir because there are other processes - * using it, for instance lttng-relayd, which can start in - * parallel with this teardown. - */ - - free(rundir); - DBG("Cleaning up all sessions"); /* Destroy session list mutex */ @@ -642,6 +669,43 @@ static void cleanup(void) free(opt_pidfile); } + if (opt_load_session_path) { + free(opt_load_session_path); + } + + if (load_info) { + load_session_destroy_data(load_info); + free(load_info); + } + + /* + * Cleanup lock file by deleting it and finaly closing it which will + * release the file system lock. + */ + if (lockfile_fd >= 0) { + char lockfile_path[PATH_MAX]; + + ret = generate_lock_file_path(lockfile_path, sizeof(lockfile_path)); + if (ret > 0) { + ret = remove(lockfile_path); + if (ret < 0) { + PERROR("remove lock file"); + } + ret = close(lockfile_fd); + if (ret < 0) { + PERROR("close lock file"); + } + } + } + + /* + * We do NOT rmdir rundir because there are other processes + * using it, for instance lttng-relayd, which can start in + * parallel with this teardown. + */ + + free(rundir); + /* */ DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm" "Matthew, BEET driven development works!%c[%dm", @@ -1150,7 +1214,6 @@ restart: } health_code_update(); - if (code == LTTCOMM_CONSUMERD_COMMAND_SOCK_READY) { /* Connect both socket, command and metadata. */ consumer_data->cmd_sock = @@ -1307,13 +1370,13 @@ error: } consumer_data->cmd_sock = -1; } - if (*consumer_data->metadata_sock.fd_ptr >= 0) { + if (consumer_data->metadata_sock.fd_ptr && + *consumer_data->metadata_sock.fd_ptr >= 0) { ret = close(*consumer_data->metadata_sock.fd_ptr); if (ret) { PERROR("close"); } } - if (sock >= 0) { ret = close(sock); if (ret) { @@ -1327,9 +1390,10 @@ error: pthread_mutex_unlock(&consumer_data->lock); /* Cleanup metadata socket mutex. */ - pthread_mutex_destroy(consumer_data->metadata_sock.lock); - free(consumer_data->metadata_sock.lock); - + if (consumer_data->metadata_sock.lock) { + pthread_mutex_destroy(consumer_data->metadata_sock.lock); + free(consumer_data->metadata_sock.lock); + } lttng_poll_clean(&events); error_poll: if (err) { @@ -1621,7 +1685,7 @@ error_create: static void *thread_dispatch_ust_registration(void *data) { int ret, err = -1; - struct cds_wfq_node *node; + struct cds_wfcq_node *node; struct ust_command *ust_cmd = NULL; struct ust_reg_wait_node *wait_node = NULL, *tmp_wait_node; struct ust_reg_wait_queue wait_queue = { @@ -1659,7 +1723,7 @@ static void *thread_dispatch_ust_registration(void *data) health_code_update(); /* Dequeue command for registration */ - node = cds_wfq_dequeue_blocking(&ust_cmd_queue.queue); + node = cds_wfcq_dequeue_blocking(&ust_cmd_queue.head, &ust_cmd_queue.tail); if (node == NULL) { DBG("Woken up but nothing in the UST command queue"); /* Continue thread execution */ @@ -2013,11 +2077,11 @@ static void *thread_registration_apps(void *data) * Lock free enqueue the registration request. The red pill * has been taken! This apps will be part of the *system*. */ - cds_wfq_enqueue(&ust_cmd_queue.queue, &ust_cmd->node); + cds_wfcq_enqueue(&ust_cmd_queue.head, &ust_cmd_queue.tail, &ust_cmd->node); /* * Wake the registration queue futex. Implicit memory - * barrier with the exchange in cds_wfq_enqueue. + * barrier with the exchange in cds_wfcq_enqueue. */ futex_nto1_wake(&ust_cmd_queue.futex); } @@ -2228,9 +2292,12 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) */ if (opt_verbose_consumer) { verbosity = "--verbose"; - } else { + } else if (lttng_opt_quiet) { verbosity = "--quiet"; + } else { + verbosity = ""; } + switch (consumer_data->type) { case LTTNG_CONSUMER_KERNEL: /* @@ -2716,6 +2783,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_SNAPSHOT_DEL_OUTPUT: case LTTNG_SNAPSHOT_LIST_OUTPUT: case LTTNG_SNAPSHOT_RECORD: + case LTTNG_SAVE_SESSION: need_domain = 0; break; default: @@ -2774,6 +2842,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_LIST_SESSIONS: case LTTNG_LIST_TRACEPOINTS: case LTTNG_LIST_TRACEPOINT_FIELDS: + case LTTNG_SAVE_SESSION: need_tracing_session = 0; break; default: @@ -2795,6 +2864,38 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, break; } + /* + * Commands that need a valid session but should NOT create one if none + * exists. Instead of creating one and destroying it when the command is + * handled, process that right before so we save some round trip in useless + * code path. + */ + switch (cmd_ctx->lsm->cmd_type) { + case LTTNG_DISABLE_CHANNEL: + case LTTNG_DISABLE_EVENT: + case LTTNG_DISABLE_ALL_EVENT: + switch (cmd_ctx->lsm->domain.type) { + case LTTNG_DOMAIN_KERNEL: + if (!cmd_ctx->session->kernel_session) { + ret = LTTNG_ERR_NO_CHANNEL; + goto error; + } + break; + case LTTNG_DOMAIN_JUL: + case LTTNG_DOMAIN_UST: + if (!cmd_ctx->session->ust_session) { + ret = LTTNG_ERR_NO_CHANNEL; + goto error; + } + break; + default: + ret = LTTNG_ERR_UNKNOWN_DOMAIN; + goto error; + } + default: + break; + } + if (!need_domain) { goto skip_domain; } @@ -2915,6 +3016,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, } /* 32-bit */ + pthread_mutex_lock(&ustconsumer32_data.pid_mutex); if (consumerd32_bin[0] != '\0' && ustconsumer32_data.pid == 0 && cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) { @@ -3037,6 +3139,7 @@ skip_domain: { struct lttng_event_exclusion *exclusion = NULL; struct lttng_filter_bytecode *bytecode = NULL; + char *filter_expression = NULL; /* Handle exclusion events and receive it from the client. */ if (cmd_ctx->lsm->u.enable.exclusion_count > 0) { @@ -3062,6 +3165,38 @@ skip_domain: } } + /* Get filter expression from client. */ + if (cmd_ctx->lsm->u.enable.expression_len > 0) { + size_t expression_len = + cmd_ctx->lsm->u.enable.expression_len; + + if (expression_len > LTTNG_FILTER_MAX_LEN) { + ret = LTTNG_ERR_FILTER_INVAL; + free(exclusion); + goto error; + } + + filter_expression = zmalloc(expression_len); + if (!filter_expression) { + free(exclusion); + ret = LTTNG_ERR_FILTER_NOMEM; + goto error; + } + + /* Receive var. len. data */ + DBG("Receiving var len filter's expression from client ..."); + ret = lttcomm_recv_unix_sock(sock, filter_expression, + expression_len); + if (ret <= 0) { + DBG("Nothing recv() from client car len data... continuing"); + *sock_error = 1; + free(filter_expression); + free(exclusion); + ret = LTTNG_ERR_FILTER_INVAL; + goto error; + } + } + /* Handle filter and get bytecode from client. */ if (cmd_ctx->lsm->u.enable.bytecode_len > 0) { size_t bytecode_len = cmd_ctx->lsm->u.enable.bytecode_len; @@ -3101,7 +3236,8 @@ skip_domain: ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain, cmd_ctx->lsm->u.enable.channel_name, - &cmd_ctx->lsm->u.enable.event, bytecode, exclusion, + &cmd_ctx->lsm->u.enable.event, + filter_expression, bytecode, exclusion, kernel_poll_pipe[1]); break; } @@ -3111,7 +3247,8 @@ skip_domain: ret = cmd_enable_event_all(cmd_ctx->session, &cmd_ctx->lsm->domain, cmd_ctx->lsm->u.enable.channel_name, - cmd_ctx->lsm->u.enable.event.type, NULL, kernel_poll_pipe[1]); + cmd_ctx->lsm->u.enable.event.type, NULL, NULL, + kernel_poll_pipe[1]); break; } case LTTNG_LIST_TRACEPOINTS: @@ -3119,7 +3256,9 @@ skip_domain: struct lttng_event *events; ssize_t nb_events; + session_lock_list(); nb_events = cmd_list_tracepoints(cmd_ctx->lsm->domain.type, &events); + session_unlock_list(); if (nb_events < 0) { /* Return value is a negative lttng_error_code. */ ret = -nb_events; @@ -3150,8 +3289,10 @@ skip_domain: struct lttng_event_field *fields; ssize_t nb_fields; + session_lock_list(); nb_fields = cmd_list_tracepoint_fields(cmd_ctx->lsm->domain.type, &fields); + session_unlock_list(); if (nb_fields < 0) { /* Return value is a negative lttng_error_code. */ ret = -nb_fields; @@ -3570,6 +3711,12 @@ skip_domain: free(uris); break; } + case LTTNG_SAVE_SESSION: + { + ret = cmd_save_sessions(&cmd_ctx->lsm->u.save_session.attr, + &cmd_ctx->creds); + break; + } default: ret = LTTNG_ERR_UND; break; @@ -3668,7 +3815,7 @@ static void *thread_manage_health(void *data) goto error; } - lttng_sessiond_notify_ready(); + sessiond_notify_ready(); while (1) { DBG("Health check ready"); @@ -3820,7 +3967,12 @@ static void *thread_manage_clients(void *data) goto error; } - lttng_sessiond_notify_ready(); + sessiond_notify_ready(); + ret = sem_post(&load_info->message_thread_ready); + if (ret) { + PERROR("sem_post message_thread_ready"); + goto error; + } /* This testpoint is after we signal readiness to the parent. */ if (testpoint(sessiond_thread_manage_clients)) { @@ -4055,6 +4207,8 @@ static void usage(void) fprintf(stderr, " --no-kernel Disable kernel tracer\n"); fprintf(stderr, " --jul-tcp-port JUL application registration TCP port\n"); fprintf(stderr, " -f --config Load daemon configuration file\n"); + fprintf(stderr, " -l --load PATH Load session configuration\n"); + fprintf(stderr, " --kmod-probes Specify kernel module probes to load\n"); } /* @@ -4087,7 +4241,20 @@ static int set_option(int opt, const char *arg, const char *optname) opt_background = 1; break; case 'g': + /* + * If the override option is set, the pointer points to a + * *non* const thus freeing it even though the variable type is + * set to const. + */ + if (tracing_group_name_override) { + free((void *) tracing_group_name); + } tracing_group_name = strdup(arg); + if (!tracing_group_name) { + perror("strdup"); + ret = -ENOMEM; + } + tracing_group_name_override = 1; break; case 'h': usage(); @@ -4125,10 +4292,15 @@ static int set_option(int opt, const char *arg, const char *optname) case 'v': /* Verbose level can increase using multiple -v */ if (arg) { + /* Value obtained from config file */ lttng_opt_verbose = config_parse_value(arg); } else { - lttng_opt_verbose += 1; + /* -v used on command line */ + lttng_opt_verbose++; } + /* Clamp value to [0, 3] */ + lttng_opt_verbose = lttng_opt_verbose < 0 ? 0 : + (lttng_opt_verbose <= 3 ? lttng_opt_verbose : 3); break; case 'Z': if (arg) { @@ -4138,25 +4310,58 @@ static int set_option(int opt, const char *arg, const char *optname) } break; case 'u': + if (consumerd32_bin_override) { + free((void *) consumerd32_bin); + } consumerd32_bin = strdup(arg); + if (!consumerd32_bin) { + perror("strdup"); + ret = -ENOMEM; + } consumerd32_bin_override = 1; break; case 'U': + if (consumerd32_libdir_override) { + free((void *) consumerd32_libdir); + } consumerd32_libdir = strdup(arg); + if (!consumerd32_libdir) { + perror("strdup"); + ret = -ENOMEM; + } consumerd32_libdir_override = 1; break; case 't': + if (consumerd64_bin_override) { + free((void *) consumerd64_bin); + } consumerd64_bin = strdup(arg); + if (!consumerd64_bin) { + perror("strdup"); + ret = -ENOMEM; + } consumerd64_bin_override = 1; break; case 'T': + if (consumerd64_libdir_override) { + free((void *) consumerd64_libdir); + } consumerd64_libdir = strdup(arg); + if (!consumerd64_libdir) { + perror("strdup"); + ret = -ENOMEM; + } consumerd64_libdir_override = 1; break; case 'p': + free(opt_pidfile); opt_pidfile = strdup(arg); + if (!opt_pidfile) { + perror("strdup"); + ret = -ENOMEM; + } break; - case 'J': /* JUL TCP port. */ + case 'J': /* Agent TCP port. */ { unsigned long v; @@ -4170,10 +4375,29 @@ static int set_option(int opt, const char *arg, const char *optname) ERR("Port overflow in --jul-tcp-port parameter: %s", arg); return -1; } - jul_tcp_port = (uint32_t) v; - DBG3("JUL TCP port set to non default: %u", jul_tcp_port); + agent_tcp_port = (uint32_t) v; + DBG3("Agent TCP port set to non default: %u", agent_tcp_port); break; } + case 'l': + free(opt_load_session_path); + opt_load_session_path = strdup(arg); + if (!opt_load_session_path) { + perror("strdup"); + ret = -ENOMEM; + } + break; + case 'P': /* probe modules list */ + free(kmod_probes_list); + kmod_probes_list = strdup(arg); + if (!kmod_probes_list) { + perror("strdup"); + ret = -ENOMEM; + } + break; + case 'f': + /* This is handled in set_options() thus silent break. */ + break; default: /* Unknown option or other error. * Error is printed by getopt, just return */ @@ -4674,9 +4898,27 @@ error: } /* - * Write JUL TCP port using the rundir. + * Create lockfile using the rundir and return its fd. + */ +static int create_lockfile(void) +{ + int ret; + char lockfile_path[PATH_MAX]; + + ret = generate_lock_file_path(lockfile_path, sizeof(lockfile_path)); + if (ret < 0) { + goto error; + } + + ret = utils_create_lock_file(lockfile_path); +error: + return ret; +} + +/* + * Write agent TCP port using the rundir. */ -static void write_julport(void) +static void write_agent_port(void) { int ret; char path[PATH_MAX]; @@ -4684,23 +4926,52 @@ static void write_julport(void) assert(rundir); ret = snprintf(path, sizeof(path), "%s/" - DEFAULT_LTTNG_SESSIOND_JULPORT_FILE, rundir); + DEFAULT_LTTNG_SESSIOND_AGENTPORT_FILE, rundir); if (ret < 0) { - PERROR("snprintf julport path"); + PERROR("snprintf agent port path"); goto error; } /* - * Create TCP JUL port file in rundir. Return value is of no importance. + * Create TCP agent port file in rundir. Return value is of no importance. * The execution will continue even though we are not able to write the * file. */ - (void) utils_create_pid_file(jul_tcp_port, path); + (void) utils_create_pid_file(agent_tcp_port, path); error: return; } +/* + * Start the load session thread and dettach from it so the main thread can + * continue. This does not return a value since whatever the outcome, the main + * thread will continue. + */ +static void start_load_session_thread(void) +{ + int ret; + + /* Create session loading thread. */ + ret = pthread_create(&load_session_thread, NULL, thread_load_session, + load_info); + if (ret != 0) { + PERROR("pthread_create load_session_thread"); + goto error_create; + } + + ret = pthread_detach(load_session_thread); + if (ret != 0) { + PERROR("pthread_detach load_session_thread"); + } + + /* Everything went well so don't cleanup anything. */ + +error_create: + /* The cleanup() function will destroy the load_info data. */ + return; +} + /* * main */ @@ -4849,6 +5120,11 @@ int main(int argc, char **argv) } } + lockfile_fd = create_lockfile(); + if (lockfile_fd < 0) { + goto error; + } + /* Set consumer initial state */ kernel_consumerd_state = CONSUMER_STOPPED; ust_consumerd_state = CONSUMER_STOPPED; @@ -4898,8 +5174,8 @@ int main(int argc, char **argv) */ ust_app_ht_alloc(); - /* Initialize JUL domain subsystem. */ - if ((ret = jul_init()) < 0) { + /* Initialize agent domain subsystem. */ + if ((ret = agent_setup()) < 0) { /* ENOMEM at this point. */ goto error; } @@ -4981,7 +5257,7 @@ int main(int argc, char **argv) buffer_reg_init_pid_registry(); /* Init UST command queue. */ - cds_wfq_init(&ust_cmd_queue.queue); + cds_wfcq_init(&ust_cmd_queue.head, &ust_cmd_queue.tail); /* * Get session list pointer. This pointer MUST NOT be free(). This list is @@ -5003,13 +5279,18 @@ int main(int argc, char **argv) } write_pidfile(); - write_julport(); + write_agent_port(); /* Initialize communication library */ lttcomm_init(); /* This is to get the TCP timeout value. */ lttcomm_inet_init(); + if (load_session_init_data(&load_info) < 0) { + goto exit; + } + load_info->path = opt_load_session_path; + /* * Initialize the health check subsystem. This call should set the * appropriate time values. @@ -5072,16 +5353,16 @@ int main(int argc, char **argv) ret = pthread_create(&apps_notify_thread, NULL, ust_thread_manage_notify, (void *) NULL); if (ret != 0) { - PERROR("pthread_create apps"); + PERROR("pthread_create notify"); goto exit_apps_notify; } - /* Create JUL registration thread. */ - ret = pthread_create(&jul_reg_thread, NULL, - jul_thread_manage_registration, (void *) NULL); + /* Create agent registration thread. */ + ret = pthread_create(&agent_reg_thread, NULL, + agent_thread_manage_registration, (void *) NULL); if (ret != 0) { - PERROR("pthread_create apps"); - goto exit_jul_reg; + PERROR("pthread_create agent"); + goto exit_agent_reg; } /* Don't start this thread if kernel tracing is not requested nor root */ @@ -5093,7 +5374,12 @@ int main(int argc, char **argv) PERROR("pthread_create kernel"); goto exit_kernel; } + } + /* Load possible session(s). */ + start_load_session_thread(); + + if (is_root && !opt_no_kernel) { ret = pthread_join(kernel_thread, &status); if (ret != 0) { PERROR("pthread_join"); @@ -5102,13 +5388,13 @@ int main(int argc, char **argv) } exit_kernel: - ret = pthread_join(jul_reg_thread, &status); + ret = pthread_join(agent_reg_thread, &status); if (ret != 0) { - PERROR("pthread_join JUL"); + PERROR("pthread_join agent"); goto error; /* join error, exit without cleanup */ } -exit_jul_reg: +exit_agent_reg: ret = pthread_join(apps_notify_thread, &status); if (ret != 0) { PERROR("pthread_join apps notify");