X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fcmd.c;h=53850f74aae784b97a668f30c429c92cca8858be;hp=a17cc678ecab2363a95166b82f1c794a15c8ff96;hb=dbfee52cc949c9ac51976ef4680f2e145aa1f1a9;hpb=3285a971b225891df3dc7c2796176ce1f94665fe diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index a17cc678e..53850f74a 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -998,6 +998,8 @@ static enum lttng_error_code create_connect_relayd(struct lttng_uri *uri, /* Create socket for control stream. */ if (uri->stype == LTTNG_STREAM_CONTROL) { + uint64_t result_flags; + DBG3("Creating relayd stream socket from URI"); /* Check relayd version */ @@ -1012,6 +1014,16 @@ static enum lttng_error_code create_connect_relayd(struct lttng_uri *uri, } consumer->relay_major_version = rsock->major; consumer->relay_minor_version = rsock->minor; + ret = relayd_get_configuration(rsock, 0, + &result_flags); + if (ret < 0) { + ERR("Unable to get relayd configuration"); + status = LTTNG_ERR_RELAYD_CONNECT_FAIL; + goto close_sock; + } + if (result_flags & LTTCOMM_RELAYD_CONFIGURATION_FLAG_CLEAR_ALLOWED) { + consumer->relay_allows_clear = true; + } } else if (uri->stype == LTTNG_STREAM_DATA) { DBG3("Creating relayd data socket from URI"); } else { @@ -1185,6 +1197,7 @@ int cmd_setup_relayd(struct ltt_session *session) DBG("Setting relayd for session %s", session->name); + rcu_read_lock(); if (session->current_trace_chunk) { enum lttng_trace_chunk_status status = lttng_trace_chunk_get_id( session->current_trace_chunk, ¤t_chunk_id.value); @@ -1198,8 +1211,6 @@ int cmd_setup_relayd(struct ltt_session *session) } } - rcu_read_lock(); - if (usess && usess->consumer && usess->consumer->type == CONSUMER_DST_NET && usess->consumer->enabled) { /* For each consumer socket, send relayd sockets */ @@ -1225,6 +1236,8 @@ int cmd_setup_relayd(struct ltt_session *session) usess->consumer->relay_major_version; session->consumer->relay_minor_version = usess->consumer->relay_minor_version; + session->consumer->relay_allows_clear = + usess->consumer->relay_allows_clear; } if (ksess && ksess->consumer && ksess->consumer->type == CONSUMER_DST_NET @@ -1251,6 +1264,8 @@ int cmd_setup_relayd(struct ltt_session *session) ksess->consumer->relay_major_version; session->consumer->relay_minor_version = ksess->consumer->relay_minor_version; + session->consumer->relay_allows_clear = + ksess->consumer->relay_allows_clear; } error: @@ -1261,7 +1276,7 @@ error: /* * Start a kernel session by opening all necessary streams. */ -static int start_kernel_session(struct ltt_kernel_session *ksess) +int start_kernel_session(struct ltt_kernel_session *ksess) { int ret; struct ltt_kernel_channel *kchan; @@ -1323,6 +1338,53 @@ error: return ret; } +int stop_kernel_session(struct ltt_kernel_session *ksess) +{ + struct ltt_kernel_channel *kchan; + bool error_occurred = false; + int ret; + + if (!ksess || !ksess->active) { + return LTTNG_OK; + } + DBG("Stopping kernel tracing"); + + ret = kernel_stop_session(ksess); + if (ret < 0) { + ret = LTTNG_ERR_KERN_STOP_FAIL; + goto error; + } + + kernel_wait_quiescent(); + + /* Flush metadata after stopping (if exists) */ + if (ksess->metadata_stream_fd >= 0) { + ret = kernel_metadata_flush_buffer(ksess->metadata_stream_fd); + if (ret < 0) { + ERR("Kernel metadata flush failed"); + error_occurred = true; + } + } + + /* Flush all buffers after stopping */ + cds_list_for_each_entry(kchan, &ksess->channel_list.head, list) { + ret = kernel_flush_buffer(kchan); + if (ret < 0) { + ERR("Kernel flush buffer error"); + error_occurred = true; + } + } + + ksess->active = 0; + if (error_occurred) { + ret = LTTNG_ERR_UNK; + } else { + ret = LTTNG_OK; + } +error: + return ret; +} + /* * Command LTTNG_DISABLE_CHANNEL processed by the client thread. */ @@ -2572,6 +2634,10 @@ int cmd_start_trace(struct ltt_session *session) unsigned long nb_chan = 0; struct ltt_kernel_session *ksession; struct ltt_ust_session *usess; + const bool session_rotated_after_last_stop = + session->rotated_after_last_stop; + const bool session_cleared_after_last_stop = + session->cleared_after_last_stop; assert(session); @@ -2585,6 +2651,22 @@ int cmd_start_trace(struct ltt_session *session) goto error; } + if (session->rotation_state == LTTNG_ROTATION_STATE_ONGOING && + !session->current_trace_chunk) { + /* + * A rotation was launched while the session was stopped and + * it has not been completed yet. It is not possible to start + * the session since starting the session here would require a + * rotation from "NULL" to a new trace chunk. That rotation + * would overlap with the ongoing rotation, which is not + * supported. + */ + WARN("Refusing to start session \"%s\" as a rotation launched after the last \"stop\" is still ongoing", + session->name); + ret = LTTNG_ERR_ROTATION_PENDING; + goto error; + } + /* * Starting a session without channel is useless since after that it's not * possible to enable channel thus inform the client. @@ -2600,21 +2682,47 @@ int cmd_start_trace(struct ltt_session *session) goto error; } + session->active = 1; + session->rotated_after_last_stop = false; + session->cleared_after_last_stop = false; if (session->output_traces && !session->current_trace_chunk) { - struct lttng_trace_chunk *trace_chunk; + if (!session->has_been_started) { + struct lttng_trace_chunk *trace_chunk; - trace_chunk = session_create_new_trace_chunk( - session, NULL, NULL, NULL); - if (!trace_chunk) { - ret = LTTNG_ERR_CREATE_DIR_FAIL; - goto error; - } - assert(!session->current_trace_chunk); - ret = session_set_trace_chunk(session, trace_chunk, NULL); - lttng_trace_chunk_put(trace_chunk); - if (ret) { - ret = LTTNG_ERR_CREATE_TRACE_CHUNK_FAIL_CONSUMER; - goto error; + DBG("Creating initial trace chunk of session \"%s\"", + session->name); + trace_chunk = session_create_new_trace_chunk( + session, NULL, NULL, NULL); + if (!trace_chunk) { + ret = LTTNG_ERR_CREATE_DIR_FAIL; + goto error; + } + assert(!session->current_trace_chunk); + ret = session_set_trace_chunk(session, trace_chunk, + NULL); + lttng_trace_chunk_put(trace_chunk); + if (ret) { + ret = LTTNG_ERR_CREATE_TRACE_CHUNK_FAIL_CONSUMER; + goto error; + } + } else { + DBG("Rotating session \"%s\" from its current \"NULL\" trace chunk to a new chunk", + session->name); + /* + * Rotate existing streams into the new chunk. + * This is a "quiet" rotation has no client has + * explicitly requested this operation. + * + * There is also no need to wait for the rotation + * to complete as it will happen immediately. No data + * was produced as the session was stopped, so the + * rotation should happen on reception of the command. + */ + ret = cmd_rotate_session(session, NULL, true, + LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION); + if (ret != LTTNG_OK) { + goto error; + } } } @@ -2637,10 +2745,6 @@ int cmd_start_trace(struct ltt_session *session) } } - /* Flag this after a successful start. */ - session->has_been_started = 1; - session->active = 1; - /* * Clear the flag that indicates that a rotation was done while the * session was stopped. @@ -2661,6 +2765,17 @@ int cmd_start_trace(struct ltt_session *session) ret = LTTNG_OK; error: + if (ret == LTTNG_OK) { + /* Flag this after a successful start. */ + session->has_been_started |= 1; + } else { + session->active = 0; + /* Restore initial state on error. */ + session->rotated_after_last_stop = + session_rotated_after_last_stop; + session->cleared_after_last_stop = + session_cleared_after_last_stop; + } return ret; } @@ -2670,14 +2785,12 @@ error: 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; - bool error_occurred = false; assert(session); - DBG("Begin stop session %s (id %" PRIu64 ")", session->name, session->id); + DBG("Begin stop session \"%s\" (id %" PRIu64 ")", session->name, session->id); /* Short cut */ ksession = session->kernel_session; usess = session->ust_session; @@ -2688,39 +2801,9 @@ int cmd_stop_trace(struct ltt_session *session) goto error; } - /* Kernel tracer */ - if (ksession && ksession->active) { - DBG("Stop kernel tracing"); - - ret = kernel_stop_session(ksession); - if (ret < 0) { - ret = LTTNG_ERR_KERN_STOP_FAIL; - goto error; - } - - kernel_wait_quiescent(); - - /* Flush metadata after stopping (if exists) */ - if (ksession->metadata_stream_fd >= 0) { - ret = kernel_metadata_flush_buffer(ksession->metadata_stream_fd); - if (ret < 0) { - ERR("Kernel metadata flush failed"); - error_occurred = true; - } - } - - /* Flush all buffers after 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"); - error_occurred = true; - } - } - - ksession->active = 0; - DBG("Kernel session stopped %s (id %" PRIu64 ")", session->name, - session->id); + ret = stop_kernel_session(ksession); + if (ret != LTTNG_OK) { + goto error; } if (usess && usess->active) { @@ -2731,14 +2814,55 @@ int cmd_stop_trace(struct ltt_session *session) } } + DBG("Completed stop session \"%s\" (id %" PRIu64 ")", session->name, + session->id); /* Flag inactive after a successful stop. */ session->active = 0; - ret = !error_occurred ? LTTNG_OK : LTTNG_ERR_UNK; + ret = LTTNG_OK; error: return ret; } +/* + * Set the base_path of the session only if subdir of a control uris is set. + * Return LTTNG_OK on success, otherwise LTTNG_ERR_*. + */ +static int set_session_base_path_from_uris(struct ltt_session *session, + size_t nb_uri, + struct lttng_uri *uris) +{ + int ret; + size_t i; + + for (i = 0; i < nb_uri; i++) { + if (uris[i].stype != LTTNG_STREAM_CONTROL || + uris[i].subdir[0] == '\0') { + /* Not interested in these URIs */ + continue; + } + + if (session->base_path != NULL) { + free(session->base_path); + session->base_path = NULL; + } + + /* Set session base_path */ + session->base_path = strdup(uris[i].subdir); + if (!session->base_path) { + PERROR("Failed to copy base path \"%s\" to session \"%s\"", + uris[i].subdir, session->name); + ret = LTTNG_ERR_NOMEM; + goto error; + } + DBG2("Setting base path \"%s\" for session \"%s\"", + session->base_path, session->name); + } + ret = LTTNG_OK; +error: + return ret; +} + /* * Command LTTNG_SET_CONSUMER_URI processed by the client thread. */ @@ -2759,11 +2883,20 @@ int cmd_set_consumer_uri(struct ltt_session *session, size_t nb_uri, goto error; } + /* + * Set the session base path if any. This is done inside + * cmd_set_consumer_uri to preserve backward compatibility of the + * previous session creation api vs the session descriptor api. + */ + ret = set_session_base_path_from_uris(session, nb_uri, uris); + if (ret != LTTNG_OK) { + goto error; + } + /* Set the "global" consumer URIs */ for (i = 0; i < nb_uri; i++) { - ret = add_uri_to_consumer(session, - session->consumer, - &uris[i], LTTNG_DOMAIN_NONE); + ret = add_uri_to_consumer(session, session->consumer, &uris[i], + LTTNG_DOMAIN_NONE); if (ret != LTTNG_OK) { goto error; } @@ -2894,7 +3027,6 @@ enum lttng_error_code cmd_create_session_from_descriptor( const char *session_name; struct ltt_session *new_session = NULL; enum lttng_session_descriptor_status descriptor_status; - const char *base_path; session_lock_list(); if (home_path) { @@ -2917,13 +3049,9 @@ enum lttng_error_code cmd_create_session_from_descriptor( ret_code = LTTNG_ERR_INVALID; goto end; } - ret = lttng_session_descriptor_get_base_path(descriptor, &base_path); - if (ret) { - ret_code = LTTNG_ERR_INVALID; - goto end; - } + ret_code = session_create(session_name, creds->uid, creds->gid, - base_path, &new_session); + &new_session); if (ret_code != LTTNG_OK) { goto end; } @@ -3200,14 +3328,13 @@ int cmd_destroy_session(struct ltt_session *session, session->rotate_size = 0; } - if (session->most_recent_chunk_id.is_set && - session->most_recent_chunk_id.value != 0 && - session->current_trace_chunk && session->output_traces) { + if (session->rotated && session->current_trace_chunk && session->output_traces) { /* * Perform a last rotation on destruction if rotations have * occurred during the session's lifetime. */ - ret = cmd_rotate_session(session, NULL, false); + ret = cmd_rotate_session(session, NULL, false, + LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED); if (ret != LTTNG_OK) { ERR("Failed to perform an implicit rotation as part of the destruction of session \"%s\": %s", session->name, lttng_strerror(-ret)); @@ -3226,7 +3353,8 @@ int cmd_destroy_session(struct ltt_session *session, * emitted and no renaming of the current trace chunk takes * place. */ - ret = cmd_rotate_session(session, NULL, true); + ret = cmd_rotate_session(session, NULL, true, + LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION); if (ret != LTTNG_OK) { ERR("Failed to perform a quiet rotation as part of the destruction of session \"%s\": %s", session->name, lttng_strerror(-ret)); @@ -4585,8 +4713,14 @@ enum lttng_error_code snapshot_record(struct ltt_session *session, } } - if (session_close_trace_chunk( - session, session->current_trace_chunk, NULL, NULL)) { + if (session_set_trace_chunk(session, NULL, &snapshot_trace_chunk)) { + ERR("Failed to release the current trace chunk of session \"%s\"", + session->name); + ret_code = LTTNG_ERR_UNK; + } + + if (session_close_trace_chunk(session, snapshot_trace_chunk, + LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION, NULL)) { /* * Don't goto end; make sure the chunk is closed for the session * to allow future snapshots. @@ -4595,11 +4729,6 @@ enum lttng_error_code snapshot_record(struct ltt_session *session, session->name); ret_code = LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER; } - if (session_set_trace_chunk(session, NULL, NULL)) { - ERR("Failed to release the current trace chunk of session \"%s\"", - session->name); - ret_code = LTTNG_ERR_UNK; - } error: if (original_ust_consumer_output) { session->ust_session->consumer = original_ust_consumer_output; @@ -4780,7 +4909,8 @@ int cmd_set_session_shm_path(struct ltt_session *session, */ int cmd_rotate_session(struct ltt_session *session, struct lttng_rotate_session_return *rotate_return, - bool quiet_rotation) + bool quiet_rotation, + enum lttng_trace_chunk_command_type command) { int ret; uint64_t ongoing_rotation_chunk_id; @@ -4788,6 +4918,8 @@ int cmd_rotate_session(struct ltt_session *session, struct lttng_trace_chunk *chunk_being_archived = NULL; struct lttng_trace_chunk *new_trace_chunk = NULL; enum lttng_trace_chunk_status chunk_status; + bool failed_to_rotate = false; + enum lttng_error_code rotation_fail_code = LTTNG_OK; assert(session); @@ -4816,6 +4948,12 @@ int cmd_rotate_session(struct ltt_session *session, goto end; } + /* Unsupported feature in lttng-modules before 2.8 (lack of sequence number). */ + if (session->kernel_session && !kernel_supports_ring_buffer_packet_sequence_number()) { + cmd_ret = LTTNG_ERR_ROTATION_NOT_AVAILABLE_KERNEL; + goto end; + } + if (session->rotation_state == LTTNG_ROTATION_STATE_ONGOING) { DBG("Refusing to launch a rotation; a rotation is already in progress for session %s", session->name); @@ -4834,7 +4972,16 @@ int cmd_rotate_session(struct ltt_session *session, goto end; } - session->rotation_state = LTTNG_ROTATION_STATE_ONGOING; + /* + * After a stop followed by a clear, disallow following rotations a they would + * generate empty chunks. + */ + if (session->cleared_after_last_stop) { + DBG("Session \"%s\" was already cleared after stop, refusing rotation", + session->name); + cmd_ret = LTTNG_ERR_ROTATION_AFTER_STOP_CLEAR; + goto end; + } if (session->active) { new_trace_chunk = session_create_new_trace_chunk(session, NULL, @@ -4845,7 +4992,13 @@ int cmd_rotate_session(struct ltt_session *session, } } - /* The current trace chunk becomes the chunk being archived. */ + /* + * The current trace chunk becomes the chunk being archived. + * + * After this point, "chunk_being_archived" must absolutely + * be closed on the consumer(s), otherwise it will never be + * cleaned-up, which will result in a leak. + */ ret = session_set_trace_chunk(session, new_trace_chunk, &chunk_being_archived); if (ret) { @@ -4853,35 +5006,53 @@ int cmd_rotate_session(struct ltt_session *session, goto error; } - assert(chunk_being_archived); - chunk_status = lttng_trace_chunk_get_id(chunk_being_archived, - &ongoing_rotation_chunk_id); - assert(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK); - if (session->kernel_session) { cmd_ret = kernel_rotate_session(session); if (cmd_ret != LTTNG_OK) { - goto error; + failed_to_rotate = true; + rotation_fail_code = cmd_ret; } } if (session->ust_session) { cmd_ret = ust_app_rotate_session(session); if (cmd_ret != LTTNG_OK) { + failed_to_rotate = true; + rotation_fail_code = cmd_ret; + } + } + + if (!session->active) { + session->rotated_after_last_stop = true; + } + + if (!chunk_being_archived) { + DBG("Rotating session \"%s\" from a \"NULL\" trace chunk to a new trace chunk, skipping completion check", + session->name); + if (failed_to_rotate) { + cmd_ret = rotation_fail_code; goto error; } + cmd_ret = LTTNG_OK; + goto end; } + session->rotation_state = LTTNG_ROTATION_STATE_ONGOING; + chunk_status = lttng_trace_chunk_get_id(chunk_being_archived, + &ongoing_rotation_chunk_id); + assert(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK); + ret = session_close_trace_chunk(session, chunk_being_archived, - quiet_rotation ? - NULL : - &((enum lttng_trace_chunk_command_type){ - LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED}), - session->last_chunk_path); + command, session->last_chunk_path); if (ret) { cmd_ret = LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER; goto error; } + if (failed_to_rotate) { + cmd_ret = rotation_fail_code; + goto error; + } + session->quiet_rotation = quiet_rotation; ret = timer_session_rotation_pending_check_start(session, DEFAULT_ROTATE_PENDING_TIMER); @@ -4890,10 +5061,6 @@ int cmd_rotate_session(struct ltt_session *session, goto error; } - if (!session->active) { - session->rotated_after_last_stop = true; - } - if (rotate_return) { rotate_return->rotation_id = ongoing_rotation_chunk_id; } @@ -4968,7 +5135,7 @@ int cmd_rotate_get_info(struct ltt_session *session, switch (rotation_state) { case LTTNG_ROTATION_STATE_NO_ROTATION: - DBG("Reporting that no rotation has occured within the lifetime of session \"%s\"", + DBG("Reporting that no rotation has occurred within the lifetime of session \"%s\"", session->name); goto end; case LTTNG_ROTATION_STATE_EXPIRED: