Fix: cmd_rotate_session() returns unexpected error codes
[lttng-tools.git] / src / bin / lttng-sessiond / cmd.c
index 545269525ccb73c909d73cba1fcda1ff306496b1..50bacf0c236dc3ea4917a6f4100a80aa39b98623 100644 (file)
@@ -4521,27 +4521,33 @@ int cmd_set_session_shm_path(struct ltt_session *session,
  * Ask the consumer to rotate the session output directory.
  * The session lock must be held.
  *
- * Return LTTNG_OK on success or else a LTTNG_ERR code.
+ * Returns LTTNG_OK on success or else a negative LTTng error code.
  */
 int cmd_rotate_session(struct ltt_session *session,
                struct lttng_rotate_session_return *rotate_return)
 {
        int ret;
+       enum lttng_error_code cmd_ret = LTTNG_OK;
        size_t strf_ret;
        struct tm *timeinfo;
        char datetime[21];
        time_t now;
+       /*
+        * Used to roll-back timestamps in case of failure to launch the
+        * rotation.
+        */
+       time_t original_last_chunk_start_ts, original_current_chunk_start_ts;
 
        assert(session);
 
        if (!session->has_been_started) {
-               ret = -LTTNG_ERR_START_SESSION_ONCE;
+               cmd_ret = LTTNG_ERR_START_SESSION_ONCE;
                goto end;
        }
 
        if (session->live_timer || session->snapshot_mode ||
                        !session->output_traces) {
-               ret = -LTTNG_ERR_ROTATION_NOT_AVAILABLE;
+               cmd_ret = LTTNG_ERR_ROTATION_NOT_AVAILABLE;
                goto end;
        }
 
@@ -4551,14 +4557,14 @@ int cmd_rotate_session(struct ltt_session *session,
        if (session->consumer->type == CONSUMER_DST_NET &&
                        (session->consumer->relay_major_version == 2 &&
                        session->consumer->relay_minor_version < 11)) {
-               ret = -LTTNG_ERR_ROTATION_NOT_AVAILABLE_RELAY;
+               cmd_ret = LTTNG_ERR_ROTATION_NOT_AVAILABLE_RELAY;
                goto end;
        }
 
        if (session->rotation_state == LTTNG_ROTATION_STATE_ONGOING) {
-               ret = -LTTNG_ERR_ROTATION_PENDING;
                DBG("Refusing to launch a rotation; a rotation is already in progress for session %s",
                                session->name);
+               cmd_ret = LTTNG_ERR_ROTATION_PENDING;
                goto end;
        }
 
@@ -4569,7 +4575,7 @@ int cmd_rotate_session(struct ltt_session *session,
        if (session->rotated_after_last_stop) {
                DBG("Session \"%s\" was already rotated after stop, refusing rotation",
                                session->name);
-               ret = -LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP;
+               cmd_ret = LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP;
                goto end;
        }
 
@@ -4587,7 +4593,7 @@ int cmd_rotate_session(struct ltt_session *session,
                                sizeof(session->rotation_chunk.current_rotate_path));
                if (ret) {
                        ERR("Failed to copy session base path to current rotation chunk path");
-                       ret = -LTTNG_ERR_UNK;
+                       cmd_ret = LTTNG_ERR_UNK;
                        goto end;
                }
        } else {
@@ -4600,7 +4606,7 @@ int cmd_rotate_session(struct ltt_session *session,
                                sizeof(session->rotation_chunk.current_rotate_path));
                if (ret) {
                        ERR("Failed to copy the active tracing path to the current rotate path");
-                       ret = -LTTNG_ERR_UNK;
+                       cmd_ret = LTTNG_ERR_UNK;
                        goto end;
                }
        }
@@ -4611,45 +4617,43 @@ int cmd_rotate_session(struct ltt_session *session,
         * archive id.
         */
        session->current_archive_id++;
-       /*
-        * A rotation has a local step even if the destination is a relay
-        * daemon; the buffers must be consumed by the consumer daemon.
-        */
-       session->rotation_pending_local = true;
-       session->rotation_pending_relay =
-               session_get_consumer_destination_type(session) == CONSUMER_DST_NET;
-       session->rotation_state = LTTNG_ROTATION_STATE_ONGOING;
-       ret = notification_thread_command_session_rotation_ongoing(
-                       notification_thread_handle,
-                       session->name, session->uid, session->gid,
-                       session->current_archive_id - 1);
-       if (ret != LTTNG_OK) {
-               ERR("Failed to notify notification thread that a session rotation is ongoing for session %s",
-                               session->name);
-       }
 
-       /* Create the path name for the next chunk. */
        now = time(NULL);
        if (now == (time_t) -1) {
-               ret = -LTTNG_ERR_ROTATION_NOT_AVAILABLE;
+               cmd_ret = LTTNG_ERR_ROTATION_NOT_AVAILABLE;
                goto end;
        }
+
+       /* Sample chunk bounds for roll-back in case of error. */
+       original_last_chunk_start_ts = session->last_chunk_start_ts;
+       original_current_chunk_start_ts = session->current_chunk_start_ts;
+
        session->last_chunk_start_ts = session->current_chunk_start_ts;
        session->current_chunk_start_ts = now;
 
        timeinfo = localtime(&now);
        if (!timeinfo) {
                PERROR("Failed to sample local time in rotate session command");
-               ret = -LTTNG_ERR_UNK;
+               cmd_ret = LTTNG_ERR_UNK;
                goto end;
        }
        strf_ret = strftime(datetime, sizeof(datetime), "%Y%m%dT%H%M%S%z",
                        timeinfo);
        if (!strf_ret) {
                ERR("Failed to format local time timestamp in rotate session command");
-               ret = -LTTNG_ERR_UNK;
+               cmd_ret = LTTNG_ERR_UNK;
                goto end;
        }
+
+       /*
+        * A rotation has a local step even if the destination is a relay
+        * daemon; the buffers must be consumed by the consumer daemon.
+        */
+       session->rotation_pending_local = true;
+       session->rotation_pending_relay =
+               session_get_consumer_destination_type(session) == CONSUMER_DST_NET;
+       session->rotation_state = LTTNG_ROTATION_STATE_ONGOING;
+
        if (session->kernel_session) {
                /*
                 * The active path for the next rotation/destroy.
@@ -4662,8 +4666,8 @@ int cmd_rotate_session(struct ltt_session *session,
                                datetime, session->current_archive_id + 1);
                if (ret < 0 || ret == sizeof(session->rotation_chunk.active_tracing_path)) {
                        ERR("Failed to format active kernel tracing path in rotate session command");
-                       ret = -LTTNG_ERR_UNK;
-                       goto end;
+                       cmd_ret = LTTNG_ERR_UNK;
+                       goto error;
                }
                /*
                 * The sub-directory for the consumer
@@ -4675,8 +4679,8 @@ int cmd_rotate_session(struct ltt_session *session,
                                session->current_archive_id + 1);
                if (ret < 0 || ret == sizeof(session->kernel_session->consumer->chunk_path)) {
                        ERR("Failed to format the kernel consumer's sub-directory in rotate session command");
-                       ret = -LTTNG_ERR_UNK;
-                       goto end;
+                       cmd_ret = LTTNG_ERR_UNK;
+                       goto error;
                }
                /*
                 * Create the new chunk folder, before the rotation begins so we don't
@@ -4688,13 +4692,12 @@ int cmd_rotate_session(struct ltt_session *session,
                if (ret) {
                        ERR("Failed to create kernel session tracing path at %s",
                                        session->kernel_session->consumer->chunk_path);
-                       ret = -LTTNG_ERR_CREATE_DIR_FAIL;
-                       goto end;
+                       cmd_ret = LTTNG_ERR_CREATE_DIR_FAIL;
+                       goto error;
                }
-               ret = kernel_rotate_session(session);
-               if (ret != LTTNG_OK) {
-                       ret = -ret;
-                       goto end;
+               cmd_ret = kernel_rotate_session(session);
+               if (cmd_ret != LTTNG_OK) {
+                       goto error;
                }
        }
        if (session->ust_session) {
@@ -4704,16 +4707,16 @@ int cmd_rotate_session(struct ltt_session *session,
                                datetime, session->current_archive_id + 1);
                if (ret < 0) {
                        ERR("Failed to format active UST tracing path in rotate session command");
-                       ret = -LTTNG_ERR_UNK;
-                       goto end;
+                       cmd_ret = LTTNG_ERR_UNK;
+                       goto error;
                }
                ret = snprintf(session->ust_session->consumer->chunk_path,
                                PATH_MAX, "/%s-%" PRIu64, datetime,
                                session->current_archive_id + 1);
                if (ret < 0) {
                        ERR("Failed to format the UST consumer's sub-directory in rotate session command");
-                       ret = -LTTNG_ERR_UNK;
-                       goto end;
+                       cmd_ret = LTTNG_ERR_UNK;
+                       goto error;
                }
                /*
                 * Create the new chunk folder, before the rotation begins so we don't
@@ -4723,19 +4726,24 @@ int cmd_rotate_session(struct ltt_session *session,
                                session->ust_session->uid,
                                session->ust_session->gid);
                if (ret) {
-                       ret = -LTTNG_ERR_CREATE_DIR_FAIL;
-                       goto end;
+                       cmd_ret = LTTNG_ERR_CREATE_DIR_FAIL;
+                       goto error;
                }
-               ret = ust_app_rotate_session(session);
-               if (ret != LTTNG_OK) {
-                       goto end;
+               /*
+                * TODO: ust_app_rotate_session must be adapted to return
+                * an lttng_error_code, like its kernel counterpart.
+                */
+               cmd_ret = ust_app_rotate_session(session);
+               if (cmd_ret != LTTNG_OK) {
+                       goto error;
                }
        }
 
        ret = timer_session_rotation_pending_check_start(session,
                        DEFAULT_ROTATE_PENDING_TIMER);
        if (ret) {
-               goto end;
+               cmd_ret = LTTNG_ERR_UNK;
+               goto error;
        }
 
        if (!session->active) {
@@ -4746,12 +4754,30 @@ int cmd_rotate_session(struct ltt_session *session,
                rotate_return->rotation_id = session->current_archive_id;
        }
 
+       ret = notification_thread_command_session_rotation_ongoing(
+                       notification_thread_handle,
+                       session->name, session->uid, session->gid,
+                       session->current_archive_id - 1);
+       if (ret != LTTNG_OK) {
+               ERR("Failed to notify notification thread that a session rotation is ongoing for session %s",
+                               session->name);
+               cmd_ret = ret;
+       }
+
        DBG("Cmd rotate session %s, archive_id %" PRIu64 " sent",
                        session->name, session->current_archive_id - 1);
-       ret = LTTNG_OK;
-
 end:
+       ret = (cmd_ret == LTTNG_OK) ? cmd_ret : -((int) cmd_ret);
        return ret;
+error:
+       session->last_chunk_start_ts = original_last_chunk_start_ts;
+       session->current_archive_id = original_current_chunk_start_ts;
+       if (session_reset_rotation_state(session,
+                       LTTNG_ROTATION_STATE_NO_ROTATION)) {
+               ERR("Failed to reset rotation state of session \"%s\"",
+                               session->name);
+       }
+       goto end;
 }
 
 /*
This page took 0.032077 seconds and 4 git commands to generate.