/*
- * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
*
- * 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,
- * as published by the Free Software Foundation.
+ * SPDX-License-Identifier: GPL-2.0-only
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define _LGPL_SOURCE
-#include <errno.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <urcu/compiler.h>
-#include <lttng/ust-error.h>
#include <signal.h>
+#include <common/compat/errno.h>
#include <common/common.h>
+#include <common/hashtable/utils.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/tracepoint.h>
+#include <lttng/condition/condition.h>
+#include <lttng/condition/event-rule-internal.h>
+#include <lttng/condition/event-rule.h>
#include <common/sessiond-comm/sessiond-comm.h>
#include "buffer-registry.h"
#include "health-sessiond.h"
#include "ust-app.h"
#include "ust-consumer.h"
-#include "ust-ctl.h"
+#include "lttng-ust-ctl.h"
+#include "lttng-ust-error.h"
#include "utils.h"
#include "session.h"
#include "lttng-sessiond.h"
#include "notification-thread-commands.h"
#include "rotate.h"
+#include "event.h"
+
+struct lttng_ht *ust_app_ht;
+struct lttng_ht *ust_app_ht_by_sock;
+struct lttng_ht *ust_app_ht_by_notify_sock;
static
int ust_app_flush_app_session(struct ust_app *app, struct ust_app_session *ua_sess);
case LTTNG_BUFFER_PER_UID:
{
struct buffer_reg_uid *reg_uid = buffer_reg_uid_find(
- ua_sess->tracing_id, ua_sess->bits_per_long, ua_sess->uid);
+ ua_sess->tracing_id, ua_sess->bits_per_long,
+ lttng_credentials_get_uid(&ua_sess->real_credentials));
if (!reg_uid) {
goto error;
}
free(ua_event);
}
+/*
+ * Delayed reclaim of a ust_app_event_notifier_rule object. This MUST be called
+ * through a call_rcu().
+ */
+static
+void free_ust_app_event_notifier_rule_rcu(struct rcu_head *head)
+{
+ struct ust_app_event_notifier_rule *obj = caa_container_of(
+ head, struct ust_app_event_notifier_rule, rcu_head);
+
+ free(obj);
+}
+
+/*
+ * Delete ust app event notifier rule safely.
+ */
+static void delete_ust_app_event_notifier_rule(int sock,
+ struct ust_app_event_notifier_rule *ua_event_notifier_rule,
+ struct ust_app *app)
+{
+ int ret;
+
+ assert(ua_event_notifier_rule);
+
+ if (ua_event_notifier_rule->exclusion != NULL) {
+ free(ua_event_notifier_rule->exclusion);
+ }
+
+ if (ua_event_notifier_rule->obj != NULL) {
+ pthread_mutex_lock(&app->sock_lock);
+ ret = ustctl_release_object(sock, ua_event_notifier_rule->obj);
+ pthread_mutex_unlock(&app->sock_lock);
+ if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+ ERR("Failed to release event notifier object: app = '%s' (ppid %d), ret = %d",
+ app->name, (int) app->ppid, ret);
+ }
+
+ free(ua_event_notifier_rule->obj);
+ }
+
+ lttng_event_rule_put(ua_event_notifier_rule->event_rule);
+ call_rcu(&ua_event_notifier_rule->rcu_head,
+ free_ust_app_event_notifier_rule_rcu);
+}
+
/*
* Release ust data object of the given stream.
*
end:
rcu_read_unlock();
+ if (session) {
+ session_put(session);
+ }
}
/*
registry = get_session_registry(ua_chan->session);
if (registry) {
ust_registry_channel_del_free(registry, ua_chan->key,
- true);
+ sock >= 0);
+ }
+ /*
+ * A negative socket can be used by the caller when
+ * cleaning-up a ua_chan in an error path. Skip the
+ * accounting in this case.
+ */
+ if (sock >= 0) {
+ save_per_pid_lost_discarded_counters(ua_chan);
}
- save_per_pid_lost_discarded_counters(ua_chan);
}
if (ua_chan->obj != NULL) {
* nullified. The session lock MUST be held unless the application is
* in the destroy path.
*
+ * Do not hold the registry lock while communicating with the consumerd, because
+ * doing so causes inter-process deadlocks between consumerd and sessiond with
+ * the metadata request notification.
+ *
* Return 0 on success else a negative value.
*/
static int close_metadata(struct ust_registry_session *registry,
{
int ret;
struct consumer_socket *socket;
+ uint64_t metadata_key;
+ bool registry_was_already_closed;
assert(registry);
assert(consumer);
rcu_read_lock();
pthread_mutex_lock(®istry->lock);
+ metadata_key = registry->metadata_key;
+ registry_was_already_closed = registry->metadata_closed;
+ if (metadata_key != 0) {
+ /*
+ * Metadata closed. Even on error this means that the consumer
+ * is not responding or not found so either way a second close
+ * should NOT be emit for this registry.
+ */
+ registry->metadata_closed = 1;
+ }
+ pthread_mutex_unlock(®istry->lock);
- if (!registry->metadata_key || registry->metadata_closed) {
+ if (metadata_key == 0 || registry_was_already_closed) {
ret = 0;
goto end;
}
consumer);
if (!socket) {
ret = -1;
- goto error;
+ goto end;
}
- ret = consumer_close_metadata(socket, registry->metadata_key);
+ ret = consumer_close_metadata(socket, metadata_key);
if (ret < 0) {
- goto error;
+ goto end;
}
-error:
- /*
- * Metadata closed. Even on error this means that the consumer is not
- * responding or not found so either way a second close should NOT be emit
- * for this registry.
- */
- registry->metadata_closed = 1;
end:
- pthread_mutex_unlock(®istry->lock);
rcu_read_unlock();
return ret;
}
{
int ret, sock;
struct ust_app_session *ua_sess, *tmp_ua_sess;
+ struct lttng_ht_iter iter;
+ struct ust_app_event_notifier_rule *event_notifier_rule;
+ bool event_notifier_write_fd_is_open;
/*
* The session list lock must be held during this function to guarantee
rcu_read_unlock();
}
+ /* Remove the event notifier rules associated with this app. */
+ rcu_read_lock();
+ cds_lfht_for_each_entry (app->token_to_event_notifier_rule_ht->ht,
+ &iter.iter, event_notifier_rule, node.node) {
+ ret = lttng_ht_del(app->token_to_event_notifier_rule_ht, &iter);
+ assert(!ret);
+
+ delete_ust_app_event_notifier_rule(
+ app->sock, event_notifier_rule, app);
+ }
+
+ rcu_read_unlock();
+
ht_cleanup_push(app->sessions);
ht_cleanup_push(app->ust_sessions_objd);
ht_cleanup_push(app->ust_objd);
+ ht_cleanup_push(app->token_to_event_notifier_rule_ht);
+
+ /*
+ * This could be NULL if the event notifier setup failed (e.g the app
+ * was killed or the tracer does not support this feature).
+ */
+ if (app->event_notifier_group.object) {
+ enum lttng_error_code ret_code;
+ const int event_notifier_read_fd = lttng_pipe_get_readfd(
+ app->event_notifier_group.event_pipe);
+
+ ret_code = notification_thread_command_remove_tracer_event_source(
+ notification_thread_handle,
+ event_notifier_read_fd);
+ if (ret_code != LTTNG_OK) {
+ ERR("Failed to remove application tracer event source from notification thread");
+ }
+
+ ustctl_release_object(sock, app->event_notifier_group.object);
+ free(app->event_notifier_group.object);
+ }
+
+ event_notifier_write_fd_is_open = lttng_pipe_is_write_open(
+ app->event_notifier_group.event_pipe);
+ lttng_pipe_destroy(app->event_notifier_group.event_pipe);
+ /*
+ * Release the file descriptors reserved for the event notifier pipe.
+ * The app could be destroyed before the write end of the pipe could be
+ * passed to the application (and closed). In that case, both file
+ * descriptors must be released.
+ */
+ lttng_fd_put(LTTNG_FD_APPS, event_notifier_write_fd_is_open ? 2 : 1);
/*
* Wait until we have deleted the application from the sock hash table
* Alloc new UST app channel.
*/
static
-struct ust_app_channel *alloc_ust_app_channel(char *name,
+struct ust_app_channel *alloc_ust_app_channel(const char *name,
struct ust_app_session *ua_sess,
struct lttng_ust_channel_attr *attr)
{
/* Init most of the default value by allocating and zeroing */
ua_event = zmalloc(sizeof(struct ust_app_event));
if (ua_event == NULL) {
- PERROR("malloc");
+ PERROR("Failed to allocate ust_app_event structure");
goto error;
}
return NULL;
}
+/*
+ * Allocate a new UST app event notifier rule.
+ */
+static struct ust_app_event_notifier_rule *alloc_ust_app_event_notifier_rule(
+ struct lttng_event_rule *event_rule, uint64_t token)
+{
+ enum lttng_event_rule_generate_exclusions_status
+ generate_exclusion_status;
+ struct ust_app_event_notifier_rule *ua_event_notifier_rule;
+
+ ua_event_notifier_rule = zmalloc(sizeof(struct ust_app_event_notifier_rule));
+ if (ua_event_notifier_rule == NULL) {
+ PERROR("Failed to allocate ust_app_event_notifier_rule structure");
+ goto error;
+ }
+
+ ua_event_notifier_rule->enabled = 1;
+ ua_event_notifier_rule->token = token;
+ lttng_ht_node_init_u64(&ua_event_notifier_rule->node, token);
+
+ /* Get reference of the event rule. */
+ if (!lttng_event_rule_get(event_rule)) {
+ abort();
+ }
+
+ ua_event_notifier_rule->event_rule = event_rule;
+ ua_event_notifier_rule->filter = lttng_event_rule_get_filter_bytecode(event_rule);
+ generate_exclusion_status = lttng_event_rule_generate_exclusions(
+ event_rule, &ua_event_notifier_rule->exclusion);
+ switch (generate_exclusion_status) {
+ case LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OK:
+ case LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE:
+ break;
+ default:
+ /* Error occured. */
+ ERR("Failed to generate exclusions from event rule while allocating an event notifier rule");
+ goto error_put_event_rule;
+ }
+
+ DBG3("UST app event notifier rule allocated: token = %" PRIu64,
+ ua_event_notifier_rule->token);
+
+ return ua_event_notifier_rule;
+
+error_put_event_rule:
+ lttng_event_rule_put(event_rule);
+error:
+ free(ua_event_notifier_rule);
+ return NULL;
+}
+
/*
* Alloc new UST app context.
*/
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;
+ 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);
return NULL;
}
-/*
- * Allocate a filter and copy the given original filter.
- *
- * Return allocated filter or NULL on error.
- */
-static struct lttng_filter_bytecode *copy_filter_bytecode(
- struct lttng_filter_bytecode *orig_f)
-{
- struct lttng_filter_bytecode *filter = NULL;
-
- /* Copy filter bytecode */
- filter = zmalloc(sizeof(*filter) + orig_f->len);
- if (!filter) {
- PERROR("zmalloc alloc filter bytecode");
- goto error;
- }
-
- memcpy(filter, orig_f, sizeof(*filter) + orig_f->len);
-
-error:
- return filter;
-}
-
/*
* Create a liblttng-ust filter bytecode from given bytecode.
*
* Return allocated filter or NULL on error.
*/
static struct lttng_ust_filter_bytecode *create_ust_bytecode_from_bytecode(
- struct lttng_filter_bytecode *orig_f)
+ const struct lttng_filter_bytecode *orig_f)
{
struct lttng_ust_filter_bytecode *filter = NULL;
* Return an ust_app_event object or NULL on error.
*/
static struct ust_app_event *find_ust_app_event(struct lttng_ht *ht,
- char *name, struct lttng_filter_bytecode *filter,
+ const char *name, const struct lttng_filter_bytecode *filter,
int loglevel_value,
const struct lttng_event_exclusion *exclusion)
{
return event;
}
+/*
+ * Look-up an event notifier rule based on its token id.
+ *
+ * Must be called with the RCU read lock held.
+ * Return an ust_app_event_notifier_rule object or NULL on error.
+ */
+static struct ust_app_event_notifier_rule *find_ust_app_event_notifier_rule(
+ struct lttng_ht *ht, uint64_t token)
+{
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_u64 *node;
+ struct ust_app_event_notifier_rule *event_notifier_rule = NULL;
+
+ assert(ht);
+
+ lttng_ht_lookup(ht, &token, &iter);
+ node = lttng_ht_iter_get_node_u64(&iter);
+ if (node == NULL) {
+ DBG2("UST app event notifier rule token not found: token = %" PRIu64,
+ token);
+ goto end;
+ }
+
+ event_notifier_rule = caa_container_of(
+ node, struct ust_app_event_notifier_rule, node);
+end:
+ return event_notifier_rule;
+}
+
/*
* Create the channel context on the tracer.
*
* continue normally.
*/
ret = 0;
- DBG3("UST app disable event failed. Application is dead.");
+ DBG3("UST app add context failed. Application is dead.");
}
goto error;
}
/*
* Set the filter on the tracer.
*/
-static
-int set_ust_event_filter(struct ust_app_event *ua_event,
- struct ust_app *app)
+static int set_ust_object_filter(struct ust_app *app,
+ const struct lttng_filter_bytecode *bytecode,
+ struct lttng_ust_object_data *ust_object)
{
int ret;
struct lttng_ust_filter_bytecode *ust_bytecode = NULL;
health_code_update();
- if (!ua_event->filter) {
- ret = 0;
- goto error;
- }
-
- ust_bytecode = create_ust_bytecode_from_bytecode(ua_event->filter);
+ ust_bytecode = create_ust_bytecode_from_bytecode(bytecode);
if (!ust_bytecode) {
ret = -LTTNG_ERR_NOMEM;
goto error;
}
pthread_mutex_lock(&app->sock_lock);
ret = ustctl_set_filter(app->sock, ust_bytecode,
- ua_event->obj);
+ ust_object);
pthread_mutex_unlock(&app->sock_lock);
if (ret < 0) {
if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
- ERR("UST app event %s filter failed for app (pid: %d) "
- "with ret %d", ua_event->attr.name, app->pid, ret);
+ ERR("UST app set object filter failed for object %p of app (pid: %d) "
+ "with ret %d", ust_object, app->pid, ret);
} else {
/*
* This is normal behavior, an application can die during the
* continue normally.
*/
ret = 0;
- DBG3("UST app filter event failed. Application is dead.");
+ DBG3("Failed to set UST app object filter. Application is dead.");
}
goto error;
}
- DBG2("UST filter set successfully for event %s", ua_event->name);
+ DBG2("UST filter successfully set for object %p", ust_object);
error:
health_code_update();
static
struct lttng_ust_event_exclusion *create_ust_exclusion_from_exclusion(
- struct lttng_event_exclusion *exclusion)
+ const struct lttng_event_exclusion *exclusion)
{
struct lttng_ust_event_exclusion *ust_exclusion = NULL;
size_t exclusion_alloc_size = sizeof(struct lttng_ust_event_exclusion) +
/*
* Set event exclusions on the tracer.
*/
-static
-int set_ust_event_exclusion(struct ust_app_event *ua_event,
- struct ust_app *app)
+static int set_ust_object_exclusions(struct ust_app *app,
+ const struct lttng_event_exclusion *exclusions,
+ struct lttng_ust_object_data *ust_object)
{
int ret;
- struct lttng_ust_event_exclusion *ust_exclusion = NULL;
+ struct lttng_ust_event_exclusion *ust_exclusions = NULL;
- health_code_update();
+ assert(exclusions && exclusions->count > 0);
- if (!ua_event->exclusion || !ua_event->exclusion->count) {
- ret = 0;
- goto error;
- }
+ health_code_update();
- ust_exclusion = create_ust_exclusion_from_exclusion(
- ua_event->exclusion);
- if (!ust_exclusion) {
+ ust_exclusions = create_ust_exclusion_from_exclusion(
+ exclusions);
+ if (!ust_exclusions) {
ret = -LTTNG_ERR_NOMEM;
goto error;
}
pthread_mutex_lock(&app->sock_lock);
- ret = ustctl_set_exclusion(app->sock, ust_exclusion, ua_event->obj);
+ ret = ustctl_set_exclusion(app->sock, ust_exclusions, ust_object);
pthread_mutex_unlock(&app->sock_lock);
if (ret < 0) {
if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
- ERR("UST app event %s exclusions failed for app (pid: %d) "
- "with ret %d", ua_event->attr.name, app->pid, ret);
+ ERR("Failed to set UST app exclusions for object %p of app (pid: %d) "
+ "with ret %d", ust_object, app->pid, ret);
} else {
/*
* This is normal behavior, an application can die during the
* continue normally.
*/
ret = 0;
- DBG3("UST app event exclusion failed. Application is dead.");
+ DBG3("Failed to set UST app object exclusions. Application is dead.");
}
goto error;
}
- DBG2("UST exclusion set successfully for event %s", ua_event->name);
+ DBG2("UST exclusions set successfully for object %p", ust_object);
error:
health_code_update();
- free(ust_exclusion);
+ free(ust_exclusions);
return ret;
}
/*
* Disable the specified event on to UST tracer for the UST session.
*/
-static int disable_ust_event(struct ust_app *app,
- struct ust_app_session *ua_sess, struct ust_app_event *ua_event)
+static int disable_ust_object(struct ust_app *app,
+ struct lttng_ust_object_data *object)
{
int ret;
health_code_update();
pthread_mutex_lock(&app->sock_lock);
- ret = ustctl_disable(app->sock, ua_event->obj);
+ ret = ustctl_disable(app->sock, object);
pthread_mutex_unlock(&app->sock_lock);
if (ret < 0) {
if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
- ERR("UST app event %s disable failed for app (pid: %d) "
- "and session handle %d with ret %d",
- ua_event->attr.name, app->pid, ua_sess->handle, ret);
+ ERR("Failed to disable UST app object %p app (pid: %d) with ret %d",
+ object, app->pid, ret);
} else {
/*
* This is normal behavior, an application can die during the
* continue normally.
*/
ret = 0;
- DBG3("UST app disable event failed. Application is dead.");
+ DBG3("Failed to disable UST app object. Application is dead.");
}
goto error;
}
- DBG2("UST app event %s disabled successfully for app (pid: %d)",
- ua_event->attr.name, app->pid);
+ DBG2("UST app object %p disabled successfully for app (pid: %d)",
+ object, app->pid);
error:
health_code_update();
/*
* Enable the specified event on to UST tracer for the UST session.
*/
-static int enable_ust_event(struct ust_app *app,
- struct ust_app_session *ua_sess, struct ust_app_event *ua_event)
+static int enable_ust_object(
+ struct ust_app *app, struct lttng_ust_object_data *ust_object)
{
int ret;
health_code_update();
pthread_mutex_lock(&app->sock_lock);
- ret = ustctl_enable(app->sock, ua_event->obj);
+ ret = ustctl_enable(app->sock, ust_object);
pthread_mutex_unlock(&app->sock_lock);
if (ret < 0) {
if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
- ERR("UST app event %s enable failed for app (pid: %d) "
- "and session handle %d with ret %d",
- ua_event->attr.name, app->pid, ua_sess->handle, ret);
+ ERR("UST app enable failed for object %p app (pid: %d) with ret %d",
+ ust_object, app->pid, ret);
} else {
/*
* This is normal behavior, an application can die during the
* continue normally.
*/
ret = 0;
- DBG3("UST app enable event failed. Application is dead.");
+ DBG3("Failed to enable UST app object. Application is dead.");
}
goto error;
}
- DBG2("UST app event %s enabled successfully for app (pid: %d)",
- ua_event->attr.name, app->pid);
+ DBG2("UST app object %p enabled successfully for app (pid: %d)",
+ ust_object, app->pid);
error:
health_code_update();
pthread_mutex_unlock(&app->sock_lock);
if (ret < 0) {
if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+ abort();
ERR("Error ustctl create event %s for app pid: %d with ret %d",
ua_event->attr.name, app->pid, ret);
} else {
ua_event->handle = ua_event->obj->handle;
- DBG2("UST app event %s created successfully for pid:%d",
- ua_event->attr.name, app->pid);
+ DBG2("UST app event %s created successfully for pid:%d object: %p",
+ ua_event->attr.name, app->pid, ua_event->obj);
health_code_update();
/* Set filter if one is present. */
if (ua_event->filter) {
- ret = set_ust_event_filter(ua_event, app);
+ ret = set_ust_object_filter(app, ua_event->filter, ua_event->obj);
if (ret < 0) {
goto error;
}
/* Set exclusions for the event */
if (ua_event->exclusion) {
- ret = set_ust_event_exclusion(ua_event, app);
+ ret = set_ust_object_exclusions(app, ua_event->exclusion, ua_event->obj);
if (ret < 0) {
goto error;
}
* We now need to explicitly enable the event, since it
* is now disabled at creation.
*/
- ret = enable_ust_event(app, ua_sess, ua_event);
+ ret = enable_ust_object(app, ua_event->obj);
if (ret < 0) {
/*
* If we hit an EPERM, something is wrong with our enable call. If
return ret;
}
+static int init_ust_event_notifier_from_event_rule(
+ const struct lttng_event_rule *rule,
+ struct lttng_ust_event_notifier *event_notifier)
+{
+ enum lttng_event_rule_status status;
+ enum lttng_loglevel_type loglevel_type;
+ enum lttng_ust_loglevel_type ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
+ int loglevel = -1, ret = 0;
+ const char *pattern;
+
+ /* For now only LTTNG_EVENT_RULE_TYPE_TRACEPOINT are supported. */
+ assert(lttng_event_rule_get_type(rule) ==
+ LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
+
+ memset(event_notifier, 0, sizeof(*event_notifier));
+
+ if (lttng_event_rule_targets_agent_domain(rule)) {
+ /*
+ * Special event for agents
+ * The actual meat of the event is in the filter that will be
+ * attached later on.
+ * Set the default values for the agent event.
+ */
+ pattern = event_get_default_agent_ust_name(
+ lttng_event_rule_get_domain_type(rule));
+ loglevel = 0;
+ ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
+ } else {
+ status = lttng_event_rule_tracepoint_get_pattern(
+ rule, &pattern);
+ if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+ /* At this point, this is a fatal error. */
+ abort();
+ }
+
+ status = lttng_event_rule_tracepoint_get_log_level_type(
+ rule, &loglevel_type);
+ if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+ /* At this point, this is a fatal error. */
+ abort();
+ }
+
+ switch (loglevel_type) {
+ case LTTNG_EVENT_LOGLEVEL_ALL:
+ ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
+ break;
+ case LTTNG_EVENT_LOGLEVEL_RANGE:
+ ust_loglevel_type = LTTNG_UST_LOGLEVEL_RANGE;
+ break;
+ case LTTNG_EVENT_LOGLEVEL_SINGLE:
+ ust_loglevel_type = LTTNG_UST_LOGLEVEL_SINGLE;
+ break;
+ default:
+ /* Unknown log level specification type. */
+ abort();
+ }
+
+ if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
+ status = lttng_event_rule_tracepoint_get_log_level(
+ rule, &loglevel);
+ assert(status == LTTNG_EVENT_RULE_STATUS_OK);
+ }
+ }
+
+ event_notifier->event.instrumentation = LTTNG_UST_TRACEPOINT;
+ ret = lttng_strncpy(event_notifier->event.name, pattern,
+ LTTNG_UST_SYM_NAME_LEN - 1);
+ if (ret) {
+ ERR("Failed to copy event rule pattern to notifier: pattern = '%s' ",
+ pattern);
+ goto end;
+ }
+
+ event_notifier->event.loglevel_type = ust_loglevel_type;
+ event_notifier->event.loglevel = loglevel;
+end:
+ return ret;
+}
+
+/*
+ * Create the specified event notifier against the user space tracer of a
+ * given application.
+ */
+static int create_ust_event_notifier(struct ust_app *app,
+ struct ust_app_event_notifier_rule *ua_event_notifier_rule)
+{
+ int ret = 0;
+ struct lttng_ust_event_notifier event_notifier;
+
+ health_code_update();
+ assert(app->event_notifier_group.object);
+
+ ret = init_ust_event_notifier_from_event_rule(
+ ua_event_notifier_rule->event_rule, &event_notifier);
+ if (ret) {
+ ERR("Failed to initialize UST event notifier from event rule: app = '%s' (ppid: %d)",
+ app->name, app->ppid);
+ goto error;
+ }
+
+ event_notifier.event.token = ua_event_notifier_rule->token;
+
+ /* Create UST event notifier against the tracer. */
+ pthread_mutex_lock(&app->sock_lock);
+ ret = ustctl_create_event_notifier(app->sock, &event_notifier,
+ app->event_notifier_group.object,
+ &ua_event_notifier_rule->obj);
+ pthread_mutex_unlock(&app->sock_lock);
+ if (ret < 0) {
+ if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+ ERR("Error ustctl create event notifier: name = '%s', app = '%s' (ppid: %d), ret = %d",
+ event_notifier.event.name, app->name,
+ app->ppid, ret);
+ } else {
+ /*
+ * This is normal behavior, an application can die
+ * during the creation process. Don't report an error so
+ * the execution can continue normally.
+ */
+ ret = 0;
+ DBG3("UST app create event notifier failed (application is dead): app = '%s' (ppid = %d)",
+ app->name, app->ppid);
+ }
+
+ goto error;
+ }
+
+ ua_event_notifier_rule->handle = ua_event_notifier_rule->obj->handle;
+
+ DBG2("UST app event notifier %s created successfully: app = '%s' (ppid: %d), object: %p",
+ event_notifier.event.name, app->name, app->ppid,
+ ua_event_notifier_rule->obj);
+
+ health_code_update();
+
+ /* Set filter if one is present. */
+ if (ua_event_notifier_rule->filter) {
+ ret = set_ust_object_filter(app, ua_event_notifier_rule->filter,
+ ua_event_notifier_rule->obj);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ /* Set exclusions for the event. */
+ if (ua_event_notifier_rule->exclusion) {
+ ret = set_ust_object_exclusions(app,
+ ua_event_notifier_rule->exclusion,
+ ua_event_notifier_rule->obj);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ /*
+ * We now need to explicitly enable the event, since it
+ * is disabled at creation.
+ */
+ ret = enable_ust_object(app, ua_event_notifier_rule->obj);
+ if (ret < 0) {
+ /*
+ * If we hit an EPERM, something is wrong with our enable call.
+ * If we get an EEXIST, there is a problem on the tracer side
+ * since we just created it.
+ */
+ switch (ret) {
+ case -LTTNG_UST_ERR_PERM:
+ /* Code flow problem. */
+ abort();
+ case -LTTNG_UST_ERR_EXIST:
+ /* It's OK for our use case. */
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ goto error;
+ }
+
+ ua_event_notifier_rule->enabled = true;
+
+error:
+ health_code_update();
+ return ret;
+}
+
/*
* Copy data between an UST app event and a LTT event.
*/
/* Copy filter bytecode */
if (uevent->filter) {
- ua_event->filter = copy_filter_bytecode(uevent->filter);
+ ua_event->filter = lttng_filter_bytecode_copy(uevent->filter);
/* Filter might be NULL here in case of ENONEM. */
}
static void shadow_copy_channel(struct ust_app_channel *ua_chan,
struct ltt_ust_channel *uchan)
{
- struct lttng_ht_iter iter;
- struct ltt_ust_event *uevent;
- struct ltt_ust_context *uctx;
- struct ust_app_event *ua_event;
-
DBG2("UST app shadow copy of channel %s started", ua_chan->name);
strncpy(ua_chan->name, uchan->name, sizeof(ua_chan->name));
ua_chan->enabled = uchan->enabled;
ua_chan->tracing_channel_id = uchan->id;
- cds_list_for_each_entry(uctx, &uchan->ctx_list, list) {
- struct ust_app_ctx *ua_ctx = alloc_ust_app_ctx(&uctx->ctx);
-
- if (ua_ctx == NULL) {
- continue;
- }
- lttng_ht_node_init_ulong(&ua_ctx->node,
- (unsigned long) ua_ctx->ctx.ctx);
- lttng_ht_add_ulong(ua_chan->ctx, &ua_ctx->node);
- cds_list_add_tail(&ua_ctx->list, &ua_chan->ctx_list);
- }
-
- /* Copy all events from ltt ust channel to ust app channel */
- cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent, node.node) {
- ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
- uevent->filter, uevent->attr.loglevel, uevent->exclusion);
- if (ua_event == NULL) {
- DBG2("UST event %s not found on shadow copy channel",
- uevent->attr.name);
- ua_event = alloc_ust_app_event(uevent->attr.name, &uevent->attr);
- if (ua_event == NULL) {
- continue;
- }
- shadow_copy_event(ua_event, uevent);
- add_unique_ust_app_event(ua_chan, ua_event);
- }
- }
-
DBG3("UST app shadow copy of channel %s done", ua_chan->name);
}
static void shadow_copy_session(struct ust_app_session *ua_sess,
struct ltt_ust_session *usess, struct ust_app *app)
{
- struct lttng_ht_node_str *ua_chan_node;
- struct lttng_ht_iter iter;
- struct ltt_ust_channel *uchan;
- struct ust_app_channel *ua_chan;
- time_t rawtime;
struct tm *timeinfo;
char datetime[16];
int ret;
char tmp_shm_path[PATH_MAX];
- /* Get date and time for unique app path */
- time(&rawtime);
- timeinfo = localtime(&rawtime);
+ timeinfo = localtime(&app->registration_time);
strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
DBG2("Shadow copy of session handle %d", ua_sess->handle);
ua_sess->tracing_id = usess->id;
ua_sess->id = get_next_session_id();
- ua_sess->uid = app->uid;
- ua_sess->gid = app->gid;
- ua_sess->euid = usess->uid;
- ua_sess->egid = usess->gid;
+ LTTNG_OPTIONAL_SET(&ua_sess->real_credentials.uid, app->uid);
+ LTTNG_OPTIONAL_SET(&ua_sess->real_credentials.gid, app->gid);
+ LTTNG_OPTIONAL_SET(&ua_sess->effective_credentials.uid, usess->uid);
+ LTTNG_OPTIONAL_SET(&ua_sess->effective_credentials.gid, usess->gid);
ua_sess->buffer_type = usess->buffer_type;
ua_sess->bits_per_long = app->bits_per_long;
break;
case LTTNG_BUFFER_PER_UID:
ret = snprintf(ua_sess->path, sizeof(ua_sess->path),
- DEFAULT_UST_TRACE_UID_PATH, ua_sess->uid, app->bits_per_long);
+ DEFAULT_UST_TRACE_UID_PATH,
+ lttng_credentials_get_uid(&ua_sess->real_credentials),
+ app->bits_per_long);
break;
default:
assert(0);
switch (ua_sess->buffer_type) {
case LTTNG_BUFFER_PER_PID:
ret = snprintf(tmp_shm_path, sizeof(tmp_shm_path),
- DEFAULT_UST_TRACE_PID_PATH "/%s-%d-%s",
+ "/" DEFAULT_UST_TRACE_PID_PATH "/%s-%d-%s",
app->name, app->pid, datetime);
break;
case LTTNG_BUFFER_PER_UID:
ret = snprintf(tmp_shm_path, sizeof(tmp_shm_path),
- DEFAULT_UST_TRACE_UID_PATH,
+ "/" DEFAULT_UST_TRACE_UID_PATH,
app->uid, app->bits_per_long);
break;
default:
sizeof(ua_sess->shm_path) - strlen(ua_sess->shm_path) - 1);
ua_sess->shm_path[sizeof(ua_sess->shm_path) - 1] = '\0';
}
+ return;
- /* Iterate over all channels in global domain. */
- cds_lfht_for_each_entry(usess->domain_global.channels->ht, &iter.iter,
- uchan, node.node) {
- struct lttng_ht_iter uiter;
-
- lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &uiter);
- ua_chan_node = lttng_ht_iter_get_node_str(&uiter);
- if (ua_chan_node != NULL) {
- /* Session exist. Contiuing. */
- continue;
- }
-
- 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);
- if (ua_chan == NULL) {
- /* malloc failed FIXME: Might want to do handle ENOMEM .. */
- continue;
- }
- shadow_copy_channel(ua_chan, uchan);
- /*
- * The concept of metadata channel does not exist on the tracing
- * registry side of the session daemon so this can only be a per CPU
- * channel and not metadata.
- */
- ua_chan->attr.type = LTTNG_UST_CHAN_PER_CPU;
-
- lttng_ht_add_unique_str(ua_sess->channels, &ua_chan->node);
- }
- return;
-
-error:
- consumer_output_put(ua_sess->consumer);
-}
+error:
+ consumer_output_put(ua_sess->consumer);
+}
/*
* Lookup sesison wrapper.
*/
static
-void __lookup_session_by_app(struct ltt_ust_session *usess,
+void __lookup_session_by_app(const struct ltt_ust_session *usess,
struct ust_app *app, struct lttng_ht_iter *iter)
{
/* Get right UST app session from app */
* id.
*/
static struct ust_app_session *lookup_session_by_app(
- struct ltt_ust_session *usess, struct ust_app *app)
+ const struct ltt_ust_session *usess, struct ust_app *app)
{
struct lttng_ht_iter iter;
struct lttng_ht_node_u64 *node;
app->bits_per_long, app->uint8_t_alignment,
app->uint16_t_alignment, app->uint32_t_alignment,
app->uint64_t_alignment, app->long_alignment,
- app->byte_order, app->version.major,
- app->version.minor, reg_pid->root_shm_path,
- reg_pid->shm_path,
- ua_sess->euid, ua_sess->egid);
+ app->byte_order, app->version.major, app->version.minor,
+ reg_pid->root_shm_path, reg_pid->shm_path,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ ua_sess->tracing_id,
+ app->uid);
if (ret < 0) {
/*
* reg_pid->registry->reg.ust is NULL upon error, so we need to
app->uint64_t_alignment, app->long_alignment,
app->byte_order, app->version.major,
app->version.minor, reg_uid->root_shm_path,
- reg_uid->shm_path, usess->uid, usess->gid);
+ reg_uid->shm_path, usess->uid, usess->gid,
+ ua_sess->tracing_id, app->uid);
if (ret < 0) {
/*
* reg_uid->registry->reg.ust is NULL upon error, so we need to
* 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_attr *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;
{
int ret;
- ret = enable_ust_event(app, ua_sess, ua_event);
+ ret = enable_ust_object(app, ua_event->obj);
if (ret < 0) {
goto error;
}
{
int ret;
- ret = disable_ust_event(app, ua_sess, ua_event);
+ ret = disable_ust_object(app, ua_event->obj);
if (ret < 0) {
goto error;
}
*/
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;
* stream we have to expect.
*/
ret = ust_consumer_ask_channel(ua_sess, ua_chan, usess->consumer, socket,
- registry);
+ registry, usess->current_trace_chunk);
if (ret < 0) {
goto error_ask;
}
int ret;
struct buffer_reg_uid *reg_uid;
struct buffer_reg_channel *reg_chan;
+ struct ltt_session *session = NULL;
+ enum lttng_error_code notification_ret;
+ struct ust_registry_channel *chan_reg;
assert(app);
assert(usess);
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);
+ app->bits_per_long, reg_uid->registry->reg.ust,
+ session->most_recent_chunk_id.value);
if (ret < 0) {
ERR("Error creating UST channel \"%s\" on the consumer daemon",
ua_chan->name);
goto error;
}
- {
- enum lttng_error_code cmd_ret;
- struct ltt_session *session;
- uint64_t chan_reg_key;
- struct ust_registry_channel *chan_reg;
-
- chan_reg_key = ua_chan->tracing_channel_id;
+ /* 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);
- pthread_mutex_lock(®_uid->registry->reg.ust->lock);
- chan_reg = ust_registry_channel_find(reg_uid->registry->reg.ust,
- chan_reg_key);
- assert(chan_reg);
- chan_reg->consumer_key = ua_chan->key;
- chan_reg = NULL;
- pthread_mutex_unlock(®_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->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;
- }
+ notification_ret = notification_thread_command_add_channel(
+ notification_thread_handle, session->name,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ 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:
}
error:
+ if (session) {
+ session_put(session);
+ }
return ret;
}
int ret;
struct ust_registry_session *registry;
enum lttng_error_code cmd_ret;
- struct ltt_session *session;
+ struct ltt_session *session = NULL;
uint64_t chan_reg_key;
struct ust_registry_channel *chan_reg;
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->most_recent_chunk_id.value);
if (ret < 0) {
ERR("Error creating UST channel \"%s\" on the consumer daemon",
ua_chan->name);
- goto error;
+ goto error_remove_from_registry;
}
ret = send_channel_pid_to_ust(app, ua_sess, ua_chan);
if (ret != -ENOTCONN) {
ERR("Error sending channel to application");
}
- goto error;
+ goto error_remove_from_registry;
}
- session = session_find_by_id(ua_sess->tracing_id);
- assert(session);
-
chan_reg_key = ua_chan->key;
pthread_mutex_lock(®istry->lock);
chan_reg = ust_registry_channel_find(registry, chan_reg_key);
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,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
ua_chan->name,
- ua_chan->key,
- LTTNG_DOMAIN_UST,
+ 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;
+ goto error_remove_from_registry;
}
+error_remove_from_registry:
+ if (ret) {
+ ust_registry_channel_del_free(registry, ua_chan->key, false);
+ }
error:
rcu_read_unlock();
+ if (session) {
+ session_put(session);
+ }
return ret;
}
/*
* From an already allocated ust app channel, create the channel buffers if
- * need and send it to the application. This MUST be called with a RCU read
+ * needed and send them 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.
*/
-static int do_create_channel(struct ust_app *app,
+static int ust_app_channel_send(struct ust_app *app,
struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
struct ust_app_channel *ua_chan)
{
assert(app);
assert(usess);
+ assert(usess->active);
assert(ua_sess);
assert(ua_chan);
}
/*
- * Create UST app channel and create it on the tracer. Set ua_chanp of the
- * newly created channel if not NULL.
+ * Create UST app channel and return it through ua_chanp if not NULL.
*
* Called with UST app session lock and RCU read-side lock held.
*
- * Return 0 on success or else a negative value. Returns -ENOTCONN if
- * the application exited concurrently.
+ * Return 0 on success or else a negative value.
*/
-static int create_ust_app_channel(struct ust_app_session *ua_sess,
- struct ltt_ust_channel *uchan, struct ust_app *app,
+static int ust_app_channel_allocate(struct ust_app_session *ua_sess,
+ struct ltt_ust_channel *uchan,
enum lttng_ust_chan_type type, struct ltt_ust_session *usess,
struct ust_app_channel **ua_chanp)
{
if (ua_chan == NULL) {
/* Only malloc can fail here */
ret = -ENOMEM;
- goto error_alloc;
+ goto error;
}
shadow_copy_channel(ua_chan, uchan);
/* Set channel type. */
ua_chan->attr.type = type;
- ret = do_create_channel(app, usess, ua_sess, ua_chan);
- if (ret < 0) {
- goto error;
- }
-
- DBG2("UST app create channel %s for PID %d completed", ua_chan->name,
- app->pid);
-
/* Only add the channel if successful on the tracer side. */
lttng_ht_add_unique_str(ua_sess->channels, &ua_chan->node);
end:
return 0;
error:
- delete_ust_app_channel(ua_chan->is_sent ? app->sock : -1, ua_chan, app);
-error_alloc:
return ret;
}
/*
* Create UST app event and create it on the tracer side.
*
+ * Must be called with the RCU read side lock held.
* Called with ust app session mutex held.
*/
static
int ret = 0;
struct ust_app_event *ua_event;
- /* Get event node */
- ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
- uevent->filter, uevent->attr.loglevel, uevent->exclusion);
- if (ua_event != NULL) {
- ret = -EEXIST;
- goto end;
- }
-
- /* Does not exist so create one */
ua_event = alloc_ust_app_event(uevent->attr.name, &uevent->attr);
if (ua_event == NULL) {
- /* Only malloc can failed so something is really wrong */
+ /* Only failure mode of alloc_ust_app_event(). */
ret = -ENOMEM;
goto end;
}
/* Create it on the tracer side */
ret = create_ust_event(app, ua_sess, ua_chan, ua_event);
if (ret < 0) {
- /* Not found previously means that it does not exist on the tracer */
- assert(ret != -LTTNG_UST_ERR_EXIST);
+ /*
+ * Not found previously means that it does not exist on the
+ * tracer. If the application reports that the event existed,
+ * it means there is a bug in the sessiond or lttng-ust
+ * (or corruption, etc.)
+ */
+ if (ret == -LTTNG_UST_ERR_EXIST) {
+ ERR("Tracer for application reported that an event being created already existed: "
+ "event_name = \"%s\", pid = %d, ppid = %d, uid = %d, gid = %d",
+ uevent->attr.name,
+ app->pid, app->ppid, app->uid,
+ app->gid);
+ }
goto error;
}
add_unique_ust_app_event(ua_chan, ua_event);
- DBG2("UST app create event %s for PID %d completed", ua_event->name,
- app->pid);
+ DBG2("UST app create event completed: app = '%s' (ppid: %d)",
+ app->name, app->ppid);
end:
return ret;
return ret;
}
+/*
+ * Create UST app event notifier rule and create it on the tracer side.
+ *
+ * Must be called with the RCU read side lock held.
+ * Called with ust app session mutex held.
+ */
+static
+int create_ust_app_event_notifier_rule(struct lttng_event_rule *rule,
+ struct ust_app *app, uint64_t token)
+{
+ int ret = 0;
+ struct ust_app_event_notifier_rule *ua_event_notifier_rule;
+
+ ua_event_notifier_rule = alloc_ust_app_event_notifier_rule(rule, token);
+ if (ua_event_notifier_rule == NULL) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ /* Create it on the tracer side. */
+ ret = create_ust_event_notifier(app, ua_event_notifier_rule);
+ if (ret < 0) {
+ /*
+ * Not found previously means that it does not exist on the
+ * tracer. If the application reports that the event existed,
+ * it means there is a bug in the sessiond or lttng-ust
+ * (or corruption, etc.)
+ */
+ if (ret == -LTTNG_UST_ERR_EXIST) {
+ ERR("Tracer for application reported that an event notifier being created already exists: "
+ "token = \"%" PRIu64 "\", pid = %d, ppid = %d, uid = %d, gid = %d",
+ token,
+ app->pid, app->ppid, app->uid,
+ app->gid);
+ }
+ goto error;
+ }
+
+ lttng_ht_add_unique_u64(app->token_to_event_notifier_rule_ht,
+ &ua_event_notifier_rule->node);
+
+ DBG2("UST app create token event rule completed: app = '%s' (ppid: %d), token = %" PRIu64,
+ app->name, app->ppid, token);
+
+end:
+ return ret;
+
+error:
+ /* The RCU read side lock is already being held by the caller. */
+ delete_ust_app_event_notifier_rule(-1, ua_event_notifier_rule, app);
+ return ret;
+}
+
/*
* Create UST metadata and open it on the tracer side.
*
struct ust_app_channel *metadata;
struct consumer_socket *socket;
struct ust_registry_session *registry;
+ struct ltt_session *session = NULL;
assert(ua_sess);
assert(app);
*/
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
* consumer.
*/
ret = ust_consumer_ask_channel(ua_sess, metadata, consumer, socket,
- registry);
+ registry, session->current_trace_chunk);
if (ret < 0) {
/* Nullify the metadata key so we don't try to close it later on. */
registry->metadata_key = 0;
delete_ust_app_channel(-1, metadata, app);
error:
pthread_mutex_unlock(®istry->lock);
+ if (session) {
+ session_put(session);
+ }
return ret;
}
*/
struct ust_app *ust_app_create(struct ust_register_msg *msg, int sock)
{
+ int ret;
struct ust_app *lta = NULL;
+ struct lttng_pipe *event_notifier_event_source_pipe = NULL;
assert(msg);
assert(sock >= 0);
goto error;
}
+ /*
+ * Reserve the two file descriptors of the event source pipe. The write
+ * end will be closed once it is passed to the application, at which
+ * point a single 'put' will be performed.
+ */
+ ret = lttng_fd_get(LTTNG_FD_APPS, 2);
+ if (ret) {
+ ERR("Failed to reserve two file descriptors for the event source pipe while creating a new application instance: app = '%s' (ppid: %d)",
+ msg->name, (int) msg->ppid);
+ goto error;
+ }
+
+ event_notifier_event_source_pipe = lttng_pipe_open(FD_CLOEXEC);
+ if (!event_notifier_event_source_pipe) {
+ PERROR("Failed to open application event source pipe: '%s' (ppid = %d)",
+ msg->name, msg->ppid);
+ goto error;
+ }
+
lta = zmalloc(sizeof(struct ust_app));
if (lta == NULL) {
PERROR("malloc");
- goto error;
+ goto error_free_pipe;
}
+ lta->event_notifier_group.event_pipe = event_notifier_event_source_pipe;
+
lta->ppid = msg->ppid;
lta->uid = msg->uid;
lta->gid = msg->gid;
lta->ust_objd = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
lta->ust_sessions_objd = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
lta->notify_sock = -1;
+ lta->token_to_event_notifier_rule_ht = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
/* Copy name and make sure it's NULL terminated. */
strncpy(lta->name, msg->name, sizeof(lta->name));
lttng_ht_node_init_ulong(<a->sock_n, (unsigned long) lta->sock);
CDS_INIT_LIST_HEAD(<a->teardown_head);
-error:
return lta;
+
+error_free_pipe:
+ lttng_pipe_destroy(event_notifier_event_source_pipe);
+ lttng_fd_put(LTTNG_FD_APPS, 2);
+error:
+ return NULL;
}
/*
assert(app);
assert(app->notify_sock >= 0);
+ app->registration_time = time(NULL);
+
rcu_read_lock();
/*
return ret;
}
+/*
+ * Setup the base event notifier group.
+ *
+ * Return 0 on success else a negative value either an errno code or a
+ * LTTng-UST error code.
+ */
+int ust_app_setup_event_notifier_group(struct ust_app *app)
+{
+ int ret;
+ int event_pipe_write_fd;
+ struct lttng_ust_object_data *event_notifier_group = NULL;
+ enum lttng_error_code lttng_ret;
+
+ assert(app);
+
+ /* Get the write side of the pipe. */
+ event_pipe_write_fd = lttng_pipe_get_writefd(
+ app->event_notifier_group.event_pipe);
+
+ pthread_mutex_lock(&app->sock_lock);
+ ret = ustctl_create_event_notifier_group(app->sock,
+ event_pipe_write_fd, &event_notifier_group);
+ pthread_mutex_unlock(&app->sock_lock);
+ if (ret < 0) {
+ if (ret != -LTTNG_UST_ERR_EXITING && ret != -EPIPE) {
+ ERR("Failed to create application event notifier group: ret = %d, app socket fd = %d, event_pipe_write_fd = %d",
+ ret, app->sock, event_pipe_write_fd);
+ } else {
+ DBG("Failed to create application event notifier group (application is dead): app socket fd = %d",
+ app->sock);
+ }
+
+ goto error;
+ }
+
+ ret = lttng_pipe_write_close(app->event_notifier_group.event_pipe);
+ if (ret) {
+ ERR("Failed to close write end of the application's event source pipe: app = '%s' (ppid = %d)",
+ app->name, app->ppid);
+ goto error;
+ }
+
+ /*
+ * Release the file descriptor that was reserved for the write-end of
+ * the pipe.
+ */
+ lttng_fd_put(LTTNG_FD_APPS, 1);
+
+ lttng_ret = notification_thread_command_add_tracer_event_source(
+ notification_thread_handle,
+ lttng_pipe_get_readfd(app->event_notifier_group.event_pipe),
+ LTTNG_DOMAIN_UST);
+ if (lttng_ret != LTTNG_OK) {
+ ERR("Failed to add tracer event source to notification thread");
+ ret = - 1;
+ goto error;
+ }
+
+ /* Assign handle only when the complete setup is valid. */
+ app->event_notifier_group.object = event_notifier_group;
+ return ret;
+
+error:
+ ustctl_release_object(app->sock, app->event_notifier_group.object);
+ free(app->event_notifier_group.object);
+ return ret;
+}
+
/*
* Unregister app by removing it from the global traceable app list and freeing
* the data struct.
rcu_read_lock();
+ /* Cleanup notify socket hash table */
+ if (ust_app_ht_by_notify_sock) {
+ cds_lfht_for_each_entry(ust_app_ht_by_notify_sock->ht, &iter.iter, app,
+ notify_sock_n.node) {
+ /*
+ * Assert that all notifiers are gone as all triggers
+ * are unregistered prior to this clean-up.
+ */
+ assert(lttng_ht_get_count(app->token_to_event_notifier_rule_ht) == 0);
+
+ ust_app_notify_sock_unregister(app->notify_sock);
+ }
+ }
+
if (ust_app_ht) {
cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
ret = lttng_ht_del(ust_app_ht, &iter);
}
}
- /* Cleanup notify socket hash table */
- if (ust_app_ht_by_notify_sock) {
- cds_lfht_for_each_entry(ust_app_ht_by_notify_sock->ht, &iter.iter, app,
- notify_sock_n.node) {
- ret = lttng_ht_del(ust_app_ht_by_notify_sock, &iter);
- assert(!ret);
- }
- }
rcu_read_unlock();
/* Destroy is done only when the ht is empty */
struct ust_app_session *ua_sess;
struct ust_app_channel *ua_chan;
- if (usess == NULL || uchan == NULL) {
- ERR("Disabling UST global channel with NULL values");
- ret = -1;
- goto error;
- }
-
+ assert(usess->active);
DBG2("UST app disabling channel %s from global domain for session id %" PRIu64,
uchan->name, usess->id);
}
rcu_read_unlock();
-
-error:
return ret;
}
struct ust_app *app;
struct ust_app_session *ua_sess;
- if (usess == NULL || uchan == NULL) {
- ERR("Adding UST global channel to NULL values");
- ret = -1;
- goto error;
- }
-
+ assert(usess->active);
DBG2("UST app enabling channel %s to global domain for session id %" PRIu64,
uchan->name, usess->id);
}
rcu_read_unlock();
-
-error:
return ret;
}
struct ust_app_channel *ua_chan;
struct ust_app_event *ua_event;
+ assert(usess->active);
DBG("UST app disabling event %s for all apps in channel "
"%s for session id %" PRIu64,
uevent->attr.name, uchan->name, usess->id);
}
rcu_read_unlock();
-
return ret;
}
-/*
- * For a specific UST session, create the channel for all registered apps.
- */
-int ust_app_create_channel_glb(struct ltt_ust_session *usess,
- struct ltt_ust_channel *uchan)
+/* The ua_sess lock must be held by the caller. */
+static
+int ust_app_channel_create(struct ltt_ust_session *usess,
+ struct ust_app_session *ua_sess,
+ struct ltt_ust_channel *uchan, struct ust_app *app,
+ struct ust_app_channel **_ua_chan)
{
- int ret = 0, created;
- struct lttng_ht_iter iter;
- struct ust_app *app;
- struct ust_app_session *ua_sess = NULL;
-
- /* Very wrong code flow */
- assert(usess);
- assert(uchan);
-
- DBG2("UST app adding channel %s to UST domain for session id %" PRIu64,
- uchan->name, usess->id);
+ int ret = 0;
+ struct ust_app_channel *ua_chan = NULL;
- rcu_read_lock();
+ assert(ua_sess);
+ ASSERT_LOCKED(ua_sess->lock);
- /* For every registered applications */
- 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;
- }
- if (!trace_ust_pid_tracker_lookup(usess, app->pid)) {
- /* Skip. */
- continue;
- }
+ if (!strncmp(uchan->name, DEFAULT_METADATA_NAME,
+ sizeof(uchan->name))) {
+ copy_channel_attr_to_ustctl(&ua_sess->metadata_attr,
+ &uchan->attr);
+ ret = 0;
+ } else {
+ struct ltt_ust_context *uctx = NULL;
/*
- * Create session on the tracer side and add it to app session HT. Note
- * that if session exist, it will simply return a pointer to the ust
- * app session.
+ * Create channel onto application and synchronize its
+ * configuration.
*/
- ret = find_or_create_ust_app_session(usess, app, &ua_sess, &created);
+ ret = ust_app_channel_allocate(ua_sess, uchan,
+ LTTNG_UST_CHAN_PER_CPU, usess,
+ &ua_chan);
if (ret < 0) {
- switch (ret) {
- case -ENOTCONN:
- /*
- * The application's socket is not valid. Either a bad socket
- * or a timeout on it. We can't inform the caller that for a
- * specific app, the session failed so lets continue here.
- */
- ret = 0; /* Not an error. */
- continue;
- case -ENOMEM:
- default:
- goto error_rcu_unlock;
- }
+ goto error;
}
- assert(ua_sess);
-
- pthread_mutex_lock(&ua_sess->lock);
- if (ua_sess->deleted) {
- pthread_mutex_unlock(&ua_sess->lock);
- continue;
+ ret = ust_app_channel_send(app, usess,
+ ua_sess, ua_chan);
+ if (ret) {
+ goto error;
}
- if (!strncmp(uchan->name, DEFAULT_METADATA_NAME,
- sizeof(uchan->name))) {
- copy_channel_attr_to_ustctl(&ua_sess->metadata_attr, &uchan->attr);
- ret = 0;
- } else {
- /* Create channel onto application. We don't need the chan ref. */
- ret = create_ust_app_channel(ua_sess, uchan, app,
- LTTNG_UST_CHAN_PER_CPU, usess, NULL);
- }
- pthread_mutex_unlock(&ua_sess->lock);
- if (ret < 0) {
- /* Cleanup the created session if it's the case. */
- if (created) {
- destroy_app_session(app, ua_sess);
- }
- switch (ret) {
- case -ENOTCONN:
- /*
- * The application's socket is not valid. Either a bad socket
- * or a timeout on it. We can't inform the caller that for a
- * specific app, the session failed so lets continue here.
- */
- ret = 0; /* Not an error. */
- continue;
- case -ENOMEM:
- default:
- goto error_rcu_unlock;
+ /* Add contexts. */
+ cds_list_for_each_entry(uctx, &uchan->ctx_list, list) {
+ ret = create_ust_app_channel_context(ua_chan,
+ &uctx->ctx, app);
+ if (ret) {
+ goto error;
}
}
}
-error_rcu_unlock:
- rcu_read_unlock();
+error:
+ if (ret < 0) {
+ switch (ret) {
+ case -ENOTCONN:
+ /*
+ * The application's socket is not valid. Either a bad socket
+ * or a timeout on it. We can't inform the caller that for a
+ * specific app, the session failed so lets continue here.
+ */
+ ret = 0; /* Not an error. */
+ break;
+ case -ENOMEM:
+ default:
+ break;
+ }
+ }
+
+ if (ret == 0 && _ua_chan) {
+ /*
+ * Only return the application's channel on success. Note
+ * that the channel can still be part of the application's
+ * channel hashtable on error.
+ */
+ *_ua_chan = ua_chan;
+ }
return ret;
}
struct ust_app_channel *ua_chan;
struct ust_app_event *ua_event;
+ assert(usess->active);
DBG("UST app enabling event %s for all apps for session id %" PRIu64,
uevent->attr.name, usess->id);
struct ust_app_session *ua_sess;
struct ust_app_channel *ua_chan;
+ assert(usess->active);
DBG("UST app creating event %s for all apps for session id %" PRIu64,
uevent->attr.name, usess->id);
}
rcu_read_unlock();
-
return ret;
}
goto end;
}
+ if (ua_sess->enabled) {
+ pthread_mutex_unlock(&ua_sess->lock);
+ goto end;
+ }
+
/* Upon restart, we skip the setup, already done */
if (ua_sess->started) {
goto skip_setup;
}
- /* Create directories if consumer is LOCAL and has a path defined. */
- if (usess->consumer->type == CONSUMER_DST_LOCAL &&
- 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");
- goto error_unlock;
- }
- }
- }
-
- /*
- * Create the metadata for the application. This returns gracefully if a
- * metadata was already set for the session.
- */
- ret = create_ust_app_metadata(ua_sess, app, usess->consumer);
- if (ret < 0) {
- goto error_unlock;
- }
-
health_code_update();
skip_setup:
- /* This start the UST tracing */
+ /* This starts the UST tracing */
pthread_mutex_lock(&app->sock_lock);
ret = ustctl_start_session(app->sock, ua_sess->handle);
pthread_mutex_unlock(&app->sock_lock);
/* Indicate that the session has been started once */
ua_sess->started = 1;
+ ua_sess->enabled = 1;
pthread_mutex_unlock(&ua_sess->lock);
}
health_code_update();
+ ua_sess->enabled = 0;
/* Quiescent wait after stopping trace */
pthread_mutex_lock(&app->sock_lock);
*/
int ust_app_start_trace_all(struct ltt_ust_session *usess)
{
- int ret = 0;
struct lttng_ht_iter iter;
struct ust_app *app;
DBG("Starting all UST traces");
+ /*
+ * Even though the start trace might fail, flag this session active so
+ * other application coming in are started by default.
+ */
+ usess->active = 1;
+
rcu_read_lock();
/*
(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) {
- /* Continue to next apps even on error */
- continue;
- }
+ ust_app_global_update(usess, app);
}
rcu_read_unlock();
DBG("Stopping all UST traces");
+ /*
+ * Even though the stop trace might fail, flag this session inactive so
+ * other application coming in are not started by default.
+ */
+ usess->active = 0;
+
rcu_read_lock();
cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
return 0;
}
+/* The ua_sess lock must be held by the caller. */
static
-void ust_app_global_create(struct ltt_ust_session *usess, struct ust_app *app)
+int find_or_create_ust_app_channel(
+ struct ltt_ust_session *usess,
+ struct ust_app_session *ua_sess,
+ struct ust_app *app,
+ struct ltt_ust_channel *uchan,
+ struct ust_app_channel **ua_chan)
{
int ret = 0;
- struct lttng_ht_iter iter, uiter;
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_str *ua_chan_node;
+
+ lttng_ht_lookup(ua_sess->channels, (void *) uchan->name, &iter);
+ ua_chan_node = lttng_ht_iter_get_node_str(&iter);
+ if (ua_chan_node) {
+ *ua_chan = caa_container_of(ua_chan_node,
+ struct ust_app_channel, node);
+ goto end;
+ }
+
+ ret = ust_app_channel_create(usess, ua_sess, uchan, app, ua_chan);
+ if (ret) {
+ goto end;
+ }
+end:
+ return ret;
+}
+
+static
+int ust_app_channel_synchronize_event(struct ust_app_channel *ua_chan,
+ struct ltt_ust_event *uevent, struct ust_app_session *ua_sess,
+ struct ust_app *app)
+{
+ int ret = 0;
+ struct ust_app_event *ua_event = NULL;
+
+ ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
+ uevent->filter, uevent->attr.loglevel, uevent->exclusion);
+ if (!ua_event) {
+ ret = create_ust_app_event(ua_sess, ua_chan, uevent, app);
+ if (ret < 0) {
+ goto end;
+ }
+ } else {
+ if (ua_event->enabled != uevent->enabled) {
+ ret = uevent->enabled ?
+ enable_ust_app_event(ua_sess, ua_event, app) :
+ disable_ust_app_event(ua_sess, ua_event, app);
+ }
+ }
+
+end:
+ return ret;
+}
+
+/* Called with RCU read-side lock held. */
+static
+void ust_app_synchronize_event_notifier_rules(struct ust_app *app)
+{
+ int ret = 0;
+ enum lttng_error_code ret_code;
+ enum lttng_trigger_status t_status;
+ struct lttng_ht_iter app_trigger_iter;
+ struct lttng_triggers *triggers = NULL;
+ struct ust_app_event_notifier_rule *event_notifier_rule;
+ unsigned int count, i;
+
+ /*
+ * Currrently, registering or unregistering a trigger with an
+ * event rule condition causes a full synchronization of the event
+ * notifiers.
+ *
+ * The first step attempts to add an event notifier for all registered
+ * triggers that apply to the user space tracers. Then, the
+ * application's event notifiers rules are all checked against the list
+ * of registered triggers. Any event notifier that doesn't have a
+ * matching trigger can be assumed to have been disabled.
+ *
+ * All of this is inefficient, but is put in place to get the feature
+ * rolling as it is simpler at this moment. It will be optimized Soon™
+ * to allow the state of enabled
+ * event notifiers to be synchronized in a piece-wise way.
+ */
+
+ /* Get all triggers using uid 0 (root) */
+ ret_code = notification_thread_command_list_triggers(
+ notification_thread_handle, 0, &triggers);
+ if (ret_code != LTTNG_OK) {
+ ret = -1;
+ goto end;
+ }
+
+ assert(triggers);
+
+ t_status = lttng_triggers_get_count(triggers, &count);
+ if (t_status != LTTNG_TRIGGER_STATUS_OK) {
+ ret = -1;
+ goto end;
+ }
+
+ for (i = 0; i < count; i++) {
+ struct lttng_condition *condition;
+ struct lttng_event_rule *event_rule;
+ struct lttng_trigger *trigger;
+ const struct ust_app_event_notifier_rule *looked_up_event_notifier_rule;
+ enum lttng_condition_status condition_status;
+ uint64_t token;
+
+ trigger = lttng_triggers_borrow_mutable_at_index(triggers, i);
+ assert(trigger);
+
+ token = lttng_trigger_get_tracer_token(trigger);
+ condition = lttng_trigger_get_condition(trigger);
+
+ if (lttng_condition_get_type(condition) != LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+ /* Does not apply */
+ continue;
+ }
+
+ condition_status = lttng_condition_event_rule_borrow_rule_mutable(condition, &event_rule);
+ assert(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+ if (lttng_event_rule_get_domain_type(event_rule) == LTTNG_DOMAIN_KERNEL) {
+ /* Skip kernel related triggers. */
+ continue;
+ }
+
+ /*
+ * Find or create the associated token event rule. The caller
+ * holds the RCU read lock, so this is safe to call without
+ * explicitly acquiring it here.
+ */
+ looked_up_event_notifier_rule = find_ust_app_event_notifier_rule(
+ app->token_to_event_notifier_rule_ht, token);
+ if (!looked_up_event_notifier_rule) {
+ ret = create_ust_app_event_notifier_rule(event_rule, app, token);
+ if (ret < 0) {
+ goto end;
+ }
+ }
+ }
+
+ rcu_read_lock();
+ /* Remove all unknown event sources from the app. */
+ cds_lfht_for_each_entry (app->token_to_event_notifier_rule_ht->ht,
+ &app_trigger_iter.iter, event_notifier_rule,
+ node.node) {
+ const uint64_t app_token = event_notifier_rule->token;
+ bool found = false;
+
+ /*
+ * Check if the app event trigger still exists on the
+ * notification side.
+ */
+ for (i = 0; i < count; i++) {
+ uint64_t notification_thread_token;
+ const struct lttng_trigger *trigger =
+ lttng_triggers_get_at_index(
+ triggers, i);
+
+ assert(trigger);
+
+ notification_thread_token =
+ lttng_trigger_get_tracer_token(trigger);
+
+ if (notification_thread_token == app_token) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ /* Still valid. */
+ continue;
+ }
+
+ /*
+ * This trigger was unregistered, disable it on the tracer's
+ * side.
+ */
+ ret = lttng_ht_del(app->token_to_event_notifier_rule_ht,
+ &app_trigger_iter);
+ assert(ret == 0);
+
+ /* Callee logs errors. */
+ (void) disable_ust_object(app, event_notifier_rule->obj);
+
+ delete_ust_app_event_notifier_rule(
+ app->sock, event_notifier_rule, app);
+ }
+
+ rcu_read_unlock();
+
+end:
+ lttng_triggers_destroy(triggers);
+ return;
+}
+
+/*
+ * The caller must ensure that the application is compatible and is tracked
+ * by the process attribute trackers.
+ */
+static
+void ust_app_synchronize(struct ltt_ust_session *usess,
+ struct ust_app *app)
+{
+ int ret = 0;
+ struct cds_lfht_iter uchan_iter;
+ struct ltt_ust_channel *uchan;
struct ust_app_session *ua_sess = NULL;
- struct ust_app_channel *ua_chan;
- struct ust_app_event *ua_event;
- struct ust_app_ctx *ua_ctx;
- int is_created = 0;
- ret = find_or_create_ust_app_session(usess, app, &ua_sess, &is_created);
+ /*
+ * The application's configuration should only be synchronized for
+ * active sessions.
+ */
+ assert(usess->active);
+
+ ret = find_or_create_ust_app_session(usess, app, &ua_sess, NULL);
if (ret < 0) {
/* Tracer is probably gone or ENOMEM. */
goto error;
}
- if (!is_created) {
- /* App session already created. */
- goto end;
- }
assert(ua_sess);
pthread_mutex_lock(&ua_sess->lock);
-
if (ua_sess->deleted) {
pthread_mutex_unlock(&ua_sess->lock);
goto end;
}
- /*
- * We can iterate safely here over all UST app session since the create ust
- * app session above made a shadow copy of the UST global domain from the
- * ltt ust session.
- */
- cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, ua_chan,
- node.node) {
- ret = do_create_channel(app, usess, ua_sess, ua_chan);
- if (ret < 0 && ret != -ENOTCONN) {
- /*
- * Stop everything. On error, the application
- * failed, no more file descriptor are available
- * or ENOMEM so stopping here is the only thing
- * we can do for now. The only exception is
- * -ENOTCONN, which indicates that the application
- * has exit.
- */
- goto error_unlock;
- }
+ rcu_read_lock();
+
+ cds_lfht_for_each_entry(usess->domain_global.channels->ht, &uchan_iter,
+ uchan, node.node) {
+ struct ust_app_channel *ua_chan;
+ struct cds_lfht_iter uevent_iter;
+ struct ltt_ust_event *uevent;
/*
- * Add context using the list so they are enabled in the same order the
- * user added them.
+ * Search for a matching ust_app_channel. If none is found,
+ * create it. Creating the channel will cause the ua_chan
+ * structure to be allocated, the channel buffers to be
+ * allocated (if necessary) and sent to the application, and
+ * all enabled contexts will be added to the channel.
*/
- cds_list_for_each_entry(ua_ctx, &ua_chan->ctx_list, list) {
- ret = create_ust_channel_context(ua_chan, ua_ctx, app);
- if (ret < 0) {
- goto error_unlock;
- }
+ ret = find_or_create_ust_app_channel(usess, ua_sess,
+ app, uchan, &ua_chan);
+ if (ret) {
+ /* Tracer is probably gone or ENOMEM. */
+ goto error_unlock;
}
+ if (!ua_chan) {
+ /* ua_chan will be NULL for the metadata channel */
+ continue;
+ }
- /* For each events */
- cds_lfht_for_each_entry(ua_chan->events->ht, &uiter.iter, ua_event,
+ cds_lfht_for_each_entry(uchan->events->ht, &uevent_iter, uevent,
node.node) {
- ret = create_ust_event(app, ua_sess, ua_chan, ua_event);
- if (ret < 0) {
+ ret = ust_app_channel_synchronize_event(ua_chan,
+ uevent, ua_sess, app);
+ if (ret) {
goto error_unlock;
}
}
- }
-
- pthread_mutex_unlock(&ua_sess->lock);
- if (usess->active) {
- ret = ust_app_start_trace(usess, app);
- if (ret < 0) {
- goto error;
+ if (ua_chan->enabled != uchan->enabled) {
+ ret = uchan->enabled ?
+ enable_ust_app_channel(ua_sess, uchan, app) :
+ disable_ust_app_channel(ua_sess, ua_chan, app);
+ if (ret) {
+ goto error_unlock;
+ }
}
+ }
- DBG2("UST trace started for app pid %d", app->pid);
+ /*
+ * Create the metadata for the application. This returns gracefully if a
+ * metadata was already set for the session.
+ *
+ * The metadata channel must be created after the data channels as the
+ * consumer daemon assumes this ordering. When interacting with a relay
+ * daemon, the consumer will use this assumption to send the
+ * "STREAMS_SENT" message to the relay daemon.
+ */
+ ret = create_ust_app_metadata(ua_sess, app, usess->consumer);
+ if (ret < 0) {
+ goto error_unlock;
}
+
+ rcu_read_unlock();
+
end:
+ pthread_mutex_unlock(&ua_sess->lock);
/* Everything went well at this point. */
return;
error_unlock:
+ rcu_read_unlock();
pthread_mutex_unlock(&ua_sess->lock);
error:
if (ua_sess) {
void ust_app_global_update(struct ltt_ust_session *usess, struct ust_app *app)
{
assert(usess);
+ assert(usess->active);
DBG2("UST app global update for app sock %d for session id %" PRIu64,
app->sock, usess->id);
if (!app->compatible) {
return;
}
-
- if (trace_ust_pid_tracker_lookup(usess, app->pid)) {
- ust_app_global_create(usess, app);
+ if (trace_ust_id_tracker_lookup(LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID,
+ usess, app->pid) &&
+ trace_ust_id_tracker_lookup(
+ LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID,
+ usess, app->uid) &&
+ trace_ust_id_tracker_lookup(
+ LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID,
+ usess, app->gid)) {
+ /*
+ * Synchronize the application's internal tracing configuration
+ * and start tracing.
+ */
+ ust_app_synchronize(usess, app);
+ ust_app_start_trace(usess, app);
} else {
ust_app_global_destroy(usess, app);
}
}
+/*
+ * Add all event notifiers to an application.
+ *
+ * Called with session lock held.
+ * Called with RCU read-side lock held.
+ */
+void ust_app_global_update_event_notifier_rules(struct ust_app *app)
+{
+ DBG2("UST application global event notifier rules update: app = '%s' (ppid: %d)",
+ app->name, app->ppid);
+
+ if (!app->compatible) {
+ return;
+ }
+
+ if (app->event_notifier_group.object == NULL) {
+ WARN("UST app global update of event notifiers for app skipped since communication handle is null: app = '%s' (ppid: %d)",
+ app->name, app->ppid);
+ return;
+ }
+
+ ust_app_synchronize_event_notifier_rules(app);
+}
+
/*
* Called with session lock held.
*/
rcu_read_unlock();
}
+void ust_app_global_update_all_event_notifier_rules(void)
+{
+ 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) {
+ ust_app_global_update_event_notifier_rules(app);
+ }
+
+ rcu_read_unlock();
+}
+
/*
* Add context to a specific channel for global UST domain.
*/
struct ust_app_session *ua_sess;
struct ust_app *app;
- rcu_read_lock();
+ assert(usess->active);
+ rcu_read_lock();
cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
if (!app->compatible) {
/*
}
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;
}
}
/*
- * Enable event for a channel from a UST session for a specific PID.
+ * Receive registration and populate the given msg structure.
+ *
+ * On success return 0 else a negative value returned by the ustctl call.
*/
-int ust_app_enable_event_pid(struct ltt_ust_session *usess,
- struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent, pid_t pid)
+int ust_app_recv_registration(int sock, struct ust_register_msg *msg)
{
- 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;
- struct ust_app_event *ua_event;
-
- DBG("UST app enabling event %s for PID %d", uevent->attr.name, pid);
+ int ret;
+ uint32_t pid, ppid, uid, gid;
- rcu_read_lock();
-
- app = ust_app_find_by_pid(pid);
- if (app == NULL) {
- ERR("UST app enable event per PID %d not found", pid);
- ret = -1;
- goto end;
- }
-
- if (!app->compatible) {
- ret = 0;
- goto end;
- }
-
- ua_sess = lookup_session_by_app(usess, app);
- if (!ua_sess) {
- /* The application has problem or is probably dead. */
- ret = 0;
- goto end;
- }
-
- pthread_mutex_lock(&ua_sess->lock);
-
- if (ua_sess->deleted) {
- ret = 0;
- goto end_unlock;
- }
-
- /* Lookup channel in the ust app session */
- lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &iter);
- ua_chan_node = lttng_ht_iter_get_node_str(&iter);
- /* If the channel is not found, there is a code flow error */
- assert(ua_chan_node);
-
- ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
-
- ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
- uevent->filter, uevent->attr.loglevel, uevent->exclusion);
- if (ua_event == NULL) {
- ret = create_ust_app_event(ua_sess, ua_chan, uevent, app);
- if (ret < 0) {
- goto end_unlock;
- }
- } else {
- ret = enable_ust_app_event(ua_sess, ua_event, app);
- if (ret < 0) {
- goto end_unlock;
- }
- }
-
-end_unlock:
- pthread_mutex_unlock(&ua_sess->lock);
-end:
- rcu_read_unlock();
- 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 ret;
- uint32_t pid, ppid, uid, gid;
-
- assert(msg);
+ assert(msg);
ret = ustctl_recv_reg_msg(sock, &msg->type, &msg->major, &msg->minor,
&pid, &ppid, &uid, &gid,
*
* 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;
- uint32_t chan_id, reg_count;
+ uint32_t chan_id;
uint64_t chan_reg_key;
enum ustctl_channel_header type;
struct ust_app *app;
assert(chan_reg);
if (!chan_reg->register_done) {
- reg_count = ust_registry_get_event_count(chan_reg);
- if (reg_count < 31) {
- type = USTCTL_CHANNEL_HEADER_COMPACT;
- } else {
- type = USTCTL_CHANNEL_HEADER_LARGE;
- }
-
+ /*
+ * TODO: eventually use the registry event count for
+ * this channel to better guess header type for per-pid
+ * buffers.
+ */
+ type = USTCTL_CHANNEL_HEADER_LARGE;
chan_reg->nr_ctx_fields = nr_fields;
chan_reg->ctx_fields = fields;
fields = NULL;
* 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;
* Take a snapshot for a given UST session. The snapshot is sent to the given
* output.
*
- * Return 0 on success or else a negative value.
+ * Returns LTTNG_OK on success or a LTTNG_ERR error code.
*/
-int ust_app_snapshot_record(struct ltt_ust_session *usess,
- struct snapshot_output *output, int wait,
+enum lttng_error_code ust_app_snapshot_record(
+ const struct ltt_ust_session *usess,
+ const struct consumer_output *output, int wait,
uint64_t nb_packets_per_stream)
{
int ret = 0;
+ enum lttng_error_code status = LTTNG_OK;
struct lttng_ht_iter iter;
struct ust_app *app;
- char pathname[PATH_MAX];
+ char *trace_path = NULL;
assert(usess);
assert(output);
cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
struct buffer_reg_channel *reg_chan;
struct consumer_socket *socket;
+ char pathname[PATH_MAX];
+ size_t consumer_path_offset = 0;
+
+ 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);
if (!socket) {
- ret = -EINVAL;
+ status = LTTNG_ERR_INVALID;
goto error;
}
reg->uid, reg->bits_per_long);
if (ret < 0) {
PERROR("snprintf snapshot path");
+ status = LTTNG_ERR_INVALID;
+ goto error;
+ }
+ /* Free path allowed on previous iteration. */
+ free(trace_path);
+ trace_path = setup_channel_trace_path(usess->consumer, pathname,
+ &consumer_path_offset);
+ if (!trace_path) {
+ status = LTTNG_ERR_INVALID;
goto error;
}
-
/* 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,
+ status = consumer_snapshot_channel(socket,
+ reg_chan->consumer_key,
+ output, 0, usess->uid,
+ usess->gid, &trace_path[consumer_path_offset], wait,
nb_packets_per_stream);
- if (ret < 0) {
+ if (status != LTTNG_OK) {
goto error;
}
}
- ret = consumer_snapshot_channel(socket,
+ status = consumer_snapshot_channel(socket,
reg->registry->reg.ust->metadata_key, output, 1,
- usess->uid, usess->gid, pathname, wait, 0);
- if (ret < 0) {
+ usess->uid, usess->gid, &trace_path[consumer_path_offset],
+ wait, 0);
+ if (status != LTTNG_OK) {
goto error;
}
}
struct ust_app_channel *ua_chan;
struct ust_app_session *ua_sess;
struct ust_registry_session *registry;
+ char pathname[PATH_MAX];
+ size_t consumer_path_offset = 0;
ua_sess = lookup_session_by_app(usess, app);
if (!ua_sess) {
/* Get the right consumer socket for the application. */
socket = consumer_find_socket_by_bitness(app->bits_per_long,
- output->consumer);
+ output);
if (!socket) {
- ret = -EINVAL;
+ status = LTTNG_ERR_INVALID;
goto error;
}
ret = snprintf(pathname, sizeof(pathname), DEFAULT_UST_TRACE_DIR "/%s",
ua_sess->path);
if (ret < 0) {
+ status = LTTNG_ERR_INVALID;
PERROR("snprintf snapshot path");
goto error;
}
-
+ /* Free path allowed on previous iteration. */
+ free(trace_path);
+ trace_path = setup_channel_trace_path(usess->consumer, pathname,
+ &consumer_path_offset);
+ if (!trace_path) {
+ status = LTTNG_ERR_INVALID;
+ goto error;
+ }
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,
+ status = consumer_snapshot_channel(socket,
+ ua_chan->key, output, 0,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ &trace_path[consumer_path_offset], wait,
nb_packets_per_stream);
- if (ret < 0) {
+ switch (status) {
+ case LTTNG_OK:
+ break;
+ case LTTNG_ERR_CHAN_NOT_FOUND:
+ continue;
+ default:
goto error;
}
}
registry = get_session_registry(ua_sess);
if (!registry) {
- DBG("Application session is being torn down. Abort snapshot record.");
- ret = -1;
- goto error;
+ DBG("Application session is being torn down. Skip application.");
+ continue;
}
- ret = consumer_snapshot_channel(socket, registry->metadata_key, output,
- 1, ua_sess->euid, ua_sess->egid, pathname, wait, 0);
- if (ret < 0) {
+ status = consumer_snapshot_channel(socket,
+ registry->metadata_key, output, 1,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ &trace_path[consumer_path_offset], wait, 0);
+ switch (status) {
+ case LTTNG_OK:
+ break;
+ case LTTNG_ERR_CHAN_NOT_FOUND:
+ continue;
+ default:
goto error;
}
}
}
error:
+ free(trace_path);
rcu_read_unlock();
- return ret;
+ return status;
}
/*
* Return the size taken by one more packet per stream.
*/
-uint64_t ust_app_get_size_one_more_packet_per_stream(struct ltt_ust_session *usess,
- uint64_t cur_nr_packets)
+uint64_t ust_app_get_size_one_more_packet_per_stream(
+ const struct ltt_ust_session *usess, uint64_t cur_nr_packets)
{
uint64_t tot_size = 0;
struct ust_app *app;
/*
* Rotate all the channels of a session.
*
- * Return 0 on success or else a negative value.
+ * Return LTTNG_OK on success or else an LTTng error code.
*/
-int ust_app_rotate_session(struct ltt_session *session, bool *ust_active)
+enum lttng_error_code ust_app_rotate_session(struct ltt_session *session)
{
- int ret = 0;
+ int ret;
+ enum lttng_error_code cmd_ret = LTTNG_OK;
struct lttng_ht_iter iter;
struct ust_app *app;
struct ltt_ust_session *usess = session->ust_session;
- char pathname[LTTNG_PATH_MAX];
assert(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);
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");
+ cmd_ret = LTTNG_ERR_INVALID;
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);
+ usess->consumer,
+ /* is_metadata_channel */ false);
if (ret < 0) {
+ cmd_ret = LTTNG_ERR_ROTATION_FAIL_CONSUMER;
goto error;
}
}
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);
+ usess->consumer,
+ /* is_metadata_channel */ true);
if (ret < 0) {
+ cmd_ret = LTTNG_ERR_ROTATION_FAIL_CONSUMER;
goto error;
}
- *ust_active = true;
}
break;
}
/* 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;
+ cmd_ret = LTTNG_ERR_INVALID;
goto error;
}
registry = get_session_registry(ua_sess);
if (!registry) {
- DBG("Application session is being torn down. Abort snapshot record.");
- ret = -1;
+ DBG("Application session is being torn down. Skip application.");
+ continue;
+ }
+
+ /* Rotate the data channels. */
+ cds_lfht_for_each_entry(ua_sess->channels->ht, &chan_iter.iter,
+ ua_chan, node.node) {
+ ret = consumer_rotate_channel(socket,
+ ua_chan->key,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ ua_sess->consumer,
+ /* is_metadata_channel */ false);
+ if (ret < 0) {
+ /* Per-PID buffer and application going away. */
+ if (ret == -LTTNG_ERR_CHAN_NOT_FOUND)
+ continue;
+ cmd_ret = LTTNG_ERR_ROTATION_FAIL_CONSUMER;
+ goto error;
+ }
+ }
+
+ /* Rotate the metadata channel. */
+ (void) push_metadata(registry, usess->consumer);
+ ret = consumer_rotate_channel(socket,
+ registry->metadata_key,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ ua_sess->consumer,
+ /* is_metadata_channel */ true);
+ if (ret < 0) {
+ /* Per-PID buffer and application going away. */
+ if (ret == -LTTNG_ERR_CHAN_NOT_FOUND)
+ continue;
+ cmd_ret = LTTNG_ERR_ROTATION_FAIL_CONSUMER;
+ goto error;
+ }
+ }
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+
+ cmd_ret = LTTNG_OK;
+
+error:
+ rcu_read_unlock();
+ return cmd_ret;
+}
+
+enum lttng_error_code ust_app_create_channel_subdirectories(
+ const struct ltt_ust_session *usess)
+{
+ enum lttng_error_code ret = LTTNG_OK;
+ struct lttng_ht_iter iter;
+ enum lttng_trace_chunk_status chunk_status;
+ char *pathname_index;
+ int fmt_ret;
+
+ assert(usess->current_trace_chunk);
+ 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) {
+ fmt_ret = asprintf(&pathname_index,
+ DEFAULT_UST_TRACE_DIR "/" DEFAULT_UST_TRACE_UID_PATH "/" DEFAULT_INDEX_DIR,
+ reg->uid, reg->bits_per_long);
+ if (fmt_ret < 0) {
+ ERR("Failed to format channel index directory");
+ ret = LTTNG_ERR_CREATE_DIR_FAIL;
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.
+ * Create the index subdirectory which will take care
+ * of implicitly creating the channel's path.
*/
- 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;
+ chunk_status = lttng_trace_chunk_create_subdirectory(
+ usess->current_trace_chunk,
+ pathname_index);
+ free(pathname_index);
+ if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+ ret = LTTNG_ERR_CREATE_DIR_FAIL;
goto error;
}
+ }
+ break;
+ }
+ case LTTNG_BUFFER_PER_PID:
+ {
+ struct ust_app *app;
- /* 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);
+ /*
+ * Create the toplevel ust/ directory in case no apps are running.
+ */
+ chunk_status = lttng_trace_chunk_create_subdirectory(
+ usess->current_trace_chunk,
+ DEFAULT_UST_TRACE_DIR);
+ if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+ ret = LTTNG_ERR_CREATE_DIR_FAIL;
+ goto error;
+ }
+
+ cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app,
+ pid_n.node) {
+ 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;
+ }
+
+ registry = get_session_registry(ua_sess);
+ if (!registry) {
+ DBG("Application session is being torn down. Skip application.");
+ continue;
+ }
+
+ fmt_ret = asprintf(&pathname_index,
+ DEFAULT_UST_TRACE_DIR "/%s/" DEFAULT_INDEX_DIR,
+ ua_sess->path);
+ if (fmt_ret < 0) {
+ ERR("Failed to format channel index directory");
+ ret = LTTNG_ERR_CREATE_DIR_FAIL;
+ goto error;
+ }
+ /*
+ * Create the index subdirectory which will take care
+ * of implicitly creating the channel's path.
+ */
+ chunk_status = lttng_trace_chunk_create_subdirectory(
+ usess->current_trace_chunk,
+ pathname_index);
+ free(pathname_index);
+ if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+ ret = LTTNG_ERR_CREATE_DIR_FAIL;
+ goto error;
+ }
+ }
+ break;
+ }
+ default:
+ abort();
+ }
+
+ ret = LTTNG_OK;
+error:
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Clear all the channels of a session.
+ *
+ * Return LTTNG_OK on success or else an LTTng error code.
+ */
+enum lttng_error_code ust_app_clear_session(struct ltt_session *session)
+{
+ int ret;
+ enum lttng_error_code cmd_ret = LTTNG_OK;
+ struct lttng_ht_iter iter;
+ struct ust_app *app;
+ struct ltt_ust_session *usess = session->ust_session;
+
+ assert(usess);
+
+ rcu_read_lock();
+
+ if (usess->active) {
+ ERR("Expecting inactive session %s (%" PRIu64 ")", session->name, session->id);
+ cmd_ret = LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ 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) {
+ cmd_ret = LTTNG_ERR_INVALID;
+ goto error_socket;
+ }
+
+ /* Clear the data channels. */
+ cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
+ reg_chan, node.node) {
+ ret = consumer_clear_channel(socket,
+ reg_chan->consumer_key);
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);
+ }
+
+ (void) push_metadata(reg->registry->reg.ust, usess->consumer);
+
+ /*
+ * Clear the metadata channel.
+ * Metadata channel is not cleared per se but we still need to
+ * perform a rotation operation on it behind the scene.
+ */
+ ret = consumer_clear_channel(socket,
+ reg->registry->reg.ust->metadata_key);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+ 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;
+ }
+
+ /* Get the right consumer socket for the application. */
+ socket = consumer_find_socket_by_bitness(app->bits_per_long,
+ usess->consumer);
+ if (!socket) {
+ cmd_ret = LTTNG_ERR_INVALID;
+ goto error_socket;
+ }
+
+ registry = get_session_registry(ua_sess);
+ if (!registry) {
+ DBG("Application session is being torn down. Skip application.");
+ continue;
+ }
+
+ /* Clear the data channels. */
+ cds_lfht_for_each_entry(ua_sess->channels->ht, &chan_iter.iter,
+ ua_chan, node.node) {
+ ret = consumer_clear_channel(socket, ua_chan->key);
if (ret < 0) {
+ /* Per-PID buffer and application going away. */
+ if (ret == -LTTNG_ERR_CHAN_NOT_FOUND) {
+ continue;
+ }
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);
+
+ /*
+ * Clear the metadata channel.
+ * Metadata channel is not cleared per se but we still need to
+ * perform rotation operation on it behind the scene.
+ */
+ ret = consumer_clear_channel(socket, registry->metadata_key);
if (ret < 0) {
+ /* Per-PID buffer and application going away. */
+ if (ret == -LTTNG_ERR_CHAN_NOT_FOUND) {
+ continue;
+ }
goto error;
}
- *ust_active = true;
}
break;
}
break;
}
- ret = LTTNG_OK;
+ cmd_ret = LTTNG_OK;
+ goto end;
+
+error:
+ switch (-ret) {
+ case LTTCOMM_CONSUMERD_RELAYD_CLEAR_DISALLOWED:
+ cmd_ret = LTTNG_ERR_CLEAR_RELAY_DISALLOWED;
+ break;
+ default:
+ cmd_ret = LTTNG_ERR_CLEAR_FAIL_CONSUMER;
+ }
+
+error_socket:
+end:
+ rcu_read_unlock();
+ return cmd_ret;
+}
+
+/*
+ * This function skips the metadata channel as the begin/end timestamps of a
+ * metadata packet are useless.
+ *
+ * Moreover, opening a packet after a "clear" will cause problems for live
+ * sessions as it will introduce padding that was not part of the first trace
+ * chunk. The relay daemon expects the content of the metadata stream of
+ * successive metadata trace chunks to be strict supersets of one another.
+ *
+ * For example, flushing a packet at the beginning of the metadata stream of
+ * a trace chunk resulting from a "clear" session command will cause the
+ * size of the metadata stream of the new trace chunk to not match the size of
+ * the metadata stream of the original chunk. This will confuse the relay
+ * daemon as the same "offset" in a metadata stream will no longer point
+ * to the same content.
+ */
+enum lttng_error_code ust_app_open_packets(struct ltt_session *session)
+{
+ enum lttng_error_code ret = LTTNG_OK;
+ struct lttng_ht_iter iter;
+ struct ltt_ust_session *usess = session->ust_session;
+
+ 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;
+
+ socket = consumer_find_socket_by_bitness(
+ reg->bits_per_long, usess->consumer);
+ if (!socket) {
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+
+ cds_lfht_for_each_entry(reg->registry->channels->ht,
+ &iter.iter, reg_chan, node.node) {
+ const int open_ret =
+ consumer_open_channel_packets(
+ socket,
+ reg_chan->consumer_key);
+
+ if (open_ret < 0) {
+ ret = LTTNG_ERR_UNK;
+ goto error;
+ }
+ }
+ }
+ break;
+ }
+ case LTTNG_BUFFER_PER_PID:
+ {
+ struct ust_app *app;
+
+ 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;
+ }
+
+ /* Get the right consumer socket for the application. */
+ socket = consumer_find_socket_by_bitness(
+ app->bits_per_long, usess->consumer);
+ if (!socket) {
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+
+ registry = get_session_registry(ua_sess);
+ if (!registry) {
+ DBG("Application session is being torn down. Skip application.");
+ continue;
+ }
+
+ cds_lfht_for_each_entry(ua_sess->channels->ht,
+ &chan_iter.iter, ua_chan, node.node) {
+ const int open_ret =
+ consumer_open_channel_packets(
+ socket,
+ ua_chan->key);
+
+ if (open_ret < 0) {
+ /*
+ * Per-PID buffer and application going
+ * away.
+ */
+ if (open_ret == -LTTNG_ERR_CHAN_NOT_FOUND) {
+ continue;
+ }
+
+ ret = LTTNG_ERR_UNK;
+ goto error;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ abort();
+ break;
+ }
error:
rcu_read_unlock();