X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fcmd.c;h=c783e82f0871f9b8516654b7e1aa58d94ad13336;hp=5d2cba1d467befbde02cfcc44183304303259421;hb=07b86b528dc279d59cdf16e6cb946c144fe773f2;hpb=bef08707d594ea79f311ff04d470436724670754 diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index 5d2cba1d4..c783e82f0 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -17,6 +17,7 @@ #define _GNU_SOURCE #include +#include #include #include @@ -546,7 +547,7 @@ error: /* * Connect to the relayd using URI and send the socket to the right consumer. */ -static int send_consumer_relayd_socket(int domain, struct ltt_session *session, +static int send_consumer_relayd_socket(int domain, unsigned int session_id, struct lttng_uri *relayd_uri, struct consumer_output *consumer, struct consumer_socket *consumer_sock) { @@ -560,11 +561,6 @@ static int send_consumer_relayd_socket(int domain, struct ltt_session *session, } assert(rsock); - /* If the control socket is connected, network session is ready */ - if (relayd_uri->stype == LTTNG_STREAM_CONTROL) { - 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); @@ -579,7 +575,7 @@ static int send_consumer_relayd_socket(int domain, struct ltt_session *session, /* Send relayd socket to consumer. */ ret = consumer_send_relayd_socket(consumer_sock, rsock, consumer, - relayd_uri->stype, session->id); + relayd_uri->stype, session_id); if (ret < 0) { ret = LTTNG_ERR_ENABLE_CONSUMER_FAIL; goto close_sock; @@ -606,10 +602,11 @@ close_sock: error: if (ret != LTTNG_OK) { /* - * On error, nullify the consumer sequence index so streams are not - * associated with it once sent to the consumer. + * The consumer output for this session should not be used anymore + * since the relayd connection failed thus making any tracing or/and + * streaming not usable. */ - uatomic_set(&consumer->net_seq_index, -1); + consumer->enabled = 0; } return ret; } @@ -619,18 +616,17 @@ error: * helper function to facilitate sending the information to the consumer for a * session. */ -static int send_consumer_relayd_sockets(int domain, - struct ltt_session *session, struct consumer_output *consumer, - struct consumer_socket *sock) +static int send_consumer_relayd_sockets(int domain, unsigned int session_id, + struct consumer_output *consumer, struct consumer_socket *sock) { int ret = LTTNG_OK; - assert(session); assert(consumer); + assert(sock); /* Sending control relayd socket. */ if (!sock->control_sock_sent) { - ret = send_consumer_relayd_socket(domain, session, + ret = send_consumer_relayd_socket(domain, session_id, &consumer->dst.net.control, consumer, sock); if (ret != LTTNG_OK) { goto error; @@ -639,7 +635,7 @@ static int send_consumer_relayd_sockets(int domain, /* Sending data relayd socket. */ if (!sock->data_sock_sent) { - ret = send_consumer_relayd_socket(domain, session, + ret = send_consumer_relayd_socket(domain, session_id, &consumer->dst.net.data, consumer, sock); if (ret != LTTNG_OK) { goto error; @@ -681,12 +677,14 @@ int cmd_setup_relayd(struct ltt_session *session) assert(socket->fd >= 0); pthread_mutex_lock(socket->lock); - ret = send_consumer_relayd_sockets(LTTNG_DOMAIN_UST, session, + ret = send_consumer_relayd_sockets(LTTNG_DOMAIN_UST, session->id, usess->consumer, socket); pthread_mutex_unlock(socket->lock); if (ret != LTTNG_OK) { goto error; } + /* Session is now ready for network streaming. */ + session->net_handle = 1; } } @@ -698,12 +696,14 @@ int cmd_setup_relayd(struct ltt_session *session) assert(socket->fd >= 0); pthread_mutex_lock(socket->lock); - ret = send_consumer_relayd_sockets(LTTNG_DOMAIN_KERNEL, session, + ret = send_consumer_relayd_sockets(LTTNG_DOMAIN_KERNEL, session->id, ksess->consumer, socket); pthread_mutex_unlock(socket->lock); if (ret != LTTNG_OK) { goto error; } + /* Session is now ready for network streaming. */ + session->net_handle = 1; } } @@ -721,7 +721,7 @@ static int start_kernel_session(struct ltt_kernel_session *ksess, int wpipe) struct ltt_kernel_channel *kchan; /* Open kernel metadata */ - if (ksess->metadata == NULL) { + if (ksess->metadata == NULL && ksess->output_traces) { ret = kernel_open_metadata(ksess); if (ret < 0) { ret = LTTNG_ERR_KERN_META_FAIL; @@ -730,7 +730,7 @@ static int start_kernel_session(struct ltt_kernel_session *ksess, int wpipe) } /* Open kernel metadata stream */ - if (ksess->metadata_stream_fd < 0) { + if (ksess->metadata && ksess->metadata_stream_fd < 0) { ret = kernel_open_metadata_stream(ksess); if (ret < 0) { ERR("Kernel create metadata stream failed"); @@ -754,7 +754,7 @@ static int start_kernel_session(struct ltt_kernel_session *ksess, int wpipe) /* Setup kernel consumer socket and send fds to it */ ret = init_kernel_tracing(ksess); - if (ret < 0) { + if (ret != 0) { ret = LTTNG_ERR_KERN_START_FAIL; goto error; } @@ -856,6 +856,15 @@ int cmd_enable_channel(struct ltt_session *session, DBG("Enabling channel %s for session %s", attr->name, session->name); + /* + * Don't try to enable a channel if the session has been started at + * some point in time before. The tracer does not allow it. + */ + if (session->started) { + ret = LTTNG_ERR_TRACE_ALREADY_STARTED; + goto error; + } + rcu_read_lock(); switch (domain->type) { @@ -876,18 +885,6 @@ int cmd_enable_channel(struct ltt_session *session, } kernel_wait_quiescent(kernel_tracer_fd); - - /* - * If the session was previously started, start as well this newly - * created kernel session so the events/channels enabled *after* the - * start actually work. - */ - if (session->started && !session->kernel_session->started) { - ret = start_kernel_session(session->kernel_session, wpipe); - if (ret != LTTNG_OK) { - goto error; - } - } break; } case LTTNG_DOMAIN_UST: @@ -902,17 +899,6 @@ int cmd_enable_channel(struct ltt_session *session, } else { ret = channel_ust_enable(usess, uchan); } - - /* Start the UST session if the session was already started. */ - if (session->started && !usess->start_trace) { - ret = ust_app_start_trace_all(usess); - if (ret < 0) { - ret = LTTNG_ERR_UST_START_FAIL; - goto error; - } - ret = LTTNG_OK; - usess->start_trace = 1; - } break; } default: @@ -1076,7 +1062,7 @@ error: int cmd_add_context(struct ltt_session *session, int domain, char *channel_name, struct lttng_event_context *ctx, int kwpipe) { - int ret; + int ret, chan_kern_created = 0, chan_ust_created = 0; switch (domain) { case LTTNG_DOMAIN_KERNEL: @@ -1088,6 +1074,7 @@ int cmd_add_context(struct ltt_session *session, int domain, if (ret != LTTNG_OK) { goto error; } + chan_kern_created = 1; } /* Add kernel context to kernel tracer */ @@ -1106,7 +1093,7 @@ int cmd_add_context(struct ltt_session *session, int domain, if (chan_count == 0) { struct lttng_channel *attr; /* Create default channel */ - attr = channel_new_default_attr(domain); + attr = channel_new_default_attr(domain, usess->buffer_type); if (attr == NULL) { ret = LTTNG_ERR_FATAL; goto error; @@ -1118,6 +1105,7 @@ int cmd_add_context(struct ltt_session *session, int domain, goto error; } free(attr); + chan_ust_created = 1; } ret = context_ust_add(usess, domain, ctx, channel_name); @@ -1136,9 +1124,30 @@ int cmd_add_context(struct ltt_session *session, int domain, goto error; } - ret = LTTNG_OK; + return LTTNG_OK; error: + if (chan_kern_created) { + struct ltt_kernel_channel *kchan = + trace_kernel_get_channel_by_name(DEFAULT_CHANNEL_NAME, + session->kernel_session); + /* Created previously, this should NOT fail. */ + assert(kchan); + kernel_destroy_channel(kchan); + } + + if (chan_ust_created) { + struct ltt_ust_channel *uchan = + trace_ust_find_channel_by_name( + session->ust_session->domain_global.channels, + DEFAULT_CHANNEL_NAME); + /* Created previously, this should NOT fail. */ + assert(uchan); + /* Remove from the channel list of the session. */ + trace_ust_delete_channel(session->ust_session->domain_global.channels, + uchan); + trace_ust_destroy_channel(uchan); + } return ret; } @@ -1166,7 +1175,8 @@ int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain, kchan = trace_kernel_get_channel_by_name(channel_name, session->kernel_session); if (kchan == NULL) { - attr = channel_new_default_attr(LTTNG_DOMAIN_KERNEL); + attr = channel_new_default_attr(LTTNG_DOMAIN_KERNEL, + LTTNG_BUFFER_GLOBAL); if (attr == NULL) { ret = LTTNG_ERR_FATAL; goto error; @@ -1216,7 +1226,8 @@ int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain, channel_name); if (uchan == NULL) { /* Create default channel */ - attr = channel_new_default_attr(LTTNG_DOMAIN_UST); + attr = channel_new_default_attr(LTTNG_DOMAIN_UST, + usess->buffer_type); if (attr == NULL) { ret = LTTNG_ERR_FATAL; goto error; @@ -1286,7 +1297,8 @@ int cmd_enable_event_all(struct ltt_session *session, session->kernel_session); if (kchan == NULL) { /* Create default channel */ - attr = channel_new_default_attr(LTTNG_DOMAIN_KERNEL); + attr = channel_new_default_attr(LTTNG_DOMAIN_KERNEL, + LTTNG_BUFFER_GLOBAL); if (attr == NULL) { ret = LTTNG_ERR_FATAL; goto error; @@ -1350,7 +1362,8 @@ int cmd_enable_event_all(struct ltt_session *session, channel_name); if (uchan == NULL) { /* Create default channel */ - attr = channel_new_default_attr(LTTNG_DOMAIN_UST); + attr = channel_new_default_attr(LTTNG_DOMAIN_UST, + usess->buffer_type); if (attr == NULL) { ret = LTTNG_ERR_FATAL; goto error; @@ -1549,7 +1562,7 @@ int cmd_stop_trace(struct ltt_session *session) session->enabled = 0; /* Kernel tracer */ - if (ksession) { + if (ksession && ksession->started) { DBG("Stop kernel tracing"); /* Flush metadata if exist */ @@ -1579,7 +1592,7 @@ int cmd_stop_trace(struct ltt_session *session) ksession->started = 0; } - if (usess) { + if (usess && usess->start_trace) { usess->start_trace = 0; ret = ust_app_stop_trace_all(usess); @@ -1589,8 +1602,6 @@ int cmd_stop_trace(struct ltt_session *session) } } - session->started = 0; - ret = LTTNG_OK; error: @@ -1670,12 +1681,7 @@ int cmd_create_session_uri(char *name, struct lttng_uri *uris, struct ltt_session *session; assert(name); - - /* No URIs is not possible. */ - if (uris == NULL) { - ret = LTTNG_ERR_SESSION_FAIL; - goto session_error; - } + assert(creds); /* * Verify if the session already exist @@ -1714,9 +1720,15 @@ int cmd_create_session_uri(char *name, struct lttng_uri *uris, goto consumer_error; } - ret = cmd_set_consumer_uri(0, session, nb_uri, uris); - if (ret != LTTNG_OK) { - goto consumer_error; + if (uris) { + ret = cmd_set_consumer_uri(0, session, nb_uri, uris); + if (ret != LTTNG_OK) { + goto consumer_error; + } + session->output_traces = 1; + } else { + session->output_traces = 0; + DBG2("Session %s created with no output", session->name); } session->consumer->enabled = 1; @@ -1827,7 +1839,7 @@ int cmd_register_consumer(struct ltt_session *session, int domain, const char *sock_path, struct consumer_data *cdata) { int ret, sock; - struct consumer_socket *socket; + struct consumer_socket *socket = NULL; assert(session); assert(cdata); @@ -1887,9 +1899,12 @@ int cmd_register_consumer(struct ltt_session *session, int domain, goto error; } - ret = LTTNG_OK; + return LTTNG_OK; error: + if (socket) { + consumer_destroy_socket(socket); + } return ret; } @@ -2123,6 +2138,440 @@ error: return ret; } +/* + * Command LTTNG_SNAPSHOT_ADD_OUTPUT from the lttng ctl library. + * + * Return LTTNG_OK on success or else a LTTNG_ERR code. + */ +int cmd_snapshot_add_output(struct ltt_session *session, + struct lttng_snapshot_output *output, uint32_t *id) +{ + int ret; + struct snapshot_output *new_output; + + assert(session); + assert(output); + + DBG("Cmd snapshot add output for session %s", session->name); + + /* + * Persmission denied to create an output if the session is not set in no + * output mode. + */ + if (session->output_traces) { + ret = LTTNG_ERR_EPERM; + goto error; + } + + /* Only one output is allowed until we have the "tee" feature. */ + if (session->snapshot.nb_output == 1) { + ret = LTTNG_ERR_SNAPSHOT_OUTPUT_EXIST; + goto error; + } + + new_output = snapshot_output_alloc(); + if (!new_output) { + ret = LTTNG_ERR_NOMEM; + goto error; + } + + ret = snapshot_output_init(output->max_size, output->name, + output->ctrl_url, output->data_url, session->consumer, new_output, + &session->snapshot); + if (ret < 0) { + if (ret == -ENOMEM) { + ret = LTTNG_ERR_NOMEM; + } else { + ret = LTTNG_ERR_INVALID; + } + goto free_error; + } + + /* + * Copy sockets so the snapshot output can use them on destroy. + */ + + if (session->ust_session) { + ret = consumer_copy_sockets(new_output->consumer, + session->ust_session->consumer); + if (ret < 0) { + goto free_error; + } + new_output->ust_sockets_copied = 1; + } + if (session->kernel_session) { + ret = consumer_copy_sockets(new_output->consumer, + session->kernel_session->consumer); + if (ret < 0) { + goto free_error; + } + new_output->kernel_sockets_copied = 1; + } + + rcu_read_lock(); + snapshot_add_output(&session->snapshot, new_output); + if (id) { + *id = new_output->id; + } + rcu_read_unlock(); + + return LTTNG_OK; + +free_error: + snapshot_output_destroy(new_output); +error: + return ret; +} + +/* + * Command LTTNG_SNAPSHOT_DEL_OUTPUT from lib lttng ctl. + * + * Return LTTNG_OK on success or else a LTTNG_ERR code. + */ +int cmd_snapshot_del_output(struct ltt_session *session, + struct lttng_snapshot_output *output) +{ + int ret; + struct snapshot_output *sout; + + assert(session); + assert(output); + + DBG("Cmd snapshot del output id %" PRIu32 " for session %s", output->id, + session->name); + + rcu_read_lock(); + + /* + * Persmission denied to create an output if the session is not set in no + * output mode. + */ + if (session->output_traces) { + ret = LTTNG_ERR_EPERM; + goto error; + } + + sout = snapshot_find_output_by_id(output->id, &session->snapshot); + if (!sout) { + ret = LTTNG_ERR_INVALID; + goto error; + } + + snapshot_delete_output(&session->snapshot, sout); + snapshot_output_destroy(sout); + ret = LTTNG_OK; + +error: + rcu_read_unlock(); + return ret; +} + +/* + * Command LTTNG_SNAPSHOT_LIST_OUTPUT from lib lttng ctl. + * + * If no output is available, outputs is untouched and 0 is returned. + * + * Return the size of the newly allocated outputs or a negative LTTNG_ERR code. + */ +ssize_t cmd_snapshot_list_outputs(struct ltt_session *session, + struct lttng_snapshot_output **outputs) +{ + int ret, idx = 0; + struct lttng_snapshot_output *list; + struct lttng_ht_iter iter; + struct snapshot_output *output; + + assert(session); + assert(outputs); + + DBG("Cmd snapshot list outputs for session %s", session->name); + + /* + * Persmission denied to create an output if the session is not set in no + * output mode. + */ + if (session->output_traces) { + ret = LTTNG_ERR_EPERM; + goto error; + } + + if (session->snapshot.nb_output == 0) { + ret = 0; + goto error; + } + + list = zmalloc(session->snapshot.nb_output * sizeof(*list)); + if (!list) { + ret = LTTNG_ERR_NOMEM; + goto error; + } + + /* Copy list from session to the new list object. */ + cds_lfht_for_each_entry(session->snapshot.output_ht->ht, &iter.iter, + output, node.node) { + assert(output->consumer); + list[idx].id = output->id; + list[idx].max_size = output->max_size; + strncpy(list[idx].name, output->name, sizeof(list[idx].name)); + if (output->consumer->type == CONSUMER_DST_LOCAL) { + strncpy(list[idx].ctrl_url, output->consumer->dst.trace_path, + sizeof(list[idx].ctrl_url)); + } else { + /* Control URI. */ + ret = uri_to_str_url(&output->consumer->dst.net.control, + list[idx].ctrl_url, sizeof(list[idx].ctrl_url)); + if (ret < 0) { + ret = LTTNG_ERR_NOMEM; + goto free_error; + } + + /* Data URI. */ + ret = uri_to_str_url(&output->consumer->dst.net.data, + list[idx].data_url, sizeof(list[idx].data_url)); + if (ret < 0) { + ret = LTTNG_ERR_NOMEM; + goto free_error; + } + } + idx++; + } + + *outputs = list; + return session->snapshot.nb_output; + +free_error: + free(list); +error: + return -ret; +} + +/* + * Send relayd sockets from snapshot output to consumer. Ignore request if the + * snapshot output is *not* set with a remote destination. + * + * Return 0 on success or else a negative value. + */ +static int set_relayd_for_snapshot(struct consumer_output *consumer, + struct snapshot_output *snap_output, struct ltt_session *session) +{ + int ret = 0; + struct lttng_ht_iter iter; + struct consumer_socket *socket; + + assert(consumer); + assert(snap_output); + assert(session); + + DBG2("Set relayd object from snapshot output"); + + /* Ignore if snapshot consumer output is not network. */ + if (snap_output->consumer->type != CONSUMER_DST_NET) { + goto error; + } + + /* + * For each consumer socket, create and send the relayd object of the + * snapshot output. + */ + rcu_read_lock(); + cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter, socket, + node.node) { + ret = send_consumer_relayd_sockets(0, session->id, + snap_output->consumer, socket); + if (ret < 0) { + rcu_read_unlock(); + goto error; + } + } + rcu_read_unlock(); + +error: + return ret; +} + +/* + * Record a kernel snapshot. + * + * Return 0 on success or else a negative value. + */ +static int record_kernel_snapshot(struct ltt_kernel_session *ksess, + struct snapshot_output *output, struct ltt_session *session, int wait) +{ + int ret; + + assert(ksess); + assert(output); + assert(session); + + if (!output->kernel_sockets_copied) { + ret = consumer_copy_sockets(output->consumer, ksess->consumer); + if (ret < 0) { + goto error; + } + output->kernel_sockets_copied = 1; + } + + ret = set_relayd_for_snapshot(ksess->consumer, output, session); + if (ret < 0) { + goto error; + } + + ret = kernel_snapshot_record(ksess, output, wait); + if (ret < 0) { + goto error; + } + +error: + return ret; +} + +/* + * Record a UST snapshot. + * + * Return 0 on success or else a negative value. + */ +static int record_ust_snapshot(struct ltt_ust_session *usess, + struct snapshot_output *output, struct ltt_session *session, int wait) +{ + int ret; + + assert(usess); + assert(output); + assert(session); + + if (!output->ust_sockets_copied) { + ret = consumer_copy_sockets(output->consumer, usess->consumer); + if (ret < 0) { + goto error; + } + output->ust_sockets_copied = 1; + } + + ret = set_relayd_for_snapshot(usess->consumer, output, session); + if (ret < 0) { + goto error; + } + + ret = ust_app_snapshot_record(usess, output, wait); + if (ret < 0) { + goto error; + } + +error: + return ret; +} + +/* + * Command LTTNG_SNAPSHOT_RECORD from lib lttng ctl. + * + * The wait parameter is ignored so this call always wait for the snapshot to + * complete before returning. + * + * Return LTTNG_OK on success or else a LTTNG_ERR code. + */ +int cmd_snapshot_record(struct ltt_session *session, + struct lttng_snapshot_output *output, int wait) +{ + int ret = LTTNG_OK; + struct snapshot_output *tmp_sout = NULL; + + assert(session); + + DBG("Cmd snapshot record for session %s", session->name); + + /* + * Persmission denied to create an output if the session is not set in no + * output mode. + */ + if (session->output_traces) { + ret = LTTNG_ERR_EPERM; + goto error; + } + + /* The session needs to be started at least once. */ + if (!session->started) { + ret = LTTNG_ERR_START_SESSION_ONCE; + goto error; + } + + /* Use temporary output for the session. */ + if (output && *output->ctrl_url != '\0') { + tmp_sout = snapshot_output_alloc(); + if (!tmp_sout) { + ret = LTTNG_ERR_NOMEM; + goto error; + } + + ret = snapshot_output_init(output->max_size, output->name, + output->ctrl_url, output->data_url, session->consumer, + tmp_sout, NULL); + if (ret < 0) { + if (ret == -ENOMEM) { + ret = LTTNG_ERR_NOMEM; + } else { + ret = LTTNG_ERR_INVALID; + } + goto error; + } + } + + if (session->kernel_session) { + struct ltt_kernel_session *ksess = session->kernel_session; + + if (tmp_sout) { + ret = record_kernel_snapshot(ksess, tmp_sout, session, wait); + if (ret < 0) { + goto error; + } + } else { + struct snapshot_output *sout; + struct lttng_ht_iter iter; + + rcu_read_lock(); + cds_lfht_for_each_entry(session->snapshot.output_ht->ht, + &iter.iter, sout, node.node) { + ret = record_kernel_snapshot(ksess, sout, session, wait); + if (ret < 0) { + rcu_read_unlock(); + goto error; + } + } + rcu_read_unlock(); + } + } + + if (session->ust_session) { + struct ltt_ust_session *usess = session->ust_session; + + if (tmp_sout) { + ret = record_ust_snapshot(usess, tmp_sout, session, wait); + if (ret < 0) { + goto error; + } + } else { + struct snapshot_output *sout; + struct lttng_ht_iter iter; + + rcu_read_lock(); + cds_lfht_for_each_entry(session->snapshot.output_ht->ht, + &iter.iter, sout, node.node) { + ret = record_ust_snapshot(usess, tmp_sout, session, wait); + if (ret < 0) { + rcu_read_unlock(); + goto error; + } + } + rcu_read_unlock(); + } + } + +error: + if (tmp_sout) { + snapshot_output_destroy(tmp_sout); + } + return ret; +} + /* * Init command subsystem. */