Fix: list_lttng_agent_events: unbalanced RCU read-side lock on error
[lttng-tools.git] / src / bin / lttng-sessiond / cmd.c
index be493fd8a5527f7795446592016c44f47eaa6d09..a635c6511e3722a1356a66ccc337a760693f9c13 100644 (file)
@@ -517,7 +517,6 @@ static int list_lttng_agent_events(struct agent *agt,
 
        rcu_read_lock();
        nb_event = lttng_ht_get_count(agt->events);
-       rcu_read_unlock();
        if (nb_event == 0) {
                ret = nb_event;
                *total_size = 0;
@@ -531,7 +530,6 @@ static int list_lttng_agent_events(struct agent *agt,
         * This is only valid because the commands which add events are
         * processed in the same thread as the listing.
         */
-       rcu_read_lock();
        cds_lfht_for_each_entry(agt->events->ht, &iter.iter, event, node.node) {
                ret = increment_extended_len(event->filter_expression, NULL, NULL,
                                &extended_len);
@@ -541,7 +539,6 @@ static int list_lttng_agent_events(struct agent *agt,
                        goto error;
                }
        }
-       rcu_read_unlock();
 
        *total_size = nb_event * sizeof(*tmp_events) + extended_len;
        tmp_events = zmalloc(*total_size);
@@ -554,7 +551,6 @@ static int list_lttng_agent_events(struct agent *agt,
        extended_at = ((uint8_t *) tmp_events) +
                nb_event * sizeof(struct lttng_event);
 
-       rcu_read_lock();
        cds_lfht_for_each_entry(agt->events->ht, &iter.iter, event, node.node) {
                strncpy(tmp_events[i].name, event->name, sizeof(tmp_events[i].name));
                tmp_events[i].name[sizeof(tmp_events[i].name) - 1] = '\0';
@@ -823,8 +819,7 @@ end:
        return nb_event;
 
 error:
-       /* Negate the error code to differentiate the size from an error */
-       return -ret;
+       return ret;
 }
 
 /*
@@ -1185,6 +1180,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, &current_chunk_id.value);
@@ -1198,8 +1194,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 */
@@ -2572,6 +2566,8 @@ 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;
 
        assert(session);
 
@@ -2585,6 +2581,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 +2612,45 @@ int cmd_start_trace(struct ltt_session *session)
                goto error;
        }
 
+       session->active = 1;
+       session->rotated_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);
+                       if (ret != LTTNG_OK) {
+                               goto error;
+                       }
                }
        }
 
@@ -2637,10 +2673,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 +2693,15 @@ 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;
+       }
        return ret;
 }
 
@@ -4494,7 +4535,7 @@ int64_t get_session_nb_packets_per_stream(const struct ltt_session *session,
                }
                cur_nb_packets++;
        }
-       if (!cur_nb_packets) {
+       if (!cur_nb_packets && size_left != max_size) {
                /* Not enough room to grab one packet of each stream, error. */
                return -1;
        }
@@ -4607,7 +4648,7 @@ enum lttng_error_code snapshot_record(struct ltt_session *session,
                        snapshot_output->max_size);
        if (nb_packets_per_stream < 0) {
                ret_code = LTTNG_ERR_MAX_SIZE_INVALID;
-               goto error;
+               goto error_close_trace_chunk;
        }
 
        if (session->kernel_session) {
@@ -4615,7 +4656,7 @@ enum lttng_error_code snapshot_record(struct ltt_session *session,
                                snapshot_kernel_consumer_output, session,
                                wait, nb_packets_per_stream);
                if (ret_code != LTTNG_OK) {
-                       goto error;
+                       goto error_close_trace_chunk;
                }
        }
 
@@ -4624,10 +4665,10 @@ enum lttng_error_code snapshot_record(struct ltt_session *session,
                                snapshot_ust_consumer_output, session,
                                wait, nb_packets_per_stream);
                if (ret_code != LTTNG_OK) {
-                       goto error;
+                       goto error_close_trace_chunk;
                }
        }
-
+error_close_trace_chunk:
        if (session_close_trace_chunk(
                            session, session->current_trace_chunk, NULL, NULL)) {
                /*
@@ -4861,6 +4902,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);
@@ -4878,9 +4925,6 @@ int cmd_rotate_session(struct ltt_session *session,
                cmd_ret = LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP;
                goto end;
        }
-
-       session->rotation_state = LTTNG_ROTATION_STATE_ONGOING;
-
        if (session->active) {
                new_trace_chunk = session_create_new_trace_chunk(session, NULL,
                                NULL, NULL);
@@ -4904,11 +4948,6 @@ 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) {
@@ -4924,6 +4963,26 @@ int cmd_rotate_session(struct ltt_session *session,
                }
        }
 
+       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 :
@@ -4948,10 +5007,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;
        }
This page took 0.026669 seconds and 4 git commands to generate.