#include "session.h"
#include "lttng-sessiond.h"
#include "notification-thread-commands.h"
+#include "rotate.h"
static
int ust_app_flush_app_session(struct ust_app *app, struct ust_app_session *ua_sess);
attr->switch_timer_interval = uattr->switch_timer_interval;
attr->read_timer_interval = uattr->read_timer_interval;
attr->output = uattr->output;
+ attr->blocking_timeout = uattr->u.s.blocking_timeout;
}
/*
ua_chan->attr.switch_timer_interval = attr->switch_timer_interval;
ua_chan->attr.read_timer_interval = attr->read_timer_interval;
ua_chan->attr.output = attr->output;
+ ua_chan->attr.blocking_timeout = attr->u.s.blocking_timeout;
}
/* By default, the channel is a per cpu channel. */
ua_chan->attr.type = LTTNG_UST_CHAN_PER_CPU;
ua_chan->attr.read_timer_interval = uchan->attr.read_timer_interval;
ua_chan->monitor_timer_interval = uchan->monitor_timer_interval;
ua_chan->attr.output = uchan->attr.output;
+ ua_chan->attr.blocking_timeout = uchan->attr.u.s.blocking_timeout;
+
/*
* Note that the attribute channel type is not set since the channel on the
* tracing registry side does not have this information.
* Returns 0 on success or else a negative code which is either -ENOMEM or
* -ENOTCONN which is the default code if the ustctl_create_session fails.
*/
-static int create_ust_app_session(struct ltt_ust_session *usess,
+static int find_or_create_ust_app_session(struct ltt_ust_session *usess,
struct ust_app *app, struct ust_app_session **ua_sess_ptr,
int *is_created)
{
ua_ctx = alloc_ust_app_ctx(uctx);
if (ua_ctx == NULL) {
/* malloc failed */
- ret = -1;
+ ret = -ENOMEM;
goto error;
}
/*
* Create and send to the application the created buffers with per UID buffers.
*
+ * This MUST be called with a RCU read side lock acquired.
+ * The session list lock and the session's lock must be acquired.
+ *
* Return 0 on success else a negative value.
*/
static int create_channel_per_uid(struct ust_app *app,
int ret;
struct buffer_reg_uid *reg_uid;
struct buffer_reg_channel *reg_chan;
- bool created = false;
assert(app);
assert(usess);
reg_chan = buffer_reg_channel_find(ua_chan->tracing_channel_id,
reg_uid);
- if (!reg_chan) {
- /* Create the buffer registry channel object. */
- ret = create_buffer_reg_channel(reg_uid->registry, ua_chan, ®_chan);
- if (ret < 0) {
- ERR("Error creating the UST channel \"%s\" registry instance",
- ua_chan->name);
- goto error;
- }
- assert(reg_chan);
+ if (reg_chan) {
+ goto send_channel;
+ }
- /*
- * Create the buffers on the consumer side. This call populates the
- * ust app channel object with all streams and data object.
- */
- ret = do_consumer_create_channel(usess, ua_sess, ua_chan,
- app->bits_per_long, reg_uid->registry->reg.ust);
- if (ret < 0) {
- ERR("Error creating UST channel \"%s\" on the consumer daemon",
+ /* Create the buffer registry channel object. */
+ ret = create_buffer_reg_channel(reg_uid->registry, ua_chan, ®_chan);
+ if (ret < 0) {
+ ERR("Error creating the UST channel \"%s\" registry instance",
ua_chan->name);
+ goto error;
+ }
- /*
- * Let's remove the previously created buffer registry channel so
- * it's not visible anymore in the session registry.
- */
- ust_registry_channel_del_free(reg_uid->registry->reg.ust,
- ua_chan->tracing_channel_id, false);
- buffer_reg_channel_remove(reg_uid->registry, reg_chan);
- buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST);
- goto error;
- }
+ /*
+ * Create the buffers on the consumer side. This call populates the
+ * ust app channel object with all streams and data object.
+ */
+ ret = do_consumer_create_channel(usess, ua_sess, ua_chan,
+ app->bits_per_long, reg_uid->registry->reg.ust);
+ if (ret < 0) {
+ ERR("Error creating UST channel \"%s\" on the consumer daemon",
+ ua_chan->name);
/*
- * Setup the streams and add it to the session registry.
+ * Let's remove the previously created buffer registry channel so
+ * it's not visible anymore in the session registry.
*/
- ret = setup_buffer_reg_channel(reg_uid->registry,
- ua_chan, reg_chan, app);
- if (ret < 0) {
- ERR("Error setting up UST channel \"%s\"",
- ua_chan->name);
- goto error;
- }
- created = true;
+ ust_registry_channel_del_free(reg_uid->registry->reg.ust,
+ ua_chan->tracing_channel_id, false);
+ buffer_reg_channel_remove(reg_uid->registry, reg_chan);
+ buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST);
+ goto error;
}
- /* Send buffers to the application. */
- ret = send_channel_uid_to_ust(reg_chan, app, ua_sess, ua_chan);
+ /*
+ * Setup the streams and add it to the session registry.
+ */
+ ret = setup_buffer_reg_channel(reg_uid->registry,
+ ua_chan, reg_chan, app);
if (ret < 0) {
- if (ret != -ENOTCONN) {
- ERR("Error sending channel to application");
- }
+ ERR("Error setting up UST channel \"%s\"", ua_chan->name);
goto error;
}
- if (created) {
+ {
enum lttng_error_code cmd_ret;
struct ltt_session *session;
uint64_t chan_reg_key;
struct ust_registry_channel *chan_reg;
- rcu_read_lock();
chan_reg_key = ua_chan->tracing_channel_id;
pthread_mutex_lock(®_uid->registry->reg.ust->lock);
session = session_find_by_id(ua_sess->tracing_id);
assert(session);
+ assert(pthread_mutex_trylock(&session->lock));
+ assert(session_trylock_list());
cmd_ret = notification_thread_command_add_channel(
notification_thread_handle, session->name,
ua_sess->euid, ua_sess->egid,
ua_chan->key,
LTTNG_DOMAIN_UST,
ua_chan->attr.subbuf_size * ua_chan->attr.num_subbuf);
- rcu_read_unlock();
if (cmd_ret != LTTNG_OK) {
ret = - (int) cmd_ret;
ERR("Failed to add channel to notification thread");
}
}
+send_channel:
+ /* Send buffers to the application. */
+ ret = send_channel_uid_to_ust(reg_chan, app, ua_sess, ua_chan);
+ if (ret < 0) {
+ if (ret != -ENOTCONN) {
+ ERR("Error sending channel to application");
+ }
+ goto error;
+ }
+
error:
return ret;
}
* Create and send to the application the created buffers with per PID buffers.
*
* Called with UST app session lock held.
+ * The session list lock and the session's lock must be acquired.
*
* Return 0 on success else a negative value.
*/
chan_reg->consumer_key = ua_chan->key;
pthread_mutex_unlock(®istry->lock);
+ assert(pthread_mutex_trylock(&session->lock));
+ assert(session_trylock_list());
+
cmd_ret = notification_thread_command_add_channel(
notification_thread_handle, session->name,
ua_sess->euid, ua_sess->egid,
/*
* Remove application from notify hash table. The thread handling the
* notify socket could have deleted the node so ignore on error because
- * either way it's valid. The close of that socket is handled by the other
- * thread.
+ * either way it's valid. The close of that socket is handled by the
+ * apps_notify_thread.
*/
iter.iter.node = <a->notify_sock_n.node;
(void) lttng_ht_del(ust_app_ht_by_notify_sock, &iter);
* that if session exist, it will simply return a pointer to the ust
* app session.
*/
- ret = create_ust_app_session(usess, app, &ua_sess, &created);
+ ret = find_or_create_ust_app_session(usess, app, &ua_sess, &created);
if (ret < 0) {
switch (ret) {
case -ENOTCONN:
/* Create directories if consumer is LOCAL and has a path defined. */
if (usess->consumer->type == CONSUMER_DST_LOCAL &&
- strlen(usess->consumer->dst.trace_path) > 0) {
- ret = run_as_mkdir_recursive(usess->consumer->dst.trace_path,
- S_IRWXU | S_IRWXG, ua_sess->euid, ua_sess->egid);
+ usess->consumer->dst.session_root_path[0] != '\0') {
+ char *tmp_path;
+
+ tmp_path = zmalloc(LTTNG_PATH_MAX);
+ if (!tmp_path) {
+ ERR("Alloc tmp_path");
+ goto error_unlock;
+ }
+ ret = snprintf(tmp_path, LTTNG_PATH_MAX, "%s%s%s",
+ usess->consumer->dst.session_root_path,
+ usess->consumer->chunk_path,
+ usess->consumer->subdir);
+ if (ret >= LTTNG_PATH_MAX) {
+ ERR("Local destination path exceeds the maximal allowed length of %i bytes (needs %i bytes) with path = \"%s%s%s\"",
+ LTTNG_PATH_MAX, ret,
+ usess->consumer->dst.session_root_path,
+ usess->consumer->chunk_path,
+ usess->consumer->subdir);
+ goto error_unlock;
+ }
+
+ DBG("Creating directory path for local tracing: \"%s\"",
+ tmp_path);
+ ret = run_as_mkdir_recursive(tmp_path, S_IRWXU | S_IRWXG,
+ ua_sess->euid, ua_sess->egid);
+ free(tmp_path);
if (ret < 0) {
if (errno != EEXIST) {
ERR("Trace directory creation error");
struct ust_app_ctx *ua_ctx;
int is_created = 0;
- ret = create_ust_app_session(usess, app, &ua_sess, &is_created);
+ ret = find_or_create_ust_app_session(usess, app, &ua_sess, &is_created);
if (ret < 0) {
/* Tracer is probably gone or ENOMEM. */
goto error;
return 0;
}
+
+/*
+ * Rotate all the channels of a session.
+ *
+ * Return 0 on success or else a negative value.
+ */
+int ust_app_rotate_session(struct ltt_session *session, bool *ust_active)
+{
+ int ret = 0;
+ struct lttng_ht_iter iter;
+ struct ust_app *app;
+ struct ltt_ust_session *usess = session->ust_session;
+ char pathname[LTTNG_PATH_MAX];
+
+ assert(usess);
+
+ rcu_read_lock();
+
+ switch (usess->buffer_type) {
+ case LTTNG_BUFFER_PER_UID:
+ {
+ struct buffer_reg_uid *reg;
+
+ cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
+ struct buffer_reg_channel *reg_chan;
+ struct consumer_socket *socket;
+
+ /* Get consumer socket to use to push the metadata.*/
+ socket = consumer_find_socket_by_bitness(reg->bits_per_long,
+ usess->consumer);
+ if (!socket) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * Account the metadata channel first to make sure the
+ * number of channels waiting for a rotation cannot
+ * reach 0 before we complete the iteration over all
+ * the channels.
+ */
+ ret = rotate_add_channel_pending(
+ reg->registry->reg.ust->metadata_key,
+ LTTNG_DOMAIN_UST, session);
+ if (ret < 0) {
+ ret = reg->bits_per_long == 32 ?
+ -LTTNG_ERR_UST_CONSUMER32_FAIL :
+ -LTTNG_ERR_UST_CONSUMER64_FAIL;
+ goto error;
+ }
+
+ ret = snprintf(pathname, sizeof(pathname),
+ DEFAULT_UST_TRACE_DIR "/" DEFAULT_UST_TRACE_UID_PATH,
+ reg->uid, reg->bits_per_long);
+ if (ret < 0 || ret == sizeof(pathname)) {
+ PERROR("Failed to format rotation path");
+ goto error;
+ }
+
+ /* Rotate the data channels. */
+ cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
+ reg_chan, node.node) {
+ ret = rotate_add_channel_pending(
+ reg_chan->consumer_key,
+ LTTNG_DOMAIN_UST, session);
+ if (ret < 0) {
+ ret = reg->bits_per_long == 32 ?
+ -LTTNG_ERR_UST_CONSUMER32_FAIL :
+ -LTTNG_ERR_UST_CONSUMER64_FAIL;
+ goto error;
+ }
+ ret = consumer_rotate_channel(socket,
+ reg_chan->consumer_key,
+ usess->uid, usess->gid,
+ usess->consumer, pathname,
+ /* is_metadata_channel */ false,
+ session->current_archive_id,
+ &session->rotate_pending_relay);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ (void) push_metadata(reg->registry->reg.ust, usess->consumer);
+
+ ret = consumer_rotate_channel(socket,
+ reg->registry->reg.ust->metadata_key,
+ usess->uid, usess->gid,
+ usess->consumer, pathname,
+ /* is_metadata_channel */ true,
+ session->current_archive_id,
+ &session->rotate_pending_relay);
+ if (ret < 0) {
+ goto error;
+ }
+ *ust_active = true;
+ }
+ break;
+ }
+ case LTTNG_BUFFER_PER_PID:
+ {
+ cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+ struct consumer_socket *socket;
+ struct lttng_ht_iter chan_iter;
+ struct ust_app_channel *ua_chan;
+ struct ust_app_session *ua_sess;
+ struct ust_registry_session *registry;
+
+ ua_sess = lookup_session_by_app(usess, app);
+ if (!ua_sess) {
+ /* Session not associated with this app. */
+ continue;
+ }
+ ret = snprintf(pathname, sizeof(pathname),
+ DEFAULT_UST_TRACE_DIR "/%s",
+ ua_sess->path);
+ if (ret < 0 || ret == sizeof(pathname)) {
+ PERROR("Failed to format rotation path");
+ goto error;
+ }
+
+ /* Get the right consumer socket for the application. */
+ socket = consumer_find_socket_by_bitness(app->bits_per_long,
+ usess->consumer);
+ if (!socket) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ registry = get_session_registry(ua_sess);
+ if (!registry) {
+ DBG("Application session is being torn down. Abort snapshot record.");
+ ret = -1;
+ goto error;
+ }
+
+ /*
+ * Account the metadata channel first to make sure the
+ * number of channels waiting for a rotation cannot
+ * reach 0 before we complete the iteration over all
+ * the channels.
+ */
+ ret = rotate_add_channel_pending(registry->metadata_key,
+ LTTNG_DOMAIN_UST, session);
+ if (ret < 0) {
+ ret = app->bits_per_long == 32 ?
+ -LTTNG_ERR_UST_CONSUMER32_FAIL :
+ -LTTNG_ERR_UST_CONSUMER64_FAIL;
+ goto error;
+ }
+
+ /* Rotate the data channels. */
+ cds_lfht_for_each_entry(ua_sess->channels->ht, &chan_iter.iter,
+ ua_chan, node.node) {
+ ret = rotate_add_channel_pending(
+ ua_chan->key, LTTNG_DOMAIN_UST,
+ session);
+ if (ret < 0) {
+ ret = app->bits_per_long == 32 ?
+ -LTTNG_ERR_UST_CONSUMER32_FAIL :
+ -LTTNG_ERR_UST_CONSUMER64_FAIL;
+ goto error;
+ }
+ ret = consumer_rotate_channel(socket, ua_chan->key,
+ ua_sess->euid, ua_sess->egid,
+ ua_sess->consumer, pathname,
+ /* is_metadata_channel */ false,
+ session->current_archive_id,
+ &session->rotate_pending_relay);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ /* Rotate the metadata channel. */
+ (void) push_metadata(registry, usess->consumer);
+ ret = consumer_rotate_channel(socket, registry->metadata_key,
+ ua_sess->euid, ua_sess->egid,
+ ua_sess->consumer, pathname,
+ /* is_metadata_channel */ true,
+ session->current_archive_id,
+ &session->rotate_pending_relay);
+ if (ret < 0) {
+ goto error;
+ }
+ *ust_active = true;
+ }
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+
+ ret = LTTNG_OK;
+
+error:
+ rcu_read_unlock();
+ return ret;
+}