X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fust-app.c;h=52d1da787f8142cd7cf92bab17acd9d3eda11235;hp=2bd48c7f30cf4e4552d7eb85b0ef6b6b557109f3;hb=2b2694892c10cdb632afac2b2f1aabf7cb9673d9;hpb=10b56aefc3e1de5cee607994f64c3b8a7d85c391 diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c index 2bd48c7f3..52d1da787 100644 --- a/src/bin/lttng-sessiond/ust-app.c +++ b/src/bin/lttng-sessiond/ust-app.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 - David Goulet + * Copyright (C) 2016 - Jérémie Galarneau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2 only, @@ -39,6 +40,10 @@ #include "ust-consumer.h" #include "ust-ctl.h" #include "utils.h" +#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); @@ -88,6 +93,7 @@ static void copy_channel_attr_to_ustctl( 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; } /* @@ -370,9 +376,74 @@ void delete_ust_app_channel_rcu(struct rcu_head *head) free(ua_chan); } +/* + * Extract the lost packet or discarded events counter when the channel is + * being deleted and store the value in the parent channel so we can + * access it from lttng list and at stop/destroy. + * + * The session list lock must be held by the caller. + */ +static +void save_per_pid_lost_discarded_counters(struct ust_app_channel *ua_chan) +{ + uint64_t discarded = 0, lost = 0; + struct ltt_session *session; + struct ltt_ust_channel *uchan; + + if (ua_chan->attr.type != LTTNG_UST_CHAN_PER_CPU) { + return; + } + + rcu_read_lock(); + session = session_find_by_id(ua_chan->session->tracing_id); + if (!session || !session->ust_session) { + /* + * Not finding the session is not an error because there are + * multiple ways the channels can be torn down. + * + * 1) The session daemon can initiate the destruction of the + * ust app session after receiving a destroy command or + * during its shutdown/teardown. + * 2) The application, since we are in per-pid tracing, is + * unregistering and tearing down its ust app session. + * + * Both paths are protected by the session list lock which + * ensures that the accounting of lost packets and discarded + * events is done exactly once. The session is then unpublished + * from the session list, resulting in this condition. + */ + goto end; + } + + if (ua_chan->attr.overwrite) { + consumer_get_lost_packets(ua_chan->session->tracing_id, + ua_chan->key, session->ust_session->consumer, + &lost); + } else { + consumer_get_discarded_events(ua_chan->session->tracing_id, + ua_chan->key, session->ust_session->consumer, + &discarded); + } + uchan = trace_ust_find_channel_by_name( + session->ust_session->domain_global.channels, + ua_chan->name); + if (!uchan) { + ERR("Missing UST channel to store discarded counters"); + goto end; + } + + uchan->per_pid_closed_app_discarded += discarded; + uchan->per_pid_closed_app_lost += lost; + +end: + rcu_read_unlock(); +} + /* * Delete ust app channel safely. RCU read lock must be held before calling * this function. + * + * The session list lock must be held by the caller. */ static void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan, @@ -415,8 +486,10 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan, /* Wipe and free registry from session registry. */ registry = get_session_registry(ua_chan->session); if (registry) { - ust_registry_channel_del_free(registry, ua_chan->key); + ust_registry_channel_del_free(registry, ua_chan->key, + true); } + save_per_pid_lost_discarded_counters(ua_chan); } if (ua_chan->obj != NULL) { @@ -483,7 +556,7 @@ ssize_t ust_app_push_metadata(struct ust_registry_session *registry, char *metadata_str = NULL; size_t len, offset, new_metadata_len_sent; ssize_t ret_val; - uint64_t metadata_key; + uint64_t metadata_key, metadata_version; assert(registry); assert(socket); @@ -498,21 +571,10 @@ ssize_t ust_app_push_metadata(struct ust_registry_session *registry, return 0; } - /* - * On a push metadata error either the consumer is dead or the - * metadata channel has been destroyed because its endpoint - * might have died (e.g: relayd), or because the application has - * exited. If so, the metadata closed flag is set to 1 so we - * deny pushing metadata again which is not valid anymore on the - * consumer side. - */ - if (registry->metadata_closed) { - return -EPIPE; - } - offset = registry->metadata_len_sent; len = registry->metadata_len - registry->metadata_len_sent; new_metadata_len_sent = registry->metadata_len; + metadata_version = registry->metadata_version; if (len == 0) { DBG3("No metadata to push for metadata key %" PRIu64, registry->metadata_key); @@ -549,7 +611,7 @@ push_data: * different bidirectionnal communication sockets. */ ret = consumer_push_metadata(socket, metadata_key, - metadata_str, len, offset); + metadata_str, len, offset, metadata_version); pthread_mutex_lock(®istry->lock); if (ret < 0) { /* @@ -733,6 +795,8 @@ void delete_ust_app_session_rcu(struct rcu_head *head) /* * Delete ust app session safely. RCU read lock must be held before calling * this function. + * + * The session list lock must be held by the caller. */ static void delete_ust_app_session(int sock, struct ust_app_session *ua_sess, @@ -751,6 +815,7 @@ void delete_ust_app_session(int sock, struct ust_app_session *ua_sess, ua_sess->deleted = true; registry = get_session_registry(ua_sess); + /* Registry can be null on error path during initialization. */ if (registry) { /* Push metadata for application before freeing the application. */ (void) push_metadata(registry, ua_sess->consumer); @@ -778,6 +843,10 @@ void delete_ust_app_session(int sock, struct ust_app_session *ua_sess, if (ua_sess->buffer_type == LTTNG_BUFFER_PER_PID) { struct buffer_reg_pid *reg_pid = buffer_reg_pid_find(ua_sess->id); if (reg_pid) { + /* + * Registry can be null on error path during + * initialization. + */ buffer_reg_pid_remove(reg_pid); buffer_reg_pid_destroy(reg_pid); } @@ -816,6 +885,11 @@ void delete_ust_app(struct ust_app *app) int ret, sock; struct ust_app_session *ua_sess, *tmp_ua_sess; + /* + * The session list lock must be held during this function to guarantee + * the existence of ua_sess. + */ + session_lock_list(); /* Delete ust app sessions info */ sock = app->sock; app->sock = -1; @@ -854,6 +928,7 @@ void delete_ust_app(struct ust_app *app) DBG2("UST app pid %d deleted", app->pid); free(app); + session_unlock_list(); } /* @@ -874,6 +949,8 @@ void delete_ust_app_rcu(struct rcu_head *head) /* * Delete the session from the application ht and delete the data structure by * freeing every object inside and releasing them. + * + * The session list lock must be held by the caller. */ static void destroy_app_session(struct ust_app *app, struct ust_app_session *ua_sess) @@ -902,7 +979,7 @@ end: * Alloc new UST app session. */ static -struct ust_app_session *alloc_ust_app_session(struct ust_app *app) +struct ust_app_session *alloc_ust_app_session(void) { struct ust_app_session *ua_sess; @@ -965,6 +1042,7 @@ struct ust_app_channel *alloc_ust_app_channel(char *name, 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; @@ -1037,7 +1115,7 @@ error: * Alloc new UST app context. */ static -struct ust_app_ctx *alloc_ust_app_ctx(struct lttng_ust_context *uctx) +struct ust_app_ctx *alloc_ust_app_ctx(struct lttng_ust_context_attr *uctx) { struct ust_app_ctx *ua_ctx; @@ -1050,12 +1128,27 @@ struct ust_app_ctx *alloc_ust_app_ctx(struct lttng_ust_context *uctx) if (uctx) { memcpy(&ua_ctx->ctx, uctx, sizeof(ua_ctx->ctx)); + if (uctx->ctx == LTTNG_UST_CONTEXT_APP_CONTEXT) { + char *provider_name = NULL, *ctx_name = NULL; + + provider_name = strdup(uctx->u.app_ctx.provider_name); + ctx_name = strdup(uctx->u.app_ctx.ctx_name); + if (!provider_name || !ctx_name) { + free(provider_name); + free(ctx_name); + goto error; + } + + ua_ctx->ctx.u.app_ctx.provider_name = provider_name; + ua_ctx->ctx.u.app_ctx.ctx_name = ctx_name; + } } DBG3("UST app context %d allocated", ua_ctx->ctx.ctx); - -error: return ua_ctx; +error: + free(ua_ctx); + return NULL; } /* @@ -1696,7 +1789,6 @@ static void shadow_copy_channel(struct ust_app_channel *ua_chan, struct ltt_ust_event *uevent; struct ltt_ust_context *uctx; struct ust_app_event *ua_event; - struct ust_app_ctx *ua_ctx; DBG2("UST app shadow copy of channel %s started", ua_chan->name); @@ -1712,7 +1804,10 @@ static void shadow_copy_channel(struct ust_app_channel *ua_chan, ua_chan->attr.overwrite = uchan->attr.overwrite; ua_chan->attr.switch_timer_interval = uchan->attr.switch_timer_interval; 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. @@ -1722,7 +1817,8 @@ static void shadow_copy_channel(struct ust_app_channel *ua_chan, ua_chan->tracing_channel_id = uchan->id; cds_list_for_each_entry(uctx, &uchan->ctx_list, list) { - ua_ctx = alloc_ust_app_ctx(&uctx->ctx); + struct ust_app_ctx *ua_ctx = alloc_ust_app_ctx(&uctx->ctx); + if (ua_ctx == NULL) { continue; } @@ -1858,7 +1954,8 @@ static void shadow_copy_session(struct ust_app_session *ua_sess, DBG2("Channel %s not found on shadow session copy, creating it", uchan->name); - ua_chan = alloc_ust_app_channel(uchan->name, ua_sess, &uchan->attr); + ua_chan = alloc_ust_app_channel(uchan->name, ua_sess, + &uchan->attr); if (ua_chan == NULL) { /* malloc failed FIXME: Might want to do handle ENOMEM .. */ continue; @@ -2057,7 +2154,7 @@ error: * 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) { @@ -2074,7 +2171,7 @@ static int create_ust_app_session(struct ltt_ust_session *usess, if (ua_sess == NULL) { DBG2("UST app pid: %d session id %" PRIu64 " not found, creating it", app->pid, usess->id); - ua_sess = alloc_ust_app_session(app); + ua_sess = alloc_ust_app_session(); if (ua_sess == NULL) { /* Only malloc can failed so something is really wrong */ ret = -ENOMEM; @@ -2173,7 +2270,7 @@ error: static int ht_match_ust_app_ctx(struct cds_lfht_node *node, const void *_key) { struct ust_app_ctx *ctx; - const struct lttng_ust_context *key; + const struct lttng_ust_context_attr *key; assert(node); assert(_key); @@ -2186,13 +2283,24 @@ static int ht_match_ust_app_ctx(struct cds_lfht_node *node, const void *_key) goto no_match; } - /* Check the name in the case of perf thread counters. */ - if (key->ctx == LTTNG_UST_CONTEXT_PERF_THREAD_COUNTER) { + switch(key->ctx) { + case LTTNG_UST_CONTEXT_PERF_THREAD_COUNTER: if (strncmp(key->u.perf_counter.name, - ctx->ctx.u.perf_counter.name, - sizeof(key->u.perf_counter.name))) { + ctx->ctx.u.perf_counter.name, + sizeof(key->u.perf_counter.name))) { + goto no_match; + } + break; + case LTTNG_UST_CONTEXT_APP_CONTEXT: + if (strcmp(key->u.app_ctx.provider_name, + ctx->ctx.u.app_ctx.provider_name) || + strcmp(key->u.app_ctx.ctx_name, + ctx->ctx.u.app_ctx.ctx_name)) { goto no_match; } + break; + default: + break; } /* Match. */ @@ -2210,7 +2318,7 @@ no_match: */ static struct ust_app_ctx *find_ust_app_context(struct lttng_ht *ht, - struct lttng_ust_context *uctx) + struct lttng_ust_context_attr *uctx) { struct lttng_ht_iter iter; struct lttng_ht_node_ulong *node; @@ -2239,8 +2347,8 @@ end: * Called with UST app session lock held and a RCU read side lock. */ static -int create_ust_app_channel_context(struct ust_app_session *ua_sess, - struct ust_app_channel *ua_chan, struct lttng_ust_context *uctx, +int create_ust_app_channel_context(struct ust_app_channel *ua_chan, + struct lttng_ust_context_attr *uctx, struct ust_app *app) { int ret = 0; @@ -2257,7 +2365,7 @@ int create_ust_app_channel_context(struct ust_app_session *ua_sess, ua_ctx = alloc_ust_app_ctx(uctx); if (ua_ctx == NULL) { /* malloc failed */ - ret = -1; + ret = -ENOMEM; goto error; } @@ -2369,11 +2477,14 @@ error: /* * Ask the consumer to create a channel and get it if successful. * + * Called with UST app session lock held. + * * Return 0 on success or else a negative value. */ static int do_consumer_create_channel(struct ltt_ust_session *usess, struct ust_app_session *ua_sess, struct ust_app_channel *ua_chan, - int bitness, struct ust_registry_session *registry) + int bitness, struct ust_registry_session *registry, + uint64_t trace_archive_id) { int ret; unsigned int nb_fd = 0; @@ -2408,7 +2519,7 @@ static int do_consumer_create_channel(struct ltt_ust_session *usess, * stream we have to expect. */ ret = ust_consumer_ask_channel(ua_sess, ua_chan, usess->consumer, socket, - registry); + registry, trace_archive_id); if (ret < 0) { goto error_ask; } @@ -2714,9 +2825,6 @@ static int send_channel_uid_to_ust(struct buffer_reg_channel *reg_chan, (void) release_ust_app_stream(-1, &stream, app); if (ret == -EPIPE || ret == -LTTNG_UST_ERR_EXITING) { ret = -ENOTCONN; /* Caused by app exiting. */ - goto error_stream_unlock; - } else if (ret < 0) { - goto error_stream_unlock; } goto error_stream_unlock; } @@ -2738,6 +2846,9 @@ 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, @@ -2747,6 +2858,9 @@ static int create_channel_per_uid(struct ust_app *app, int ret; struct buffer_reg_uid *reg_uid; struct buffer_reg_channel *reg_chan; + struct ltt_session *session; + enum lttng_error_code notification_ret; + struct ust_registry_channel *chan_reg; assert(app); assert(usess); @@ -2765,50 +2879,78 @@ static int create_channel_per_uid(struct ust_app *app, 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); - buffer_reg_channel_remove(reg_uid->registry, reg_chan); - buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST); - goto error; - } + session = session_find_by_id(ua_sess->tracing_id); + assert(session); + assert(pthread_mutex_trylock(&session->lock)); + assert(session_trylock_list()); + + /* + * 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, + session->current_archive_id); + 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; - } + 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; + } + + /* + * 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) { + ERR("Error setting up UST channel \"%s\"", ua_chan->name); + goto error; + } + /* Notify the notification subsystem of the channel's creation. */ + pthread_mutex_lock(®_uid->registry->reg.ust->lock); + chan_reg = ust_registry_channel_find(reg_uid->registry->reg.ust, + ua_chan->tracing_channel_id); + assert(chan_reg); + chan_reg->consumer_key = ua_chan->key; + chan_reg = NULL; + pthread_mutex_unlock(®_uid->registry->reg.ust->lock); + + notification_ret = notification_thread_command_add_channel( + notification_thread_handle, session->name, + ua_sess->euid, ua_sess->egid, + ua_chan->name, + ua_chan->key, + LTTNG_DOMAIN_UST, + ua_chan->attr.subbuf_size * ua_chan->attr.num_subbuf); + if (notification_ret != LTTNG_OK) { + ret = - (int) notification_ret; + ERR("Failed to add channel to notification thread"); + goto error; } +send_channel: /* Send buffers to the application. */ ret = send_channel_uid_to_ust(reg_chan, app, ua_sess, ua_chan); if (ret < 0) { @@ -2825,6 +2967,9 @@ error: /* * 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. */ static int create_channel_per_pid(struct ust_app *app, @@ -2833,6 +2978,10 @@ static int create_channel_per_pid(struct ust_app *app, { int ret; struct ust_registry_session *registry; + enum lttng_error_code cmd_ret; + struct ltt_session *session; + uint64_t chan_reg_key; + struct ust_registry_channel *chan_reg; assert(app); assert(usess); @@ -2844,6 +2993,7 @@ static int create_channel_per_pid(struct ust_app *app, rcu_read_lock(); registry = get_session_registry(ua_sess); + /* The UST app session lock is held, registry shall not be null. */ assert(registry); /* Create and add a new channel registry to session. */ @@ -2854,9 +3004,16 @@ static int create_channel_per_pid(struct ust_app *app, goto error; } + session = session_find_by_id(ua_sess->tracing_id); + assert(session); + + assert(pthread_mutex_trylock(&session->lock)); + assert(session_trylock_list()); + /* Create and get channel on the consumer side. */ ret = do_consumer_create_channel(usess, ua_sess, ua_chan, - app->bits_per_long, registry); + app->bits_per_long, registry, + session->current_archive_id); if (ret < 0) { ERR("Error creating UST channel \"%s\" on the consumer daemon", ua_chan->name); @@ -2871,6 +3028,26 @@ static int create_channel_per_pid(struct ust_app *app, goto error; } + chan_reg_key = ua_chan->key; + pthread_mutex_lock(®istry->lock); + chan_reg = ust_registry_channel_find(registry, chan_reg_key); + assert(chan_reg); + chan_reg->consumer_key = ua_chan->key; + pthread_mutex_unlock(®istry->lock); + + cmd_ret = notification_thread_command_add_channel( + notification_thread_handle, session->name, + ua_sess->euid, ua_sess->egid, + ua_chan->name, + ua_chan->key, + LTTNG_DOMAIN_UST, + ua_chan->attr.subbuf_size * ua_chan->attr.num_subbuf); + if (cmd_ret != LTTNG_OK) { + ret = - (int) cmd_ret; + ERR("Failed to add channel to notification thread"); + goto error; + } + error: rcu_read_unlock(); return ret; @@ -2881,6 +3058,8 @@ error: * need and send it to the application. This MUST be called with a RCU read * side lock acquired. * + * Called with UST app session lock held. + * * Return 0 on success or else a negative value. Returns -ENOTCONN if * the application exited concurrently. */ @@ -2983,7 +3162,6 @@ static int create_ust_app_channel(struct ust_app_session *ua_sess, /* Only add the channel if successful on the tracer side. */ lttng_ht_add_unique_str(ua_sess->channels, &ua_chan->node); - end: if (ua_chanp) { *ua_chanp = ua_chan; @@ -3062,12 +3240,14 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, struct ust_app_channel *metadata; struct consumer_socket *socket; struct ust_registry_session *registry; + struct ltt_session *session; assert(ua_sess); assert(app); assert(consumer); registry = get_session_registry(ua_sess); + /* The UST app session is held registry shall not be null. */ assert(registry); pthread_mutex_lock(®istry->lock); @@ -3110,6 +3290,12 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, */ registry->metadata_key = metadata->key; + session = session_find_by_id(ua_sess->tracing_id); + assert(session); + + assert(pthread_mutex_trylock(&session->lock)); + assert(session_trylock_list()); + /* * Ask the metadata channel creation to the consumer. The metadata object * will be created by the consumer and kept their. However, the stream is @@ -3117,7 +3303,7 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, * consumer. */ ret = ust_consumer_ask_channel(ua_sess, metadata, consumer, socket, - registry); + registry, session->current_archive_id); if (ret < 0) { /* Nullify the metadata key so we don't try to close it later on. */ registry->metadata_key = 0; @@ -3402,8 +3588,8 @@ void ust_app_unregister(int sock) /* * 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); @@ -3989,7 +4175,7 @@ int ust_app_create_channel_glb(struct ltt_ust_session *usess, * 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: @@ -4204,6 +4390,9 @@ int ust_app_create_event_glb(struct ltt_ust_session *usess, /* * Start tracing for a specific UST session and app. + * + * Called with UST app session lock held. + * */ static int ust_app_start_trace(struct ltt_ust_session *usess, struct ust_app *app) @@ -4239,9 +4428,33 @@ int ust_app_start_trace(struct ltt_ust_session *usess, struct ust_app *app) /* 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); + free(tmp_path); + 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"); @@ -4387,6 +4600,8 @@ int ust_app_stop_trace(struct ltt_ust_session *usess, struct ust_app *app) health_code_update(); registry = get_session_registry(ua_sess); + + /* The UST app session is held registry shall not be null. */ assert(registry); /* Push metadata for application before freeing the application. */ @@ -4441,7 +4656,6 @@ int ust_app_flush_app_session(struct ust_app *app, cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, ua_chan, node.node) { health_code_update(); - assert(ua_chan->is_sent); ret = consumer_flush_channel(socket, ua_chan->key); if (ret) { ERR("Error flushing consumer channel"); @@ -4544,6 +4758,155 @@ int ust_app_flush_session(struct ltt_ust_session *usess) return ret; } +static +int ust_app_clear_quiescent_app_session(struct ust_app *app, + struct ust_app_session *ua_sess) +{ + int ret = 0; + struct lttng_ht_iter iter; + struct ust_app_channel *ua_chan; + struct consumer_socket *socket; + + DBG("Clearing stream quiescent state for ust app pid %d", app->pid); + + rcu_read_lock(); + + if (!app->compatible) { + goto end_not_compatible; + } + + pthread_mutex_lock(&ua_sess->lock); + + if (ua_sess->deleted) { + goto end_unlock; + } + + health_code_update(); + + socket = consumer_find_socket_by_bitness(app->bits_per_long, + ua_sess->consumer); + if (!socket) { + ERR("Failed to find consumer (%" PRIu32 ") socket", + app->bits_per_long); + ret = -1; + goto end_unlock; + } + + /* Clear quiescent state. */ + switch (ua_sess->buffer_type) { + case LTTNG_BUFFER_PER_PID: + cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, + ua_chan, node.node) { + health_code_update(); + ret = consumer_clear_quiescent_channel(socket, + ua_chan->key); + if (ret) { + ERR("Error clearing quiescent state for consumer channel"); + ret = -1; + continue; + } + } + break; + case LTTNG_BUFFER_PER_UID: + default: + assert(0); + ret = -1; + break; + } + + health_code_update(); + +end_unlock: + pthread_mutex_unlock(&ua_sess->lock); + +end_not_compatible: + rcu_read_unlock(); + health_code_update(); + return ret; +} + +/* + * Clear quiescent state in each stream for all applications for a + * specific UST session. + * Called with UST session lock held. + */ +static +int ust_app_clear_quiescent_session(struct ltt_ust_session *usess) + +{ + int ret = 0; + + DBG("Clearing stream quiescent state for all ust apps"); + + rcu_read_lock(); + + switch (usess->buffer_type) { + case LTTNG_BUFFER_PER_UID: + { + struct lttng_ht_iter iter; + struct buffer_reg_uid *reg; + + /* + * Clear quiescent for all per UID buffers associated to + * that session. + */ + cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) { + struct consumer_socket *socket; + struct buffer_reg_channel *reg_chan; + + /* Get associated consumer socket.*/ + socket = consumer_find_socket_by_bitness( + reg->bits_per_long, usess->consumer); + if (!socket) { + /* + * Ignore request if no consumer is found for + * the session. + */ + continue; + } + + cds_lfht_for_each_entry(reg->registry->channels->ht, + &iter.iter, reg_chan, node.node) { + /* + * The following call will print error values so + * the return code is of little importance + * because whatever happens, we have to try them + * all. + */ + (void) consumer_clear_quiescent_channel(socket, + reg_chan->consumer_key); + } + } + break; + } + case LTTNG_BUFFER_PER_PID: + { + struct ust_app_session *ua_sess; + struct lttng_ht_iter iter; + struct ust_app *app; + + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, + pid_n.node) { + ua_sess = lookup_session_by_app(usess, app); + if (ua_sess == NULL) { + continue; + } + (void) ust_app_clear_quiescent_app_session(app, + ua_sess); + } + break; + } + default: + ret = -1; + assert(0); + break; + } + + rcu_read_unlock(); + health_code_update(); + return ret; +} + /* * Destroy a specific UST session in apps. */ @@ -4602,6 +4965,14 @@ int ust_app_start_trace_all(struct ltt_ust_session *usess) rcu_read_lock(); + /* + * In a start-stop-start use-case, we need to clear the quiescent state + * of each channel set by the prior stop command, thus ensuring that a + * following stop or destroy is sure to grab a timestamp_end near those + * operations, even if the packet is empty. + */ + (void) ust_app_clear_quiescent_session(usess); + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { ret = ust_app_start_trace(usess, app); if (ret < 0) { @@ -4681,7 +5052,7 @@ void ust_app_global_create(struct ltt_ust_session *usess, struct ust_app *app) 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; @@ -4858,7 +5229,7 @@ int ust_app_add_ctx_channel_glb(struct ltt_ust_session *usess, } ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node); - ret = create_ust_app_channel_context(ua_sess, ua_chan, &uctx->ctx, app); + ret = create_ust_app_channel_context(ua_chan, &uctx->ctx, app); if (ret < 0) { goto next_app; } @@ -4944,59 +5315,11 @@ end: } /* - * Calibrate registered applications. + * Receive registration and populate the given msg structure. + * + * On success return 0 else a negative value returned by the ustctl call. */ -int ust_app_calibrate_glb(struct lttng_ust_calibrate *calibrate) -{ - int ret = 0; - struct lttng_ht_iter iter; - struct ust_app *app; - - rcu_read_lock(); - - cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { - if (!app->compatible) { - /* - * TODO: In time, we should notice the caller of this error by - * telling him that this is a version error. - */ - continue; - } - - health_code_update(); - - pthread_mutex_lock(&app->sock_lock); - ret = ustctl_calibrate(app->sock, calibrate); - pthread_mutex_unlock(&app->sock_lock); - if (ret < 0) { - switch (ret) { - case -ENOSYS: - /* Means that it's not implemented on the tracer side. */ - ret = 0; - break; - default: - DBG2("Calibrate app PID %d returned with error %d", - app->pid, ret); - break; - } - } - } - - DBG("UST app global domain calibration finished"); - - rcu_read_unlock(); - - health_code_update(); - - return ret; -} - -/* - * Receive registration and populate the given msg structure. - * - * On success return 0 else a negative value returned by the ustctl call. - */ -int ust_app_recv_registration(int sock, struct ust_register_msg *msg) +int ust_app_recv_registration(int sock, struct ust_register_msg *msg) { int ret; uint32_t pid, ppid, uid, gid; @@ -5102,7 +5425,7 @@ error: * * On success 0 is returned else a negative value. */ -static int reply_ust_register_channel(int sock, int sobjd, int cobjd, +static int reply_ust_register_channel(int sock, int cobjd, size_t nr_fields, struct ustctl_field *fields) { int ret, ret_code = 0; @@ -5120,19 +5443,17 @@ static int reply_ust_register_channel(int sock, int sobjd, int cobjd, /* Lookup application. If not found, there is a code flow error. */ app = find_app_by_notify_sock(sock); if (!app) { - DBG("Application socket %d is being teardown. Abort event notify", + DBG("Application socket %d is being torn down. Abort event notify", sock); ret = 0; - free(fields); goto error_rcu_unlock; } /* Lookup channel by UST object descriptor. */ ua_chan = find_channel_by_objd(app, cobjd); if (!ua_chan) { - DBG("Application channel is being teardown. Abort event notify"); + DBG("Application channel is being torn down. Abort event notify"); ret = 0; - free(fields); goto error_rcu_unlock; } @@ -5141,7 +5462,11 @@ static int reply_ust_register_channel(int sock, int sobjd, int cobjd, /* Get right session registry depending on the session buffer type. */ registry = get_session_registry(ua_sess); - assert(registry); + if (!registry) { + DBG("Application session is being torn down. Abort event notify"); + ret = 0; + goto error_rcu_unlock; + }; /* Depending on the buffer type, a different channel key is used. */ if (ua_sess->buffer_type == LTTNG_BUFFER_PER_UID) { @@ -5165,13 +5490,11 @@ static int reply_ust_register_channel(int sock, int sobjd, int cobjd, chan_reg->nr_ctx_fields = nr_fields; chan_reg->ctx_fields = fields; + fields = NULL; chan_reg->header_type = type; } else { /* Get current already assigned values. */ type = chan_reg->header_type; - free(fields); - /* Set to NULL so the error path does not do a double free. */ - fields = NULL; } /* Channel id is set during the object creation. */ chan_id = chan_reg->chan_id; @@ -5207,9 +5530,7 @@ error: pthread_mutex_unlock(®istry->lock); error_rcu_unlock: rcu_read_unlock(); - if (ret) { - free(fields); - } + free(fields); return ret; } @@ -5239,23 +5560,17 @@ static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name, /* Lookup application. If not found, there is a code flow error. */ app = find_app_by_notify_sock(sock); if (!app) { - DBG("Application socket %d is being teardown. Abort event notify", + DBG("Application socket %d is being torn down. Abort event notify", sock); ret = 0; - free(sig); - free(fields); - free(model_emf_uri); goto error_rcu_unlock; } /* Lookup channel by UST object descriptor. */ ua_chan = find_channel_by_objd(app, cobjd); if (!ua_chan) { - DBG("Application channel is being teardown. Abort event notify"); + DBG("Application channel is being torn down. Abort event notify"); ret = 0; - free(sig); - free(fields); - free(model_emf_uri); goto error_rcu_unlock; } @@ -5263,7 +5578,11 @@ static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name, ua_sess = ua_chan->session; registry = get_session_registry(ua_sess); - assert(registry); + if (!registry) { + DBG("Application session is being torn down. Abort event notify"); + ret = 0; + goto error_rcu_unlock; + } if (ua_sess->buffer_type == LTTNG_BUFFER_PER_UID) { chan_reg_key = ua_chan->tracing_channel_id; @@ -5282,6 +5601,9 @@ static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name, sobjd, cobjd, name, sig, nr_fields, fields, loglevel_value, model_emf_uri, ua_sess->buffer_type, &event_id, app); + sig = NULL; + fields = NULL; + model_emf_uri = NULL; /* * The return value is returned to ustctl so in case of an error, the @@ -5309,6 +5631,9 @@ error: pthread_mutex_unlock(®istry->lock); error_rcu_unlock: rcu_read_unlock(); + free(sig); + free(fields); + free(model_emf_uri); return ret; } @@ -5345,13 +5670,17 @@ static int add_enum_ust_registry(int sock, int sobjd, char *name, ua_sess = find_session_by_objd(app, sobjd); if (!ua_sess) { /* Return an error since this is not an error */ - DBG("Application session is being torn down. Aborting enum registration."); + DBG("Application session is being torn down (session not found). Aborting enum registration."); free(entries); goto error_rcu_unlock; } registry = get_session_registry(ua_sess); - assert(registry); + if (!registry) { + DBG("Application session is being torn down (registry not found). Aborting enum registration."); + free(entries); + goto error_rcu_unlock; + } pthread_mutex_lock(®istry->lock); @@ -5474,7 +5803,7 @@ int ust_app_recv_notify(int sock) * that if needed it will be freed. After this, it's invalid to access * fields or clean it up. */ - ret = reply_ust_register_channel(sock, sobjd, cobjd, nr_fields, + ret = reply_ust_register_channel(sock, cobjd, nr_fields, fields); if (ret < 0) { goto error; @@ -5620,16 +5949,23 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, uint64_t nb_packets_per_stream) { int ret = 0; - unsigned int snapshot_done = 0; struct lttng_ht_iter iter; struct ust_app *app; char pathname[PATH_MAX]; + struct ltt_session *session; + uint64_t trace_archive_id; assert(usess); assert(output); rcu_read_lock(); + session = session_find_by_id(usess->id); + assert(session); + assert(pthread_mutex_trylock(&session->lock)); + assert(session_trylock_list()); + trace_archive_id = session->current_archive_id; + switch (usess->buffer_type) { case LTTNG_BUFFER_PER_UID: { @@ -5639,6 +5975,11 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, struct buffer_reg_channel *reg_chan; struct consumer_socket *socket; + if (!reg->registry->reg.ust->metadata_key) { + /* Skip since no metadata is present */ + continue; + } + /* Get consumer socket to use to push the metadata.*/ socket = consumer_find_socket_by_bitness(reg->bits_per_long, usess->consumer); @@ -5659,20 +6000,23 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, /* Add the UST default trace dir to path. */ cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter, reg_chan, node.node) { - ret = consumer_snapshot_channel(socket, reg_chan->consumer_key, - output, 0, usess->uid, usess->gid, pathname, wait, - nb_packets_per_stream); + ret = consumer_snapshot_channel(socket, + reg_chan->consumer_key, + output, 0, usess->uid, + usess->gid, pathname, wait, + nb_packets_per_stream, + trace_archive_id); if (ret < 0) { goto error; } } ret = consumer_snapshot_channel(socket, reg->registry->reg.ust->metadata_key, output, 1, - usess->uid, usess->gid, pathname, wait, 0); + usess->uid, usess->gid, pathname, wait, 0, + trace_archive_id); if (ret < 0) { goto error; } - snapshot_done = 1; } break; } @@ -5710,22 +6054,31 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, cds_lfht_for_each_entry(ua_sess->channels->ht, &chan_iter.iter, ua_chan, node.node) { - ret = consumer_snapshot_channel(socket, ua_chan->key, output, - 0, ua_sess->euid, ua_sess->egid, pathname, wait, - nb_packets_per_stream); + ret = consumer_snapshot_channel(socket, + ua_chan->key, output, + 0, ua_sess->euid, ua_sess->egid, + pathname, wait, + nb_packets_per_stream, + trace_archive_id); if (ret < 0) { goto error; } } registry = get_session_registry(ua_sess); - assert(registry); - ret = consumer_snapshot_channel(socket, registry->metadata_key, output, - 1, ua_sess->euid, ua_sess->egid, pathname, wait, 0); + if (!registry) { + DBG("Application session is being torn down. Abort snapshot record."); + ret = -1; + goto error; + } + ret = consumer_snapshot_channel(socket, + registry->metadata_key, output, + 1, ua_sess->euid, ua_sess->egid, + pathname, wait, 0, + trace_archive_id); if (ret < 0) { goto error; } - snapshot_done = 1; } break; } @@ -5734,15 +6087,6 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, break; } - if (!snapshot_done) { - /* - * If no snapshot was made and we are not in the error path, this means - * that there are no buffers thus no (prior) application to snapshot - * data from so we have simply NO data. - */ - ret = -ENODATA; - } - error: rcu_read_unlock(); return ret; @@ -5820,3 +6164,361 @@ uint64_t ust_app_get_size_one_more_packet_per_stream(struct ltt_ust_session *use return tot_size; } + +int ust_app_uid_get_channel_runtime_stats(uint64_t ust_session_id, + struct cds_list_head *buffer_reg_uid_list, + struct consumer_output *consumer, uint64_t uchan_id, + int overwrite, uint64_t *discarded, uint64_t *lost) +{ + int ret; + uint64_t consumer_chan_key; + + *discarded = 0; + *lost = 0; + + ret = buffer_reg_uid_consumer_channel_key( + buffer_reg_uid_list, uchan_id, &consumer_chan_key); + if (ret < 0) { + /* Not found */ + ret = 0; + goto end; + } + + if (overwrite) { + ret = consumer_get_lost_packets(ust_session_id, + consumer_chan_key, consumer, lost); + } else { + ret = consumer_get_discarded_events(ust_session_id, + consumer_chan_key, consumer, discarded); + } + +end: + return ret; +} + +int ust_app_pid_get_channel_runtime_stats(struct ltt_ust_session *usess, + struct ltt_ust_channel *uchan, + struct consumer_output *consumer, int overwrite, + uint64_t *discarded, uint64_t *lost) +{ + int ret = 0; + struct lttng_ht_iter iter; + struct lttng_ht_node_str *ua_chan_node; + struct ust_app *app; + struct ust_app_session *ua_sess; + struct ust_app_channel *ua_chan; + + *discarded = 0; + *lost = 0; + + rcu_read_lock(); + /* + * Iterate over every registered applications. Sum counters for + * all applications containing requested session and channel. + */ + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { + struct lttng_ht_iter uiter; + + ua_sess = lookup_session_by_app(usess, app); + if (ua_sess == NULL) { + continue; + } + + /* Get channel */ + lttng_ht_lookup(ua_sess->channels, (void *) uchan->name, &uiter); + ua_chan_node = lttng_ht_iter_get_node_str(&uiter); + /* If the session is found for the app, the channel must be there */ + assert(ua_chan_node); + + ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node); + + if (overwrite) { + uint64_t _lost; + + ret = consumer_get_lost_packets(usess->id, ua_chan->key, + consumer, &_lost); + if (ret < 0) { + break; + } + (*lost) += _lost; + } else { + uint64_t _discarded; + + ret = consumer_get_discarded_events(usess->id, + ua_chan->key, consumer, &_discarded); + if (ret < 0) { + break; + } + (*discarded) += _discarded; + } + } + + rcu_read_unlock(); + return ret; +} + +static +int ust_app_regenerate_statedump(struct ltt_ust_session *usess, + struct ust_app *app) +{ + int ret = 0; + struct ust_app_session *ua_sess; + + DBG("Regenerating the metadata for ust app pid %d", app->pid); + + rcu_read_lock(); + + ua_sess = lookup_session_by_app(usess, app); + if (ua_sess == NULL) { + /* The session is in teardown process. Ignore and continue. */ + goto end; + } + + pthread_mutex_lock(&ua_sess->lock); + + if (ua_sess->deleted) { + goto end_unlock; + } + + pthread_mutex_lock(&app->sock_lock); + ret = ustctl_regenerate_statedump(app->sock, ua_sess->handle); + pthread_mutex_unlock(&app->sock_lock); + +end_unlock: + pthread_mutex_unlock(&ua_sess->lock); + +end: + rcu_read_unlock(); + health_code_update(); + return ret; +} + +/* + * Regenerate the statedump for each app in the session. + */ +int ust_app_regenerate_statedump_all(struct ltt_ust_session *usess) +{ + int ret = 0; + struct lttng_ht_iter iter; + struct ust_app *app; + + DBG("Regenerating the metadata for all UST apps"); + + rcu_read_lock(); + + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { + if (!app->compatible) { + continue; + } + + ret = ust_app_regenerate_statedump(usess, app); + if (ret < 0) { + /* Continue to the next app even on error */ + continue; + } + } + + rcu_read_unlock(); + + 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; +}