/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2011 EfficiOS Inc.
* Copyright (C) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
*
* SPDX-License-Identifier: GPL-2.0-only
#include "rotate.h"
#include "event.h"
#include "event-notifier-error-accounting.h"
-
+#include "ust-field-utils.h"
struct lttng_ht *ust_app_ht;
struct lttng_ht *ust_app_ht_by_sock;
int ret;
LTTNG_ASSERT(ua_ctx);
+ ASSERT_RCU_READ_LOCKED();
if (ua_ctx->obj) {
pthread_mutex_lock(&app->sock_lock);
int ret;
LTTNG_ASSERT(ua_event);
+ ASSERT_RCU_READ_LOCKED();
free(ua_event->filter);
if (ua_event->exclusion != NULL)
struct ust_app *app)
{
LTTNG_ASSERT(stream);
+ ASSERT_RCU_READ_LOCKED();
(void) release_ust_app_stream(sock, stream, app);
free(stream);
}
-/*
- * We need to execute ht_destroy outside of RCU read-side critical
- * section and outside of call_rcu thread, so we postpone its execution
- * using ht_cleanup_push. It is simpler than to change the semantic of
- * the many callers of delete_ust_app_session().
- */
static
void delete_ust_app_channel_rcu(struct rcu_head *head)
{
struct ust_app_channel *ua_chan =
caa_container_of(head, struct ust_app_channel, rcu_head);
- ht_cleanup_push(ua_chan->ctx);
- ht_cleanup_push(ua_chan->events);
+ lttng_ht_destroy(ua_chan->ctx);
+ lttng_ht_destroy(ua_chan->events);
free(ua_chan);
}
struct ust_registry_session *registry;
LTTNG_ASSERT(ua_chan);
+ ASSERT_RCU_READ_LOCKED();
DBG3("UST app deleting channel %s", ua_chan->name);
/*
* Push metadata to consumer socket.
*
- * RCU read-side lock must be held to guarantee existance of socket.
+ * RCU read-side lock must be held to guarantee existence of socket.
* Must be called with the ust app session lock held.
* Must be called with the registry lock held.
*
LTTNG_ASSERT(registry);
LTTNG_ASSERT(socket);
+ ASSERT_RCU_READ_LOCKED();
metadata_key = registry->metadata_key;
* socket to send the metadata is retrieved from consumer, if sock
* is not NULL we use it to send the metadata.
* RCU read-side lock must be held while calling this function,
- * therefore ensuring existance of registry. It also ensures existance
+ * therefore ensuring existence of registry. It also ensures existence
* of socket throughout this function.
*
* Return 0 on success else a negative error.
LTTNG_ASSERT(registry);
LTTNG_ASSERT(consumer);
+ ASSERT_RCU_READ_LOCKED();
pthread_mutex_lock(®istry->lock);
if (registry->metadata_closed) {
return ret;
}
-/*
- * We need to execute ht_destroy outside of RCU read-side critical
- * section and outside of call_rcu thread, so we postpone its execution
- * using ht_cleanup_push. It is simpler than to change the semantic of
- * the many callers of delete_ust_app_session().
- */
static
void delete_ust_app_session_rcu(struct rcu_head *head)
{
struct ust_app_session *ua_sess =
caa_container_of(head, struct ust_app_session, rcu_head);
- ht_cleanup_push(ua_sess->channels);
+ lttng_ht_destroy(ua_sess->channels);
free(ua_sess);
}
struct ust_registry_session *registry;
LTTNG_ASSERT(ua_sess);
+ ASSERT_RCU_READ_LOCKED();
pthread_mutex_lock(&ua_sess->lock);
/*
* Delete a traceable application structure from the global list. Never call
* this function outside of a call_rcu call.
- *
- * RCU read side lock should _NOT_ be held when calling this function.
*/
static
void delete_ust_app(struct ust_app *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);
+ lttng_ht_destroy(app->sessions);
+ lttng_ht_destroy(app->ust_sessions_objd);
+ lttng_ht_destroy(app->ust_objd);
+ lttng_ht_destroy(app->token_to_event_notifier_rule_ht);
/*
* This could be NULL if the event notifier setup failed (e.g the app
struct lttng_ht_node_ulong *node;
struct lttng_ht_iter iter;
+ ASSERT_RCU_READ_LOCKED();
+
lttng_ht_lookup(ust_app_ht_by_sock, (void *)((unsigned long) sock), &iter);
node = lttng_ht_iter_get_node_ulong(&iter);
if (node == NULL) {
struct lttng_ht_node_ulong *node;
struct lttng_ht_iter iter;
+ ASSERT_RCU_READ_LOCKED();
+
lttng_ht_lookup(ust_app_ht_by_notify_sock, (void *)((unsigned long) sock),
&iter);
node = lttng_ht_iter_get_node_ulong(&iter);
struct ust_app_event_notifier_rule *event_notifier_rule = NULL;
LTTNG_ASSERT(ht);
+ ASSERT_RCU_READ_LOCKED();
lttng_ht_lookup(ht, &token, &iter);
node = lttng_ht_iter_get_node_u64(&iter);
ua_event_notifier_rule->handle = ua_event_notifier_rule->obj->handle;
- DBG2("UST app event notifier %s created successfully: app = '%s': pid = %d), object = %p",
+ DBG2("UST app event notifier %s created successfully: app = '%s': pid = %d, object = %p",
event_notifier.event.name, app->name, app->pid,
ua_event_notifier_rule->obj);
LTTNG_ASSERT(uctx);
LTTNG_ASSERT(ht);
+ ASSERT_RCU_READ_LOCKED();
/* Lookup using the lttng_ust_context_type and a custom match fct. */
cds_lfht_lookup(ht->ht, ht->hash_fct((void *) uctx->ctx, lttng_ht_seed),
int ret = 0;
struct ust_app_ctx *ua_ctx;
+ ASSERT_RCU_READ_LOCKED();
+
DBG2("UST app adding context to channel %s", ua_chan->name);
ua_ctx = find_ust_app_context(ua_chan->ctx, uctx);
struct lttng_ht_node_str *ua_chan_node;
struct ust_app_channel *ua_chan;
+ ASSERT_RCU_READ_LOCKED();
+
lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &iter);
ua_chan_node = lttng_ht_iter_get_node_str(&iter);
if (ua_chan_node == NULL) {
LTTNG_ASSERT(usess);
LTTNG_ASSERT(ua_sess);
LTTNG_ASSERT(ua_chan);
+ ASSERT_RCU_READ_LOCKED();
DBG("UST app creating channel %s with per UID buffers", ua_chan->name);
LTTNG_ASSERT(usess->active);
LTTNG_ASSERT(ua_sess);
LTTNG_ASSERT(ua_chan);
+ ASSERT_RCU_READ_LOCKED();
/* Handle buffer type before sending the channel to the application. */
switch (usess->buffer_type) {
struct lttng_ht_node_str *ua_chan_node;
struct ust_app_channel *ua_chan;
+ ASSERT_RCU_READ_LOCKED();
+
/* 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);
int ret = 0;
struct ust_app_event *ua_event;
+ ASSERT_RCU_READ_LOCKED();
+
ua_event = alloc_ust_app_event(uevent->attr.name, &uevent->attr);
if (ua_event == NULL) {
/* Only failure mode of alloc_ust_app_event(). */
int ret = 0;
struct ust_app_event_notifier_rule *ua_event_notifier_rule;
+ ASSERT_RCU_READ_LOCKED();
+
ua_event_notifier_rule = alloc_ust_app_event_notifier_rule(trigger);
if (ua_event_notifier_rule == NULL) {
ret = -ENOMEM;
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', pid = %d), token = %" PRIu64,
+ DBG2("UST app create token event rule completed: app = '%s', pid = %d, token = %" PRIu64,
app->name, app->pid, lttng_trigger_get_tracer_token(trigger));
goto end;
LTTNG_ASSERT(ua_sess);
LTTNG_ASSERT(app);
LTTNG_ASSERT(consumer);
+ ASSERT_RCU_READ_LOCKED();
registry = get_session_registry(ua_sess);
/* The UST app session is held registry shall not be null. */
/*
* Free and clean all traceable apps of the global list.
- *
- * Should _NOT_ be called with RCU read-side lock held.
*/
void ust_app_clean_list(void)
{
/* Destroy is done only when the ht is empty */
if (ust_app_ht) {
- ht_cleanup_push(ust_app_ht);
+ lttng_ht_destroy(ust_app_ht);
}
if (ust_app_ht_by_sock) {
- ht_cleanup_push(ust_app_ht_by_sock);
+ lttng_ht_destroy(ust_app_ht_by_sock);
}
if (ust_app_ht_by_notify_sock) {
- ht_cleanup_push(ust_app_ht_by_notify_sock);
+ lttng_ht_destroy(ust_app_ht_by_notify_sock);
}
}
pthread_mutex_unlock(&app->sock_lock);
if (ret < 0) {
if (ret == -EPIPE || ret == -LTTNG_UST_ERR_EXITING) {
- DBG3("UST app wait quiescent failed. Application is dead: pid= %d, sock = %d)",
+ DBG3("UST app wait quiescent failed. Application is dead: pid= %d, sock = %d",
app->pid, app->sock);
} else if (ret == -EAGAIN) {
- WARN("UST app wait quiescent failed. Communication time out: pid= %d, sock = %d)",
+ WARN("UST app wait quiescent failed. Communication time out: pid= %d, sock = %d",
app->pid, app->sock);
} else {
- ERR("UST app wait quiescent failed with ret %d: pid= %d, sock = %d)",
+ ERR("UST app wait quiescent failed with ret %d: pid= %d, sock = %d",
ret, app->pid, app->sock);
}
}
pthread_mutex_unlock(&app->sock_lock);
if (ret < 0) {
if (ret == -EPIPE || ret == -LTTNG_UST_ERR_EXITING) {
- DBG3("UST app wait quiescent failed. Application is dead: pid= %d, sock = %d)",
+ DBG3("UST app wait quiescent failed. Application is dead: pid= %d, sock = %d",
app->pid, app->sock);
} else if (ret == -EAGAIN) {
- WARN("UST app wait quiescent failed. Communication time out: pid= %d, sock = %d)",
+ WARN("UST app wait quiescent failed. Communication time out: pid= %d, sock = %d",
app->pid, app->sock);
} else {
- ERR("UST app wait quiescent failed with ret %d: pid= %d, sock = %d)",
+ ERR("UST app wait quiescent failed with ret %d: pid= %d, sock = %d",
ret, app->pid, app->sock);
}
}
struct ust_app_event_notifier_rule *event_notifier_rule;
unsigned int count, i;
+ ASSERT_RCU_READ_LOCKED();
+
if (!ust_app_supports_notifiers(app)) {
goto end;
}
LTTNG_ASSERT(usess);
LTTNG_ASSERT(ua_sess);
LTTNG_ASSERT(app);
+ ASSERT_RCU_READ_LOCKED();
cds_lfht_for_each_entry(usess->domain_global.channels->ht, &uchan_iter,
uchan, node.node) {
{
LTTNG_ASSERT(usess);
LTTNG_ASSERT(usess->active);
+ ASSERT_RCU_READ_LOCKED();
DBG2("UST app global update for app sock %d for session id %" PRIu64,
app->sock, usess->id);
*/
void ust_app_global_update_event_notifier_rules(struct ust_app *app)
{
- DBG2("UST application global event notifier rules update: app = '%s', pid = %d)",
+ ASSERT_RCU_READ_LOCKED();
+
+ DBG2("UST application global event notifier rules update: app = '%s', pid = %d",
app->name, app->pid);
if (!app->compatible || !ust_app_supports_notifiers(app)) {
}
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' pid = %d)",
+ WARN("UST app global update of event notifiers for app skipped since communication handle is null: app = '%s', pid = %d",
app->name, app->pid);
return;
}
struct ust_app_session *ua_sess = NULL;
LTTNG_ASSERT(app);
+ ASSERT_RCU_READ_LOCKED();
lttng_ht_lookup(app->ust_sessions_objd, (void *)((unsigned long) objd), &iter);
node = lttng_ht_iter_get_node_ulong(&iter);
struct ust_app_channel *ua_chan = NULL;
LTTNG_ASSERT(app);
+ ASSERT_RCU_READ_LOCKED();
lttng_ht_lookup(app->ust_objd, (void *)((unsigned long) objd), &iter);
node = lttng_ht_iter_get_node_ulong(&iter);
return ua_chan;
}
+/*
+ * Fixup legacy context fields for comparison:
+ * - legacy array becomes array_nestable,
+ * - legacy struct becomes struct_nestable,
+ * - legacy variant becomes variant_nestable,
+ * legacy sequences are not emitted in LTTng-UST contexts.
+ */
+static int ust_app_fixup_legacy_context_fields(size_t *_nr_fields,
+ struct lttng_ust_ctl_field **_fields)
+{
+ struct lttng_ust_ctl_field *fields = *_fields, *new_fields = NULL;
+ size_t nr_fields = *_nr_fields, new_nr_fields = 0, i, j;
+ bool found = false;
+ int ret = 0;
+
+ for (i = 0; i < nr_fields; i++) {
+ const struct lttng_ust_ctl_field *field = &fields[i];
+
+ switch (field->type.atype) {
+ case lttng_ust_ctl_atype_sequence:
+ ERR("Unexpected legacy sequence context.");
+ ret = -EINVAL;
+ goto end;
+ case lttng_ust_ctl_atype_array:
+ switch (field->type.u.legacy.array.elem_type.atype) {
+ case lttng_ust_ctl_atype_integer:
+ break;
+ default:
+ ERR("Unexpected legacy array element type in context.");
+ ret = -EINVAL;
+ goto end;
+ }
+ found = true;
+ /* One field for array_nested, one field for elem type. */
+ new_nr_fields += 2;
+ break;
+
+ case lttng_ust_ctl_atype_struct: /* Fallthrough */
+ case lttng_ust_ctl_atype_variant:
+ found = true;
+ new_nr_fields++;
+ break;
+ default:
+ new_nr_fields++;
+ break;
+ }
+ }
+ if (!found) {
+ goto end;
+ }
+ new_fields = (struct lttng_ust_ctl_field *) zmalloc(sizeof(*new_fields) * new_nr_fields);
+ if (!new_fields) {
+ ret = -ENOMEM;
+ goto end;
+ }
+ for (i = 0, j = 0; i < nr_fields; i++, j++) {
+ const struct lttng_ust_ctl_field *field = &fields[i];
+ struct lttng_ust_ctl_field *new_field = &new_fields[j];
+
+ switch (field->type.atype) {
+ case lttng_ust_ctl_atype_array:
+ /* One field for array_nested, one field for elem type. */
+ strncpy(new_field->name, field->name, LTTNG_UST_ABI_SYM_NAME_LEN - 1);
+ new_field->type.atype = lttng_ust_ctl_atype_array_nestable;
+ new_field->type.u.array_nestable.length = field->type.u.legacy.array.length;
+ new_field->type.u.array_nestable.alignment = 0;
+ new_field = &new_fields[++j]; /* elem type */
+ new_field->type.atype = field->type.u.legacy.array.elem_type.atype;
+ assert(new_field->type.atype == lttng_ust_ctl_atype_integer);
+ new_field->type.u.integer = field->type.u.legacy.array.elem_type.u.basic.integer;
+ break;
+ case lttng_ust_ctl_atype_struct:
+ strncpy(new_field->name, field->name, LTTNG_UST_ABI_SYM_NAME_LEN - 1);
+ new_field->type.atype = lttng_ust_ctl_atype_struct_nestable;
+ new_field->type.u.struct_nestable.nr_fields = field->type.u.legacy._struct.nr_fields;
+ new_field->type.u.struct_nestable.alignment = 0;
+ break;
+ case lttng_ust_ctl_atype_variant:
+ strncpy(new_field->name, field->name, LTTNG_UST_ABI_SYM_NAME_LEN - 1);
+ new_field->type.atype = lttng_ust_ctl_atype_variant_nestable;
+ new_field->type.u.variant_nestable.nr_choices = field->type.u.legacy.variant.nr_choices;
+ strncpy(new_field->type.u.variant_nestable.tag_name,
+ field->type.u.legacy.variant.tag_name,
+ LTTNG_UST_ABI_SYM_NAME_LEN - 1);
+ new_field->type.u.variant_nestable.alignment = 0;
+ break;
+ default:
+ *new_field = *field;
+ break;
+ }
+ }
+ free(fields);
+ *_fields = new_fields;
+ *_nr_fields = new_nr_fields;
+end:
+ return ret;
+}
+
/*
* Reply to a register channel notification from an application on the notify
* socket. The channel metadata is also created.
int ret, ret_code = 0;
uint32_t chan_id;
uint64_t chan_reg_key;
- enum lttng_ust_ctl_channel_header type;
+ enum lttng_ust_ctl_channel_header type = LTTNG_UST_CTL_CHANNEL_HEADER_UNKNOWN;
struct ust_app *app;
struct ust_app_channel *ua_chan;
struct ust_app_session *ua_sess;
ust_reg_chan = ust_registry_channel_find(registry, chan_reg_key);
LTTNG_ASSERT(ust_reg_chan);
+ /* Channel id is set during the object creation. */
+ chan_id = ust_reg_chan->chan_id;
+
+ ret = ust_app_fixup_legacy_context_fields(&nr_fields, &fields);
+ if (ret < 0) {
+ ERR("Registering application channel due to legacy context fields fixup error: pid = %d, sock = %d",
+ app->pid, app->sock);
+ ret_code = -EINVAL;
+ goto reply;
+ }
if (!ust_reg_chan->register_done) {
/*
* TODO: eventually use the registry event count for
} else {
/* Get current already assigned values. */
type = ust_reg_chan->header_type;
+ /*
+ * Validate that the context fields match between
+ * registry and newcoming application.
+ */
+ if (!match_lttng_ust_ctl_field_array(ust_reg_chan->ctx_fields,
+ ust_reg_chan->nr_ctx_fields,
+ fields, nr_fields)) {
+ ERR("Registering application channel due to context field mismatch: pid = %d, sock = %d",
+ app->pid, app->sock);
+ ret_code = -EINVAL;
+ goto reply;
+ }
}
- /* Channel id is set during the object creation. */
- chan_id = ust_reg_chan->chan_id;
/* Append to metadata */
if (!ust_reg_chan->metadata_dumped) {
WARN("UST app recv channel failed. Communication time out: sock = %d",
sock);
} else {
- ERR("UST app recv channel failed with ret %d: sock = %d)",
+ ERR("UST app recv channel failed with ret %d: sock = %d",
ret, sock);
}
goto error;