Create an initial trace chunk on first start of an ltt_session
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 26 Feb 2019 03:11:08 +0000 (22:11 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 18 Jul 2019 19:58:24 +0000 (15:58 -0400)
Add a current trace chunk to an ltt_session on session start.
The session base output directory is created at that moment and an
handle to it is provided to the session daemon's trace chunk when
it is set in 'owner' mode.

Setting the trace chunk in "owner" mode results in the creation of
the chunk's output directory. In the case, of the first chunk,
the chunk output directory matches the session output directory.
Hence, this has no visible effect.

Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/kernel.c
src/bin/lttng-sessiond/session.c
src/bin/lttng-sessiond/session.h
src/bin/lttng-sessiond/trace-kernel.c
src/bin/lttng-sessiond/trace-kernel.h
src/bin/lttng-sessiond/trace-ust.c
src/bin/lttng-sessiond/trace-ust.h

index 01efcaf05371fc178e14f13ff24c2aa1368053d8..0ba1ec4f778a9682081f11c656d6132c488eee13 100644 (file)
@@ -32,6 +32,7 @@
 #include <common/kernel-ctl/kernel-ctl.h>
 #include <common/dynamic-buffer.h>
 #include <common/buffer-view.h>
+#include <common/trace-chunk.h>
 #include <lttng/trigger/trigger-internal.h>
 #include <lttng/condition/condition.h>
 #include <lttng/action/action.h>
@@ -2559,54 +2560,6 @@ end:
        return ret;
 }
 
-static
-int session_mkdir(const struct ltt_session *session)
-{
-       int ret;
-       struct consumer_output *output;
-       uid_t uid;
-       gid_t gid;
-
-       /*
-        * Unsupported feature in lttng-relayd before 2.11, not an error since it
-        * is only needed for session rotation and the user will get an error
-        * on rotate.
-        */
-       if (session->consumer->type == CONSUMER_DST_NET &&
-                       session->consumer->relay_major_version == 2 &&
-                       session->consumer->relay_minor_version < 11) {
-               ret = 0;
-               goto end;
-       }
-
-       if (session->kernel_session) {
-               output = session->kernel_session->consumer;
-               uid = session->kernel_session->uid;
-               gid = session->kernel_session->gid;
-               ret = domain_mkdir(output, session, uid, gid);
-               if (ret) {
-                       ERR("Mkdir kernel");
-                       goto end;
-               }
-       }
-
-       if (session->ust_session) {
-               output = session->ust_session->consumer;
-               uid = session->ust_session->uid;
-               gid = session->ust_session->gid;
-               ret = domain_mkdir(output, session, uid, gid);
-               if (ret) {
-                       ERR("Mkdir UST");
-                       goto end;
-               }
-       }
-
-       ret = 0;
-
-end:
-       return ret;
-}
-
 /*
  * Command LTTNG_START_TRACE processed by the client thread.
  *
@@ -2614,7 +2567,7 @@ end:
  */
 int cmd_start_trace(struct ltt_session *session)
 {
-       int ret;
+       enum lttng_error_code ret;
        unsigned long nb_chan = 0;
        struct ltt_kernel_session *ksession;
        struct ltt_ust_session *usess;
@@ -2646,26 +2599,11 @@ int cmd_start_trace(struct ltt_session *session)
                goto error;
        }
 
