cmd.c: fix typos in snapshot commands
[lttng-tools.git] / src / bin / lttng-sessiond / cmd.c
index bba77023a6415ff0b52e9f0dcfde6729c5a0856f..a351d63de706b8843c7b16059f45ba2173b91e6c 100644 (file)
@@ -17,6 +17,7 @@
 
 #define _GNU_SOURCE
 #include <assert.h>
+#include <inttypes.h>
 #include <urcu/list.h>
 #include <urcu/uatomic.h>
 
@@ -24,6 +25,7 @@
 #include <common/common.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <common/relayd/relayd.h>
+#include <common/utils.h>
 
 #include "channel.h"
 #include "consumer.h"
@@ -546,7 +548,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 +562,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 +576,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 +603,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 +617,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 +636,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 +678,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 +697,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 +722,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 +731,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");
@@ -856,6 +857,8 @@ int cmd_enable_channel(struct ltt_session *session,
 
        DBG("Enabling channel %s for session %s", attr->name, session->name);
 
+       rcu_read_lock();
+
        /*
         * 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.
@@ -865,8 +868,6 @@ int cmd_enable_channel(struct ltt_session *session,
                goto error;
        }
 
-       rcu_read_lock();
-
        switch (domain->type) {
        case LTTNG_DOMAIN_KERNEL:
        {
@@ -1681,12 +1682,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
@@ -1725,9 +1721,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;
@@ -1741,6 +1743,72 @@ find_error:
        return ret;
 }
 
+/*
+ * Command LTTNG_CREATE_SESSION_SNAPSHOT processed by the client thread.
+ */
+int cmd_create_session_snapshot(char *name, struct lttng_uri *uris,
+               size_t nb_uri, lttng_sock_cred *creds)
+{
+       int ret;
+       struct ltt_session *session;
+       struct snapshot_output *new_output = NULL;
+
+       assert(name);
+       assert(creds);
+
+       /*
+        * Create session in no output mode with URIs set to NULL. The uris we've
+        * received are for a default snapshot output if one.
+        */
+       ret = cmd_create_session_uri(name, NULL, 0, creds);
+       if (ret != LTTNG_OK) {
+               goto error;
+       }
+
+       /* Get the newly created session pointer back. This should NEVER fail. */
+       session = session_find_by_name(name);
+       assert(session);
+
+       /* Flag session for snapshot mode. */
+       session->snapshot_mode = 1;
+
+       /* Skip snapshot output creation if no URI is given. */
+       if (nb_uri == 0) {
+               goto end;
+       }
+
+       new_output = snapshot_output_alloc();
+       if (!new_output) {
+               ret = LTTNG_ERR_NOMEM;
+               goto error_snapshot_alloc;
+       }
+
+       ret = snapshot_output_init_with_uri(DEFAULT_SNAPSHOT_MAX_SIZE, NULL,
+                       uris, nb_uri, session->consumer, new_output, &session->snapshot);
+       if (ret < 0) {
+               if (ret == -ENOMEM) {
+                       ret = LTTNG_ERR_NOMEM;
+               } else {
+                       ret = LTTNG_ERR_INVALID;
+               }
+               goto error_snapshot;
+       }
+
+       rcu_read_lock();
+       snapshot_add_output(&session->snapshot, new_output);
+       rcu_read_unlock();
+
+end:
+       return LTTNG_OK;
+
+error_snapshot:
+       snapshot_output_destroy(new_output);
+error_snapshot_alloc:
+       session_destroy(session);
+error:
+       return ret;
+}
+
 /*
  * Command LTTNG_DESTROY_SESSION processed by the client thread.
  */
@@ -2092,13 +2160,14 @@ void cmd_list_lttng_sessions(struct lttng_session *sessions, uid_t uid,
                strncpy(sessions[i].name, session->name, NAME_MAX);
                sessions[i].name[NAME_MAX - 1] = '\0';
                sessions[i].enabled = session->enabled;
+               sessions[i].snapshot_mode = session->snapshot_mode;
                i++;
        }
 }
 
 /*
  * Command LTTNG_DATA_PENDING returning 0 if the data is NOT pending meaning
- * ready for trace analysis (or anykind of reader) or else 1 for pending data.
+ * ready for trace analysis (or any kind of reader) or else 1 for pending data.
  */
 int cmd_data_pending(struct ltt_session *session)
 {
@@ -2137,6 +2206,541 @@ 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);
+
+       /*
+        * Permission 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;
+       }
+
+       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 = NULL;
+
+       assert(session);
+       assert(output);
+
+       rcu_read_lock();
+
+       /*
+        * Permission 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 (output->id) {
+               DBG("Cmd snapshot del output id %" PRIu32 " for session %s", output->id,
+                               session->name);
+               sout = snapshot_find_output_by_id(output->id, &session->snapshot);
+       } else if (*output->name != '\0') {
+               DBG("Cmd snapshot del output name %s for session %s", output->name,
+                               session->name);
+               sout = snapshot_find_output_by_name(output->name, &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);
+
+       /*
+        * Permission 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 a LTTNG_ERR code.
+ */
+static int set_relayd_for_snapshot(struct consumer_output *consumer,
+               struct snapshot_output *snap_output, struct ltt_session *session)
+{
+       int ret = LTTNG_OK;
+       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(snap_output->consumer->socks->ht, &iter.iter,
+                       socket, node.node) {
+               ret = send_consumer_relayd_sockets(0, session->id,
+                               snap_output->consumer, socket);
+               if (ret != LTTNG_OK) {
+                       rcu_read_unlock();
+                       goto error;
+               }
+       }
+       rcu_read_unlock();
+
+error:
+       return ret;
+}
+
+/*
+ * Record a kernel snapshot.
+ *
+ * Return 0 on success or a LTTNG_ERR code.
+ */
+static int record_kernel_snapshot(struct ltt_kernel_session *ksess,
+               struct snapshot_output *output, struct ltt_session *session,
+               int wait, int nb_streams)
+{
+       int ret;
+
+       assert(ksess);
+       assert(output);
+       assert(session);
+
+       /* Get the datetime for the snapshot output directory. */
+       ret = utils_get_current_time_str("%Y%m%d-%H%M%S", output->datetime,
+                       sizeof(output->datetime));
+       if (!ret) {
+               ret = LTTNG_ERR_INVALID;
+               goto error;
+       }
+
+       /*
+        * Copy kernel session sockets so we can communicate with the right
+        * consumer for the snapshot record command.
+        */
+       ret = consumer_copy_sockets(output->consumer, ksess->consumer);
+       if (ret < 0) {
+               ret = LTTNG_ERR_NOMEM;
+               goto error;
+       }
+
+       ret = set_relayd_for_snapshot(ksess->consumer, output, session);
+       if (ret != LTTNG_OK) {
+               goto error_snapshot;
+       }
+
+       ret = kernel_snapshot_record(ksess, output, wait, nb_streams);
+       if (ret < 0) {
+               ret = LTTNG_ERR_SNAPSHOT_FAIL;
+               if (ret == -EINVAL) {
+                       ret = LTTNG_ERR_INVALID;
+               }
+               goto error_snapshot;
+       }
+
+       ret = LTTNG_OK;
+
+error_snapshot:
+       /* Clean up copied sockets so this output can use some other later on. */
+       consumer_destroy_output_sockets(output->consumer);
+error:
+       return ret;
+}
+
+/*
+ * Record a UST snapshot.
+ *
+ * Return 0 on success or a LTTNG_ERR error code.
+ */
+static int record_ust_snapshot(struct ltt_ust_session *usess,
+               struct snapshot_output *output, struct ltt_session *session,
+               int wait, int nb_streams)
+{
+       int ret;
+
+       assert(usess);
+       assert(output);
+       assert(session);
+
+       /* Get the datetime for the snapshot output directory. */
+       ret = utils_get_current_time_str("%Y%m%d-%H%M%S", output->datetime,
+                       sizeof(output->datetime));
+       if (!ret) {
+               ret = LTTNG_ERR_INVALID;
+               goto error;
+       }
+
+       /*
+        * Copy UST session sockets so we can communicate with the right
+        * consumer for the snapshot record command.
+        */
+       ret = consumer_copy_sockets(output->consumer, usess->consumer);
+       if (ret < 0) {
+               ret = LTTNG_ERR_NOMEM;
+               goto error;
+       }
+
+       ret = set_relayd_for_snapshot(usess->consumer, output, session);
+       if (ret != LTTNG_OK) {
+               goto error_snapshot;
+       }
+
+       ret = ust_app_snapshot_record(usess, output, wait, nb_streams);
+       if (ret < 0) {
+               ret = LTTNG_ERR_SNAPSHOT_FAIL;
+               if (ret == -EINVAL) {
+                       ret = LTTNG_ERR_INVALID;
+               }
+               goto error_snapshot;
+       }
+
+       ret = LTTNG_OK;
+
+error_snapshot:
+       /* Clean up copied sockets so this output can use some other later on. */
+       consumer_destroy_output_sockets(output->consumer);
+error:
+       return ret;
+}
+
+/*
+ * Returns the total number of streams for a session or a negative value
+ * on error.
+ */
+static unsigned int get_total_nb_stream(struct ltt_session *session)
+{
+       unsigned int total_streams = 0;
+
+       if (session->kernel_session) {
+               struct ltt_kernel_session *ksess = session->kernel_session;
+
+               total_streams += ksess->stream_count_global;
+       }
+
+       if (session->ust_session) {
+               struct ltt_ust_session *usess = session->ust_session;
+
+               total_streams += ust_app_get_nb_stream(usess);
+       }
+
+       return total_streams;
+}
+
+/*
+ * 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;
+       unsigned int use_tmp_output = 0;
+       struct snapshot_output tmp_output;
+       unsigned int nb_streams, snapshot_success = 0;
+
+       assert(session);
+
+       DBG("Cmd snapshot record for session %s", session->name);
+
+       /*
+        * Permission 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') {
+               ret = snapshot_output_init(output->max_size, output->name,
+                               output->ctrl_url, output->data_url, session->consumer,
+                               &tmp_output, NULL);
+               if (ret < 0) {
+                       if (ret == -ENOMEM) {
+                               ret = LTTNG_ERR_NOMEM;
+                       } else {
+                               ret = LTTNG_ERR_INVALID;
+                       }
+                       goto error;
+               }
+               /* Use the global session count for the temporary snapshot. */
+               tmp_output.nb_snapshot = session->snapshot.nb_snapshot;
+               use_tmp_output = 1;
+       }
+
+       /*
+        * Get the total number of stream of that session which is used by the
+        * maximum size of the snapshot feature.
+        */
+       nb_streams = get_total_nb_stream(session);
+
+       if (session->kernel_session) {
+               struct ltt_kernel_session *ksess = session->kernel_session;
+
+               if (use_tmp_output) {
+                       ret = record_kernel_snapshot(ksess, &tmp_output, session,
+                                       wait, nb_streams);
+                       if (ret != LTTNG_OK) {
+                               goto error;
+                       }
+                       snapshot_success = 1;
+               } 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) {
+                               /*
+                                * Make a local copy of the output and assign the possible
+                                * temporary value given by the caller.
+                                */
+                               memset(&tmp_output, 0, sizeof(tmp_output));
+                               memcpy(&tmp_output, sout, sizeof(tmp_output));
+
+                               /* Use temporary max size. */
+                               if (output->max_size != (uint64_t) -1ULL) {
+                                       tmp_output.max_size = output->max_size;
+                               }
+
+                               /* Use temporary name. */
+                               if (*output->name != '\0') {
+                                       strncpy(tmp_output.name, output->name,
+                                                       sizeof(tmp_output.name));
+                               }
+
+                               tmp_output.nb_snapshot = session->snapshot.nb_snapshot;
+
+                               ret = record_kernel_snapshot(ksess, &tmp_output,
+                                               session, wait, nb_streams);
+                               if (ret != LTTNG_OK) {
+                                       rcu_read_unlock();
+                                       goto error;
+                               }
+                               snapshot_success = 1;
+                       }
+                       rcu_read_unlock();
+               }
+       }
+
+       if (session->ust_session) {
+               struct ltt_ust_session *usess = session->ust_session;
+
+               if (use_tmp_output) {
+                       ret = record_ust_snapshot(usess, &tmp_output, session,
+                                       wait, nb_streams);
+                       if (ret != LTTNG_OK) {
+                               goto error;
+                       }
+                       snapshot_success = 1;
+               } 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) {
+                               /*
+                                * Make a local copy of the output and assign the possible
+                                * temporary value given by the caller.
+                                */
+                               memset(&tmp_output, 0, sizeof(tmp_output));
+                               memcpy(&tmp_output, sout, sizeof(tmp_output));
+
+                               /* Use temporary max size. */
+                               if (output->max_size != (uint64_t) -1ULL) {
+                                       tmp_output.max_size = output->max_size;
+                               }
+
+                               /* Use temporary name. */
+                               if (*output->name != '\0') {
+                                       strncpy(tmp_output.name, output->name,
+                                                       sizeof(tmp_output.name));
+                               }
+
+                               tmp_output.nb_snapshot = session->snapshot.nb_snapshot;
+
+                               ret = record_ust_snapshot(usess, &tmp_output, session,
+                                               wait, nb_streams);
+                               if (ret != LTTNG_OK) {
+                                       rcu_read_unlock();
+                                       goto error;
+                               }
+                               snapshot_success = 1;
+                       }
+                       rcu_read_unlock();
+               }
+       }
+
+       if (snapshot_success) {
+               session->snapshot.nb_snapshot++;
+       }
+
+error:
+       return ret;
+}
+
 /*
  * Init command subsystem.
  */
This page took 0.031925 seconds and 4 git commands to generate.