X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fcmd.c;h=1a8fbba1eea75f30f4559274a3790f1e1ba599cc;hp=3a70d48692917108d8ed1447b6a7a2a409542d3d;hb=5d2e1e66a968d9e555f9b8b00d0589ebfaf3de32;hpb=e7fe706f887aa4d753b102a610f802f7dd816655 diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index 3a70d4869..1a8fbba1e 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -38,12 +38,11 @@ /* * 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. + * to send to. It must be accessed with the relayd_net_seq_idx_lock + * held. */ -static unsigned int relayd_net_seq_idx; +static pthread_mutex_t relayd_net_seq_idx_lock = PTHREAD_MUTEX_INITIALIZER; +static uint64_t relayd_net_seq_idx; /* * Create a session path used by list_lttng_sessions for the case that the @@ -105,7 +104,7 @@ static int build_network_session_path(char *dst, size_t size, * Do we have a UST url set. If yes, this means we have both kernel and UST * to print. */ - if (strlen(tmp_uurl) > 0) { + if (*tmp_uurl != '\0') { ret = snprintf(dst, size, "[K]: %s [data: %d] -- [U]: %s [data: %d]", tmp_urls, kdata_port, tmp_uurl, udata_port); } else { @@ -376,6 +375,16 @@ static int add_uri_to_consumer(struct consumer_output *consumer, case LTTNG_DST_IPV6: DBG2("Setting network URI to consumer"); + consumer->type = CONSUMER_DST_NET; + + if ((uri->stype == LTTNG_STREAM_CONTROL && + consumer->dst.net.control_isset) || + (uri->stype == LTTNG_STREAM_DATA && + consumer->dst.net.data_isset)) { + ret = LTTNG_ERR_URL_EXIST; + goto error; + } + /* Set URI into consumer output object */ ret = consumer_set_network_uri(consumer, uri); if (ret < 0) { @@ -484,8 +493,14 @@ static int create_connect_relayd(struct consumer_output *output, goto error; } - /* Connect to relayd so we can proceed with a session creation. */ + /* + * Connect to relayd so we can proceed with a session creation. This call + * can possibly block for an arbitrary amount of time to set the health + * state to be in poll execution. + */ + health_poll_entry(); ret = relayd_connect(sock); + health_poll_exit(); if (ret < 0) { ERR("Unable to reach lttng-relayd"); ret = LTTNG_ERR_RELAYD_CONNECT_FAIL; @@ -538,18 +553,6 @@ static int send_consumer_relayd_socket(int domain, struct ltt_session *session, 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 */ - uatomic_set(&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 != LTTNG_OK) { @@ -561,6 +564,18 @@ static int send_consumer_relayd_socket(int domain, struct ltt_session *session, session->net_handle = 1; } + /* Set the network sequence index if not set. */ + if (consumer->net_seq_index == (uint64_t) -1ULL) { + pthread_mutex_lock(&relayd_net_seq_idx_lock); + /* + * Increment net_seq_idx because we are about to transfer the + * new relayd socket to the consumer. + * Assign unique key so the consumer can match streams. + */ + consumer->net_seq_index = ++relayd_net_seq_idx; + pthread_mutex_unlock(&relayd_net_seq_idx_lock); + } + /* Send relayd socket to consumer. */ ret = consumer_send_relayd_socket(consumer_sock, sock, consumer, relayd_uri->stype, session->id); @@ -571,9 +586,9 @@ static int send_consumer_relayd_socket(int domain, struct ltt_session *session, /* Flag that the corresponding socket was sent. */ if (relayd_uri->stype == LTTNG_STREAM_CONTROL) { - consumer->dst.net.control_sock_sent = 1; + consumer_sock->control_sock_sent = 1; } else if (relayd_uri->stype == LTTNG_STREAM_DATA) { - consumer->dst.net.data_sock_sent = 1; + consumer_sock->data_sock_sent = 1; } ret = LTTNG_OK; @@ -589,6 +604,14 @@ close_sock: lttcomm_destroy_sock(sock); } + if (ret != LTTNG_OK) { + /* + * On error, nullify the consumer sequence index so streams are not + * associated with it once sent to the consumer. + */ + uatomic_set(&consumer->net_seq_index, -1); + } + return ret; } @@ -607,7 +630,7 @@ static int send_consumer_relayd_sockets(int domain, assert(consumer); /* Sending control relayd socket. */ - if (!consumer->dst.net.control_sock_sent) { + if (!sock->control_sock_sent) { ret = send_consumer_relayd_socket(domain, session, &consumer->dst.net.control, consumer, sock); if (ret != LTTNG_OK) { @@ -616,7 +639,7 @@ static int send_consumer_relayd_sockets(int domain, } /* Sending data relayd socket. */ - if (!consumer->dst.net.data_sock_sent) { + if (!sock->data_sock_sent) { ret = send_consumer_relayd_socket(domain, session, &consumer->dst.net.data, consumer, sock); if (ret != LTTNG_OK) { @@ -633,7 +656,7 @@ error: * the relayd and send them to the right domain consumer. Consumer type MUST be * network. */ -static int setup_relayd(struct ltt_session *session) +int cmd_setup_relayd(struct ltt_session *session) { int ret = LTTNG_OK; struct ltt_ust_session *usess; @@ -646,7 +669,7 @@ static int setup_relayd(struct ltt_session *session) usess = session->ust_session; ksess = session->kernel_session; - DBG2("Setting relayd for session %s", session->name); + DBG("Setting relayd for session %s", session->name); rcu_read_lock(); @@ -766,6 +789,8 @@ int cmd_disable_channel(struct ltt_session *session, int domain, usess = session->ust_session; + rcu_read_lock(); + switch (domain) { case LTTNG_DOMAIN_KERNEL: { @@ -810,6 +835,7 @@ int cmd_disable_channel(struct ltt_session *session, int domain, ret = LTTNG_OK; error: + rcu_read_unlock(); return ret; } @@ -830,6 +856,8 @@ int cmd_enable_channel(struct ltt_session *session, DBG("Enabling channel %s for session %s", attr->name, session->name); + rcu_read_lock(); + switch (domain) { case LTTNG_DOMAIN_KERNEL: { @@ -898,6 +926,7 @@ int cmd_enable_channel(struct ltt_session *session, } error: + rcu_read_unlock(); return ret; } @@ -910,6 +939,8 @@ int cmd_disable_event(struct ltt_session *session, int domain, { int ret; + rcu_read_lock(); + switch (domain) { case LTTNG_DOMAIN_KERNEL: { @@ -924,7 +955,7 @@ int cmd_disable_event(struct ltt_session *session, int domain, goto error; } - ret = event_kernel_disable_tracepoint(ksess, kchan, event_name); + ret = event_kernel_disable_tracepoint(kchan, event_name); if (ret != LTTNG_OK) { goto error; } @@ -968,6 +999,7 @@ int cmd_disable_event(struct ltt_session *session, int domain, ret = LTTNG_OK; error: + rcu_read_unlock(); return ret; } @@ -979,6 +1011,8 @@ int cmd_disable_event_all(struct ltt_session *session, int domain, { int ret; + rcu_read_lock(); + switch (domain) { case LTTNG_DOMAIN_KERNEL: { @@ -993,7 +1027,7 @@ int cmd_disable_event_all(struct ltt_session *session, int domain, goto error; } - ret = event_kernel_disable_all(ksess, kchan); + ret = event_kernel_disable_all(kchan); if (ret != LTTNG_OK) { goto error; } @@ -1037,6 +1071,7 @@ int cmd_disable_event_all(struct ltt_session *session, int domain, ret = LTTNG_OK; error: + rcu_read_unlock(); return ret; } @@ -1126,6 +1161,8 @@ int cmd_enable_event(struct ltt_session *session, int domain, assert(event); assert(channel_name); + rcu_read_lock(); + switch (domain) { case LTTNG_DOMAIN_KERNEL: { @@ -1160,8 +1197,7 @@ int cmd_enable_event(struct ltt_session *session, int domain, goto error; } - ret = event_kernel_enable_tracepoint(session->kernel_session, kchan, - event); + ret = event_kernel_enable_tracepoint(kchan, event); if (ret != LTTNG_OK) { if (channel_created) { /* Let's not leak a useless channel. */ @@ -1225,6 +1261,7 @@ int cmd_enable_event(struct ltt_session *session, int domain, ret = LTTNG_OK; error: + rcu_read_unlock(); return ret; } @@ -1241,6 +1278,8 @@ int cmd_enable_event_all(struct ltt_session *session, int domain, assert(session); assert(channel_name); + rcu_read_lock(); + switch (domain) { case LTTNG_DOMAIN_KERNEL: { @@ -1274,21 +1313,18 @@ int cmd_enable_event_all(struct ltt_session *session, int domain, switch (event_type) { case LTTNG_EVENT_SYSCALL: - ret = event_kernel_enable_all_syscalls(session->kernel_session, - kchan, kernel_tracer_fd); + ret = event_kernel_enable_all_syscalls(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); + ret = event_kernel_enable_all_tracepoints(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); + ret = event_kernel_enable_all(kchan, kernel_tracer_fd); break; default: ret = LTTNG_ERR_KERN_ENABLE_FAIL; @@ -1375,6 +1411,7 @@ int cmd_enable_event_all(struct ltt_session *session, int domain, ret = LTTNG_OK; error: + rcu_read_unlock(); return ret; } @@ -1467,12 +1504,6 @@ int cmd_start_trace(struct ltt_session *session) session->enabled = 1; - ret = setup_relayd(session); - if (ret != LTTNG_OK) { - ERR("Error setting up relayd for session %s", session->name); - goto error; - } - /* Kernel tracing */ if (ksession != NULL) { ret = start_kernel_session(ksession, kernel_tracer_fd); @@ -1610,80 +1641,22 @@ int cmd_set_consumer_uri(int domain, struct ltt_session *session, 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 = LTTNG_ERR_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; - } - + assert(ksess->consumer); + consumer = ksess->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 = LTTNG_ERR_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; - } - + assert(usess->consumer); + consumer = usess->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 - * socket for the session was already sent. - */ - if (uris[i].dtype == LTTNG_DST_PATH || - (uris[i].stype == LTTNG_STREAM_CONTROL && - consumer->dst.net.control_sock_sent) || - (uris[i].stype == LTTNG_STREAM_DATA && - consumer->dst.net.data_sock_sent)) { - continue; - } - - /* Try to send relayd URI to the consumer if exist. */ - rcu_read_lock(); - 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_consumer_relayd_socket(domain, session, &uris[i], - consumer, socket); - pthread_mutex_unlock(socket->lock); - if (ret != LTTNG_OK) { - rcu_read_unlock(); - goto error; - } - } - rcu_read_unlock(); } /* All good! */ @@ -1705,6 +1678,12 @@ int cmd_create_session_uri(char *name, struct lttng_uri *uris, assert(name); + /* No URIs is not possible. */ + if (uris == NULL) { + ret = LTTNG_ERR_SESSION_FAIL; + goto session_error; + } + /* * Verify if the session already exist * @@ -1742,22 +1721,6 @@ int cmd_create_session_uri(char *name, struct lttng_uri *uris, 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 != LTTNG_OK) { goto consumer_error; @@ -1765,7 +1728,6 @@ int cmd_create_session_uri(char *name, struct lttng_uri *uris, session->consumer->enabled = 1; -end: return LTTNG_OK; consumer_error: @@ -2126,266 +2088,6 @@ void cmd_list_lttng_sessions(struct lttng_session *sessions, uid_t uid, } } -/* - * Command LTTNG_DISABLE_CONSUMER processed by the client thread. - */ -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; - - assert(session); - - if (session->enabled) { - /* Can't disable consumer on an already started session */ - ret = LTTNG_ERR_TRACE_ALREADY_STARTED; - goto error; - } - - if (!session->start_consumer) { - ret = LTTNG_ERR_NO_CONSUMER; - 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; - - break; - default: - ret = LTTNG_ERR_UNKNOWN_DOMAIN; - goto error; - } - - if (consumer) { - consumer->enabled = 0; - /* Success at this point */ - ret = LTTNG_OK; - } else { - ret = LTTNG_ERR_NO_CONSUMER; - } - -error: - return ret; -} - -/* - * Command LTTNG_ENABLE_CONSUMER processed by the client thread. - */ -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 *consumer = NULL; - - assert(session); - - /* Can't enable consumer after session started. */ - if (session->enabled) { - ret = LTTNG_ERR_TRACE_ALREADY_STARTED; - 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 = LTTNG_ERR_ENABLE_CONSUMER_FAIL; - goto error; - } - - consumer = ksess->tmp_consumer; - if (consumer == NULL) { - ret = LTTNG_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 = LTTNG_ERR_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 = LTTNG_ERR_URL_CTRL_MISS; - goto error; - } - - if (!consumer->dst.net.data_isset) { - ret = LTTNG_ERR_URL_DATA_MISS; - goto error; - } - - /* Check established network session state */ - if (session->net_handle == 0) { - ret = LTTNG_ERR_ENABLE_CONSUMER_FAIL; - ERR("Session network handle is not set on enable-consumer"); - goto error; - } - - 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. - */ - rcu_read_lock(); - /* Destroy current consumer. We are about to replace it */ - 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 = LTTNG_ERR_ENABLE_CONSUMER_FAIL; - goto error; - } - - consumer = usess->tmp_consumer; - if (consumer == NULL) { - ret = LTTNG_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 = LTTNG_ERR_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 = LTTNG_ERR_URL_CTRL_MISS; - goto error; - } - - if (!consumer->dst.net.data_isset) { - ret = LTTNG_ERR_URL_DATA_MISS; - goto error; - } - - /* Check established network session state */ - if (session->net_handle == 0) { - ret = LTTNG_ERR_ENABLE_CONSUMER_FAIL; - DBG2("Session network handle is not set on enable-consumer"); - goto error; - } - - if (consumer->net_seq_index == -1) { - ret = LTTNG_ERR_ENABLE_CONSUMER_FAIL; - DBG2("Network index is not set on the consumer"); - goto error; - } - - 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. - */ - rcu_read_lock(); - /* Destroy current consumer. We are about to replace it */ - consumer_destroy_output(usess->consumer); - rcu_read_unlock(); - usess->consumer = consumer; - usess->tmp_consumer = NULL; - - break; - } - - session->start_consumer = 1; - - /* Enable it */ - if (consumer) { - consumer->enabled = 1; - /* Success at this point */ - ret = LTTNG_OK; - } else { - /* Should not really happend... */ - ret = LTTNG_ERR_NO_CONSUMER; - } - -error: - return ret; -} - /* * Command LTTNG_DATA_PENDING returning 0 if the data is NOT pending meaning * ready for trace analysis (or anykind of reader) or else 1 for pending data. @@ -2433,10 +2135,12 @@ error: void cmd_init(void) { /* - * Set network sequence index to 1 for streams to match a relayd socket on - * the consumer side. + * Set network sequence index to 1 for streams to match a relayd + * socket on the consumer side. */ - uatomic_set(&relayd_net_seq_idx, 1); + pthread_mutex_lock(&relayd_net_seq_idx_lock); + relayd_net_seq_idx = 1; + pthread_mutex_unlock(&relayd_net_seq_idx_lock); DBG("Command subsystem initialized"); }