X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=0e20b4f67886dc656e88e5631cce8fc223379205;hp=f24b317d02a89e5bedf8baee7d1a671076b95022;hb=1400a85d14101d8ed140f44011a183f6b5b80d29;hpb=07424f161f4afbd07fd165e4ae492726e1de7769 diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index f24b317d0..0e20b4f67 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -48,6 +47,7 @@ #include "lttng-sessiond.h" #include "channel.h" +#include "cmd.h" #include "consumer.h" #include "context.h" #include "event.h" @@ -61,6 +61,7 @@ #include "fd-limit.h" #include "filter.h" #include "health.h" +#include "testpoint.h" #define CONSUMERD_FILE "lttng-consumerd" @@ -80,7 +81,10 @@ static int is_root; /* Set to 1 if the daemon is running as root */ static pid_t ppid; /* Parent PID for --sig-parent option */ static char *rundir; -/* Consumer daemon specific control data */ +/* + * Consumer daemon specific control data. Every value not initialized here is + * set to 0 by the static definition. + */ static struct consumer_data kconsumer_data = { .type = LTTNG_CONSUMER_KERNEL, .err_unix_sock_path = DEFAULT_KCONSUMERD_ERR_SOCK_PATH, @@ -89,6 +93,8 @@ static struct consumer_data kconsumer_data = { .cmd_sock = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, + .cond = PTHREAD_COND_INITIALIZER, + .cond_mutex = PTHREAD_MUTEX_INITIALIZER, }; static struct consumer_data ustconsumer64_data = { .type = LTTNG_CONSUMER64_UST, @@ -98,6 +104,8 @@ static struct consumer_data ustconsumer64_data = { .cmd_sock = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, + .cond = PTHREAD_COND_INITIALIZER, + .cond_mutex = PTHREAD_MUTEX_INITIALIZER, }; static struct consumer_data ustconsumer32_data = { .type = LTTNG_CONSUMER32_UST, @@ -107,6 +115,8 @@ static struct consumer_data ustconsumer32_data = { .cmd_sock = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, + .cond = PTHREAD_COND_INITIALIZER, + .cond_mutex = PTHREAD_MUTEX_INITIALIZER, }; /* Shared between threads */ @@ -124,7 +134,7 @@ static char health_unix_sock_path[PATH_MAX]; /* Sockets and FDs */ static int client_sock = -1; static int apps_sock = -1; -static int kernel_tracer_fd = -1; +int kernel_tracer_fd = -1; static int kernel_poll_pipe[2] = { -1, -1 }; /* @@ -176,6 +186,8 @@ static const char *consumerd64_bin = CONFIG_CONSUMERD64_BIN; static const char *consumerd32_libdir = CONFIG_CONSUMERD32_LIBDIR; static const char *consumerd64_libdir = CONFIG_CONSUMERD64_LIBDIR; +static const char *module_proc_lttng = "/proc/lttng"; + /* * Consumer daemon state which is changed when spawning it, killing it or in * case of a fatal error. @@ -210,16 +222,6 @@ enum consumerd_state { static enum consumerd_state ust_consumerd_state; static enum consumerd_state kernel_consumerd_state; -/* - * Used to keep a unique index for each relayd socket created where this value - * is associated with streams on the consumer so it can match the right relayd - * to send to. - * - * This value should be incremented atomically for safety purposes and future - * possible concurrent access. - */ -static unsigned int relayd_net_seq_idx; - /* Used for the health monitoring of the session daemon. See health.h */ struct health_state health_thread_cmd; struct health_state health_thread_app_manage; @@ -365,111 +367,6 @@ error: return ret; } -/* - * Complete teardown of a kernel session. This free all data structure related - * to a kernel session and update counter. - */ -static void teardown_kernel_session(struct ltt_session *session) -{ - int ret; - struct lttng_ht_iter iter; - struct ltt_kernel_session *ksess; - struct consumer_socket *socket; - - if (!session->kernel_session) { - DBG3("No kernel session when tearing down session"); - return; - } - - ksess = session->kernel_session; - - DBG("Tearing down kernel session"); - - /* - * Destroy relayd associated with the session consumer. This action is - * valid since in order to destroy a session we must acquire the session - * lock. This means that there CAN NOT be stream(s) being sent to a - * consumer since this action also requires the session lock at any time. - * - * At this point, we are sure that not streams data will be lost after this - * command is issued. - */ - if (ksess->consumer && ksess->consumer->type == CONSUMER_DST_NET) { - cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter, socket, - node.node) { - ret = consumer_send_destroy_relayd(socket, ksess->consumer); - if (ret < 0) { - ERR("Unable to send destroy relayd command to consumer"); - /* Continue since we MUST delete everything at this point. */ - } - } - } - - /* - * If a custom kernel consumer was registered, close the socket before - * tearing down the complete kernel session structure - */ - cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter, socket, - node.node) { - if (socket->fd != kconsumer_data.cmd_sock) { - rcu_read_lock(); - consumer_del_socket(socket, ksess->consumer); - lttcomm_close_unix_sock(socket->fd); - consumer_destroy_socket(socket); - rcu_read_unlock(); - } - } - - trace_kernel_destroy_session(ksess); -} - -/* - * Complete teardown of all UST sessions. This will free everything on his path - * and destroy the core essence of all ust sessions :) - */ -static void teardown_ust_session(struct ltt_session *session) -{ - int ret; - struct lttng_ht_iter iter; - struct ltt_ust_session *usess; - struct consumer_socket *socket; - - if (!session->ust_session) { - DBG3("No UST session when tearing down session"); - return; - } - usess = session->ust_session; - - DBG("Tearing down UST session(s)"); - - /* - * Destroy relayd associated with the session consumer. This action is - * valid since in order to destroy a session we must acquire the session - * lock. This means that there CAN NOT be stream(s) being sent to a - * consumer since this action also requires the session lock at any time. - * - * At this point, we are sure that no data will be lost after this command - * is issued. - */ - if (usess->consumer && usess->consumer->type == CONSUMER_DST_NET) { - cds_lfht_for_each_entry(usess->consumer->socks->ht, &iter.iter, socket, - node.node) { - ret = consumer_send_destroy_relayd(socket, usess->consumer); - if (ret < 0) { - ERR("Unable to send destroy relayd command to consumer"); - /* Continue since we MUST delete everything at this point. */ - } - } - } - - ret = ust_app_destroy_trace_all(usess); - if (ret) { - ERR("Error in ust_app_destroy_trace_all"); - } - - trace_ust_destroy_session(usess); -} - /* * Stop all threads by closing the thread quit pipe. */ @@ -500,6 +397,9 @@ static void cleanup(void) DBG("Cleaning up"); + /* First thing first, stop all threads */ + utils_close_pipe(thread_quit_pipe); + DBG("Removing %s directory", rundir); ret = asprintf(&cmd, "rm -rf %s", rundir); if (ret < 0) { @@ -522,9 +422,7 @@ static void cleanup(void) /* Cleanup ALL session */ cds_list_for_each_entry_safe(sess, stmp, &session_list_ptr->head, list) { - teardown_kernel_session(sess); - teardown_ust_session(sess); - free(sess); + cmd_destroy_session(sess, kernel_poll_pipe[1]); } } @@ -542,8 +440,8 @@ static void cleanup(void) DBG("Unloading kernel modules"); modprobe_remove_lttng_all(); } + utils_close_pipe(kernel_poll_pipe); - utils_close_pipe(thread_quit_pipe); utils_close_pipe(apps_cmd_pipe); /* */ @@ -791,8 +689,12 @@ static void *thread_manage_kernel(void *data) DBG("Thread manage kernel started"); + testpoint(thread_manage_kernel); + health_code_update(&health_thread_kernel); + testpoint(thread_manage_kernel_before_loop); + ret = create_thread_poll_set(&events, 2); if (ret < 0) { goto error_poll_create; @@ -899,6 +801,29 @@ error_poll_create: return NULL; } +/* + * Signal pthread condition of the consumer data that the thread. + */ +static void signal_consumer_condition(struct consumer_data *data, int state) +{ + pthread_mutex_lock(&data->cond_mutex); + + /* + * The state is set before signaling. It can be any value, it's the waiter + * job to correctly interpret this condition variable associated to the + * consumer pthread_cond. + * + * A value of 0 means that the corresponding thread of the consumer data + * was not started. 1 indicates that the thread has started and is ready + * for action. A negative value means that there was an error during the + * thread bootstrap. + */ + data->consumer_thread_is_ready = state; + (void) pthread_cond_signal(&data->cond); + + pthread_mutex_unlock(&data->cond_mutex); +} + /* * This thread manage the consumer error sent back to the session daemon. */ @@ -940,6 +865,9 @@ static void *thread_manage_consumer(void *data) /* Inifinite blocking call, waiting for transmission */ restart: health_poll_update(&consumer_data->health); + + testpoint(thread_manage_consumer); + ret = lttng_poll_wait(&events, -1); health_poll_update(&consumer_data->health); if (ret < 0) { @@ -993,17 +921,17 @@ restart: health_code_update(&consumer_data->health); - if (code == CONSUMERD_COMMAND_SOCK_READY) { + if (code == LTTCOMM_CONSUMERD_COMMAND_SOCK_READY) { consumer_data->cmd_sock = lttcomm_connect_unix_sock(consumer_data->cmd_unix_sock_path); if (consumer_data->cmd_sock < 0) { - sem_post(&consumer_data->sem); + /* On error, signal condition and quit. */ + signal_consumer_condition(consumer_data, -1); PERROR("consumer connect"); goto error; } - /* Signal condition to tell that the kconsumerd is ready */ - sem_post(&consumer_data->sem); - DBG("consumer command socket ready"); + signal_consumer_condition(consumer_data, 1); + DBG("Consumer command socket ready"); } else { ERR("consumer error when waiting for SOCK_READY : %s", lttcomm_get_readable_code(-code)); @@ -1137,6 +1065,8 @@ static void *thread_manage_apps(void *data) DBG("[thread] Manage application started"); + testpoint(thread_manage_apps); + rcu_register_thread(); rcu_thread_online(); @@ -1152,6 +1082,8 @@ static void *thread_manage_apps(void *data) goto error; } + testpoint(thread_manage_apps_before_loop); + health_code_update(&health_thread_app_manage); while (1) { @@ -1375,6 +1307,8 @@ static void *thread_registration_apps(void *data) DBG("[thread] Manage application registration started"); + testpoint(thread_registration_apps); + ret = lttcomm_listen_unix_sock(apps_sock); if (ret < 0) { goto error_listen; @@ -1557,59 +1491,110 @@ error_create_poll: */ static int spawn_consumer_thread(struct consumer_data *consumer_data) { - int ret; + int ret, clock_ret; struct timespec timeout; - timeout.tv_sec = DEFAULT_SEM_WAIT_TIMEOUT; - timeout.tv_nsec = 0; + /* Make sure we set the readiness flag to 0 because we are NOT ready */ + consumer_data->consumer_thread_is_ready = 0; - /* Setup semaphore */ - ret = sem_init(&consumer_data->sem, 0, 0); - if (ret < 0) { - PERROR("sem_init consumer semaphore"); + /* Setup pthread condition */ + ret = pthread_condattr_init(&consumer_data->condattr); + if (ret != 0) { + errno = ret; + PERROR("pthread_condattr_init consumer data"); + goto error; + } + + /* + * Set the monotonic clock in order to make sure we DO NOT jump in time + * between the clock_gettime() call and the timedwait call. See bug #324 + * for a more details and how we noticed it. + */ + ret = pthread_condattr_setclock(&consumer_data->condattr, CLOCK_MONOTONIC); + if (ret != 0) { + errno = ret; + PERROR("pthread_condattr_setclock consumer data"); + goto error; + } + + ret = pthread_cond_init(&consumer_data->cond, &consumer_data->condattr); + if (ret != 0) { + errno = ret; + PERROR("pthread_cond_init consumer data"); goto error; } - ret = pthread_create(&consumer_data->thread, NULL, - thread_manage_consumer, consumer_data); + ret = pthread_create(&consumer_data->thread, NULL, thread_manage_consumer, + consumer_data); if (ret != 0) { PERROR("pthread_create consumer"); ret = -1; goto error; } + /* We are about to wait on a pthread condition */ + pthread_mutex_lock(&consumer_data->cond_mutex); + /* Get time for sem_timedwait absolute timeout */ - ret = clock_gettime(CLOCK_REALTIME, &timeout); - if (ret < 0) { - PERROR("clock_gettime spawn consumer"); - /* Infinite wait for the kconsumerd thread to be ready */ - ret = sem_wait(&consumer_data->sem); - } else { - /* Normal timeout if the gettime was successful */ - timeout.tv_sec += DEFAULT_SEM_WAIT_TIMEOUT; - ret = sem_timedwait(&consumer_data->sem, &timeout); + clock_ret = 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 + * increment the timeout too many times. + */ + timeout.tv_sec += DEFAULT_SEM_WAIT_TIMEOUT; + + /* + * The following loop COULD be skipped in some conditions so this is why we + * set ret to 0 in order to make sure at least one round of the loop is + * done. + */ + ret = 0; + + /* + * Loop until the condition is reached or when a timeout is reached. Note + * that the pthread_cond_timedwait(P) man page specifies that EINTR can NOT + * be returned but the pthread_cond(3), from the glibc-doc, says that it is + * possible. This loop does not take any chances and works with both of + * them. + */ + while (!consumer_data->consumer_thread_is_ready && ret != ETIMEDOUT) { + if (clock_ret < 0) { + PERROR("clock_gettime spawn consumer"); + /* Infinite wait for the consumerd thread to be ready */ + ret = pthread_cond_wait(&consumer_data->cond, + &consumer_data->cond_mutex); + } else { + ret = pthread_cond_timedwait(&consumer_data->cond, + &consumer_data->cond_mutex, &timeout); + } } - if (ret < 0) { - if (errno == ETIMEDOUT) { + /* Release the pthread condition */ + pthread_mutex_unlock(&consumer_data->cond_mutex); + + if (ret != 0) { + errno = ret; + if (ret == ETIMEDOUT) { /* * Call has timed out so we kill the kconsumerd_thread and return * an error. */ - ERR("The consumer thread was never ready. Killing it"); + ERR("Condition timed out. The consumer thread was never ready." + " Killing it"); ret = pthread_cancel(consumer_data->thread); if (ret < 0) { PERROR("pthread_cancel consumer thread"); } } else { - PERROR("semaphore wait failed consumer thread"); + PERROR("pthread_cond_wait failed consumer thread"); } goto error; } pthread_mutex_lock(&consumer_data->pid_mutex); if (consumer_data->pid == 0) { - ERR("Kconsumerd did not start"); + ERR("Consumerd did not start"); pthread_mutex_unlock(&consumer_data->pid_mutex); goto error; } @@ -1861,2428 +1846,245 @@ static int check_consumer_health(void) } /* - * Check version of the lttng-modules. - */ -static int validate_lttng_modules_version(void) -{ - return kernel_validate_version(kernel_tracer_fd); -} - -/* - * Setup necessary data for kernel tracer action. - */ -static int init_kernel_tracer(void) -{ - int ret; - - /* Modprobe lttng kernel modules */ - ret = modprobe_lttng_control(); - if (ret < 0) { - goto error; - } - - /* Open debugfs lttng */ - kernel_tracer_fd = open(module_proc_lttng, O_RDWR); - if (kernel_tracer_fd < 0) { - DBG("Failed to open %s", module_proc_lttng); - ret = -1; - goto error_open; - } - - /* Validate kernel version */ - ret = validate_lttng_modules_version(); - if (ret < 0) { - goto error_version; - } - - ret = modprobe_lttng_data(); - if (ret < 0) { - goto error_modules; - } - - DBG("Kernel tracer fd %d", kernel_tracer_fd); - return 0; - -error_version: - modprobe_remove_lttng_control(); - ret = close(kernel_tracer_fd); - if (ret) { - PERROR("close"); - } - kernel_tracer_fd = -1; - return LTTCOMM_KERN_VERSION; - -error_modules: - ret = close(kernel_tracer_fd); - if (ret) { - PERROR("close"); - } - -error_open: - modprobe_remove_lttng_control(); - -error: - WARN("No kernel tracer available"); - kernel_tracer_fd = -1; - if (!is_root) { - return LTTCOMM_NEED_ROOT_SESSIOND; - } else { - return LTTCOMM_KERN_NA; - } -} - -/* - * Init tracing by creating trace directory and sending fds kernel consumer. - */ -static int init_kernel_tracing(struct ltt_kernel_session *session) -{ - int ret = 0; - struct lttng_ht_iter iter; - struct consumer_socket *socket; - - assert(session); - - if (session->consumer_fds_sent == 0 && session->consumer != NULL) { - cds_lfht_for_each_entry(session->consumer->socks->ht, &iter.iter, - socket, node.node) { - /* Code flow error */ - assert(socket->fd >= 0); - - pthread_mutex_lock(socket->lock); - ret = kernel_consumer_send_session(socket->fd, session); - pthread_mutex_unlock(socket->lock); - if (ret < 0) { - ret = LTTCOMM_KERN_CONSUMER_FAIL; - goto error; - } - } - } - -error: - return ret; -} - -/* - * Create a socket to the relayd using the URI. - * - * On success, the relayd_sock pointer is set to the created socket. - * Else, it is untouched and an lttcomm error code is returned. - */ -static int create_connect_relayd(struct consumer_output *output, - const char *session_name, struct lttng_uri *uri, - struct lttcomm_sock **relayd_sock) -{ - int ret; - struct lttcomm_sock *sock; - - /* Create socket object from URI */ - sock = lttcomm_alloc_sock_from_uri(uri); - if (sock == NULL) { - ret = LTTCOMM_FATAL; - goto error; - } - - ret = lttcomm_create_sock(sock); - if (ret < 0) { - ret = LTTCOMM_FATAL; - goto error; - } - - /* Connect to relayd so we can proceed with a session creation. */ - ret = relayd_connect(sock); - if (ret < 0) { - ERR("Unable to reach lttng-relayd"); - ret = LTTCOMM_RELAYD_SESSION_FAIL; - goto free_sock; - } - - /* Create socket for control stream. */ - if (uri->stype == LTTNG_STREAM_CONTROL) { - DBG3("Creating relayd stream socket from URI"); - - /* Check relayd version */ - ret = relayd_version_check(sock, LTTNG_UST_COMM_MAJOR, 0); - if (ret < 0) { - ret = LTTCOMM_RELAYD_VERSION_FAIL; - goto close_sock; - } - } else if (uri->stype == LTTNG_STREAM_DATA) { - DBG3("Creating relayd data socket from URI"); - } else { - /* Command is not valid */ - ERR("Relayd invalid stream type: %d", uri->stype); - ret = LTTCOMM_INVALID; - goto close_sock; - } - - *relayd_sock = sock; - - return LTTCOMM_OK; - -close_sock: - if (sock) { - (void) relayd_close(sock); - } -free_sock: - if (sock) { - lttcomm_destroy_sock(sock); - } -error: - return ret; -} - -/* - * Connect to the relayd using URI and send the socket to the right consumer. - */ -static int send_socket_relayd_consumer(int domain, struct ltt_session *session, - struct lttng_uri *relayd_uri, struct consumer_output *consumer, - int consumer_fd) -{ - int ret; - struct lttcomm_sock *sock = NULL; - - /* Set the network sequence index if not set. */ - if (consumer->net_seq_index == -1) { - /* - * Increment net_seq_idx because we are about to transfer the - * new relayd socket to the consumer. - */ - uatomic_inc(&relayd_net_seq_idx); - /* Assign unique key so the consumer can match streams */ - consumer->net_seq_index = uatomic_read(&relayd_net_seq_idx); - } - - /* Connect to relayd and make version check if uri is the control. */ - ret = create_connect_relayd(consumer, session->name, relayd_uri, &sock); - if (ret != LTTCOMM_OK) { - goto close_sock; - } - - /* If the control socket is connected, network session is ready */ - if (relayd_uri->stype == LTTNG_STREAM_CONTROL) { - session->net_handle = 1; - } - - /* Send relayd socket to consumer. */ - ret = consumer_send_relayd_socket(consumer_fd, sock, - consumer, relayd_uri->stype); - if (ret < 0) { - ret = LTTCOMM_ENABLE_CONSUMER_FAIL; - goto close_sock; - } - - ret = LTTCOMM_OK; - - /* - * Close socket which was dup on the consumer side. The session daemon does - * NOT keep track of the relayd socket(s) once transfer to the consumer. - */ - -close_sock: - if (sock) { - (void) relayd_close(sock); - lttcomm_destroy_sock(sock); - } - - return ret; -} - -/* - * Send both relayd sockets to a specific consumer and domain. This is a - * helper function to facilitate sending the information to the consumer for a - * session. - */ -static int send_sockets_relayd_consumer(int domain, - struct ltt_session *session, struct consumer_output *consumer, int fd) -{ - int ret; - - assert(session); - assert(consumer); - - /* Don't resend the sockets to the consumer. */ - if (consumer->dst.net.relayd_socks_sent) { - ret = LTTCOMM_OK; - goto error; - } - - /* Sending control relayd socket. */ - ret = send_socket_relayd_consumer(domain, session, - &consumer->dst.net.control, consumer, fd); - if (ret != LTTCOMM_OK) { - goto error; - } - - /* Sending data relayd socket. */ - ret = send_socket_relayd_consumer(domain, session, - &consumer->dst.net.data, consumer, fd); - if (ret != LTTCOMM_OK) { - goto error; - } - - /* Flag that all relayd sockets were sent to the consumer. */ - consumer->dst.net.relayd_socks_sent = 1; - -error: - return ret; -} - -/* - * Setup relayd connections for a tracing session. First creates the socket to - * the relayd and send them to the right domain consumer. Consumer type MUST be - * network. - */ -static int setup_relayd(struct ltt_session *session) -{ - int ret = LTTCOMM_OK; - struct ltt_ust_session *usess; - struct ltt_kernel_session *ksess; - struct consumer_socket *socket; - struct lttng_ht_iter iter; - - assert(session); - - usess = session->ust_session; - ksess = session->kernel_session; - - DBG2("Setting relayd for session %s", session->name); - - if (usess && usess->consumer && usess->consumer->type == CONSUMER_DST_NET - && usess->consumer->enabled) { - /* For each consumer socket, send relayd sockets */ - cds_lfht_for_each_entry(usess->consumer->socks->ht, &iter.iter, - socket, node.node) { - /* Code flow error */ - assert(socket->fd >= 0); - - pthread_mutex_lock(socket->lock); - send_sockets_relayd_consumer(LTTNG_DOMAIN_UST, session, - usess->consumer, socket->fd); - pthread_mutex_unlock(socket->lock); - if (ret != LTTCOMM_OK) { - goto error; - } - } - } - - if (ksess && ksess->consumer && ksess->consumer->type == CONSUMER_DST_NET - && ksess->consumer->enabled) { - cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter, - socket, node.node) { - /* Code flow error */ - assert(socket->fd >= 0); - - pthread_mutex_lock(socket->lock); - send_sockets_relayd_consumer(LTTNG_DOMAIN_KERNEL, session, - ksess->consumer, socket->fd); - pthread_mutex_unlock(socket->lock); - if (ret != LTTCOMM_OK) { - goto error; - } - } - } - -error: - return ret; -} - -/* - * Set consumer subdirectory using the session name and a generated datetime if - * needed. This is appended to the current subdirectory. - */ -static int set_consumer_subdir(struct consumer_output *consumer, - const char *session_name) -{ - int ret = 0; - unsigned int have_default_name = 0; - char datetime[16], tmp_path[PATH_MAX]; - time_t rawtime; - struct tm *timeinfo; - - assert(consumer); - assert(session_name); - - memset(tmp_path, 0, sizeof(tmp_path)); - - /* Flag if we have a default session. */ - if (strncmp(session_name, DEFAULT_SESSION_NAME "-", - strlen(DEFAULT_SESSION_NAME) + 1) == 0) { - have_default_name = 1; - } else { - /* Get date and time for session path */ - time(&rawtime); - timeinfo = localtime(&rawtime); - strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo); - } - - if (have_default_name) { - ret = snprintf(tmp_path, sizeof(tmp_path), - "%s/%s", consumer->subdir, session_name); - } else { - ret = snprintf(tmp_path, sizeof(tmp_path), - "%s/%s-%s/", consumer->subdir, session_name, datetime); - } - if (ret < 0) { - PERROR("snprintf session name date"); - goto error; - } - - strncpy(consumer->subdir, tmp_path, sizeof(consumer->subdir)); - DBG2("Consumer subdir set to %s", consumer->subdir); - -error: - return ret; -} - -/* - * Copy consumer output from the tracing session to the domain session. The - * function also applies the right modification on a per domain basis for the - * trace files destination directory. - */ -static int copy_session_consumer(int domain, struct ltt_session *session) -{ - int ret; - const char *dir_name; - struct consumer_output *consumer; - - assert(session); - assert(session->consumer); - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - DBG3("Copying tracing session consumer output in kernel session"); - session->kernel_session->consumer = - consumer_copy_output(session->consumer); - /* Ease our life a bit for the next part */ - consumer = session->kernel_session->consumer; - dir_name = DEFAULT_KERNEL_TRACE_DIR; - break; - case LTTNG_DOMAIN_UST: - DBG3("Copying tracing session consumer output in UST session"); - session->ust_session->consumer = - consumer_copy_output(session->consumer); - /* Ease our life a bit for the next part */ - consumer = session->ust_session->consumer; - dir_name = DEFAULT_UST_TRACE_DIR; - break; - default: - ret = LTTCOMM_UNKNOWN_DOMAIN; - goto error; - } - - ret = set_consumer_subdir(session->consumer, session->name); - if (ret < 0) { - ret = LTTCOMM_FATAL; - goto error; - } - - /* Append correct directory to subdir */ - strncat(consumer->subdir, dir_name, sizeof(consumer->subdir)); - DBG3("Copy session consumer subdir %s", consumer->subdir); - - ret = LTTCOMM_OK; - -error: - return ret; -} - -/* - * Create an UST session and add it to the session ust list. - */ -static int create_ust_session(struct ltt_session *session, - struct lttng_domain *domain) -{ - int ret; - struct ltt_ust_session *lus = NULL; - - assert(session); - assert(domain); - assert(session->consumer); - - switch (domain->type) { - case LTTNG_DOMAIN_UST: - break; - default: - ERR("Unknown UST domain on create session %d", domain->type); - ret = LTTCOMM_UNKNOWN_DOMAIN; - goto error; - } - - DBG("Creating UST session"); - - lus = trace_ust_create_session(session->path, session->id, domain); - if (lus == NULL) { - ret = LTTCOMM_UST_SESS_FAIL; - goto error; - } - - lus->uid = session->uid; - lus->gid = session->gid; - session->ust_session = lus; - - /* Copy session output to the newly created UST session */ - ret = copy_session_consumer(domain->type, session); - if (ret != LTTCOMM_OK) { - goto error; - } - - return LTTCOMM_OK; - -error: - free(lus); - session->ust_session = NULL; - return ret; -} - -/* - * Create a kernel tracer session then create the default channel. - */ -static int create_kernel_session(struct ltt_session *session) -{ - int ret; - - DBG("Creating kernel session"); - - ret = kernel_create_session(session, kernel_tracer_fd); - if (ret < 0) { - ret = LTTCOMM_KERN_SESS_FAIL; - goto error; - } - - /* Code flow safety */ - assert(session->kernel_session); - - /* Copy session output to the newly created Kernel session */ - ret = copy_session_consumer(LTTNG_DOMAIN_KERNEL, session); - if (ret != LTTCOMM_OK) { - 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 (ret != -EEXIST) { - ERR("Trace directory creation error"); - goto error; - } - } - } - - session->kernel_session->uid = session->uid; - session->kernel_session->gid = session->gid; - - return LTTCOMM_OK; - -error: - trace_kernel_destroy_session(session->kernel_session); - session->kernel_session = NULL; - return ret; -} - -/* - * Check if the UID or GID match the session. Root user has access to all - * sessions. - */ -static int session_access_ok(struct ltt_session *session, uid_t uid, gid_t gid) -{ - if (uid != session->uid && gid != session->gid && uid != 0) { - return 0; - } else { - return 1; - } -} - -/* - * Count number of session permitted by uid/gid. - */ -static unsigned int lttng_sessions_count(uid_t uid, gid_t gid) -{ - unsigned int i = 0; - struct ltt_session *session; - - DBG("Counting number of available session for UID %d GID %d", - uid, gid); - cds_list_for_each_entry(session, &session_list_ptr->head, list) { - /* - * Only list the sessions the user can control. - */ - if (!session_access_ok(session, uid, gid)) { - continue; - } - i++; - } - return i; -} - -/* - * Using the session list, filled a lttng_session array to send back to the - * client for session listing. - * - * The session list lock MUST be acquired before calling this function. Use - * session_lock_list() and session_unlock_list(). - */ -static void list_lttng_sessions(struct lttng_session *sessions, uid_t uid, - gid_t gid) -{ - unsigned int i = 0; - struct ltt_session *session; - - DBG("Getting all available session for UID %d GID %d", - uid, gid); - /* - * Iterate over session list and append data after the control struct in - * the buffer. - */ - cds_list_for_each_entry(session, &session_list_ptr->head, list) { - /* - * Only list the sessions the user can control. - */ - if (!session_access_ok(session, uid, gid)) { - continue; - } - strncpy(sessions[i].path, session->path, PATH_MAX); - sessions[i].path[PATH_MAX - 1] = '\0'; - strncpy(sessions[i].name, session->name, NAME_MAX); - sessions[i].name[NAME_MAX - 1] = '\0'; - sessions[i].enabled = session->enabled; - i++; - } -} - -/* - * Fill lttng_channel array of all channels. - */ -static void list_lttng_channels(int domain, struct ltt_session *session, - struct lttng_channel *channels) -{ - int i = 0; - struct ltt_kernel_channel *kchan; - - DBG("Listing channels for session %s", session->name); - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - /* Kernel channels */ - if (session->kernel_session != NULL) { - cds_list_for_each_entry(kchan, - &session->kernel_session->channel_list.head, list) { - /* Copy lttng_channel struct to array */ - memcpy(&channels[i], kchan->channel, sizeof(struct lttng_channel)); - channels[i].enabled = kchan->enabled; - i++; - } - } - break; - case LTTNG_DOMAIN_UST: - { - struct lttng_ht_iter iter; - struct ltt_ust_channel *uchan; - - cds_lfht_for_each_entry(session->ust_session->domain_global.channels->ht, - &iter.iter, uchan, node.node) { - strncpy(channels[i].name, uchan->name, LTTNG_SYMBOL_NAME_LEN); - channels[i].attr.overwrite = uchan->attr.overwrite; - channels[i].attr.subbuf_size = uchan->attr.subbuf_size; - channels[i].attr.num_subbuf = uchan->attr.num_subbuf; - channels[i].attr.switch_timer_interval = - uchan->attr.switch_timer_interval; - channels[i].attr.read_timer_interval = - uchan->attr.read_timer_interval; - channels[i].enabled = uchan->enabled; - switch (uchan->attr.output) { - case LTTNG_UST_MMAP: - default: - channels[i].attr.output = LTTNG_EVENT_MMAP; - break; - } - i++; - } - break; - } - default: - break; - } -} - -/* - * Create a list of ust global domain events. - */ -static int list_lttng_ust_global_events(char *channel_name, - struct ltt_ust_domain_global *ust_global, struct lttng_event **events) -{ - int i = 0, ret = 0; - unsigned int nb_event = 0; - struct lttng_ht_iter iter; - struct lttng_ht_node_str *node; - struct ltt_ust_channel *uchan; - struct ltt_ust_event *uevent; - struct lttng_event *tmp; - - DBG("Listing UST global events for channel %s", channel_name); - - rcu_read_lock(); - - lttng_ht_lookup(ust_global->channels, (void *)channel_name, &iter); - node = lttng_ht_iter_get_node_str(&iter); - if (node == NULL) { - ret = -LTTCOMM_UST_CHAN_NOT_FOUND; - goto error; - } - - uchan = caa_container_of(&node->node, struct ltt_ust_channel, node.node); - - nb_event += lttng_ht_get_count(uchan->events); - - if (nb_event == 0) { - ret = nb_event; - goto error; - } - - DBG3("Listing UST global %d events", nb_event); - - tmp = zmalloc(nb_event * sizeof(struct lttng_event)); - if (tmp == NULL) { - ret = -LTTCOMM_FATAL; - goto error; - } - - cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent, node.node) { - strncpy(tmp[i].name, uevent->attr.name, LTTNG_SYMBOL_NAME_LEN); - tmp[i].name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; - tmp[i].enabled = uevent->enabled; - switch (uevent->attr.instrumentation) { - case LTTNG_UST_TRACEPOINT: - tmp[i].type = LTTNG_EVENT_TRACEPOINT; - break; - case LTTNG_UST_PROBE: - tmp[i].type = LTTNG_EVENT_PROBE; - break; - case LTTNG_UST_FUNCTION: - tmp[i].type = LTTNG_EVENT_FUNCTION; - break; - } - tmp[i].loglevel = uevent->attr.loglevel; - switch (uevent->attr.loglevel_type) { - case LTTNG_UST_LOGLEVEL_ALL: - tmp[i].loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; - break; - case LTTNG_UST_LOGLEVEL_RANGE: - tmp[i].loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE; - break; - case LTTNG_UST_LOGLEVEL_SINGLE: - tmp[i].loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE; - break; - } - if (uevent->filter) { - tmp[i].filter = 1; - } - i++; - } - - ret = nb_event; - *events = tmp; - -error: - rcu_read_unlock(); - return ret; -} - -/* - * Fill lttng_event array of all kernel events in the channel. - */ -static int list_lttng_kernel_events(char *channel_name, - struct ltt_kernel_session *kernel_session, struct lttng_event **events) -{ - int i = 0, ret; - unsigned int nb_event; - struct ltt_kernel_event *event; - struct ltt_kernel_channel *kchan; - - kchan = trace_kernel_get_channel_by_name(channel_name, kernel_session); - if (kchan == NULL) { - ret = LTTCOMM_KERN_CHAN_NOT_FOUND; - goto error; - } - - nb_event = kchan->event_count; - - DBG("Listing events for channel %s", kchan->channel->name); - - if (nb_event == 0) { - ret = nb_event; - goto error; - } - - *events = zmalloc(nb_event * sizeof(struct lttng_event)); - if (*events == NULL) { - ret = LTTCOMM_FATAL; - goto error; - } - - /* Kernel channels */ - cds_list_for_each_entry(event, &kchan->events_list.head , list) { - strncpy((*events)[i].name, event->event->name, LTTNG_SYMBOL_NAME_LEN); - (*events)[i].name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; - (*events)[i].enabled = event->enabled; - switch (event->event->instrumentation) { - case LTTNG_KERNEL_TRACEPOINT: - (*events)[i].type = LTTNG_EVENT_TRACEPOINT; - break; - case LTTNG_KERNEL_KPROBE: - case LTTNG_KERNEL_KRETPROBE: - (*events)[i].type = LTTNG_EVENT_PROBE; - memcpy(&(*events)[i].attr.probe, &event->event->u.kprobe, - sizeof(struct lttng_kernel_kprobe)); - break; - case LTTNG_KERNEL_FUNCTION: - (*events)[i].type = LTTNG_EVENT_FUNCTION; - memcpy(&((*events)[i].attr.ftrace), &event->event->u.ftrace, - sizeof(struct lttng_kernel_function)); - break; - case LTTNG_KERNEL_NOOP: - (*events)[i].type = LTTNG_EVENT_NOOP; - break; - case LTTNG_KERNEL_SYSCALL: - (*events)[i].type = LTTNG_EVENT_SYSCALL; - break; - case LTTNG_KERNEL_ALL: - assert(0); - break; - } - i++; - } - - return nb_event; - -error: - return ret; -} - - -/* - * Add URI so the consumer output object. Set the correct path depending on the - * domain adding the default trace directory. - */ -static int add_uri_to_consumer(struct consumer_output *consumer, - struct lttng_uri *uri, int domain, const char *session_name) -{ - int ret = LTTCOMM_OK; - const char *default_trace_dir; - - assert(uri); - - if (consumer == NULL) { - DBG("No consumer detected. Don't add URI. Stopping."); - ret = LTTCOMM_NO_CONSUMER; - goto error; - } - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - default_trace_dir = DEFAULT_KERNEL_TRACE_DIR; - break; - case LTTNG_DOMAIN_UST: - default_trace_dir = DEFAULT_UST_TRACE_DIR; - break; - default: - /* - * This case is possible is we try to add the URI to the global tracing - * session consumer object which in this case there is no subdir. - */ - default_trace_dir = ""; - } - - switch (uri->dtype) { - case LTTNG_DST_IPV4: - case LTTNG_DST_IPV6: - DBG2("Setting network URI to consumer"); - - /* Set URI into consumer output object */ - ret = consumer_set_network_uri(consumer, uri); - if (ret < 0) { - ret = LTTCOMM_FATAL; - goto error; - } - - if (uri->stype == LTTNG_STREAM_CONTROL && strlen(uri->subdir) == 0) { - ret = set_consumer_subdir(consumer, session_name); - if (ret < 0) { - ret = LTTCOMM_FATAL; - goto error; - } - } - - if (uri->stype == LTTNG_STREAM_CONTROL) { - /* On a new subdir, reappend the default trace dir. */ - strncat(consumer->subdir, default_trace_dir, sizeof(consumer->subdir)); - DBG3("Append domain trace name to subdir %s", consumer->subdir); - } - - break; - case LTTNG_DST_PATH: - DBG2("Setting trace directory path from URI to %s", uri->dst.path); - memset(consumer->dst.trace_path, 0, - sizeof(consumer->dst.trace_path)); - strncpy(consumer->dst.trace_path, uri->dst.path, - sizeof(consumer->dst.trace_path)); - /* Append default trace dir */ - strncat(consumer->dst.trace_path, default_trace_dir, - sizeof(consumer->dst.trace_path)); - /* Flag consumer as local. */ - consumer->type = CONSUMER_DST_LOCAL; - break; - } - -error: - return ret; -} - -/* - * Command LTTNG_DISABLE_CHANNEL processed by the client thread. - */ -static int cmd_disable_channel(struct ltt_session *session, - int domain, char *channel_name) -{ - int ret; - struct ltt_ust_session *usess; - - usess = session->ust_session; - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - { - ret = channel_kernel_disable(session->kernel_session, - channel_name); - if (ret != LTTCOMM_OK) { - goto error; - } - - kernel_wait_quiescent(kernel_tracer_fd); - break; - } - case LTTNG_DOMAIN_UST: - { - struct ltt_ust_channel *uchan; - struct lttng_ht *chan_ht; - - chan_ht = usess->domain_global.channels; - - uchan = trace_ust_find_channel_by_name(chan_ht, channel_name); - if (uchan == NULL) { - ret = LTTCOMM_UST_CHAN_NOT_FOUND; - goto error; - } - - ret = channel_ust_disable(usess, domain, uchan); - if (ret != LTTCOMM_OK) { - goto error; - } - break; - } -#if 0 - case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: - case LTTNG_DOMAIN_UST_EXEC_NAME: - case LTTNG_DOMAIN_UST_PID: -#endif - default: - ret = LTTCOMM_UNKNOWN_DOMAIN; - goto error; - } - - ret = LTTCOMM_OK; - -error: - return ret; -} - -/* - * Command LTTNG_ENABLE_CHANNEL processed by the client thread. - */ -static int cmd_enable_channel(struct ltt_session *session, - int domain, struct lttng_channel *attr) -{ - int ret; - struct ltt_ust_session *usess = session->ust_session; - struct lttng_ht *chan_ht; - - DBG("Enabling channel %s for session %s", attr->name, session->name); - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - { - struct ltt_kernel_channel *kchan; - - kchan = trace_kernel_get_channel_by_name(attr->name, - session->kernel_session); - if (kchan == NULL) { - ret = channel_kernel_create(session->kernel_session, - attr, kernel_poll_pipe[1]); - } else { - ret = channel_kernel_enable(session->kernel_session, kchan); - } - - if (ret != LTTCOMM_OK) { - goto error; - } - - kernel_wait_quiescent(kernel_tracer_fd); - break; - } - case LTTNG_DOMAIN_UST: - { - struct ltt_ust_channel *uchan; - - chan_ht = usess->domain_global.channels; - - uchan = trace_ust_find_channel_by_name(chan_ht, attr->name); - if (uchan == NULL) { - ret = channel_ust_create(usess, domain, attr); - } else { - ret = channel_ust_enable(usess, domain, uchan); - } - break; - } -#if 0 - case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: - case LTTNG_DOMAIN_UST_EXEC_NAME: - case LTTNG_DOMAIN_UST_PID: -#endif - default: - ret = LTTCOMM_UNKNOWN_DOMAIN; - goto error; - } - -error: - return ret; -} - -/* - * Command LTTNG_DISABLE_EVENT processed by the client thread. - */ -static int cmd_disable_event(struct ltt_session *session, int domain, - char *channel_name, char *event_name) -{ - int ret; - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - { - struct ltt_kernel_channel *kchan; - struct ltt_kernel_session *ksess; - - ksess = session->kernel_session; - - kchan = trace_kernel_get_channel_by_name(channel_name, ksess); - if (kchan == NULL) { - ret = LTTCOMM_KERN_CHAN_NOT_FOUND; - goto error; - } - - ret = event_kernel_disable_tracepoint(ksess, kchan, event_name); - if (ret != LTTCOMM_OK) { - goto error; - } - - kernel_wait_quiescent(kernel_tracer_fd); - break; - } - case LTTNG_DOMAIN_UST: - { - struct ltt_ust_channel *uchan; - struct ltt_ust_session *usess; - - usess = session->ust_session; - - uchan = trace_ust_find_channel_by_name(usess->domain_global.channels, - channel_name); - if (uchan == NULL) { - ret = LTTCOMM_UST_CHAN_NOT_FOUND; - goto error; - } - - ret = event_ust_disable_tracepoint(usess, domain, uchan, event_name); - if (ret != LTTCOMM_OK) { - goto error; - } - - DBG3("Disable UST event %s in channel %s completed", event_name, - channel_name); - break; - } -#if 0 - case LTTNG_DOMAIN_UST_EXEC_NAME: - case LTTNG_DOMAIN_UST_PID: - case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: -#endif - default: - ret = LTTCOMM_UND; - goto error; - } - - ret = LTTCOMM_OK; - -error: - return ret; -} - -/* - * Command LTTNG_DISABLE_ALL_EVENT processed by the client thread. - */ -static int cmd_disable_event_all(struct ltt_session *session, int domain, - char *channel_name) -{ - int ret; - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - { - struct ltt_kernel_session *ksess; - struct ltt_kernel_channel *kchan; - - ksess = session->kernel_session; - - kchan = trace_kernel_get_channel_by_name(channel_name, ksess); - if (kchan == NULL) { - ret = LTTCOMM_KERN_CHAN_NOT_FOUND; - goto error; - } - - ret = event_kernel_disable_all(ksess, kchan); - if (ret != LTTCOMM_OK) { - goto error; - } - - kernel_wait_quiescent(kernel_tracer_fd); - break; - } - case LTTNG_DOMAIN_UST: - { - struct ltt_ust_session *usess; - struct ltt_ust_channel *uchan; - - usess = session->ust_session; - - uchan = trace_ust_find_channel_by_name(usess->domain_global.channels, - channel_name); - if (uchan == NULL) { - ret = LTTCOMM_UST_CHAN_NOT_FOUND; - goto error; - } - - ret = event_ust_disable_all_tracepoints(usess, domain, uchan); - if (ret != 0) { - goto error; - } - - DBG3("Disable all UST events in channel %s completed", channel_name); - - break; - } -#if 0 - case LTTNG_DOMAIN_UST_EXEC_NAME: - case LTTNG_DOMAIN_UST_PID: - case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: -#endif - default: - ret = LTTCOMM_UND; - goto error; - } - - ret = LTTCOMM_OK; - -error: - return ret; -} - -/* - * Command LTTNG_ADD_CONTEXT processed by the client thread. - */ -static int cmd_add_context(struct ltt_session *session, int domain, - char *channel_name, char *event_name, struct lttng_event_context *ctx) -{ - int ret; - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - /* Add kernel context to kernel tracer */ - ret = context_kernel_add(session->kernel_session, ctx, - event_name, channel_name); - if (ret != LTTCOMM_OK) { - goto error; - } - break; - case LTTNG_DOMAIN_UST: - { - struct ltt_ust_session *usess = session->ust_session; - - ret = context_ust_add(usess, domain, ctx, event_name, channel_name); - if (ret != LTTCOMM_OK) { - goto error; - } - break; - } -#if 0 - case LTTNG_DOMAIN_UST_EXEC_NAME: - case LTTNG_DOMAIN_UST_PID: - case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: -#endif - default: - ret = LTTCOMM_UND; - goto error; - } - - ret = LTTCOMM_OK; - -error: - return ret; -} - -/* - * Command LTTNG_SET_FILTER processed by the client thread. - */ -static int cmd_set_filter(struct ltt_session *session, int domain, - char *channel_name, char *event_name, - struct lttng_filter_bytecode *bytecode) -{ - int ret; - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - ret = LTTCOMM_FATAL; - break; - case LTTNG_DOMAIN_UST: - { - struct ltt_ust_session *usess = session->ust_session; - - ret = filter_ust_set(usess, domain, bytecode, event_name, channel_name); - if (ret != LTTCOMM_OK) { - goto error; - } - break; - } -#if 0 - case LTTNG_DOMAIN_UST_EXEC_NAME: - case LTTNG_DOMAIN_UST_PID: - case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: -#endif - default: - ret = LTTCOMM_UND; - goto error; - } - - ret = LTTCOMM_OK; - -error: - return ret; - -} - -/* - * Command LTTNG_ENABLE_EVENT processed by the client thread. - */ -static int cmd_enable_event(struct ltt_session *session, int domain, - char *channel_name, struct lttng_event *event) -{ - int ret; - struct lttng_channel *attr; - struct ltt_ust_session *usess = session->ust_session; - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - { - struct ltt_kernel_channel *kchan; - - kchan = trace_kernel_get_channel_by_name(channel_name, - session->kernel_session); - if (kchan == NULL) { - attr = channel_new_default_attr(domain); - if (attr == NULL) { - ret = LTTCOMM_FATAL; - goto error; - } - snprintf(attr->name, NAME_MAX, "%s", channel_name); - - /* This call will notify the kernel thread */ - ret = channel_kernel_create(session->kernel_session, - attr, kernel_poll_pipe[1]); - if (ret != LTTCOMM_OK) { - free(attr); - goto error; - } - free(attr); - } - - /* Get the newly created kernel channel pointer */ - kchan = trace_kernel_get_channel_by_name(channel_name, - session->kernel_session); - if (kchan == NULL) { - /* This sould not happen... */ - ret = LTTCOMM_FATAL; - goto error; - } - - ret = event_kernel_enable_tracepoint(session->kernel_session, kchan, - event); - if (ret != LTTCOMM_OK) { - goto error; - } - - kernel_wait_quiescent(kernel_tracer_fd); - break; - } - case LTTNG_DOMAIN_UST: - { - struct lttng_channel *attr; - struct ltt_ust_channel *uchan; - - /* Get channel from global UST domain */ - uchan = trace_ust_find_channel_by_name(usess->domain_global.channels, - channel_name); - if (uchan == NULL) { - /* Create default channel */ - attr = channel_new_default_attr(domain); - if (attr == NULL) { - ret = LTTCOMM_FATAL; - goto error; - } - snprintf(attr->name, NAME_MAX, "%s", channel_name); - attr->name[NAME_MAX - 1] = '\0'; - - ret = channel_ust_create(usess, domain, attr); - if (ret != LTTCOMM_OK) { - free(attr); - goto error; - } - free(attr); - - /* Get the newly created channel reference back */ - uchan = trace_ust_find_channel_by_name( - usess->domain_global.channels, channel_name); - if (uchan == NULL) { - /* Something is really wrong */ - ret = LTTCOMM_FATAL; - goto error; - } - } - - /* At this point, the session and channel exist on the tracer */ - ret = event_ust_enable_tracepoint(usess, domain, uchan, event); - if (ret != LTTCOMM_OK) { - goto error; - } - break; - } -#if 0 - case LTTNG_DOMAIN_UST_EXEC_NAME: - case LTTNG_DOMAIN_UST_PID: - case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: -#endif - default: - ret = LTTCOMM_UND; - goto error; - } - - ret = LTTCOMM_OK; - -error: - return ret; -} - -/* - * Command LTTNG_ENABLE_ALL_EVENT processed by the client thread. - */ -static int cmd_enable_event_all(struct ltt_session *session, int domain, - char *channel_name, int event_type) -{ - int ret; - struct ltt_kernel_channel *kchan; - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - kchan = trace_kernel_get_channel_by_name(channel_name, - session->kernel_session); - if (kchan == NULL) { - /* This call will notify the kernel thread */ - ret = channel_kernel_create(session->kernel_session, NULL, - kernel_poll_pipe[1]); - if (ret != LTTCOMM_OK) { - goto error; - } - - /* Get the newly created kernel channel pointer */ - kchan = trace_kernel_get_channel_by_name(channel_name, - session->kernel_session); - if (kchan == NULL) { - /* This sould not happen... */ - ret = LTTCOMM_FATAL; - goto error; - } - - } - - switch (event_type) { - case LTTNG_EVENT_SYSCALL: - ret = event_kernel_enable_all_syscalls(session->kernel_session, - kchan, kernel_tracer_fd); - break; - case LTTNG_EVENT_TRACEPOINT: - /* - * This call enables all LTTNG_KERNEL_TRACEPOINTS and - * events already registered to the channel. - */ - ret = event_kernel_enable_all_tracepoints(session->kernel_session, - kchan, kernel_tracer_fd); - break; - case LTTNG_EVENT_ALL: - /* Enable syscalls and tracepoints */ - ret = event_kernel_enable_all(session->kernel_session, - kchan, kernel_tracer_fd); - break; - default: - ret = LTTCOMM_KERN_ENABLE_FAIL; - goto error; - } - - /* Manage return value */ - if (ret != LTTCOMM_OK) { - goto error; - } - - kernel_wait_quiescent(kernel_tracer_fd); - break; - case LTTNG_DOMAIN_UST: - { - struct lttng_channel *attr; - struct ltt_ust_channel *uchan; - struct ltt_ust_session *usess = session->ust_session; - - /* Get channel from global UST domain */ - uchan = trace_ust_find_channel_by_name(usess->domain_global.channels, - channel_name); - if (uchan == NULL) { - /* Create default channel */ - attr = channel_new_default_attr(domain); - if (attr == NULL) { - ret = LTTCOMM_FATAL; - goto error; - } - snprintf(attr->name, NAME_MAX, "%s", channel_name); - attr->name[NAME_MAX - 1] = '\0'; - - /* Use the internal command enable channel */ - ret = channel_ust_create(usess, domain, attr); - if (ret != LTTCOMM_OK) { - free(attr); - goto error; - } - free(attr); - - /* Get the newly created channel reference back */ - uchan = trace_ust_find_channel_by_name( - usess->domain_global.channels, channel_name); - if (uchan == NULL) { - /* Something is really wrong */ - ret = LTTCOMM_FATAL; - goto error; - } - } - - /* At this point, the session and channel exist on the tracer */ - - switch (event_type) { - case LTTNG_EVENT_ALL: - case LTTNG_EVENT_TRACEPOINT: - ret = event_ust_enable_all_tracepoints(usess, domain, uchan); - if (ret != LTTCOMM_OK) { - goto error; - } - break; - default: - ret = LTTCOMM_UST_ENABLE_FAIL; - goto error; - } - - /* Manage return value */ - if (ret != LTTCOMM_OK) { - goto error; - } - - break; - } -#if 0 - case LTTNG_DOMAIN_UST_EXEC_NAME: - case LTTNG_DOMAIN_UST_PID: - case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: -#endif - default: - ret = LTTCOMM_UND; - goto error; - } - - ret = LTTCOMM_OK; - -error: - return ret; -} - -/* - * Command LTTNG_LIST_TRACEPOINTS processed by the client thread. - */ -static ssize_t cmd_list_tracepoints(int domain, struct lttng_event **events) -{ - int ret; - ssize_t nb_events = 0; - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - nb_events = kernel_list_events(kernel_tracer_fd, events); - if (nb_events < 0) { - ret = LTTCOMM_KERN_LIST_FAIL; - goto error; - } - break; - case LTTNG_DOMAIN_UST: - nb_events = ust_app_list_events(events); - if (nb_events < 0) { - ret = LTTCOMM_UST_LIST_FAIL; - goto error; - } - break; - default: - ret = LTTCOMM_UND; - goto error; - } - - return nb_events; - -error: - /* Return negative value to differentiate return code */ - return -ret; -} - -/* - * Command LTTNG_LIST_TRACEPOINT_FIELDS processed by the client thread. - */ -static ssize_t cmd_list_tracepoint_fields(int domain, - struct lttng_event_field **fields) -{ - int ret; - ssize_t nb_fields = 0; - - switch (domain) { - case LTTNG_DOMAIN_UST: - nb_fields = ust_app_list_event_fields(fields); - if (nb_fields < 0) { - ret = LTTCOMM_UST_LIST_FAIL; - goto error; - } - break; - case LTTNG_DOMAIN_KERNEL: - default: /* fall-through */ - ret = LTTCOMM_UND; - goto error; - } - - return nb_fields; - -error: - /* Return negative value to differentiate return code */ - return -ret; -} - -/* - * Command LTTNG_START_TRACE processed by the client thread. - */ -static int cmd_start_trace(struct ltt_session *session) -{ - int ret; - struct ltt_kernel_session *ksession; - struct ltt_ust_session *usess; - struct ltt_kernel_channel *kchan; - - /* Ease our life a bit ;) */ - ksession = session->kernel_session; - usess = session->ust_session; - - if (session->enabled) { - /* Already started. */ - ret = LTTCOMM_TRACE_ALREADY_STARTED; - goto error; - } - - session->enabled = 1; - - ret = setup_relayd(session); - if (ret != LTTCOMM_OK) { - ERR("Error setting up relayd for session %s", session->name); - goto error; - } - - /* Kernel tracing */ - if (ksession != NULL) { - /* Open kernel metadata */ - if (ksession->metadata == NULL) { - ret = kernel_open_metadata(ksession); - if (ret < 0) { - ret = LTTCOMM_KERN_META_FAIL; - goto error; - } - } - - /* Open kernel metadata stream */ - if (ksession->metadata_stream_fd < 0) { - ret = kernel_open_metadata_stream(ksession); - if (ret < 0) { - ERR("Kernel create metadata stream failed"); - ret = LTTCOMM_KERN_STREAM_FAIL; - goto error; - } - } - - /* For each channel */ - cds_list_for_each_entry(kchan, &ksession->channel_list.head, list) { - if (kchan->stream_count == 0) { - ret = kernel_open_channel_stream(kchan); - if (ret < 0) { - ret = LTTCOMM_KERN_STREAM_FAIL; - goto error; - } - /* Update the stream global counter */ - ksession->stream_count_global += ret; - } - } - - /* Setup kernel consumer socket and send fds to it */ - ret = init_kernel_tracing(ksession); - if (ret < 0) { - ret = LTTCOMM_KERN_START_FAIL; - goto error; - } - - /* This start the kernel tracing */ - ret = kernel_start_session(ksession); - if (ret < 0) { - ret = LTTCOMM_KERN_START_FAIL; - goto error; - } - - /* Quiescent wait after starting trace */ - kernel_wait_quiescent(kernel_tracer_fd); - } - - /* Flag session that trace should start automatically */ - if (usess) { - usess->start_trace = 1; - - ret = ust_app_start_trace_all(usess); - if (ret < 0) { - ret = LTTCOMM_UST_START_FAIL; - goto error; - } - } - - ret = LTTCOMM_OK; - -error: - return ret; -} - -/* - * Command LTTNG_STOP_TRACE processed by the client thread. - */ -static int cmd_stop_trace(struct ltt_session *session) -{ - int ret; - struct ltt_kernel_channel *kchan; - struct ltt_kernel_session *ksession; - struct ltt_ust_session *usess; - - /* Short cut */ - ksession = session->kernel_session; - usess = session->ust_session; - - if (!session->enabled) { - ret = LTTCOMM_TRACE_ALREADY_STOPPED; - goto error; - } - - session->enabled = 0; - - /* Kernel tracer */ - if (ksession != NULL) { - DBG("Stop kernel tracing"); - - /* Flush metadata if exist */ - if (ksession->metadata_stream_fd >= 0) { - ret = kernel_metadata_flush_buffer(ksession->metadata_stream_fd); - if (ret < 0) { - ERR("Kernel metadata flush failed"); - } - } - - /* Flush all buffers before stopping */ - cds_list_for_each_entry(kchan, &ksession->channel_list.head, list) { - ret = kernel_flush_buffer(kchan); - if (ret < 0) { - ERR("Kernel flush buffer error"); - } - } - - ret = kernel_stop_session(ksession); - if (ret < 0) { - ret = LTTCOMM_KERN_STOP_FAIL; - goto error; - } - - kernel_wait_quiescent(kernel_tracer_fd); - } - - if (usess) { - usess->start_trace = 0; - - ret = ust_app_stop_trace_all(usess); - if (ret < 0) { - ret = LTTCOMM_UST_STOP_FAIL; - goto error; - } - } - - ret = LTTCOMM_OK; - -error: - return ret; -} - -/* - * Command LTTNG_SET_CONSUMER_URI processed by the client thread. - */ -static int cmd_set_consumer_uri(int domain, struct ltt_session *session, - size_t nb_uri, struct lttng_uri *uris) -{ - int ret, i; - struct ltt_kernel_session *ksess = session->kernel_session; - struct ltt_ust_session *usess = session->ust_session; - struct consumer_output *consumer = NULL; - - assert(session); - assert(uris); - assert(nb_uri > 0); - - /* Can't enable consumer after session started. */ - if (session->enabled) { - ret = LTTCOMM_TRACE_ALREADY_STARTED; - goto error; - } - - if (!session->start_consumer) { - ret = LTTCOMM_NO_CONSUMER; - goto error; - } - - /* - * This case switch makes sure the domain session has a temporary consumer - * so the URL can be set. - */ - switch (domain) { - case 0: - /* Code flow error. A session MUST always have a consumer object */ - assert(session->consumer); - /* - * The URL will be added to the tracing session consumer instead of a - * specific domain consumer. - */ - consumer = session->consumer; - break; - case LTTNG_DOMAIN_KERNEL: - /* Code flow error if we don't have a kernel session here. */ - assert(ksess); - - /* Create consumer output if none exists */ - consumer = ksess->tmp_consumer; - if (consumer == NULL) { - consumer = consumer_copy_output(ksess->consumer); - if (consumer == NULL) { - ret = LTTCOMM_FATAL; - goto error; - } - /* Trash the consumer subdir, we are about to set a new one. */ - memset(consumer->subdir, 0, sizeof(consumer->subdir)); - ksess->tmp_consumer = consumer; - } - - break; - case LTTNG_DOMAIN_UST: - /* Code flow error if we don't have a kernel session here. */ - assert(usess); - - /* Create consumer output if none exists */ - consumer = usess->tmp_consumer; - if (consumer == NULL) { - consumer = consumer_copy_output(usess->consumer); - if (consumer == NULL) { - ret = LTTCOMM_FATAL; - goto error; - } - /* Trash the consumer subdir, we are about to set a new one. */ - memset(consumer->subdir, 0, sizeof(consumer->subdir)); - usess->tmp_consumer = consumer; - } - - break; - } - - for (i = 0; i < nb_uri; i++) { - struct consumer_socket *socket; - struct lttng_ht_iter iter; - - ret = add_uri_to_consumer(consumer, &uris[i], domain, session->name); - if (ret < 0) { - goto error; - } - - /* - * Don't send relayd socket if URI is NOT remote or if the relayd - * sockets for the session are already sent. - */ - if (uris[i].dtype == LTTNG_DST_PATH || - consumer->dst.net.relayd_socks_sent) { - continue; - } - - /* Try to send relayd URI to the consumer if exist. */ - cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter, - socket, node.node) { - - /* A socket in the HT should never have a negative fd */ - assert(socket->fd >= 0); - - pthread_mutex_lock(socket->lock); - ret = send_socket_relayd_consumer(domain, session, &uris[i], - consumer, socket->fd); - pthread_mutex_unlock(socket->lock); - if (ret != LTTCOMM_OK) { - goto error; - } - } - } - - /* All good! */ - ret = LTTCOMM_OK; - -error: - return ret; -} - - -/* - * Command LTTNG_CREATE_SESSION processed by the client thread. - */ -static int cmd_create_session_uri(char *name, struct lttng_uri *uris, - size_t nb_uri, lttng_sock_cred *creds) -{ - int ret; - char *path = NULL; - struct ltt_session *session; - //struct consumer_output *consumer = NULL; - //struct lttng_uri *ctrl_uri, *data_uri = NULL; - - assert(name); - - /* - * Verify if the session already exist - * - * XXX: There is no need for the session lock list here since the caller - * (process_client_msg) is holding it. We might want to change that so a - * single command does not lock the entire session list. - */ - session = session_find_by_name(name); - if (session != NULL) { - ret = LTTCOMM_EXIST_SESS; - goto find_error; - } - - /* Create tracing session in the registry */ - ret = session_create(name, path, LTTNG_SOCK_GET_UID_CRED(creds), - LTTNG_SOCK_GET_GID_CRED(creds)); - if (ret != LTTCOMM_OK) { - goto session_error; - } - - /* - * Get the newly created session pointer back - * - * XXX: There is no need for the session lock list here since the caller - * (process_client_msg) is holding it. We might want to change that so a - * single command does not lock the entire session list. - */ - session = session_find_by_name(name); - assert(session); - - /* Create default consumer output for the session not yet created. */ - session->consumer = consumer_create_output(CONSUMER_DST_LOCAL); - if (session->consumer == NULL) { - ret = LTTCOMM_FATAL; - goto consumer_error; - } - - /* - * This means that the lttng_create_session call was called with the _path_ - * argument set to NULL. - */ - if (uris == NULL) { - /* - * At this point, we'll skip the consumer URI setup and create a - * session with a NULL path which will flag the session to NOT spawn a - * consumer. - */ - DBG("Create session %s with NO uri, skipping consumer setup", name); - goto end; - } - - session->start_consumer = 1; - - ret = cmd_set_consumer_uri(0, session, nb_uri, uris); - if (ret != LTTCOMM_OK) { - goto consumer_error; - } - - session->consumer->enabled = 1; - -end: - return LTTCOMM_OK; - -consumer_error: - session_destroy(session); -session_error: -find_error: - return ret; -} - -/* - * Command LTTNG_DESTROY_SESSION processed by the client thread. - */ -static int cmd_destroy_session(struct ltt_session *session, char *name) -{ - int ret; - - /* Safety net */ - assert(session); - - /* Clean kernel session teardown */ - teardown_kernel_session(session); - /* UST session teardown */ - teardown_ust_session(session); - - /* - * Must notify the kernel thread here to update it's poll setin order - * to remove the channel(s)' fd just destroyed. - */ - ret = notify_thread_pipe(kernel_poll_pipe[1]); - if (ret < 0) { - PERROR("write kernel poll pipe"); - } - - ret = session_destroy(session); - - return ret; -} - -/* - * Command LTTNG_CALIBRATE processed by the client thread. - */ -static int cmd_calibrate(int domain, struct lttng_calibrate *calibrate) -{ - int ret; - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - { - struct lttng_kernel_calibrate kcalibrate; - - kcalibrate.type = calibrate->type; - ret = kernel_calibrate(kernel_tracer_fd, &kcalibrate); - if (ret < 0) { - ret = LTTCOMM_KERN_ENABLE_FAIL; - goto error; - } - break; - } - case LTTNG_DOMAIN_UST: - { - struct lttng_ust_calibrate ucalibrate; - - ucalibrate.type = calibrate->type; - ret = ust_app_calibrate_glb(&ucalibrate); - if (ret < 0) { - ret = LTTCOMM_UST_CALIBRATE_FAIL; - goto error; - } - break; - } - default: - ret = LTTCOMM_UND; - goto error; - } - - ret = LTTCOMM_OK; - -error: - return ret; -} - -/* - * Command LTTNG_REGISTER_CONSUMER processed by the client thread. - */ -static int cmd_register_consumer(struct ltt_session *session, int domain, - char *sock_path) -{ - int ret, sock; - struct consumer_socket *socket; - - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - /* Can't register a consumer if there is already one */ - if (session->kernel_session->consumer_fds_sent != 0) { - ret = LTTCOMM_KERN_CONSUMER_FAIL; - goto error; - } - - sock = lttcomm_connect_unix_sock(sock_path); - if (sock < 0) { - ret = LTTCOMM_CONNECT_FAIL; - goto error; - } - - socket = consumer_allocate_socket(sock); - if (socket == NULL) { - ret = LTTCOMM_FATAL; - close(sock); - goto error; - } - - socket->lock = zmalloc(sizeof(pthread_mutex_t)); - if (socket->lock == NULL) { - PERROR("zmalloc pthread mutex"); - ret = LTTCOMM_FATAL; - goto error; - } - pthread_mutex_init(socket->lock, NULL); - - rcu_read_lock(); - consumer_add_socket(socket, session->kernel_session->consumer); - rcu_read_unlock(); - - pthread_mutex_lock(&kconsumer_data.pid_mutex); - kconsumer_data.pid = -1; - pthread_mutex_unlock(&kconsumer_data.pid_mutex); - - break; - default: - /* TODO: Userspace tracing */ - ret = LTTCOMM_UND; - goto error; - } - - ret = LTTCOMM_OK; - -error: - return ret; -} - -/* - * Command LTTNG_LIST_DOMAINS processed by the client thread. - */ -static ssize_t cmd_list_domains(struct ltt_session *session, - struct lttng_domain **domains) -{ - int ret, index = 0; - ssize_t nb_dom = 0; - - if (session->kernel_session != NULL) { - DBG3("Listing domains found kernel domain"); - nb_dom++; - } - - if (session->ust_session != NULL) { - DBG3("Listing domains found UST global domain"); - nb_dom++; - } - - *domains = zmalloc(nb_dom * sizeof(struct lttng_domain)); - if (*domains == NULL) { - ret = -LTTCOMM_FATAL; - goto error; - } - - if (session->kernel_session != NULL) { - (*domains)[index].type = LTTNG_DOMAIN_KERNEL; - index++; - } - - if (session->ust_session != NULL) { - (*domains)[index].type = LTTNG_DOMAIN_UST; - index++; - } - - return nb_dom; - -error: - return ret; -} - -/* - * Command LTTNG_LIST_CHANNELS processed by the client thread. + * Setup necessary data for kernel tracer action. */ -static ssize_t cmd_list_channels(int domain, struct ltt_session *session, - struct lttng_channel **channels) +static int init_kernel_tracer(void) { int ret; - ssize_t nb_chan = 0; - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - if (session->kernel_session != NULL) { - nb_chan = session->kernel_session->channel_count; - } - DBG3("Number of kernel channels %zd", nb_chan); - break; - case LTTNG_DOMAIN_UST: - if (session->ust_session != NULL) { - nb_chan = lttng_ht_get_count( - session->ust_session->domain_global.channels); - } - DBG3("Number of UST global channels %zd", nb_chan); - break; - default: - *channels = NULL; - ret = -LTTCOMM_UND; + /* Modprobe lttng kernel modules */ + ret = modprobe_lttng_control(); + if (ret < 0) { goto error; } - if (nb_chan > 0) { - *channels = zmalloc(nb_chan * sizeof(struct lttng_channel)); - if (*channels == NULL) { - ret = -LTTCOMM_FATAL; - goto error; - } + /* Open debugfs lttng */ + kernel_tracer_fd = open(module_proc_lttng, O_RDWR); + if (kernel_tracer_fd < 0) { + DBG("Failed to open %s", module_proc_lttng); + ret = -1; + goto error_open; + } - list_lttng_channels(domain, session, *channels); - } else { - *channels = NULL; + /* Validate kernel version */ + ret = kernel_validate_version(kernel_tracer_fd); + if (ret < 0) { + goto error_version; + } + + ret = modprobe_lttng_data(); + if (ret < 0) { + goto error_modules; + } + + DBG("Kernel tracer fd %d", kernel_tracer_fd); + return 0; + +error_version: + modprobe_remove_lttng_control(); + ret = close(kernel_tracer_fd); + if (ret) { + PERROR("close"); + } + kernel_tracer_fd = -1; + return LTTNG_ERR_KERN_VERSION; + +error_modules: + ret = close(kernel_tracer_fd); + if (ret) { + PERROR("close"); } - return nb_chan; +error_open: + modprobe_remove_lttng_control(); error: - return ret; + WARN("No kernel tracer available"); + kernel_tracer_fd = -1; + if (!is_root) { + return LTTNG_ERR_NEED_ROOT_SESSIOND; + } else { + return LTTNG_ERR_KERN_NA; + } } + /* - * Command LTTNG_LIST_EVENTS processed by the client thread. + * Copy consumer output from the tracing session to the domain session. The + * function also applies the right modification on a per domain basis for the + * trace files destination directory. */ -static ssize_t cmd_list_events(int domain, struct ltt_session *session, - char *channel_name, struct lttng_event **events) +static int copy_session_consumer(int domain, struct ltt_session *session) { - int ret = 0; - ssize_t nb_event = 0; + int ret; + const char *dir_name; + struct consumer_output *consumer; + + assert(session); + assert(session->consumer); switch (domain) { case LTTNG_DOMAIN_KERNEL: - if (session->kernel_session != NULL) { - nb_event = list_lttng_kernel_events(channel_name, - session->kernel_session, events); + DBG3("Copying tracing session consumer output in kernel session"); + /* + * XXX: We should audit the session creation and what this function + * does "extra" in order to avoid a destroy since this function is used + * in the domain session creation (kernel and ust) only. Same for UST + * domain. + */ + if (session->kernel_session->consumer) { + consumer_destroy_output(session->kernel_session->consumer); } + session->kernel_session->consumer = + consumer_copy_output(session->consumer); + /* Ease our life a bit for the next part */ + consumer = session->kernel_session->consumer; + dir_name = DEFAULT_KERNEL_TRACE_DIR; break; case LTTNG_DOMAIN_UST: - { - if (session->ust_session != NULL) { - nb_event = list_lttng_ust_global_events(channel_name, - &session->ust_session->domain_global, events); + DBG3("Copying tracing session consumer output in UST session"); + if (session->ust_session->consumer) { + consumer_destroy_output(session->ust_session->consumer); } + session->ust_session->consumer = + consumer_copy_output(session->consumer); + /* Ease our life a bit for the next part */ + consumer = session->ust_session->consumer; + dir_name = DEFAULT_UST_TRACE_DIR; break; - } default: - ret = -LTTCOMM_UND; + ret = LTTNG_ERR_UNKNOWN_DOMAIN; goto error; } - ret = nb_event; + /* Append correct directory to subdir */ + strncat(consumer->subdir, dir_name, + sizeof(consumer->subdir) - strlen(consumer->subdir) - 1); + DBG3("Copy session consumer subdir %s", consumer->subdir); + + ret = LTTNG_OK; error: return ret; } /* - * Command LTTNG_DISABLE_CONSUMER processed by the client thread. + * Create an UST session and add it to the session ust list. */ -static int cmd_disable_consumer(int domain, struct ltt_session *session) +static int create_ust_session(struct ltt_session *session, + struct lttng_domain *domain) { int ret; - struct ltt_kernel_session *ksess = session->kernel_session; - struct ltt_ust_session *usess = session->ust_session; - struct consumer_output *consumer; + struct ltt_ust_session *lus = NULL; assert(session); + assert(domain); + assert(session->consumer); - if (session->enabled) { - /* Can't disable consumer on an already started session */ - ret = LTTCOMM_TRACE_ALREADY_STARTED; + switch (domain->type) { + case LTTNG_DOMAIN_UST: + break; + default: + ERR("Unknown UST domain on create session %d", domain->type); + ret = LTTNG_ERR_UNKNOWN_DOMAIN; goto error; } - if (!session->start_consumer) { - ret = LTTCOMM_NO_CONSUMER; + DBG("Creating UST session"); + + lus = trace_ust_create_session(session->path, session->id, domain); + if (lus == NULL) { + ret = LTTNG_ERR_UST_SESS_FAIL; goto error; } - switch (domain) { - case 0: - DBG("Disable tracing session %s consumer", session->name); - consumer = session->consumer; - break; - case LTTNG_DOMAIN_KERNEL: - /* Code flow error if we don't have a kernel session here. */ - assert(ksess); - - DBG("Disabling kernel consumer"); - consumer = ksess->consumer; - - break; - case LTTNG_DOMAIN_UST: - /* Code flow error if we don't have a UST session here. */ - assert(usess); - - DBG("Disabling UST consumer"); - consumer = usess->consumer; + lus->uid = session->uid; + lus->gid = session->gid; + session->ust_session = lus; - break; - default: - ret = LTTCOMM_UNKNOWN_DOMAIN; + /* Copy session output to the newly created UST session */ + ret = copy_session_consumer(domain->type, session); + if (ret != LTTNG_OK) { goto error; } - if (consumer) { - consumer->enabled = 0; - /* Success at this point */ - ret = LTTCOMM_OK; - } else { - ret = LTTCOMM_NO_CONSUMER; - } + return LTTNG_OK; error: + free(lus); + session->ust_session = NULL; return ret; } /* - * Command LTTNG_ENABLE_CONSUMER processed by the client thread. + * Create a kernel tracer session then create the default channel. */ -static int cmd_enable_consumer(int domain, struct ltt_session *session) +static int create_kernel_session(struct ltt_session *session) { int ret; - struct ltt_kernel_session *ksess = session->kernel_session; - struct ltt_ust_session *usess = session->ust_session; - struct consumer_output *consumer = NULL; - assert(session); + DBG("Creating kernel session"); - /* Can't enable consumer after session started. */ - if (session->enabled) { - ret = LTTCOMM_TRACE_ALREADY_STARTED; + ret = kernel_create_session(session, kernel_tracer_fd); + if (ret < 0) { + ret = LTTNG_ERR_KERN_SESS_FAIL; goto error; } - if (!session->start_consumer) { - ret = LTTCOMM_NO_CONSUMER; + /* Code flow safety */ + assert(session->kernel_session); + + /* Copy session output to the newly created Kernel session */ + ret = copy_session_consumer(LTTNG_DOMAIN_KERNEL, session); + if (ret != LTTNG_OK) { goto error; } - switch (domain) { - case 0: - assert(session->consumer); - consumer = session->consumer; - break; - case LTTNG_DOMAIN_KERNEL: - /* Code flow error if we don't have a kernel session here. */ - assert(ksess); - - /* - * Check if we have already sent fds to the consumer. In that case, - * the enable-consumer command can't be used because a start trace - * had previously occured. - */ - if (ksess->consumer_fds_sent) { - ret = LTTCOMM_ENABLE_CONSUMER_FAIL; - goto error; - } - - consumer = ksess->tmp_consumer; - if (consumer == NULL) { - ret = LTTCOMM_OK; - /* No temp. consumer output exists. Using the current one. */ - DBG3("No temporary consumer. Using default"); - consumer = ksess->consumer; - goto error; - } - - switch (consumer->type) { - case CONSUMER_DST_LOCAL: - DBG2("Consumer output is local. Creating directory(ies)"); - - /* Create directory(ies) */ - ret = run_as_mkdir_recursive(consumer->dst.trace_path, - S_IRWXU | S_IRWXG, session->uid, session->gid); - if (ret < 0) { - if (ret != -EEXIST) { - ERR("Trace directory creation error"); - ret = LTTCOMM_FATAL; - goto error; - } - } - break; - case CONSUMER_DST_NET: - DBG2("Consumer output is network. Validating URIs"); - /* Validate if we have both control and data path set. */ - if (!consumer->dst.net.control_isset) { - ret = LTTCOMM_URL_CTRL_MISS; - goto error; - } - - if (!consumer->dst.net.data_isset) { - ret = LTTCOMM_URL_DATA_MISS; - goto error; - } - - /* Check established network session state */ - if (session->net_handle == 0) { - ret = LTTCOMM_ENABLE_CONSUMER_FAIL; - ERR("Session network handle is not set on enable-consumer"); + /* 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 (ret != -EEXIST) { + ERR("Trace directory creation error"); goto error; } - - break; - } - - /* Append default kernel trace dir to subdir */ - strncat(ksess->consumer->subdir, DEFAULT_KERNEL_TRACE_DIR, - sizeof(ksess->consumer->subdir)); - - /* - * @session-lock - * This is race free for now since the session lock is acquired before - * ending up in this function. No other threads can access this kernel - * session without this lock hence freeing the consumer output object - * is valid. - */ - rcu_read_lock(); - consumer_destroy_output(ksess->consumer); - rcu_read_unlock(); - ksess->consumer = consumer; - ksess->tmp_consumer = NULL; - - break; - case LTTNG_DOMAIN_UST: - /* Code flow error if we don't have a UST session here. */ - assert(usess); - - /* - * Check if we have already sent fds to the consumer. In that case, - * the enable-consumer command can't be used because a start trace - * had previously occured. - */ - if (usess->start_trace) { - ret = LTTCOMM_ENABLE_CONSUMER_FAIL; - goto error; } + } - consumer = usess->tmp_consumer; - if (consumer == NULL) { - ret = LTTCOMM_OK; - /* No temp. consumer output exists. Using the current one. */ - DBG3("No temporary consumer. Using default"); - consumer = usess->consumer; - goto error; - } - - switch (consumer->type) { - case CONSUMER_DST_LOCAL: - DBG2("Consumer output is local. Creating directory(ies)"); - - /* Create directory(ies) */ - ret = run_as_mkdir_recursive(consumer->dst.trace_path, - S_IRWXU | S_IRWXG, session->uid, session->gid); - if (ret < 0) { - if (ret != -EEXIST) { - ERR("Trace directory creation error"); - ret = LTTCOMM_FATAL; - goto error; - } - } - break; - case CONSUMER_DST_NET: - DBG2("Consumer output is network. Validating URIs"); - /* Validate if we have both control and data path set. */ - if (!consumer->dst.net.control_isset) { - ret = LTTCOMM_URL_CTRL_MISS; - goto error; - } - - if (!consumer->dst.net.data_isset) { - ret = LTTCOMM_URL_DATA_MISS; - goto error; - } - - /* Check established network session state */ - if (session->net_handle == 0) { - ret = LTTCOMM_ENABLE_CONSUMER_FAIL; - DBG2("Session network handle is not set on enable-consumer"); - goto error; - } + session->kernel_session->uid = session->uid; + session->kernel_session->gid = session->gid; - if (consumer->net_seq_index == -1) { - ret = LTTCOMM_ENABLE_CONSUMER_FAIL; - DBG2("Network index is not set on the consumer"); - goto error; - } + return LTTNG_OK; - break; - } +error: + trace_kernel_destroy_session(session->kernel_session); + session->kernel_session = NULL; + return ret; +} - /* Append default kernel trace dir to subdir */ - strncat(usess->consumer->subdir, DEFAULT_UST_TRACE_DIR, - sizeof(usess->consumer->subdir)); +/* + * Count number of session permitted by uid/gid. + */ +static unsigned int lttng_sessions_count(uid_t uid, gid_t gid) +{ + unsigned int i = 0; + struct ltt_session *session; + DBG("Counting number of available session for UID %d GID %d", + uid, gid); + cds_list_for_each_entry(session, &session_list_ptr->head, list) { /* - * @session-lock - * This is race free for now since the session lock is acquired before - * ending up in this function. No other threads can access this kernel - * session without this lock hence freeing the consumer output object - * is valid. + * Only list the sessions the user can control. */ - rcu_read_lock(); - consumer_destroy_output(usess->consumer); - rcu_read_unlock(); - usess->consumer = consumer; - usess->tmp_consumer = NULL; - - break; - } - - /* Enable it */ - if (consumer) { - consumer->enabled = 1; - /* Success at this point */ - ret = LTTCOMM_OK; - } else { - /* Should not really happend... */ - ret = LTTCOMM_NO_CONSUMER; + if (!session_access_ok(session, uid, gid)) { + continue; + } + i++; } - -error: - return ret; + return i; } /* @@ -4297,7 +2099,7 @@ error: static int process_client_msg(struct command_ctx *cmd_ctx, int sock, int *sock_error) { - int ret = LTTCOMM_OK; + int ret = LTTNG_OK; int need_tracing_session = 1; int need_domain; @@ -4312,6 +2114,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_LIST_DOMAINS: case LTTNG_START_TRACE: case LTTNG_STOP_TRACE: + case LTTNG_DATA_AVAILABLE: need_domain = 0; break; default: @@ -4321,13 +2124,24 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, if (opt_no_kernel && need_domain && cmd_ctx->lsm->domain.type == LTTNG_DOMAIN_KERNEL) { if (!is_root) { - ret = LTTCOMM_NEED_ROOT_SESSIOND; + ret = LTTNG_ERR_NEED_ROOT_SESSIOND; } else { - ret = LTTCOMM_KERN_NA; + ret = LTTNG_ERR_KERN_NA; } goto error; } + /* Deny register consumer if we already have a spawned consumer. */ + if (cmd_ctx->lsm->cmd_type == LTTNG_REGISTER_CONSUMER) { + pthread_mutex_lock(&kconsumer_data.pid_mutex); + if (kconsumer_data.pid > 0) { + ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + pthread_mutex_unlock(&kconsumer_data.pid_mutex); + goto error; + } + pthread_mutex_unlock(&kconsumer_data.pid_mutex); + } + /* * Check for command that don't needs to allocate a returned payload. We do * this here so we don't have to make the call for no payload at each @@ -4370,10 +2184,10 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, cmd_ctx->session = session_find_by_name(cmd_ctx->lsm->session.name); if (cmd_ctx->session == NULL) { if (cmd_ctx->lsm->session.name != NULL) { - ret = LTTCOMM_SESS_NOT_FOUND; + ret = LTTNG_ERR_SESS_NOT_FOUND; } else { /* If no session name specified */ - ret = LTTCOMM_SELECT_SESS; + ret = LTTNG_ERR_SELECT_SESS; } goto error; } else { @@ -4393,7 +2207,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, switch (cmd_ctx->lsm->domain.type) { case LTTNG_DOMAIN_KERNEL: if (!is_root) { - ret = LTTCOMM_NEED_ROOT_SESSIOND; + ret = LTTNG_ERR_NEED_ROOT_SESSIOND; goto error; } @@ -4408,7 +2222,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, /* Consumer is in an ERROR state. Report back to client */ if (uatomic_read(&kernel_consumerd_state) == CONSUMER_ERROR) { - ret = LTTCOMM_NO_KERNCONSUMERD; + ret = LTTNG_ERR_NO_KERNCONSUMERD; goto error; } @@ -4417,7 +2231,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, if (cmd_ctx->session->kernel_session == NULL) { ret = create_kernel_session(cmd_ctx->session); if (ret < 0) { - ret = LTTCOMM_KERN_SESS_FAIL; + ret = LTTNG_ERR_KERN_SESS_FAIL; goto error; } } @@ -4430,7 +2244,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, pthread_mutex_unlock(&kconsumer_data.pid_mutex); ret = start_consumerd(&kconsumer_data); if (ret < 0) { - ret = LTTCOMM_KERN_CONSUMER_FAIL; + ret = LTTNG_ERR_KERN_CONSUMER_FAIL; goto error; } uatomic_set(&kernel_consumerd_state, CONSUMER_STARTED); @@ -4454,7 +2268,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, { /* Consumer is in an ERROR state. Report back to client */ if (uatomic_read(&ust_consumerd_state) == CONSUMER_ERROR) { - ret = LTTCOMM_NO_USTCONSUMERD; + ret = LTTNG_ERR_NO_USTCONSUMERD; goto error; } @@ -4463,7 +2277,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, if (cmd_ctx->session->ust_session == NULL) { ret = create_ust_session(cmd_ctx->session, &cmd_ctx->lsm->domain); - if (ret != LTTCOMM_OK) { + if (ret != LTTNG_OK) { goto error; } } @@ -4478,7 +2292,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, pthread_mutex_unlock(&ustconsumer64_data.pid_mutex); ret = start_consumerd(&ustconsumer64_data); if (ret < 0) { - ret = LTTCOMM_UST_CONSUMER64_FAIL; + ret = LTTNG_ERR_UST_CONSUMER64_FAIL; uatomic_set(&ust_consumerd64_fd, -EINVAL); goto error; } @@ -4507,7 +2321,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, pthread_mutex_unlock(&ustconsumer32_data.pid_mutex); ret = start_consumerd(&ustconsumer32_data); if (ret < 0) { - ret = LTTCOMM_UST_CONSUMER32_FAIL; + ret = LTTNG_ERR_UST_CONSUMER32_FAIL; uatomic_set(&ust_consumerd32_fd, -EINVAL); goto error; } @@ -4541,13 +2355,13 @@ skip_domain: switch (cmd_ctx->lsm->domain.type) { case LTTNG_DOMAIN_UST: if (uatomic_read(&ust_consumerd_state) != CONSUMER_STARTED) { - ret = LTTCOMM_NO_USTCONSUMERD; + ret = LTTNG_ERR_NO_USTCONSUMERD; goto error; } break; case LTTNG_DOMAIN_KERNEL: if (uatomic_read(&kernel_consumerd_state) != CONSUMER_STARTED) { - ret = LTTCOMM_NO_KERNCONSUMERD; + ret = LTTNG_ERR_NO_KERNCONSUMERD; goto error; } break; @@ -4562,7 +2376,7 @@ skip_domain: if (!session_access_ok(cmd_ctx->session, LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds), LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds))) { - ret = LTTCOMM_EPERM; + ret = LTTNG_ERR_EPERM; goto error; } } @@ -4606,7 +2420,7 @@ skip_domain: case LTTNG_ENABLE_CHANNEL: { ret = cmd_enable_channel(cmd_ctx->session, cmd_ctx->lsm->domain.type, - &cmd_ctx->lsm->u.channel.chan); + &cmd_ctx->lsm->u.channel.chan, kernel_poll_pipe[1]); break; } case LTTNG_ENABLE_CONSUMER: @@ -4616,7 +2430,7 @@ skip_domain: * be a DOMAIN enuam. */ ret = cmd_enable_consumer(cmd_ctx->lsm->domain.type, cmd_ctx->session); - if (ret != LTTCOMM_OK) { + if (ret != LTTNG_OK) { goto error; } @@ -4637,7 +2451,7 @@ skip_domain: { ret = cmd_enable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type, cmd_ctx->lsm->u.enable.channel_name, - &cmd_ctx->lsm->u.enable.event); + &cmd_ctx->lsm->u.enable.event, kernel_poll_pipe[1]); break; } case LTTNG_ENABLE_ALL_EVENT: @@ -4646,7 +2460,7 @@ skip_domain: ret = cmd_enable_event_all(cmd_ctx->session, cmd_ctx->lsm->domain.type, cmd_ctx->lsm->u.enable.channel_name, - cmd_ctx->lsm->u.enable.event.type); + cmd_ctx->lsm->u.enable.event.type, kernel_poll_pipe[1]); break; } case LTTNG_LIST_TRACEPOINTS: @@ -4656,6 +2470,7 @@ skip_domain: nb_events = cmd_list_tracepoints(cmd_ctx->lsm->domain.type, &events); if (nb_events < 0) { + /* Return value is a negative lttng_error_code. */ ret = -nb_events; goto error; } @@ -4676,7 +2491,7 @@ skip_domain: free(events); - ret = LTTCOMM_OK; + ret = LTTNG_OK; break; } case LTTNG_LIST_TRACEPOINT_FIELDS: @@ -4687,6 +2502,7 @@ skip_domain: nb_fields = cmd_list_tracepoint_fields(cmd_ctx->lsm->domain.type, &fields); if (nb_fields < 0) { + /* Return value is a negative lttng_error_code. */ ret = -nb_fields; goto error; } @@ -4708,7 +2524,7 @@ skip_domain: free(fields); - ret = LTTCOMM_OK; + ret = LTTNG_OK; break; } case LTTNG_SET_CONSUMER_URI: @@ -4720,13 +2536,13 @@ skip_domain: len = nb_uri * sizeof(struct lttng_uri); if (nb_uri == 0) { - ret = LTTCOMM_INVALID; + ret = LTTNG_ERR_INVALID; goto error; } uris = zmalloc(len); if (uris == NULL) { - ret = LTTCOMM_FATAL; + ret = LTTNG_ERR_FATAL; goto error; } @@ -4736,13 +2552,15 @@ skip_domain: if (ret <= 0) { DBG("No URIs received from client... continuing"); *sock_error = 1; - ret = LTTCOMM_SESSION_FAIL; + ret = LTTNG_ERR_SESSION_FAIL; + free(uris); goto error; } ret = cmd_set_consumer_uri(cmd_ctx->lsm->domain.type, cmd_ctx->session, nb_uri, uris); - if (ret != LTTCOMM_OK) { + if (ret != LTTNG_OK) { + free(uris); goto error; } @@ -4763,6 +2581,8 @@ skip_domain: } } + free(uris); + break; } case LTTNG_START_TRACE: @@ -4786,7 +2606,7 @@ skip_domain: if (nb_uri > 0) { uris = zmalloc(len); if (uris == NULL) { - ret = LTTCOMM_FATAL; + ret = LTTNG_ERR_FATAL; goto error; } @@ -4796,13 +2616,15 @@ skip_domain: if (ret <= 0) { DBG("No URIs received from client... continuing"); *sock_error = 1; - ret = LTTCOMM_SESSION_FAIL; + ret = LTTNG_ERR_SESSION_FAIL; + free(uris); goto error; } if (nb_uri == 1 && uris[0].dtype != LTTNG_DST_PATH) { DBG("Creating session with ONE network URI is a bad call"); - ret = LTTCOMM_SESSION_FAIL; + ret = LTTNG_ERR_SESSION_FAIL; + free(uris); goto error; } } @@ -4810,12 +2632,13 @@ skip_domain: ret = cmd_create_session_uri(cmd_ctx->lsm->session.name, uris, nb_uri, &cmd_ctx->creds); + free(uris); + break; } case LTTNG_DESTROY_SESSION: { - ret = cmd_destroy_session(cmd_ctx->session, - cmd_ctx->lsm->session.name); + ret = cmd_destroy_session(cmd_ctx->session, kernel_poll_pipe[1]); /* Set session to NULL so we do not unlock it after free. */ cmd_ctx->session = NULL; @@ -4828,6 +2651,7 @@ skip_domain: nb_dom = cmd_list_domains(cmd_ctx->session, &domains); if (nb_dom < 0) { + /* Return value is a negative lttng_error_code. */ ret = -nb_dom; goto error; } @@ -4843,7 +2667,7 @@ skip_domain: free(domains); - ret = LTTCOMM_OK; + ret = LTTNG_OK; break; } case LTTNG_LIST_CHANNELS: @@ -4854,6 +2678,7 @@ skip_domain: nb_chan = cmd_list_channels(cmd_ctx->lsm->domain.type, cmd_ctx->session, &channels); if (nb_chan < 0) { + /* Return value is a negative lttng_error_code. */ ret = -nb_chan; goto error; } @@ -4869,7 +2694,7 @@ skip_domain: free(channels); - ret = LTTCOMM_OK; + ret = LTTNG_OK; break; } case LTTNG_LIST_EVENTS: @@ -4880,6 +2705,7 @@ skip_domain: nb_event = cmd_list_events(cmd_ctx->lsm->domain.type, cmd_ctx->session, cmd_ctx->lsm->u.list.channel_name, &events); if (nb_event < 0) { + /* Return value is a negative lttng_error_code. */ ret = -nb_event; goto error; } @@ -4895,7 +2721,7 @@ skip_domain: free(events); - ret = LTTCOMM_OK; + ret = LTTNG_OK; break; } case LTTNG_LIST_SESSIONS: @@ -4914,13 +2740,13 @@ skip_domain: } /* Filled the session array */ - list_lttng_sessions((struct lttng_session *)(cmd_ctx->llm->payload), + cmd_list_lttng_sessions((struct lttng_session *)(cmd_ctx->llm->payload), LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds), LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds)); session_unlock_list(); - ret = LTTCOMM_OK; + ret = LTTNG_OK; break; } case LTTNG_CALIBRATE: @@ -4931,21 +2757,32 @@ skip_domain: } case LTTNG_REGISTER_CONSUMER: { + struct consumer_data *cdata; + + switch (cmd_ctx->lsm->domain.type) { + case LTTNG_DOMAIN_KERNEL: + cdata = &kconsumer_data; + break; + default: + ret = LTTNG_ERR_UND; + goto error; + } + ret = cmd_register_consumer(cmd_ctx->session, cmd_ctx->lsm->domain.type, - cmd_ctx->lsm->u.reg.path); + cmd_ctx->lsm->u.reg.path, cdata); break; } case LTTNG_SET_FILTER: { struct lttng_filter_bytecode *bytecode; - if (cmd_ctx->lsm->u.filter.bytecode_len > 65336) { - ret = LTTCOMM_FILTER_INVAL; + if (cmd_ctx->lsm->u.filter.bytecode_len > LTTNG_FILTER_MAX_LEN) { + ret = LTTNG_ERR_FILTER_INVAL; goto error; } bytecode = zmalloc(cmd_ctx->lsm->u.filter.bytecode_len); if (!bytecode) { - ret = LTTCOMM_FILTER_NOMEM; + ret = LTTNG_ERR_FILTER_NOMEM; goto error; } /* Receive var. len. data */ @@ -4955,14 +2792,14 @@ skip_domain: if (ret <= 0) { DBG("Nothing recv() from client var len data... continuing"); *sock_error = 1; - ret = LTTCOMM_FILTER_INVAL; + ret = LTTNG_ERR_FILTER_INVAL; goto error; } if (bytecode->len + sizeof(*bytecode) != cmd_ctx->lsm->u.filter.bytecode_len) { free(bytecode); - ret = LTTCOMM_FILTER_INVAL; + ret = LTTNG_ERR_FILTER_INVAL; goto error; } @@ -4972,8 +2809,13 @@ skip_domain: bytecode); break; } + case LTTNG_DATA_AVAILABLE: + { + ret = cmd_data_available(cmd_ctx->session); + break; + } default: - ret = LTTCOMM_UND; + ret = LTTNG_ERR_UND; break; } @@ -5123,7 +2965,7 @@ restart: check_consumer_health(); break; default: - reply.ret_code = LTTCOMM_UND; + reply.ret_code = LTTNG_ERR_UND; break; } @@ -5192,6 +3034,8 @@ static void *thread_manage_clients(void *data) DBG("[thread] Manage client started"); + testpoint(thread_manage_clients); + rcu_register_thread(); health_code_update(&health_thread_cmd); @@ -5223,6 +3067,8 @@ static void *thread_manage_clients(void *data) kill(ppid, SIGUSR1); } + testpoint(thread_manage_clients_before_loop); + health_code_update(&health_thread_cmd); while (1) { @@ -6119,11 +3965,7 @@ int main(int argc, char **argv) /* Set up max poll set size */ lttng_poll_set_max_size(); - /* - * Set network sequence index to 1 for streams to match a relayd socket on - * the consumer side. - */ - uatomic_set(&relayd_net_seq_idx, 1); + cmd_init(); /* Init all health thread counters. */ health_init(&health_thread_cmd); @@ -6143,6 +3985,9 @@ int main(int argc, char **argv) health_init(&ustconsumer64_data.health); health_poll_update(&ustconsumer64_data.health); + /* Not needed anymore. */ + free(rundir); + /* Create thread to manage the client socket */ ret = pthread_create(&health_thread, NULL, thread_manage_health, (void *) NULL);