-       /*
-        * Record the timestamp of the first time the session is started for
-        * an eventual session rotation call.
-        */
-       if (!session->has_been_started) {
-               session->current_chunk_start_ts = time(NULL);
-               if (session->current_chunk_start_ts == (time_t) -1) {
-                       PERROR("Failed to retrieve the \"%s\" session's start time",
-                                       session->name);
-                       ret = LTTNG_ERR_FATAL;
+       if (!session->has_been_started && session->output_traces) {
+               ret = session_switch_trace_chunk(session, NULL, NULL);
+               if (ret != LTTNG_OK) {
                        goto error;
                }
-               if (!session->snapshot_mode && session->output_traces) {
-                       ret = session_mkdir(session);
-                       if (ret) {
-                               ERR("Failed to create the session directories");
-                               ret = LTTNG_ERR_CREATE_DIR_FAIL;
-                               goto error;
-                       }
-               }
        }
 
        /* Kernel tracing */
@@ -2679,8 +2617,9 @@ int cmd_start_trace(struct ltt_session *session)
 
        /* Flag session that trace should start automatically */
        if (usess) {
-               ret = ust_app_start_trace_all(usess);
-               if (ret < 0) {
+               int int_ret = ust_app_start_trace_all(usess);
+
+               if (int_ret < 0) {
                        ret = LTTNG_ERR_UST_START_FAIL;
                        goto error;
                }
@@ -2697,9 +2636,10 @@ int cmd_start_trace(struct ltt_session *session)
        session->rotated_after_last_stop = false;
 
        if (session->rotate_timer_period) {
-               ret = timer_session_rotation_schedule_timer_start(session,
-                               session->rotate_timer_period);
-               if (ret < 0) {
+               int int_ret = timer_session_rotation_schedule_timer_start(
+                               session, session->rotate_timer_period);
+
+               if (int_ret < 0) {
                        ERR("Failed to enable rotate timer");
                        ret = LTTNG_ERR_UNK;
                        goto error;
index b4fc995ce118762630292f4a9623fcd78c5995cf..7173fac16348d59cab3f2e220cb927797761fcf3 100644 (file)
@@ -24,6 +24,7 @@
 #include <inttypes.h>
 
 #include <common/common.h>
+#include <common/trace-chunk.h>
 #include <common/kernel-ctl/kernel-ctl.h>
 #include <common/kernel-ctl/kernel-ioctl.h>
 #include <common/sessiond-comm/sessiond-comm.h>
@@ -1159,12 +1160,15 @@ end_boot_id:
  */
 void kernel_destroy_session(struct ltt_kernel_session *ksess)
 {
+       struct lttng_trace_chunk *trace_chunk;
+
        if (ksess == NULL) {
                DBG3("No kernel session when tearing down session");
                return;
        }
 
        DBG("Tearing down kernel session");
+       trace_chunk = ksess->current_trace_chunk;
 
        /*
         * Destroy channels on the consumer if at least one FD has been sent and we
@@ -1198,6 +1202,7 @@ void kernel_destroy_session(struct ltt_kernel_session *ksess)
        consumer_output_send_destroy_relayd(ksess->consumer);
 
        trace_kernel_destroy_session(ksess);
+       lttng_trace_chunk_put(trace_chunk);
 }
 
 /*
index 491de61759825f0485326cae5b2d7e72db72c6ad..6c10aaeba9259286cdac4a43db72619d8a4e8f51 100644 (file)
@@ -28,6 +28,8 @@
 #include <pthread.h>
 
 #include <common/common.h>
+#include <common/utils.h>
+#include <common/trace-chunk.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <lttng/location-internal.h>
 #include "lttng-sessiond.h"
@@ -65,6 +67,13 @@ static const char *forbidden_name_chars = "/";
 /* Global hash table to keep the sessions, indexed by id. */
 static struct lttng_ht *ltt_sessions_ht_by_id = NULL;
 
+struct consumer_create_chunk_transaction {
+       struct consumer_socket *socket;
+       struct lttng_trace_chunk *new_chunk;
+       struct lttng_trace_chunk *previous_chunk;
+       bool new_chunk_created;
+};
+
 /*
  * Validate the session name for forbidden characters.
  *
@@ -400,6 +409,328 @@ void session_unlock(struct ltt_session *session)
        pthread_mutex_unlock(&session->lock);
 }
 
+static
+int _session_set_trace_chunk_no_lock_check(struct ltt_session *session,
+               struct lttng_trace_chunk *new_trace_chunk)
+{
+       int ret;
+       unsigned int i, refs_to_acquire = 0, refs_acquired = 0, refs_to_release = 0;
+       unsigned int consumer_count = 0;
+       /*
+        * The maximum amount of consumers to reach is 3
+        * (32/64 userspace + kernel).
+        */
+       struct consumer_create_chunk_transaction transactions[3] = {};
+       struct cds_lfht_iter iter;
+       struct consumer_socket *socket;
+       bool close_error_occured = false;
+
+       if (new_trace_chunk) {
+               uint64_t chunk_id;
+               enum lttng_trace_chunk_status chunk_status =
+                               lttng_trace_chunk_get_id(new_trace_chunk,
+                                       &chunk_id);
+
+               assert(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK);
+               LTTNG_OPTIONAL_SET(&session->last_trace_chunk_id, chunk_id)
+       }
+
+       if (new_trace_chunk) {
+               refs_to_acquire = 1;
+               refs_to_acquire += !!session->ust_session;
+               refs_to_acquire += !!session->kernel_session;
+       }
+
+       /*
+        * Build a list of consumers to reach to announce the new trace chunk.
+        *
+        * Rolling back the annoucement in case of an error is important since
+        * not doing so would result in a leak; the chunk will not be
+        * "reclaimed" by the consumer(s) since they have no concept of the
+        * lifetime of a session.
+        */
+       if (session->ust_session) {
+               cds_lfht_for_each_entry(
+                               session->ust_session->consumer->socks->ht,
+                               &iter, socket, node.node) {
+                       transactions[consumer_count].socket = socket;
+                       transactions[consumer_count].new_chunk = new_trace_chunk;
+                       transactions[consumer_count].previous_chunk =
+                                       session->current_trace_chunk;
+                       consumer_count++;
+                       assert(consumer_count <= 3);
+               }
+       }
+       if (session->kernel_session) {
+               cds_lfht_for_each_entry(
+                               session->kernel_session->consumer->socks->ht,
+                               &iter, socket, node.node) {
+                       transactions[consumer_count].socket = socket;
+                       transactions[consumer_count].new_chunk = new_trace_chunk;
+                       transactions[consumer_count].previous_chunk =
+                                       session->current_trace_chunk;
+                       consumer_count++;
+                       assert(consumer_count <= 3);
+               }
+       }
+       for (refs_acquired = 0; refs_acquired < refs_to_acquire; refs_acquired++) {
+               if (new_trace_chunk && !lttng_trace_chunk_get(new_trace_chunk)) {
+                       ERR("Failed to acquire reference to new current trace chunk of session \"%s\"",
+                                       session->name);
+                       goto error;
+               }
+       }
+
+       /*
+        * Close the previous chunk on remote peers (consumers and relayd).
+        */
+       for (i = 0; i < consumer_count; i++) {
+               if (!transactions[i].previous_chunk) {
+                       continue;
+               }
+               pthread_mutex_lock(transactions[i].socket->lock);
+               ret = consumer_close_trace_chunk(transactions[i].socket,
+                               session->consumer->net_seq_index,
+                               session->id,
+                               transactions[i].previous_chunk);
+               pthread_mutex_unlock(transactions[i].socket->lock);
+               if (ret) {
+                       ERR("Failed to close trace chunk on consumer");
+                       close_error_occured = true;
+               }
+       }
+
+       if (close_error_occured) {
+               /*
+                * Skip the creation of the new trace chunk and report the
+                * error.
+                */
+               goto error;
+       }
+
+       /* Create the new chunk on remote peers (consumers and relayd) */
+       if (new_trace_chunk) {
+               for (i = 0; i < consumer_count; i++) {
+                       pthread_mutex_lock(transactions[i].socket->lock);
+                       ret = consumer_create_trace_chunk(transactions[i].socket,
+                                       session->consumer->net_seq_index,
+                                       session->id,
+                                       transactions[i].new_chunk);
+                       pthread_mutex_unlock(transactions[i].socket->lock);
+                       if (ret) {
+                               ERR("Failed to create trace chunk on consumer");
+                               goto error;
+                       }
+                       /* This will have to be rolled-back on error. */
+                       transactions[i].new_chunk_created = true;
+               }
+       }
+
+       lttng_trace_chunk_put(session->current_trace_chunk);
+       session->current_trace_chunk = NULL;
+       if (session->ust_session) {
+               lttng_trace_chunk_put(
+                               session->ust_session->current_trace_chunk);
+               session->ust_session->current_trace_chunk = NULL;
+       }
+       if (session->kernel_session) {
+               lttng_trace_chunk_put(
+                               session->kernel_session->current_trace_chunk);
+               session->kernel_session->current_trace_chunk = NULL;
+       }
+
+       /*
+        * Update local current trace chunk state last, only if all remote
+        * annoucements succeeded.
+        */
+       session->current_trace_chunk = new_trace_chunk;
+       if (session->ust_session) {
+               session->ust_session->current_trace_chunk = new_trace_chunk;
+       }
+       if (session->kernel_session) {
+               session->kernel_session->current_trace_chunk =
+                               new_trace_chunk;
+       }
+
+       return 0;
+error:
+       /*
+        * Release references taken in the case where all references could not
+        * be acquired.
+        */
+       refs_to_release = refs_to_acquire - refs_acquired;
+       for (i = 0; i < refs_to_release; i++) {
+               lttng_trace_chunk_put(new_trace_chunk);
+       }
+
+       /*
+        * Close the newly-created chunk from remote peers (consumers and
+        * relayd).
+        */
+       DBG("Rolling back the creation of the new trace chunk on consumers");
+       for (i = 0; i < consumer_count; i++) {
+               if (!transactions[i].new_chunk_created) {
+                       continue;
+               }
+
+               pthread_mutex_lock(transactions[i].socket->lock);
+               ret = consumer_close_trace_chunk(transactions[i].socket,
+                               session->consumer->net_seq_index,
+                               session->id,
+                               transactions[i].new_chunk);
+               pthread_mutex_unlock(transactions[i].socket->lock);
+               if (ret) {
+                       ERR("Failed to close trace chunk on consumer");
+                       close_error_occured = true;
+               }
+       }
+
+       return -1;
+}
+
+static
+bool output_supports_chunks(const struct ltt_session *session)
+{
+       if (session->consumer->type == CONSUMER_DST_LOCAL) {
+               return true;
+       } else {
+               struct consumer_output *output;
+
+               if (session->ust_session) {
+                       output = session->ust_session->consumer;
+               } else if (session->kernel_session) {
+                       output = session->kernel_session->consumer;
+               } else {
+                       abort();
+               }
+
+               if (output->relay_major_version > 2) {
+                       return true;
+               } else if (output->relay_major_version == 2 &&
+                               output->relay_minor_version >= 11) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+enum lttng_error_code session_switch_trace_chunk(struct ltt_session *session,
+               const char *session_base_path_override,
+               const char *chunk_name_override)
+{
+       int ret;
+       enum lttng_error_code ret_code = LTTNG_OK;
+       struct lttng_trace_chunk *trace_chunk = NULL;
+       enum lttng_trace_chunk_status chunk_status;
+       const time_t timestamp_begin = time(NULL);
+       const bool is_local_trace =
+                       session->consumer->type == CONSUMER_DST_LOCAL;
+       const char *base_path = session_base_path_override ? :
+                       session_get_base_path(session);
+       struct lttng_directory_handle session_output_directory;
+       const struct lttng_credentials session_credentials = {
+               .uid = session->uid,
+               .gid = session->gid,
+       };
+       uint64_t next_chunk_id;
+
+       if (timestamp_begin == (time_t) -1) {
+               PERROR("Failed to sample time while changing session \"%s\" trace chunk",
+                               session->name);
+               ret_code = LTTNG_ERR_FATAL;
+               goto error;
+       }
+       session->current_chunk_start_ts = timestamp_begin;
+
+       if (!output_supports_chunks(session)) {
+               goto end;
+       }
+       next_chunk_id = session->last_trace_chunk_id.is_set ?
+                       session->last_trace_chunk_id.value + 1 : 0;
+
+       trace_chunk = lttng_trace_chunk_create(next_chunk_id, timestamp_begin);
+       if (!trace_chunk) {
+               ret_code = LTTNG_ERR_FATAL;
+               goto error;
+       }
+
+       if (chunk_name_override) {
+               chunk_status = lttng_trace_chunk_override_name(trace_chunk,
+                               chunk_name_override);
+               switch (chunk_status) {
+               case LTTNG_TRACE_CHUNK_STATUS_OK:
+                       break;
+               case LTTNG_TRACE_CHUNK_STATUS_INVALID_ARGUMENT:
+                       ret_code = LTTNG_ERR_INVALID;
+                       goto error;
+               default:
+                       ret_code = LTTNG_ERR_NOMEM;
+                       goto error;
+               }
+       }
+
+       if (!is_local_trace) {
+               /*
+                * No need to set crendentials and output directory
+                * for remote trace chunks.
+                */
+               goto publish;
+       }
+
+       chunk_status = lttng_trace_chunk_set_credentials(trace_chunk,
+                       &session_credentials);
+       if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+               ret_code = LTTNG_ERR_FATAL;
+               goto error;
+       }
+
+       if (!session->current_trace_chunk) {
+               DBG("Creating base output directory of session \"%s\" at %s",
+                               session->name, base_path);
+       }
+       ret = utils_mkdir_recursive(base_path, S_IRWXU | S_IRWXG,
+                       session->uid, session->gid);
+       if (ret) {
+               ret = LTTNG_ERR_FATAL;
+               goto error;
+       }
+       ret = lttng_directory_handle_init(&session_output_directory,
+                       base_path);
+       if (ret) {
+               ret = LTTNG_ERR_FATAL;
+               goto error;
+       }
+       chunk_status = lttng_trace_chunk_set_as_owner(trace_chunk,
+                       &session_output_directory);
+       lttng_directory_handle_fini(&session_output_directory);
+       if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+               ret = LTTNG_ERR_CREATE_DIR_FAIL;
+               goto error;
+       }
+publish:
+       ret = session_set_trace_chunk(session, trace_chunk);
+       if (ret) {
+               ret_code = LTTNG_ERR_FATAL;
+               goto error;
+       }
+error:
+       lttng_trace_chunk_put(trace_chunk);
+end:
+       return ret_code;
+}
+
+/*
+ * Set a session's current trace chunk.
+ *
+ * Must be called with the session lock held.
+ */
+int session_set_trace_chunk(struct ltt_session *session,
+               struct lttng_trace_chunk *new_trace_chunk)
+{
+       ASSERT_LOCKED(session->lock);
+       return _session_set_trace_chunk_no_lock_check(session, new_trace_chunk);
+}
+
 static
 void session_release(struct urcu_ref *ref)
 {
@@ -410,9 +741,11 @@ void session_release(struct urcu_ref *ref)
 
        usess = session->ust_session;
        ksess = session->kernel_session;
+       (void) _session_set_trace_chunk_no_lock_check(session, NULL);
 
        /* Clean kernel session teardown */
        kernel_destroy_session(ksess);
+       session->kernel_session = NULL;
 
        /* UST session teardown */
        if (usess) {
@@ -427,6 +760,7 @@ void session_release(struct urcu_ref *ref)
 
                /* Clean up the rest. */
                trace_ust_destroy_session(usess);
+               session->ust_session = NULL;
        }
 
        /*
@@ -439,11 +773,12 @@ void session_release(struct urcu_ref *ref)
        }
 
        DBG("Destroying session %s (id %" PRIu64 ")", session->name, session->id);
-       pthread_mutex_destroy(&session->lock);
 
        consumer_output_put(session->consumer);
        snapshot_destroy(&session->snapshot);
 
+       pthread_mutex_destroy(&session->lock);
+
        if (session->published) {
                ASSERT_LOCKED(ltt_session_list.lock);
                del_session_list(session);
index b008c967ec21b610651c5c4071842b236c2d2360..19dabb727179bb23a64e2b5cf3a1bba8a5f4ffc3 100644 (file)
@@ -25,6 +25,7 @@
 #include <common/hashtable/hashtable.h>
 #include <lttng/rotation.h>
 #include <lttng/location.h>
+#include <lttng/lttng-error.h>
 
 #include "snapshot.h"
 #include "trace-kernel.h"
@@ -225,6 +226,8 @@ struct ltt_session {
         */
        struct lttng_condition *rotate_condition;
        struct lttng_trigger *rotate_trigger;
+       LTTNG_OPTIONAL(uint64_t) last_trace_chunk_id;
+       struct lttng_trace_chunk *current_trace_chunk;
 };
 
 /* Prototypes */
@@ -262,4 +265,10 @@ int session_access_ok(struct ltt_session *session, uid_t uid, gid_t gid);
 int session_reset_rotation_state(struct ltt_session *session,
                enum lttng_rotation_state result);
 
+enum lttng_error_code session_switch_trace_chunk(struct ltt_session *session,
+               const char *session_base_path_override,
+               const char *chunk_name_override);
+int session_set_trace_chunk(struct ltt_session *session,
+               struct lttng_trace_chunk *current_trace_chunk);
+
 #endif /* _LTT_SESSION_H */
index b9d03a72e002ca0042764a877f0ae556e87f1faa..a8aa01b269e9bc05bd4aeb28148899f38a154a06 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <common/common.h>
 #include <common/defaults.h>
+#include <common/trace-chunk.h>
 
 #include "consumer.h"
 #include "trace-kernel.h"
index b1534197136ddfe735f63a5a7404b4b460f35182..00c76a8d321d0102a3f2257c9e1fdb1161cf1873 100644 (file)
@@ -120,6 +120,8 @@ struct ltt_kernel_session {
        unsigned int output_traces;
        unsigned int snapshot_mode;
        unsigned int has_non_default_channel;
+       /* Current trace chunk of the ltt_session. */
+       struct lttng_trace_chunk *current_trace_chunk;
 };
 
 /*
index 8d63e2525192ad3ef2f473c99f9245b955f86eb0..b1bae1794ab70560d7e4e74c4520793659de4ac9 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <common/common.h>
 #include <common/defaults.h>
+#include <common/trace-chunk.h>
 
 #include "buffer-registry.h"
 #include "trace-ust.h"
@@ -1199,6 +1200,6 @@ void trace_ust_destroy_session(struct ltt_ust_session *session)
        consumer_output_put(session->consumer);
 
        fini_pid_tracker(&session->pid_tracker);
-
+       lttng_trace_chunk_put(session->current_trace_chunk);
        free(session);
 }
index 5e0b3c51866ef579d5b66b25b8d352cd182f9188..58339802671b11e3fdb0dfd07bd0587eb3edc8d3 100644 (file)
@@ -139,6 +139,9 @@ struct ltt_ust_session {
        char shm_path[PATH_MAX];
 
        struct ust_pid_tracker pid_tracker;
+
+       /* Current trace chunk of the ltt_session. */
+       struct lttng_trace_chunk *current_trace_chunk;
 };
 
 /*
This page took 0.03577 seconds and 5 git commands to generate.