X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=e2ca01eb54fe6541323f971095c1d329f28cf747;hp=a9d538c7cd4b5e201bfafc29981e49409cf5081c;hb=53a80697a772bc2e260e3dff006f910be6709f04;hpb=f1e1679499bf3e76127c8812c72a6e9ba69e02e5 diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index a9d538c7c..e2ca01eb5 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -42,11 +42,12 @@ #include #include #include -#include #include +#include #include "lttng-sessiond.h" #include "channel.h" +#include "consumer.h" #include "context.h" #include "event.h" #include "kernel.h" @@ -54,8 +55,10 @@ #include "modprobe.h" #include "shm.h" #include "ust-ctl.h" +#include "ust-consumer.h" #include "utils.h" #include "fd-limit.h" +#include "filter.h" #define CONSUMERD_FILE "lttng-consumerd" @@ -132,7 +135,6 @@ static pthread_t client_thread; static pthread_t kernel_thread; static pthread_t dispatch_thread; - /* * UST registration command queue. This queue is tied with a futex and uses a N * wakers / 1 waiter implemented and detailed in futex.c/.h @@ -196,6 +198,16 @@ 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; + static void setup_consumerd_path(void) { @@ -407,7 +419,7 @@ static void stop_threads(void) */ static void cleanup(void) { - int ret, i; + int ret; char *cmd; struct ltt_session *sess, *stmp; @@ -457,34 +469,9 @@ static void cleanup(void) DBG("Unloading kernel modules"); modprobe_remove_lttng_all(); } - - /* - * Closing all pipes used for communication between threads. - */ - for (i = 0; i < 2; i++) { - if (kernel_poll_pipe[i] >= 0) { - ret = close(kernel_poll_pipe[i]); - if (ret) { - PERROR("close"); - } - } - } - for (i = 0; i < 2; i++) { - if (thread_quit_pipe[i] >= 0) { - ret = close(thread_quit_pipe[i]); - if (ret) { - PERROR("close"); - } - } - } - for (i = 0; i < 2; i++) { - if (apps_cmd_pipe[i] >= 0) { - ret = close(apps_cmd_pipe[i]); - if (ret) { - PERROR("close"); - } - } - } + utils_close_pipe(kernel_poll_pipe); + utils_close_pipe(thread_quit_pipe); + utils_close_pipe(apps_cmd_pipe); /* */ DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm" @@ -666,10 +653,11 @@ static int update_kernel_stream(struct consumer_data *consumer_data, int fd) * that tracing is started so it is safe to send our updated * stream fds. */ - if (session->kernel_session->consumer_fds_sent == 1) { - ret = kernel_consumer_send_channel_stream(consumer_data, + if (session->kernel_session->consumer_fds_sent == 1 && + session->kernel_session->consumer != NULL) { + ret = kernel_consumer_send_channel_stream( session->kernel_session->consumer_fd, channel, - session->uid, session->gid); + session->kernel_session); if (ret < 0) { goto error; } @@ -1771,7 +1759,7 @@ static int init_kernel_tracing(struct ltt_kernel_session *session) { int ret = 0; - if (session->consumer_fds_sent == 0) { + if (session->consumer_fds_sent == 0 && session->consumer != NULL) { /* * Assign default kernel consumer socket if no consumer assigned to the * kernel session. At this point, it's NOT supposed to be -1 but this is @@ -1781,15 +1769,280 @@ static int init_kernel_tracing(struct ltt_kernel_session *session) session->consumer_fd = kconsumer_data.cmd_sock; } - ret = kernel_consumer_send_session(&kconsumer_data, session); + ret = kernel_consumer_send_session(session->consumer_fd, session); 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; + } + + switch (domain) { + case LTTNG_DOMAIN_KERNEL: + /* Send relayd socket to consumer. */ + ret = kernel_consumer_send_relayd_socket(consumer_fd, sock, + consumer, relayd_uri->stype); + if (ret < 0) { + ret = LTTCOMM_ENABLE_CONSUMER_FAIL; + goto close_sock; + } + break; + case LTTNG_DOMAIN_UST: + /* Send relayd socket to consumer. */ + ret = ust_consumer_send_relayd_socket(consumer_fd, sock, + consumer, relayd_uri->stype); + if (ret < 0) { + ret = LTTCOMM_ENABLE_CONSUMER_FAIL; + goto close_sock; + } + break; + } + + 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; + + /* 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; + } + +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; + + assert(session); + + usess = session->ust_session; + ksess = session->kernel_session; + + DBG2("Setting relayd for session %s", session->name); + + if (usess && usess->consumer->sock == -1 && + usess->consumer->type == CONSUMER_DST_NET && + usess->consumer->enabled) { + /* Setup relayd for 64 bits consumer */ + if (ust_consumerd64_fd >= 0) { + send_sockets_relayd_consumer(LTTNG_DOMAIN_UST, session, + usess->consumer, ust_consumerd64_fd); + if (ret != LTTCOMM_OK) { + goto error; + } + } + + /* Setup relayd for 32 bits consumer */ + if (ust_consumerd32_fd >= 0) { + send_sockets_relayd_consumer(LTTNG_DOMAIN_UST, session, + usess->consumer, ust_consumerd32_fd); + if (ret != LTTCOMM_OK) { + goto error; + } + } + } else if (ksess && ksess->consumer->sock == -1 && + ksess->consumer->type == CONSUMER_DST_NET && + ksess->consumer->enabled) { + send_sockets_relayd_consumer(LTTNG_DOMAIN_KERNEL, session, + ksess->consumer, ksess->consumer_fd); + if (ret != LTTCOMM_OK) { + goto error; + } + } + +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; + + 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; + } + + /* Append correct directory to subdir */ + strncat(consumer->subdir, dir_name, sizeof(consumer->subdir)); + DBG3("Copy session consumer subdir %s", consumer->subdir); - session->consumer_fds_sent = 1; + /* Add default trace directory name */ + if (consumer->type == CONSUMER_DST_LOCAL) { + strncat(consumer->dst.trace_path, dir_name, + sizeof(consumer->dst.trace_path)); } + ret = LTTCOMM_OK; + error: return ret; } @@ -1800,13 +2053,17 @@ error: static int create_ust_session(struct ltt_session *session, struct lttng_domain *domain) { - struct ltt_ust_session *lus = NULL; int ret; + struct ltt_ust_session *lus = NULL; + + assert(session); + 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; } @@ -1819,33 +2076,33 @@ static int create_ust_session(struct ltt_session *session, goto error; } - ret = run_as_mkdir_recursive(lus->pathname, S_IRWXU | S_IRWXG, - session->uid, session->gid); - if (ret < 0) { - if (ret != -EEXIST) { - ERR("Trace directory creation error"); - ret = LTTCOMM_UST_SESS_FAIL; - goto error; + if (session->consumer->type == CONSUMER_DST_LOCAL) { + ret = run_as_mkdir_recursive(lus->pathname, S_IRWXU | S_IRWXG, + session->uid, session->gid); + if (ret < 0) { + if (ret != -EEXIST) { + ERR("Trace directory creation error"); + ret = LTTCOMM_UST_SESS_FAIL; + goto error; + } } } - /* The domain type dictate different actions on session creation */ - switch (domain->type) { - case LTTNG_DOMAIN_UST: - /* No ustctl for the global UST domain */ - break; - default: - ERR("Unknown UST domain on create session %d", domain->type); - 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; } @@ -1869,18 +2126,33 @@ static int create_kernel_session(struct ltt_session *session) session->kernel_session->consumer_fd = kconsumer_data.cmd_sock; } - ret = run_as_mkdir_recursive(session->kernel_session->trace_path, - S_IRWXU | S_IRWXG, session->uid, session->gid); - if (ret < 0) { - if (ret != -EEXIST) { - ERR("Trace directory creation error"); - goto error; + /* 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->consumer->type == CONSUMER_DST_LOCAL) { + 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; } @@ -1897,6 +2169,9 @@ static int session_access_ok(struct ltt_session *session, uid_t uid, gid_t gid) } } +/* + * Count number of session permitted by uid/gid. + */ static unsigned int lttng_sessions_count(uid_t uid, gid_t gid) { unsigned int i = 0; @@ -2457,6 +2732,46 @@ 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. */ @@ -2778,8 +3093,9 @@ 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; - /* Short cut */ + /* Ease our life a bit ;) */ ksession = session->kernel_session; usess = session->ust_session; @@ -2791,13 +3107,18 @@ static int cmd_start_trace(struct ltt_session *session) 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) { - struct ltt_kernel_channel *kchan; - /* Open kernel metadata */ if (ksession->metadata == NULL) { - ret = kernel_open_metadata(ksession, ksession->trace_path); + ret = kernel_open_metadata(ksession, + ksession->consumer->dst.trace_path); if (ret < 0) { ret = LTTCOMM_KERN_META_FAIL; goto error; @@ -2887,12 +3208,15 @@ static int cmd_stop_trace(struct ltt_session *session) if (ksession != NULL) { DBG("Stop kernel tracing"); - /* Flush all buffers before stopping */ - ret = kernel_metadata_flush_buffer(ksession->metadata_stream_fd); - if (ret < 0) { - ERR("Kernel metadata flush failed"); + /* 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) { @@ -2926,22 +3250,111 @@ error: } /* - * Command LTTNG_CREATE_SESSION processed by the client thread. + * Command LTTNG_CREATE_SESSION_URI processed by the client thread. */ -static int cmd_create_session(char *name, char *path, lttng_sock_cred *creds) +static int cmd_create_session_uri(char *name, struct lttng_uri *ctrl_uri, + struct lttng_uri *data_uri, unsigned int enable_consumer, + lttng_sock_cred *creds) { int ret; + char *path = NULL; + struct ltt_session *session; + struct consumer_output *consumer; - ret = session_create(name, path, LTTNG_SOCK_GET_UID_CRED(creds), - LTTNG_SOCK_GET_GID_CRED(creds)); - if (ret != LTTCOMM_OK) { + /* Verify if the session already exist */ + session = session_find_by_name(name); + if (session != NULL) { + ret = LTTCOMM_EXIST_SESS; goto error; } - ret = LTTCOMM_OK; + /* TODO: validate URIs */ -error: - return ret; + /* Create default consumer output */ + consumer = consumer_create_output(CONSUMER_DST_LOCAL); + if (consumer == NULL) { + ret = LTTCOMM_FATAL; + goto error; + } + strncpy(consumer->subdir, ctrl_uri->subdir, sizeof(consumer->subdir)); + DBG2("Consumer subdir set to %s", consumer->subdir); + + switch (ctrl_uri->dtype) { + case LTTNG_DST_IPV4: + case LTTNG_DST_IPV6: + /* Set control URI into consumer output object */ + ret = consumer_set_network_uri(consumer, ctrl_uri); + if (ret < 0) { + ret = LTTCOMM_FATAL; + goto error; + } + + /* Set data URI into consumer output object */ + ret = consumer_set_network_uri(consumer, data_uri); + if (ret < 0) { + ret = LTTCOMM_FATAL; + goto error; + } + + /* Empty path since the session is network */ + path = ""; + break; + case LTTNG_DST_PATH: + /* Very volatile pointer. Only used for the create session. */ + path = ctrl_uri->dst.path; + strncpy(consumer->dst.trace_path, path, + sizeof(consumer->dst.trace_path)); + break; + } + + /* Set if the consumer is enabled or not */ + consumer->enabled = enable_consumer; + + ret = session_create(name, path, LTTNG_SOCK_GET_UID_CRED(creds), + LTTNG_SOCK_GET_GID_CRED(creds)); + if (ret != LTTCOMM_OK) { + goto consumer_error; + } + + /* Get the newly created session pointer back */ + session = session_find_by_name(name); + assert(session); + + /* Assign consumer to session */ + session->consumer = consumer; + + return LTTCOMM_OK; + +consumer_error: + consumer_destroy_output(consumer); +error: + return ret; +} + +/* + * Command LTTNG_CREATE_SESSION processed by the client thread. + */ +static int cmd_create_session(char *name, char *path, lttng_sock_cred *creds) +{ + int ret; + struct lttng_uri uri; + + /* Zeroed temporary URI */ + memset(&uri, 0, sizeof(uri)); + + uri.dtype = LTTNG_DST_PATH; + uri.utype = LTTNG_URI_DST; + strncpy(uri.dst.path, path, sizeof(uri.dst.path)); + + /* TODO: Strip date-time from path and put it in uri's subdir */ + + ret = cmd_create_session_uri(name, &uri, NULL, 1, creds); + if (ret != LTTCOMM_OK) { + goto error; + } + +error: + return ret; } /* @@ -3172,14 +3585,395 @@ 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, + struct lttng_uri *uri) +{ + int ret; + struct ltt_kernel_session *ksess = session->kernel_session; + struct ltt_ust_session *usess = session->ust_session; + struct consumer_output *consumer; + + /* Can't enable consumer after session started. */ + if (session->enabled) { + ret = LTTCOMM_TRACE_ALREADY_STARTED; + goto error; + } + + switch (domain) { + 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; + } + /* Reassign new pointer */ + ksess->tmp_consumer = consumer; + } + + switch (uri->dtype) { + case LTTNG_DST_IPV4: + case LTTNG_DST_IPV6: + DBG2("Setting network URI for kernel session %s", session->name); + + /* Set URI into consumer output object */ + ret = consumer_set_network_uri(consumer, uri); + if (ret < 0) { + ret = LTTCOMM_FATAL; + goto error; + } + + /* On a new subdir, reappend the default trace dir. */ + if (strlen(uri->subdir) != 0) { + strncat(consumer->subdir, DEFAULT_KERNEL_TRACE_DIR, + sizeof(consumer->subdir)); + } + + ret = send_socket_relayd_consumer(domain, session, uri, consumer, + ksess->consumer_fd); + if (ret != LTTCOMM_OK) { + goto error; + } + 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 kernel trace dir */ + strncat(consumer->dst.trace_path, DEFAULT_KERNEL_TRACE_DIR, + sizeof(consumer->dst.trace_path)); + break; + } + + /* All good! */ + 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; + } + /* Reassign new pointer */ + usess->tmp_consumer = consumer; + } + + switch (uri->dtype) { + case LTTNG_DST_IPV4: + case LTTNG_DST_IPV6: + { + DBG2("Setting network URI for UST session %s", session->name); + + /* Set URI into consumer object */ + ret = consumer_set_network_uri(consumer, uri); + if (ret < 0) { + ret = LTTCOMM_FATAL; + goto error; + } + + /* On a new subdir, reappend the default trace dir. */ + if (strlen(uri->subdir) != 0) { + strncat(consumer->subdir, DEFAULT_UST_TRACE_DIR, + sizeof(consumer->subdir)); + } + + if (ust_consumerd64_fd >= 0) { + ret = send_socket_relayd_consumer(domain, session, uri, + consumer, ust_consumerd64_fd); + if (ret != LTTCOMM_OK) { + goto error; + } + } + + if (ust_consumerd32_fd >= 0) { + ret = send_socket_relayd_consumer(domain, session, uri, + consumer, ust_consumerd32_fd); + if (ret != LTTCOMM_OK) { + goto error; + } + } + + 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 UST trace dir */ + strncat(consumer->dst.trace_path, DEFAULT_UST_TRACE_DIR, + sizeof(consumer->dst.trace_path)); + break; + } + break; + } + + /* All good! */ + ret = LTTCOMM_OK; + +error: + return ret; +} + +/* + * Command LTTNG_DISABLE_CONSUMER processed by the client thread. + */ +static int cmd_disable_consumer(int domain, 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; + + if (session->enabled) { + /* Can't disable consumer on an already started session */ + ret = LTTCOMM_TRACE_ALREADY_STARTED; + goto error; + } + + switch (domain) { + 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; + + break; + default: + ret = LTTCOMM_UNKNOWN_DOMAIN; + goto error; + } + + assert(consumer); + consumer->enabled = 0; + + /* Success at this point */ + ret = LTTCOMM_OK; + +error: + return ret; +} + +/* + * Command LTTNG_ENABLE_CONSUMER processed by the client thread. + */ +static int cmd_enable_consumer(int domain, 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 *tmp_out; + + /* Can't enable consumer after session started. */ + if (session->enabled) { + ret = LTTCOMM_TRACE_ALREADY_STARTED; + goto error; + } + + switch (domain) { + 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; + } + + tmp_out = ksess->tmp_consumer; + if (tmp_out == NULL) { + /* No temp. consumer output exists. Using the current one. */ + DBG3("No temporary consumer. Using default"); + ret = LTTCOMM_OK; + goto error; + } + + switch (tmp_out->type) { + case CONSUMER_DST_LOCAL: + DBG2("Consumer output is local. Creating directory(ies)"); + + /* Create directory(ies) */ + ret = run_as_mkdir_recursive(tmp_out->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 (!tmp_out->dst.net.control_isset) { + ret = LTTCOMM_URI_CTRL_MISS; + goto error; + } + + if (!tmp_out->dst.net.data_isset) { + ret = LTTCOMM_URI_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"); + goto error; + } + + /* Append default kernel trace dir to subdir */ + strncat(ksess->consumer->subdir, DEFAULT_KERNEL_TRACE_DIR, + sizeof(ksess->consumer->subdir)); + + break; + } + + /* + * @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. + */ + consumer_destroy_output(ksess->consumer); + ksess->consumer = tmp_out; + 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; + } + + tmp_out = usess->tmp_consumer; + if (tmp_out == NULL) { + /* No temp. consumer output exists. Using the current one. */ + DBG3("No temporary consumer. Using default"); + ret = LTTCOMM_OK; + goto error; + } + + switch (tmp_out->type) { + case CONSUMER_DST_LOCAL: + DBG2("Consumer output is local. Creating directory(ies)"); + + /* Create directory(ies) */ + ret = run_as_mkdir_recursive(tmp_out->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 (!tmp_out->dst.net.control_isset) { + ret = LTTCOMM_URI_CTRL_MISS; + goto error; + } + + if (!tmp_out->dst.net.data_isset) { + ret = LTTCOMM_URI_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; + } + + if (tmp_out->net_seq_index == -1) { + ret = LTTCOMM_ENABLE_CONSUMER_FAIL; + DBG2("Network index is not set on the consumer"); + goto error; + } + + /* Append default kernel trace dir to subdir */ + strncat(usess->consumer->subdir, DEFAULT_UST_TRACE_DIR, + sizeof(usess->consumer->subdir)); + + break; + } + + /* + * @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. + */ + consumer_destroy_output(usess->consumer); + usess->consumer = tmp_out; + usess->tmp_consumer = NULL; + + break; + } + + /* Success at this point */ + ret = LTTCOMM_OK; + +error: + return ret; +} + /* * Process the command requested by the lttng client within the command * context structure. This function make sure that the return structure (llm) * is set and ready for transmission before returning. * * Return any error encountered or 0 for success. + * + * "sock" is only used for special-case var. len data. */ -static int process_client_msg(struct command_ctx *cmd_ctx) +static int process_client_msg(struct command_ctx *cmd_ctx, int sock, + int *sock_error) { int ret = LTTCOMM_OK; int need_tracing_session = 1; @@ -3187,8 +3981,11 @@ static int process_client_msg(struct command_ctx *cmd_ctx) DBG("Processing client command %d", cmd_ctx->lsm->cmd_type); + *sock_error = 0; + switch (cmd_ctx->lsm->cmd_type) { case LTTNG_CREATE_SESSION: + case LTTNG_CREATE_SESSION_URI: case LTTNG_DESTROY_SESSION: case LTTNG_LIST_SESSIONS: case LTTNG_LIST_DOMAINS: @@ -3235,6 +4032,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx) /* Commands that DO NOT need a session. */ switch (cmd_ctx->lsm->cmd_type) { case LTTNG_CREATE_SESSION: + case LTTNG_CREATE_SESSION_URI: case LTTNG_CALIBRATE: case LTTNG_LIST_SESSIONS: case LTTNG_LIST_TRACEPOINTS: @@ -3314,6 +4112,10 @@ static int process_client_msg(struct command_ctx *cmd_ctx) goto error; } uatomic_set(&kernel_consumerd_state, CONSUMER_STARTED); + + /* Set consumer fd of the session */ + cmd_ctx->session->kernel_session->consumer_fd = + kconsumer_data.cmd_sock; } else { pthread_mutex_unlock(&kconsumer_data.pid_mutex); } @@ -3336,6 +4138,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx) goto error; } } + /* Start the UST consumer daemons */ /* 64-bit */ pthread_mutex_lock(&ustconsumer64_data.pid_mutex); @@ -3443,12 +4246,22 @@ skip_domain: cmd_ctx->lsm->u.disable.channel_name); break; } + case LTTNG_DISABLE_CONSUMER: + { + ret = cmd_disable_consumer(cmd_ctx->lsm->domain.type, cmd_ctx->session); + break; + } case LTTNG_ENABLE_CHANNEL: { ret = cmd_enable_channel(cmd_ctx->session, cmd_ctx->lsm->domain.type, &cmd_ctx->lsm->u.channel.chan); break; } + case LTTNG_ENABLE_CONSUMER: + { + ret = cmd_enable_consumer(cmd_ctx->lsm->domain.type, cmd_ctx->session); + break; + } case LTTNG_ENABLE_EVENT: { ret = cmd_enable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type, @@ -3525,7 +4338,12 @@ skip_domain: ret = LTTCOMM_OK; break; } - + case LTTNG_SET_CONSUMER_URI: + { + ret = cmd_set_consumer_uri(cmd_ctx->lsm->domain.type, cmd_ctx->session, + &cmd_ctx->lsm->u.uri); + break; + } case LTTNG_START_TRACE: { ret = cmd_start_trace(cmd_ctx->session); @@ -3542,6 +4360,14 @@ skip_domain: cmd_ctx->lsm->session.path, &cmd_ctx->creds); break; } + case LTTNG_CREATE_SESSION_URI: + { + ret = cmd_create_session_uri(cmd_ctx->lsm->session.name, + &cmd_ctx->lsm->u.create_uri.ctrl_uri, + &cmd_ctx->lsm->u.create_uri.data_uri, + cmd_ctx->lsm->u.create_uri.enable_consumer, &cmd_ctx->creds); + break; + } case LTTNG_DESTROY_SESSION: { ret = cmd_destroy_session(cmd_ctx->session, @@ -3667,6 +4493,43 @@ skip_domain: cmd_ctx->lsm->u.reg.path); break; } + case LTTNG_SET_FILTER: + { + struct lttng_filter_bytecode *bytecode; + + if (cmd_ctx->lsm->u.filter.bytecode_len > 65336) { + ret = LTTCOMM_FILTER_INVAL; + goto error; + } + bytecode = zmalloc(cmd_ctx->lsm->u.filter.bytecode_len); + if (!bytecode) { + ret = LTTCOMM_FILTER_NOMEM; + goto error; + } + /* Receive var. len. data */ + DBG("Receiving var len data from client ..."); + ret = lttcomm_recv_unix_sock(sock, bytecode, + cmd_ctx->lsm->u.filter.bytecode_len); + if (ret <= 0) { + DBG("Nothing recv() from client var len data... continuing"); + *sock_error = 1; + ret = LTTCOMM_FILTER_INVAL; + goto error; + } + + if (bytecode->len + sizeof(*bytecode) + != cmd_ctx->lsm->u.filter.bytecode_len) { + free(bytecode); + ret = LTTCOMM_FILTER_INVAL; + goto error; + } + + ret = cmd_set_filter(cmd_ctx->session, cmd_ctx->lsm->domain.type, + cmd_ctx->lsm->u.filter.channel_name, + cmd_ctx->lsm->u.filter.event_name, + bytecode); + break; + } default: ret = LTTCOMM_UND; break; @@ -3699,6 +4562,7 @@ init_setup_error: static void *thread_manage_clients(void *data) { int sock = -1, ret, i, pollfd; + int sock_error; uint32_t revents, nb_fd; struct command_ctx *cmd_ctx = NULL; struct lttng_poll_event events; @@ -3831,13 +4695,22 @@ static void *thread_manage_clients(void *data) * informations for the client. The command context struct contains * everything this function may needs. */ - ret = process_client_msg(cmd_ctx); + ret = process_client_msg(cmd_ctx, sock, &sock_error); rcu_thread_offline(); if (ret < 0) { + if (sock_error) { + ret = close(sock); + if (ret) { + PERROR("close"); + } + sock = -1; + } /* * TODO: Inform client somehow of the fatal error. At * this point, ret < 0 means that a zmalloc failed - * (ENOMEM). Error detected but still accept command. + * (ENOMEM). Error detected but still accept + * command, unless a socket error has been + * detected. */ clean_command_ctx(&cmd_ctx); continue; @@ -4167,58 +5040,6 @@ end: return ret; } -/* - * Create the pipe used to wake up the kernel thread. - * Closed in cleanup(). - */ -static int create_kernel_poll_pipe(void) -{ - int ret, i; - - ret = pipe(kernel_poll_pipe); - if (ret < 0) { - PERROR("kernel poll pipe"); - goto error; - } - - for (i = 0; i < 2; i++) { - ret = fcntl(kernel_poll_pipe[i], F_SETFD, FD_CLOEXEC); - if (ret < 0) { - PERROR("fcntl kernel_poll_pipe"); - goto error; - } - } - -error: - return ret; -} - -/* - * Create the application command pipe to wake thread_manage_apps. - * Closed in cleanup(). - */ -static int create_apps_cmd_pipe(void) -{ - int ret, i; - - ret = pipe(apps_cmd_pipe); - if (ret < 0) { - PERROR("apps cmd pipe"); - goto error; - } - - for (i = 0; i < 2; i++) { - ret = fcntl(apps_cmd_pipe[i], F_SETFD, FD_CLOEXEC); - if (ret < 0) { - PERROR("fcntl apps_cmd_pipe"); - goto error; - } - } - -error: - return ret; -} - /* * Create the lttng run directory needed for all global sockets and pipe. */ @@ -4617,12 +5438,12 @@ int main(int argc, char **argv) } /* Setup the kernel pipe for waking up the kernel thread */ - if ((ret = create_kernel_poll_pipe()) < 0) { + if ((ret = utils_create_pipe_cloexec(kernel_poll_pipe)) < 0) { goto exit; } /* Setup the thread apps communication pipe. */ - if ((ret = create_apps_cmd_pipe()) < 0) { + if ((ret = utils_create_pipe_cloexec(apps_cmd_pipe)) < 0) { goto exit; } @@ -4638,6 +5459,12 @@ 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); + /* Create thread to manage the client socket */ ret = pthread_create(&client_thread, NULL, thread_manage_clients, (void *) NULL);