X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=b856e126fa3fae8c6cc2c3e3d69ae63dd43a84fc;hp=dbd99cc637659e242c1012cd6717f20b4e0a36d4;hb=4fc83d948cea6b10484e65f004a6c167e71ac440;hpb=b2d6628742a005a7583d4d884643ca8658b25ba2 diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index dbd99cc63..b856e126f 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -70,13 +71,24 @@ #include "agent-thread.h" #include "save.h" #include "load-session-thread.h" +#include "notification-thread.h" +#include "notification-thread-commands.h" #include "syscall.h" #include "agent.h" +#include "ht-cleanup.h" #define CONSUMERD_FILE "lttng-consumerd" +static const char *help_msg = +#ifdef LTTNG_EMBED_HELP +#include +#else +NULL +#endif +; + const char *progname; -static const char *tracing_group_name = DEFAULT_TRACING_GROUP; +const char *tracing_group_name = DEFAULT_TRACING_GROUP; static int tracing_group_name_override; static char *opt_pidfile; static int opt_sig_parent; @@ -102,6 +114,7 @@ static struct consumer_data kconsumer_data = { .cmd_unix_sock_path = DEFAULT_KCONSUMERD_CMD_SOCK_PATH, .err_sock = -1, .cmd_sock = -1, + .channel_monitor_pipe = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, @@ -113,6 +126,7 @@ static struct consumer_data ustconsumer64_data = { .cmd_unix_sock_path = DEFAULT_USTCONSUMERD64_CMD_SOCK_PATH, .err_sock = -1, .cmd_sock = -1, + .channel_monitor_pipe = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, @@ -124,6 +138,7 @@ static struct consumer_data ustconsumer32_data = { .cmd_unix_sock_path = DEFAULT_USTCONSUMERD32_CMD_SOCK_PATH, .err_sock = -1, .cmd_sock = -1, + .channel_monitor_pipe = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, @@ -189,7 +204,6 @@ static int kernel_poll_pipe[2] = { -1, -1 }; * for all threads when receiving an event on the pipe. */ static int thread_quit_pipe[2] = { -1, -1 }; -static int ht_cleanup_quit_pipe[2] = { -1, -1 }; /* * This pipe is used to inform the thread managing application communication @@ -210,6 +224,7 @@ static pthread_t health_thread; static pthread_t ht_cleanup_thread; static pthread_t agent_reg_thread; static pthread_t load_session_thread; +static pthread_t notification_thread; /* * UST registration command queue. This queue is tied with a futex and uses a N @@ -304,17 +319,26 @@ const char * const config_section_name = "sessiond"; /* Load session thread information to operate. */ struct load_session_thread_data *load_info; +/* Notification thread handle. */ +struct notification_thread_handle *notification_thread_handle; + /* Global hash tables */ struct lttng_ht *agent_apps_ht_by_sock = NULL; /* - * Whether sessiond is ready for commands/health check requests. + * Whether sessiond is ready for commands/notification channel/health check + * requests. * NR_LTTNG_SESSIOND_READY must match the number of calls to * sessiond_notify_ready(). */ -#define NR_LTTNG_SESSIOND_READY 3 +#define NR_LTTNG_SESSIOND_READY 4 int lttng_sessiond_ready = NR_LTTNG_SESSIOND_READY; +int sessiond_check_thread_quit_pipe(int fd, uint32_t events) +{ + return (fd == thread_quit_pipe[0] && (events & LPOLLIN)) ? 1 : 0; +} + /* Notify parents that we are ready for cmd and health check */ LTTNG_HIDDEN void sessiond_notify_ready(void) @@ -421,47 +445,6 @@ int sessiond_set_thread_pollset(struct lttng_poll_event *events, size_t size) return __sessiond_set_thread_pollset(events, size, thread_quit_pipe); } -/* - * Create a poll set with O_CLOEXEC and add the thread quit pipe to the set. - */ -int sessiond_set_ht_cleanup_thread_pollset(struct lttng_poll_event *events, - size_t size) -{ - return __sessiond_set_thread_pollset(events, size, - ht_cleanup_quit_pipe); -} - -static -int __sessiond_check_thread_quit_pipe(int fd, uint32_t events, int a_pipe) -{ - if (fd == a_pipe && (events & LPOLLIN)) { - return 1; - } - return 0; -} - -/* - * Check if the thread quit pipe was triggered. - * - * Return 1 if it was triggered else 0; - */ -int sessiond_check_thread_quit_pipe(int fd, uint32_t events) -{ - return __sessiond_check_thread_quit_pipe(fd, events, - thread_quit_pipe[0]); -} - -/* - * Check if the ht_cleanup thread quit pipe was triggered. - * - * Return 1 if it was triggered else 0; - */ -int sessiond_check_ht_cleanup_quit(int fd, uint32_t events) -{ - return __sessiond_check_thread_quit_pipe(fd, events, - ht_cleanup_quit_pipe[0]); -} - /* * Init thread quit pipe. * @@ -494,11 +477,6 @@ static int init_thread_quit_pipe(void) return __init_thread_quit_pipe(thread_quit_pipe); } -static int init_ht_cleanup_quit_pipe(void) -{ - return __init_thread_quit_pipe(ht_cleanup_quit_pipe); -} - /* * Stop all threads by closing the thread quit pipe. */ @@ -561,6 +539,24 @@ static void close_consumer_sockets(void) PERROR("UST consumerd64 cmd_sock close"); } } + if (kconsumer_data.channel_monitor_pipe >= 0) { + ret = close(kconsumer_data.channel_monitor_pipe); + if (ret < 0) { + PERROR("kernel consumer channel monitor pipe close"); + } + } + if (ustconsumer32_data.channel_monitor_pipe >= 0) { + ret = close(ustconsumer32_data.channel_monitor_pipe); + if (ret < 0) { + PERROR("UST consumerd32 channel monitor pipe close"); + } + } + if (ustconsumer64_data.channel_monitor_pipe >= 0) { + ret = close(ustconsumer64_data.channel_monitor_pipe); + if (ret < 0) { + PERROR("UST consumerd64 channel monitor pipe close"); + } + } } /* @@ -800,12 +796,6 @@ static void sessiond_cleanup_options(void) free(kmod_extra_probes_list); run_as_destroy_worker(); - - /* */ - DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm" - "Matthew, BEET driven development works!%c[%dm", - 27, 1, 31, 27, 0, 27, 1, 33, 27, 0); - /* */ } /* @@ -1270,6 +1260,7 @@ static void *thread_manage_consumer(void *data) enum lttcomm_return_code code; struct lttng_poll_event events; struct consumer_data *consumer_data = data; + struct consumer_socket *cmd_socket_wrapper = NULL; DBG("[thread] Manage consumer started"); @@ -1379,40 +1370,43 @@ restart: } health_code_update(); - if (code == LTTCOMM_CONSUMERD_COMMAND_SOCK_READY) { - /* Connect both socket, command and metadata. */ - consumer_data->cmd_sock = - lttcomm_connect_unix_sock(consumer_data->cmd_unix_sock_path); - consumer_data->metadata_fd = - lttcomm_connect_unix_sock(consumer_data->cmd_unix_sock_path); - if (consumer_data->cmd_sock < 0 - || consumer_data->metadata_fd < 0) { - PERROR("consumer connect cmd socket"); - /* On error, signal condition and quit. */ - signal_consumer_condition(consumer_data, -1); - goto error; - } - consumer_data->metadata_sock.fd_ptr = &consumer_data->metadata_fd; - /* Create metadata socket lock. */ - consumer_data->metadata_sock.lock = zmalloc(sizeof(pthread_mutex_t)); - if (consumer_data->metadata_sock.lock == NULL) { - PERROR("zmalloc pthread mutex"); - ret = -1; - goto error; - } - pthread_mutex_init(consumer_data->metadata_sock.lock, NULL); - - signal_consumer_condition(consumer_data, 1); - DBG("Consumer command socket ready (fd: %d", consumer_data->cmd_sock); - DBG("Consumer metadata socket ready (fd: %d)", - consumer_data->metadata_fd); - } else { + if (code != LTTCOMM_CONSUMERD_COMMAND_SOCK_READY) { ERR("consumer error when waiting for SOCK_READY : %s", lttcomm_get_readable_code(-code)); goto error; } - /* Remove the consumerd error sock since we've established a connexion */ + /* Connect both command and metadata sockets. */ + consumer_data->cmd_sock = + lttcomm_connect_unix_sock( + consumer_data->cmd_unix_sock_path); + consumer_data->metadata_fd = + lttcomm_connect_unix_sock( + consumer_data->cmd_unix_sock_path); + if (consumer_data->cmd_sock < 0 || consumer_data->metadata_fd < 0) { + PERROR("consumer connect cmd socket"); + /* On error, signal condition and quit. */ + signal_consumer_condition(consumer_data, -1); + goto error; + } + + consumer_data->metadata_sock.fd_ptr = &consumer_data->metadata_fd; + + /* Create metadata socket lock. */ + consumer_data->metadata_sock.lock = zmalloc(sizeof(pthread_mutex_t)); + if (consumer_data->metadata_sock.lock == NULL) { + PERROR("zmalloc pthread mutex"); + goto error; + } + pthread_mutex_init(consumer_data->metadata_sock.lock, NULL); + + DBG("Consumer command socket ready (fd: %d", consumer_data->cmd_sock); + DBG("Consumer metadata socket ready (fd: %d)", + consumer_data->metadata_fd); + + /* + * Remove the consumerd error sock since we've established a connection. + */ ret = lttng_poll_del(&events, consumer_data->err_sock); if (ret < 0) { goto error; @@ -1433,6 +1427,27 @@ restart: health_code_update(); + /* + * Transfer the write-end of the channel monitoring pipe to the + * by issuing a SET_CHANNEL_MONITOR_PIPE command. + */ + cmd_socket_wrapper = consumer_allocate_socket(&consumer_data->cmd_sock); + if (!cmd_socket_wrapper) { + goto error; + } + + ret = consumer_send_channel_monitor_pipe(cmd_socket_wrapper, + consumer_data->channel_monitor_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; + + /* The thread is completely initialized, signal that it is ready. */ + signal_consumer_condition(consumer_data, 1); + /* Infinite blocking call, waiting for transmission */ restart_poll: while (1) { @@ -1576,6 +1591,10 @@ error: free(consumer_data->metadata_sock.lock); } lttng_poll_clean(&events); + + if (cmd_socket_wrapper) { + consumer_destroy_socket(cmd_socket_wrapper); + } error_poll: if (err) { health_error(); @@ -1902,6 +1921,8 @@ static void *thread_dispatch_ust_registration(void *data) .count = 0, }; + rcu_register_thread(); + health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG_DISPATCH); if (testpoint(sessiond_thread_app_reg_dispatch)) { @@ -2135,6 +2156,7 @@ error_testpoint: ERR("Health error occurred in %s", __func__); } health_unregister(health_sessiond); + rcu_unregister_thread(); return NULL; } @@ -2242,10 +2264,12 @@ static void *thread_registration_apps(void *data) * lttcomm_setsockopt_snd_timeout expect msec as * parameter. */ - (void) lttcomm_setsockopt_rcv_timeout(sock, - app_socket_timeout * 1000); - (void) lttcomm_setsockopt_snd_timeout(sock, - app_socket_timeout * 1000); + if (app_socket_timeout >= 0) { + (void) lttcomm_setsockopt_rcv_timeout(sock, + app_socket_timeout * 1000); + (void) lttcomm_setsockopt_snd_timeout(sock, + app_socket_timeout * 1000); + } /* * Set the CLOEXEC flag. Return code is useless because @@ -2371,7 +2395,12 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) int ret, clock_ret; struct timespec timeout; - /* Make sure we set the readiness flag to 0 because we are NOT ready */ + /* + * Make sure we set the readiness flag to 0 because we are NOT ready. + * This access to consumer_thread_is_ready does not need to be + * protected by consumer_data.cond_mutex (yet) since the consumer + * management thread has not been started at this point. + */ consumer_data->consumer_thread_is_ready = 0; /* Setup pthread condition */ @@ -2401,8 +2430,8 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) goto error; } - ret = pthread_create(&consumer_data->thread, NULL, thread_manage_consumer, - consumer_data); + ret = pthread_create(&consumer_data->thread, default_pthread_attr(), + thread_manage_consumer, consumer_data); if (ret) { errno = ret; PERROR("pthread_create consumer"); @@ -2414,7 +2443,7 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) pthread_mutex_lock(&consumer_data->cond_mutex); /* Get time for sem_timedwait absolute timeout */ - clock_ret = clock_gettime(CLOCK_MONOTONIC, &timeout); + clock_ret = lttng_clock_gettime(CLOCK_MONOTONIC, &timeout); /* * Set the timeout for the condition timed wait even if the clock gettime * call fails since we might loop on that call and we want to avoid to @@ -3039,6 +3068,10 @@ 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_REGENERATE_METADATA: + case LTTNG_REGENERATE_STATEDUMP: + case LTTNG_REGISTER_TRIGGER: + case LTTNG_UNREGISTER_TRIGGER: need_domain = 0; break; default: @@ -3080,6 +3113,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_LIST_EVENTS: case LTTNG_LIST_SYSCALLS: case LTTNG_LIST_TRACKER_PIDS: + case LTTNG_DATA_PENDING: break; default: /* Setup lttng message with no payload */ @@ -3095,12 +3129,13 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_CREATE_SESSION: case LTTNG_CREATE_SESSION_SNAPSHOT: case LTTNG_CREATE_SESSION_LIVE: - case LTTNG_CALIBRATE: case LTTNG_LIST_SESSIONS: case LTTNG_LIST_TRACEPOINTS: case LTTNG_LIST_SYSCALLS: case LTTNG_LIST_TRACEPOINT_FIELDS: case LTTNG_SAVE_SESSION: + case LTTNG_REGISTER_TRIGGER: + case LTTNG_UNREGISTER_TRIGGER: need_tracing_session = 0; break; default: @@ -3316,6 +3351,8 @@ skip_domain: if (cmd_ctx->lsm->cmd_type == LTTNG_START_TRACE || cmd_ctx->lsm->cmd_type == LTTNG_STOP_TRACE) { switch (cmd_ctx->lsm->domain.type) { + case LTTNG_DOMAIN_NONE: + break; case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: case LTTNG_DOMAIN_PYTHON: @@ -3331,6 +3368,9 @@ skip_domain: goto error; } break; + default: + ret = LTTNG_ERR_UNKNOWN_DOMAIN; + goto error; } } @@ -3479,8 +3519,11 @@ error_add_context: } case LTTNG_ENABLE_CHANNEL: { + cmd_ctx->lsm->u.channel.chan.attr.extended.ptr = + (struct lttng_channel_extended *) &cmd_ctx->lsm->u.channel.extended; ret = cmd_enable_channel(cmd_ctx->session, &cmd_ctx->lsm->domain, - &cmd_ctx->lsm->u.channel.chan, kernel_poll_pipe[1]); + &cmd_ctx->lsm->u.channel.chan, + kernel_poll_pipe[1]); break; } case LTTNG_TRACK_PID: @@ -3932,12 +3975,6 @@ error_add_context: ret = LTTNG_OK; break; } - case LTTNG_CALIBRATE: - { - ret = cmd_calibrate(cmd_ctx->lsm->domain.type, - &cmd_ctx->lsm->u.calibrate); - break; - } case LTTNG_REGISTER_CONSUMER: { struct consumer_data *cdata; @@ -4143,6 +4180,28 @@ error_add_context: cmd_ctx->lsm->u.set_shm_path.shm_path); break; } + case LTTNG_REGENERATE_METADATA: + { + ret = cmd_regenerate_metadata(cmd_ctx->session); + break; + } + case LTTNG_REGENERATE_STATEDUMP: + { + ret = cmd_regenerate_statedump(cmd_ctx->session); + break; + } + case LTTNG_REGISTER_TRIGGER: + { + ret = cmd_register_trigger(cmd_ctx, sock, + notification_thread_handle); + break; + } + case LTTNG_UNREGISTER_TRIGGER: + { + ret = cmd_unregister_trigger(cmd_ctx, sock, + notification_thread_handle); + break; + } default: ret = LTTNG_ERR_UND; break; @@ -4191,7 +4250,6 @@ static void *thread_manage_health(void *data) sock = lttcomm_create_unix_sock(health_unix_sock_path); if (sock < 0) { ERR("Unable to create health check Unix socket"); - ret = -1; goto error; } @@ -4202,7 +4260,6 @@ static void *thread_manage_health(void *data) if (ret < 0) { ERR("Unable to set group on %s", health_unix_sock_path); PERROR("chown"); - ret = -1; goto error; } @@ -4211,7 +4268,6 @@ static void *thread_manage_health(void *data) if (ret < 0) { ERR("Unable to set permissions on %s", health_unix_sock_path); PERROR("chmod"); - ret = -1; goto error; } } @@ -4312,7 +4368,6 @@ restart: if (ret) { PERROR("close"); } - new_sock = -1; continue; } @@ -4341,7 +4396,6 @@ restart: if (ret) { PERROR("close"); } - new_sock = -1; } exit: @@ -4359,7 +4413,7 @@ error: } lttng_poll_clean(&events); - + stop_threads(); rcu_unregister_thread(); return NULL; } @@ -4645,43 +4699,6 @@ error_create_poll: return NULL; } - -/* - * usage function on stderr - */ -static void usage(void) -{ - fprintf(stderr, "Usage: %s OPTIONS\n\nOptions:\n", progname); - fprintf(stderr, " -h, --help Display this usage.\n"); - fprintf(stderr, " -c, --client-sock PATH Specify path for the client unix socket\n"); - fprintf(stderr, " -a, --apps-sock PATH Specify path for apps unix socket\n"); - fprintf(stderr, " --kconsumerd-err-sock PATH Specify path for the kernel consumer error socket\n"); - fprintf(stderr, " --kconsumerd-cmd-sock PATH Specify path for the kernel consumer command socket\n"); - fprintf(stderr, " --ustconsumerd32-err-sock PATH Specify path for the 32-bit UST consumer error socket\n"); - fprintf(stderr, " --ustconsumerd64-err-sock PATH Specify path for the 64-bit UST consumer error socket\n"); - fprintf(stderr, " --ustconsumerd32-cmd-sock PATH Specify path for the 32-bit UST consumer command socket\n"); - fprintf(stderr, " --ustconsumerd64-cmd-sock PATH Specify path for the 64-bit UST consumer command socket\n"); - fprintf(stderr, " --consumerd32-path PATH Specify path for the 32-bit UST consumer daemon binary\n"); - fprintf(stderr, " --consumerd32-libdir PATH Specify path for the 32-bit UST consumer daemon libraries\n"); - fprintf(stderr, " --consumerd64-path PATH Specify path for the 64-bit UST consumer daemon binary\n"); - fprintf(stderr, " --consumerd64-libdir PATH Specify path for the 64-bit UST consumer daemon libraries\n"); - fprintf(stderr, " -d, --daemonize Start as a daemon.\n"); - fprintf(stderr, " -b, --background Start as a daemon, keeping console open.\n"); - fprintf(stderr, " -g, --group NAME Specify the tracing group name. (default: tracing)\n"); - fprintf(stderr, " -V, --version Show version number.\n"); - fprintf(stderr, " -S, --sig-parent Send SIGUSR1 to parent pid to notify readiness.\n"); - fprintf(stderr, " -q, --quiet No output at all.\n"); - fprintf(stderr, " -v, --verbose Verbose mode. Activate DBG() macro.\n"); - fprintf(stderr, " -p, --pidfile FILE Write a pid to FILE name overriding the default value.\n"); - fprintf(stderr, " --verbose-consumer Verbose mode for consumer. Activate DBG() macro.\n"); - fprintf(stderr, " --no-kernel Disable kernel tracer\n"); - fprintf(stderr, " --agent-tcp-port Agent registration TCP port\n"); - fprintf(stderr, " -f --config PATH 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"); - fprintf(stderr, " --extra-kmod-probes Specify extra kernel module probes to load\n"); -} - static int string_match(const char *str1, const char *str2) { return (str1 && str2) && !strcmp(str1, str2); @@ -4697,18 +4714,11 @@ static int set_option(int opt, const char *arg, const char *optname) { int ret = 0; - if (arg && arg[0] == '\0') { - /* - * This only happens if the value is read from daemon config - * file. This means the option requires an argument and the - * configuration file contains a line such as: - * my_option = - */ - ret = -EINVAL; - goto end; - } - if (string_match(optname, "client-sock") || opt == 'c') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-c, --client-sock"); @@ -4716,6 +4726,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(client_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "apps-sock") || opt == 'a') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-a, --apps-sock"); @@ -4727,6 +4741,10 @@ static int set_option(int opt, const char *arg, const char *optname) } else if (string_match(optname, "background") || opt == 'b') { opt_background = 1; } else if (string_match(optname, "group") || opt == 'g') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-g, --group"); @@ -4747,14 +4765,22 @@ static int set_option(int opt, const char *arg, const char *optname) tracing_group_name_override = 1; } } else if (string_match(optname, "help") || opt == 'h') { - usage(); - exit(EXIT_SUCCESS); + ret = utils_show_help(8, "lttng-sessiond", help_msg); + if (ret) { + ERR("Cannot show --help for `lttng-sessiond`"); + perror("exec"); + } + exit(ret ? EXIT_FAILURE : EXIT_SUCCESS); } else if (string_match(optname, "version") || opt == 'V') { fprintf(stdout, "%s\n", VERSION); exit(EXIT_SUCCESS); } else if (string_match(optname, "sig-parent") || opt == 'S') { opt_sig_parent = 1; } else if (string_match(optname, "kconsumerd-err-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kconsumerd-err-sock"); @@ -4762,6 +4788,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "kconsumerd-cmd-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kconsumerd-cmd-sock"); @@ -4769,6 +4799,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "ustconsumerd64-err-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd64-err-sock"); @@ -4776,6 +4810,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "ustconsumerd64-cmd-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd64-cmd-sock"); @@ -4783,6 +4821,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "ustconsumerd32-err-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd32-err-sock"); @@ -4790,6 +4832,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "ustconsumerd32-cmd-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd32-cmd-sock"); @@ -4816,9 +4862,13 @@ static int set_option(int opt, const char *arg, const char *optname) if (arg) { opt_verbose_consumer = config_parse_value(arg); } else { - opt_verbose_consumer += 1; + opt_verbose_consumer++; } } else if (string_match(optname, "consumerd32-path")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd32-path"); @@ -4834,6 +4884,10 @@ static int set_option(int opt, const char *arg, const char *optname) consumerd32_bin_override = 1; } } else if (string_match(optname, "consumerd32-libdir")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd32-libdir"); @@ -4849,6 +4903,10 @@ static int set_option(int opt, const char *arg, const char *optname) consumerd32_libdir_override = 1; } } else if (string_match(optname, "consumerd64-path")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd64-path"); @@ -4864,6 +4922,10 @@ static int set_option(int opt, const char *arg, const char *optname) consumerd64_bin_override = 1; } } else if (string_match(optname, "consumerd64-libdir")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd64-libdir"); @@ -4879,6 +4941,10 @@ static int set_option(int opt, const char *arg, const char *optname) consumerd64_libdir_override = 1; } } else if (string_match(optname, "pidfile") || opt == 'p') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-p, --pidfile"); @@ -4891,16 +4957,16 @@ static int set_option(int opt, const char *arg, const char *optname) } } } else if (string_match(optname, "agent-tcp-port")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--agent-tcp-port"); } else { unsigned long v; - if (!arg) { - ret = -EINVAL; - goto end; - } errno = 0; v = strtoul(arg, NULL, 0); if (errno != 0 || !isdigit(arg[0])) { @@ -4915,6 +4981,10 @@ static int set_option(int opt, const char *arg, const char *optname) DBG3("Agent TCP port set to non default: %u", agent_tcp_port); } } else if (string_match(optname, "load") || opt == 'l') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-l, --load"); @@ -4927,6 +4997,10 @@ static int set_option(int opt, const char *arg, const char *optname) } } } else if (string_match(optname, "kmod-probes")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kmod-probes"); @@ -4939,6 +5013,10 @@ static int set_option(int opt, const char *arg, const char *optname) } } } else if (string_match(optname, "extra-kmod-probes")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--extra-kmod-probes"); @@ -5373,9 +5451,6 @@ error: static void sighandler(int sig) { switch (sig) { - case SIGPIPE: - DBG("SIGPIPE caught"); - return; case SIGINT: DBG("SIGINT caught"); stop_threads(); @@ -5407,9 +5482,10 @@ static int set_signal_handler(void) return ret; } - sa.sa_handler = sighandler; sa.sa_mask = sigset; sa.sa_flags = 0; + + sa.sa_handler = sighandler; if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) { PERROR("sigaction"); return ret; @@ -5420,12 +5496,13 @@ static int set_signal_handler(void) return ret; } - if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) { + if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) { PERROR("sigaction"); return ret; } - if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) { + sa.sa_handler = SIG_IGN; + if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) { PERROR("sigaction"); return ret; } @@ -5437,14 +5514,14 @@ static int set_signal_handler(void) /* * Set open files limit to unlimited. This daemon can open a large number of - * file descriptors in order to consumer multiple kernel traces. + * file descriptors in order to consume multiple kernel traces. */ static void set_ulimit(void) { int ret; struct rlimit lim; - /* The kernel does not allowed an infinite limit for open files */ + /* The kernel does not allow an infinite limit for open files */ lim.rlim_cur = 65535; lim.rlim_max = 65535; @@ -5465,7 +5542,10 @@ static int write_pidfile(void) assert(rundir); if (opt_pidfile) { - strncpy(pidfile_path, opt_pidfile, sizeof(pidfile_path)); + if (lttng_strncpy(pidfile_path, opt_pidfile, sizeof(pidfile_path))) { + ret = -1; + goto error; + } } else { /* Build pidfile path from rundir and opt_pidfile. */ ret = snprintf(pidfile_path, sizeof(pidfile_path), "%s/" @@ -5536,6 +5616,9 @@ int main(int argc, char **argv) int ret = 0, retval = 0; void *status; const char *home_path, *env_app_timeout; + struct lttng_pipe *ust32_channel_monitor_pipe = NULL, + *ust64_channel_monitor_pipe = NULL, + *kernel_channel_monitor_pipe = NULL; init_kernel_workarounds(); @@ -5610,29 +5693,8 @@ int main(int argc, char **argv) goto exit_health_sessiond_cleanup; } - if (init_ht_cleanup_quit_pipe()) { - retval = -1; - goto exit_ht_cleanup_quit_pipe; - } - - /* Setup the thread ht_cleanup communication pipe. */ - if (utils_create_pipe_cloexec(ht_cleanup_pipe)) { - retval = -1; - goto exit_ht_cleanup_pipe; - } - - /* Set up max poll set size */ - if (lttng_poll_set_max_size()) { - retval = -1; - goto exit_set_max_size; - } - /* Create thread to clean up RCU hash tables */ - ret = pthread_create(&ht_cleanup_thread, NULL, - thread_ht_cleanup, (void *) NULL); - if (ret) { - errno = ret; - PERROR("pthread_create ht_cleanup"); + if (init_ht_cleanup_thread(&ht_cleanup_thread)) { retval = -1; goto exit_ht_cleanup; } @@ -5715,6 +5777,19 @@ int main(int argc, char **argv) kconsumer_data.err_unix_sock_path); DBG2("Kernel consumer cmd path: %s", kconsumer_data.cmd_unix_sock_path); + kernel_channel_monitor_pipe = lttng_pipe_open(0); + if (!kernel_channel_monitor_pipe) { + ERR("Failed to create kernel consumer channel monitor pipe"); + retval = -1; + goto exit_init_data; + } + kconsumer_data.channel_monitor_pipe = + lttng_pipe_release_writefd( + kernel_channel_monitor_pipe); + if (kconsumer_data.channel_monitor_pipe < 0) { + retval = -1; + goto exit_init_data; + } } else { home_path = utils_get_home_dir(); if (home_path == NULL) { @@ -5819,6 +5894,18 @@ int main(int argc, char **argv) ustconsumer32_data.err_unix_sock_path); DBG2("UST consumer 32 bits cmd path: %s", ustconsumer32_data.cmd_unix_sock_path); + ust32_channel_monitor_pipe = lttng_pipe_open(0); + if (!ust32_channel_monitor_pipe) { + ERR("Failed to create 32-bit user space consumer channel monitor pipe"); + retval = -1; + goto exit_init_data; + } + ustconsumer32_data.channel_monitor_pipe = lttng_pipe_release_writefd( + ust32_channel_monitor_pipe); + if (ustconsumer32_data.channel_monitor_pipe < 0) { + retval = -1; + goto exit_init_data; + } /* 64 bits consumerd path setup */ ret = snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, @@ -5840,6 +5927,18 @@ int main(int argc, char **argv) ustconsumer64_data.err_unix_sock_path); DBG2("UST consumer 64 bits cmd path: %s", ustconsumer64_data.cmd_unix_sock_path); + ust64_channel_monitor_pipe = lttng_pipe_open(0); + if (!ust64_channel_monitor_pipe) { + ERR("Failed to create 64-bit user space consumer channel monitor pipe"); + retval = -1; + goto exit_init_data; + } + ustconsumer64_data.channel_monitor_pipe = lttng_pipe_release_writefd( + ust64_channel_monitor_pipe); + if (ustconsumer64_data.channel_monitor_pipe < 0) { + retval = -1; + goto exit_init_data; + } /* * See if daemon already exist. @@ -5999,8 +6098,8 @@ int main(int argc, char **argv) } load_info->path = opt_load_session_path; - /* Create health-check thread */ - ret = pthread_create(&health_thread, NULL, + /* Create health-check thread. */ + ret = pthread_create(&health_thread, default_pthread_attr(), thread_manage_health, (void *) NULL); if (ret) { errno = ret; @@ -6009,86 +6108,117 @@ int main(int argc, char **argv) goto exit_health; } + /* notification_thread_data acquires the pipes' read side. */ + notification_thread_handle = notification_thread_handle_create( + ust32_channel_monitor_pipe, + ust64_channel_monitor_pipe, + kernel_channel_monitor_pipe); + if (!notification_thread_handle) { + retval = -1; + ERR("Failed to create notification thread shared data"); + stop_threads(); + goto exit_notification; + } + + /* Create notification thread. */ + ret = pthread_create(¬ification_thread, default_pthread_attr(), + thread_notification, notification_thread_handle); + if (ret) { + errno = ret; + PERROR("pthread_create notification"); + retval = -1; + stop_threads(); + goto exit_notification; + } + /* Create thread to manage the client socket */ - ret = pthread_create(&client_thread, NULL, + ret = pthread_create(&client_thread, default_pthread_attr(), thread_manage_clients, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create clients"); retval = -1; + stop_threads(); goto exit_client; } /* Create thread to dispatch registration */ - ret = pthread_create(&dispatch_thread, NULL, + ret = pthread_create(&dispatch_thread, default_pthread_attr(), thread_dispatch_ust_registration, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create dispatch"); retval = -1; + stop_threads(); goto exit_dispatch; } /* Create thread to manage application registration. */ - ret = pthread_create(®_apps_thread, NULL, + ret = pthread_create(®_apps_thread, default_pthread_attr(), thread_registration_apps, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create registration"); retval = -1; + stop_threads(); goto exit_reg_apps; } /* Create thread to manage application socket */ - ret = pthread_create(&apps_thread, NULL, + ret = pthread_create(&apps_thread, default_pthread_attr(), thread_manage_apps, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create apps"); retval = -1; + stop_threads(); goto exit_apps; } /* Create thread to manage application notify socket */ - ret = pthread_create(&apps_notify_thread, NULL, + ret = pthread_create(&apps_notify_thread, default_pthread_attr(), ust_thread_manage_notify, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create notify"); retval = -1; + stop_threads(); goto exit_apps_notify; } /* Create agent registration thread. */ - ret = pthread_create(&agent_reg_thread, NULL, + ret = pthread_create(&agent_reg_thread, default_pthread_attr(), agent_thread_manage_registration, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create agent"); retval = -1; + stop_threads(); goto exit_agent_reg; } /* Don't start this thread if kernel tracing is not requested nor root */ if (is_root && !opt_no_kernel) { /* Create kernel thread to manage kernel event */ - ret = pthread_create(&kernel_thread, NULL, + ret = pthread_create(&kernel_thread, default_pthread_attr(), thread_manage_kernel, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create kernel"); retval = -1; + stop_threads(); goto exit_kernel; } } /* Create session loading thread. */ - ret = pthread_create(&load_session_thread, NULL, thread_load_session, - load_info); + ret = pthread_create(&load_session_thread, default_pthread_attr(), + thread_load_session, load_info); if (ret) { errno = ret; PERROR("pthread_create load_session_thread"); retval = -1; + stop_threads(); goto exit_load_session; } @@ -6165,62 +6295,75 @@ exit_dispatch: PERROR("pthread_join"); retval = -1; } -exit_client: +exit_client: +exit_notification: ret = pthread_join(health_thread, &status); if (ret) { errno = ret; PERROR("pthread_join health thread"); retval = -1; } -exit_health: +exit_health: exit_init_data: + /* + * Wait for all pending call_rcu work to complete before tearing + * down data structures. call_rcu worker may be trying to + * perform lookups in those structures. + */ + rcu_barrier(); /* * sessiond_cleanup() is called when no other thread is running, except * the ht_cleanup thread, which is needed to destroy the hash tables. */ rcu_thread_online(); sessiond_cleanup(); - rcu_thread_offline(); - rcu_unregister_thread(); - ret = notify_thread_pipe(ht_cleanup_quit_pipe[1]); - if (ret < 0) { - ERR("write error on ht_cleanup quit pipe"); - retval = -1; + /* + * Ensure all prior call_rcu are done. call_rcu callbacks may push + * hash tables to the ht_cleanup thread. Therefore, we ensure that + * the queue is empty before shutting down the clean-up thread. + */ + rcu_barrier(); + + /* + * The teardown of the notification system is performed after the + * session daemon's teardown in order to allow it to be notified + * of the active session and channels at the moment of the teardown. + */ + if (notification_thread_handle) { + notification_thread_command_quit(notification_thread_handle); + notification_thread_handle_destroy(notification_thread_handle); } - ret = pthread_join(ht_cleanup_thread, &status); + ret = pthread_join(notification_thread, &status); if (ret) { errno = ret; - PERROR("pthread_join ht cleanup thread"); + PERROR("pthread_join notification thread"); retval = -1; } -exit_ht_cleanup: -exit_set_max_size: - utils_close_pipe(ht_cleanup_pipe); -exit_ht_cleanup_pipe: + rcu_thread_offline(); + rcu_unregister_thread(); - /* - * Close the ht_cleanup quit pipe. - */ - utils_close_pipe(ht_cleanup_quit_pipe); -exit_ht_cleanup_quit_pipe: + ret = fini_ht_cleanup_thread(&ht_cleanup_thread); + if (ret) { + retval = -1; + } + lttng_pipe_destroy(ust32_channel_monitor_pipe); + lttng_pipe_destroy(ust64_channel_monitor_pipe); + lttng_pipe_destroy(kernel_channel_monitor_pipe); +exit_ht_cleanup: health_app_destroy(health_sessiond); exit_health_sessiond_cleanup: exit_create_run_as_worker_cleanup: exit_options: - /* Ensure all prior call_rcu are done. */ - rcu_barrier(); - sessiond_cleanup_options(); exit_set_signal_handler: - if (!retval) { exit(EXIT_SUCCESS); } else {