+ return 0;
+}
+
+/*
+ * Called at module load: connect the probe on all enablers matching
+ * this event.
+ * Called with sessions lock held.
+ */
+int lttng_fix_pending_events(void)
+{
+ struct lttng_session *session;
+
+ list_for_each_entry(session, &sessions, list)
+ lttng_session_lazy_sync_enablers(session);
+ return 0;
+}
+
+struct lttng_enabler *lttng_enabler_create(enum lttng_enabler_type type,
+ struct lttng_kernel_event *event_param,
+ struct lttng_channel *chan)
+{
+ struct lttng_enabler *enabler;
+
+ enabler = kzalloc(sizeof(*enabler), GFP_KERNEL);
+ if (!enabler)
+ return NULL;
+ enabler->type = type;
+ INIT_LIST_HEAD(&enabler->filter_bytecode_head);
+ memcpy(&enabler->event_param, event_param,
+ sizeof(enabler->event_param));
+ enabler->chan = chan;
+ /* ctx left NULL */
+ enabler->enabled = 0;
+ enabler->evtype = LTTNG_TYPE_ENABLER;
+ mutex_lock(&sessions_mutex);
+ list_add(&enabler->node, &enabler->chan->session->enablers_head);
+ lttng_session_lazy_sync_enablers(enabler->chan->session);
+ mutex_unlock(&sessions_mutex);
+ return enabler;
+}
+
+int lttng_enabler_enable(struct lttng_enabler *enabler)
+{
+ mutex_lock(&sessions_mutex);
+ enabler->enabled = 1;
+ lttng_session_lazy_sync_enablers(enabler->chan->session);
+ mutex_unlock(&sessions_mutex);
+ return 0;
+}
+
+int lttng_enabler_disable(struct lttng_enabler *enabler)
+{
+ mutex_lock(&sessions_mutex);
+ enabler->enabled = 0;
+ lttng_session_lazy_sync_enablers(enabler->chan->session);
+ mutex_unlock(&sessions_mutex);
+ return 0;
+}
+
+int lttng_enabler_attach_bytecode(struct lttng_enabler *enabler,
+ struct lttng_kernel_filter_bytecode __user *bytecode)
+{
+ struct lttng_filter_bytecode_node *bytecode_node;
+ uint32_t bytecode_len;
+ int ret;
+
+ ret = get_user(bytecode_len, &bytecode->len);
+ if (ret)
+ return ret;
+ bytecode_node = kzalloc(sizeof(*bytecode_node) + bytecode_len,
+ GFP_KERNEL);
+ if (!bytecode_node)
+ return -ENOMEM;
+ ret = copy_from_user(&bytecode_node->bc, bytecode,
+ sizeof(*bytecode) + bytecode_len);
+ if (ret)
+ goto error_free;
+ bytecode_node->enabler = enabler;
+ /* Enforce length based on allocated size */
+ bytecode_node->bc.len = bytecode_len;
+ list_add_tail(&bytecode_node->node, &enabler->filter_bytecode_head);
+ lttng_session_lazy_sync_enablers(enabler->chan->session);
+ return 0;
+
+error_free:
+ kfree(bytecode_node);
+ return ret;
+}
+
+int lttng_event_add_callsite(struct lttng_event *event,
+ struct lttng_kernel_event_callsite __user *callsite)
+{
+
+ switch (event->instrumentation) {
+ case LTTNG_KERNEL_UPROBE:
+ return lttng_uprobes_add_callsite(event, callsite);
+ default:
+ return -EINVAL;
+ }
+}
+
+int lttng_enabler_attach_context(struct lttng_enabler *enabler,
+ struct lttng_kernel_context *context_param)
+{
+ return -ENOSYS;
+}
+
+static
+void lttng_enabler_destroy(struct lttng_enabler *enabler)
+{
+ struct lttng_filter_bytecode_node *filter_node, *tmp_filter_node;
+
+ /* Destroy filter bytecode */
+ list_for_each_entry_safe(filter_node, tmp_filter_node,
+ &enabler->filter_bytecode_head, node) {
+ kfree(filter_node);
+ }
+
+ /* Destroy contexts */
+ lttng_destroy_context(enabler->ctx);
+
+ list_del(&enabler->node);
+ kfree(enabler);
+}
+
+/*
+ * lttng_session_sync_enablers should be called just before starting a
+ * session.
+ * Should be called with sessions mutex held.
+ */
+static
+void lttng_session_sync_enablers(struct lttng_session *session)
+{
+ struct lttng_enabler *enabler;
+ struct lttng_event *event;
+
+ list_for_each_entry(enabler, &session->enablers_head, node)
+ lttng_enabler_ref_events(enabler);
+ /*
+ * For each event, if at least one of its enablers is enabled,
+ * and its channel and session transient states are enabled, we
+ * enable the event, else we disable it.
+ */
+ list_for_each_entry(event, &session->events, list) {
+ struct lttng_enabler_ref *enabler_ref;
+ struct lttng_bytecode_runtime *runtime;
+ int enabled = 0, has_enablers_without_bytecode = 0;
+
+ switch (event->instrumentation) {
+ case LTTNG_KERNEL_TRACEPOINT:
+ case LTTNG_KERNEL_SYSCALL:
+ /* Enable events */
+ list_for_each_entry(enabler_ref,
+ &event->enablers_ref_head, node) {
+ if (enabler_ref->ref->enabled) {
+ enabled = 1;
+ break;
+ }
+ }
+ break;
+ default:
+ /* Not handled with lazy sync. */
+ continue;
+ }
+ /*
+ * Enabled state is based on union of enablers, with
+ * intesection of session and channel transient enable
+ * states.
+ */
+ enabled = enabled && session->tstate && event->chan->tstate;
+
+ WRITE_ONCE(event->enabled, enabled);
+ /*
+ * Sync tracepoint registration with event enabled
+ * state.
+ */
+ if (enabled) {
+ register_event(event);
+ } else {
+ _lttng_event_unregister(event);
+ }
+
+ /* Check if has enablers without bytecode enabled */
+ list_for_each_entry(enabler_ref,
+ &event->enablers_ref_head, node) {
+ if (enabler_ref->ref->enabled
+ && list_empty(&enabler_ref->ref->filter_bytecode_head)) {
+ has_enablers_without_bytecode = 1;
+ break;
+ }
+ }
+ event->has_enablers_without_bytecode =
+ has_enablers_without_bytecode;
+
+ /* Enable filters */
+ list_for_each_entry(runtime,
+ &event->bytecode_runtime_head, node)
+ lttng_filter_sync_state(runtime);
+ }
+}
+
+/*
+ * Apply enablers to session events, adding events to session if need
+ * be. It is required after each modification applied to an active
+ * session, and right before session "start".
+ * "lazy" sync means we only sync if required.
+ * Should be called with sessions mutex held.
+ */
+static
+void lttng_session_lazy_sync_enablers(struct lttng_session *session)
+{
+ /* We can skip if session is not active */
+ if (!session->active)
+ return;
+ lttng_session_sync_enablers(session);
+}
+
+/*
+ * Serialize at most one packet worth of metadata into a metadata
+ * channel.
+ * We grab the metadata cache mutex to get exclusive access to our metadata
+ * buffer and to the metadata cache. Exclusive access to the metadata buffer
+ * allows us to do racy operations such as looking for remaining space left in
+ * packet and write, since mutual exclusion protects us from concurrent writes.
+ * Mutual exclusion on the metadata cache allow us to read the cache content
+ * without racing against reallocation of the cache by updates.
+ * Returns the number of bytes written in the channel, 0 if no data
+ * was written and a negative value on error.
+ */
+int lttng_metadata_output_channel(struct lttng_metadata_stream *stream,
+ struct channel *chan)
+{
+ struct lib_ring_buffer_ctx ctx;
+ int ret = 0;
+ size_t len, reserve_len;
+
+ /*
+ * Ensure we support mutiple get_next / put sequences followed by
+ * put_next. The metadata cache lock protects reading the metadata
+ * cache. It can indeed be read concurrently by "get_next_subbuf" and
+ * "flush" operations on the buffer invoked by different processes.
+ * Moreover, since the metadata cache memory can be reallocated, we
+ * need to have exclusive access against updates even though we only
+ * read it.
+ */
+ mutex_lock(&stream->metadata_cache->lock);
+ WARN_ON(stream->metadata_in < stream->metadata_out);
+ if (stream->metadata_in != stream->metadata_out)
+ goto end;
+
+ /* Metadata regenerated, change the version. */
+ if (stream->metadata_cache->version != stream->version)
+ stream->version = stream->metadata_cache->version;
+
+ len = stream->metadata_cache->metadata_written -
+ stream->metadata_in;
+ if (!len)
+ goto end;
+ reserve_len = min_t(size_t,
+ stream->transport->ops.packet_avail_size(chan),
+ len);
+ lib_ring_buffer_ctx_init(&ctx, chan, NULL, reserve_len,
+ sizeof(char), -1);
+ /*
+ * If reservation failed, return an error to the caller.
+ */
+ ret = stream->transport->ops.event_reserve(&ctx, 0);
+ if (ret != 0) {
+ printk(KERN_WARNING "LTTng: Metadata event reservation failed\n");
+ goto end;
+ }
+ stream->transport->ops.event_write(&ctx,
+ stream->metadata_cache->data + stream->metadata_in,
+ reserve_len);
+ stream->transport->ops.event_commit(&ctx);
+ stream->metadata_in += reserve_len;
+ ret = reserve_len;
+
+end:
+ mutex_unlock(&stream->metadata_cache->lock);
+ return ret;
+}
+
+/*
+ * Write the metadata to the metadata cache.
+ * Must be called with sessions_mutex held.
+ * The metadata cache lock protects us from concurrent read access from
+ * thread outputting metadata content to ring buffer.
+ */
+int lttng_metadata_printf(struct lttng_session *session,
+ const char *fmt, ...)
+{
+ char *str;
+ size_t len;
+ va_list ap;
+ struct lttng_metadata_stream *stream;
+
+ WARN_ON_ONCE(!READ_ONCE(session->active));
+
+ va_start(ap, fmt);
+ str = kvasprintf(GFP_KERNEL, fmt, ap);
+ va_end(ap);
+ if (!str)
+ return -ENOMEM;
+
+ len = strlen(str);
+ mutex_lock(&session->metadata_cache->lock);
+ if (session->metadata_cache->metadata_written + len >
+ session->metadata_cache->cache_alloc) {
+ char *tmp_cache_realloc;
+ unsigned int tmp_cache_alloc_size;
+
+ tmp_cache_alloc_size = max_t(unsigned int,
+ session->metadata_cache->cache_alloc + len,
+ session->metadata_cache->cache_alloc << 1);
+ tmp_cache_realloc = vzalloc(tmp_cache_alloc_size);
+ if (!tmp_cache_realloc)
+ goto err;
+ if (session->metadata_cache->data) {
+ memcpy(tmp_cache_realloc,
+ session->metadata_cache->data,
+ session->metadata_cache->cache_alloc);
+ vfree(session->metadata_cache->data);
+ }
+
+ session->metadata_cache->cache_alloc = tmp_cache_alloc_size;
+ session->metadata_cache->data = tmp_cache_realloc;
+ }
+ memcpy(session->metadata_cache->data +
+ session->metadata_cache->metadata_written,
+ str, len);
+ session->metadata_cache->metadata_written += len;
+ mutex_unlock(&session->metadata_cache->lock);
+ kfree(str);
+
+ list_for_each_entry(stream, &session->metadata_cache->metadata_stream, list)
+ wake_up_interruptible(&stream->read_wait);
+
+ return 0;
+
+err:
+ mutex_unlock(&session->metadata_cache->lock);
+ kfree(str);
+ return -ENOMEM;
+}
+
+static
+int print_tabs(struct lttng_session *session, size_t nesting)
+{
+ size_t i;
+
+ for (i = 0; i < nesting; i++) {
+ int ret;
+
+ ret = lttng_metadata_printf(session, " ");
+ if (ret) {
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static
+int lttng_field_name_statedump(struct lttng_session *session,
+ const struct lttng_event_field *field,
+ size_t nesting)
+{
+ return lttng_metadata_printf(session, " _%s;\n", field->name);
+}
+
+static
+int _lttng_integer_type_statedump(struct lttng_session *session,
+ const struct lttng_type *type,
+ size_t nesting)
+{
+ int ret;
+
+ WARN_ON_ONCE(type->atype != atype_integer);
+ ret = print_tabs(session, nesting);
+ if (ret)
+ return ret;
+ ret = lttng_metadata_printf(session,
+ "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s }",
+ type->u.integer.size,
+ type->u.integer.alignment,
+ type->u.integer.signedness,
+ (type->u.integer.encoding == lttng_encode_none)
+ ? "none"
+ : (type->u.integer.encoding == lttng_encode_UTF8)
+ ? "UTF8"
+ : "ASCII",
+ type->u.integer.base,
+#if __BYTE_ORDER == __BIG_ENDIAN
+ type->u.integer.reverse_byte_order ? " byte_order = le;" : ""
+#else
+ type->u.integer.reverse_byte_order ? " byte_order = be;" : ""
+#endif
+ );
+ return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_struct_type_statedump(struct lttng_session *session,
+ const struct lttng_type *type,
+ size_t nesting)
+{
+ int ret;
+ uint32_t i, nr_fields;
+ unsigned int alignment;
+
+ WARN_ON_ONCE(type->atype != atype_struct_nestable);
+
+ ret = print_tabs(session, nesting);
+ if (ret)
+ return ret;
+ ret = lttng_metadata_printf(session,
+ "struct {\n");
+ if (ret)
+ return ret;
+ nr_fields = type->u.struct_nestable.nr_fields;
+ for (i = 0; i < nr_fields; i++) {
+ const struct lttng_event_field *iter_field;
+
+ iter_field = &type->u.struct_nestable.fields[i];
+ ret = _lttng_field_statedump(session, iter_field, nesting + 1);
+ if (ret)
+ return ret;
+ }
+ ret = print_tabs(session, nesting);
+ if (ret)
+ return ret;
+ alignment = type->u.struct_nestable.alignment;
+ if (alignment) {
+ ret = lttng_metadata_printf(session,
+ "} align(%u)",
+ alignment);
+ } else {
+ ret = lttng_metadata_printf(session,
+ "}");
+ }
+ return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_struct_field_statedump(struct lttng_session *session,
+ const struct lttng_event_field *field,
+ size_t nesting)
+{
+ int ret;
+
+ ret = _lttng_struct_type_statedump(session,
+ &field->type, nesting);
+ if (ret)
+ return ret;
+ return lttng_field_name_statedump(session, field, nesting);
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_variant_type_statedump(struct lttng_session *session,
+ const struct lttng_type *type,
+ size_t nesting)
+{
+ int ret;
+ uint32_t i, nr_choices;
+
+ WARN_ON_ONCE(type->atype != atype_variant_nestable);
+ /*
+ * CTF 1.8 does not allow expressing nonzero variant alignment in a nestable way.
+ */
+ if (type->u.variant_nestable.alignment != 0)
+ return -EINVAL;
+ ret = print_tabs(session, nesting);
+ if (ret)
+ return ret;
+ ret = lttng_metadata_printf(session,
+ "variant <_%s> {\n",
+ type->u.variant_nestable.tag_name);
+ if (ret)
+ return ret;
+ nr_choices = type->u.variant_nestable.nr_choices;
+ for (i = 0; i < nr_choices; i++) {
+ const struct lttng_event_field *iter_field;
+
+ iter_field = &type->u.variant_nestable.choices[i];
+ ret = _lttng_field_statedump(session, iter_field, nesting + 1);
+ if (ret)
+ return ret;
+ }
+ ret = print_tabs(session, nesting);
+ if (ret)
+ return ret;
+ ret = lttng_metadata_printf(session,
+ "}");
+ return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_variant_field_statedump(struct lttng_session *session,
+ const struct lttng_event_field *field,
+ size_t nesting)
+{
+ int ret;
+
+ ret = _lttng_variant_type_statedump(session,
+ &field->type, nesting);
+ if (ret)
+ return ret;
+ return lttng_field_name_statedump(session, field, nesting);
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_array_field_statedump(struct lttng_session *session,
+ const struct lttng_event_field *field,
+ size_t nesting)
+{
+ int ret;
+ const struct lttng_type *elem_type;
+
+ WARN_ON_ONCE(field->type.atype != atype_array_nestable);
+
+ if (field->type.u.array_nestable.alignment) {
+ ret = print_tabs(session, nesting);
+ if (ret)
+ return ret;
+ ret = lttng_metadata_printf(session,
+ "struct { } align(%u) _%s_padding;\n",
+ field->type.u.array_nestable.alignment * CHAR_BIT,
+ field->name);
+ if (ret)
+ return ret;
+ }
+ /*
+ * Nested compound types: Only array of structures and variants are
+ * currently supported.
+ */
+ elem_type = field->type.u.array_nestable.elem_type;
+ switch (elem_type->atype) {
+ case atype_integer:
+ case atype_struct_nestable:
+ case atype_variant_nestable:
+ ret = _lttng_type_statedump(session, elem_type, nesting);
+ if (ret)
+ return ret;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ ret = lttng_metadata_printf(session,
+ " _%s[%u];\n",
+ field->name,
+ field->type.u.array_nestable.length);
+ return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_sequence_field_statedump(struct lttng_session *session,
+ const struct lttng_event_field *field,
+ size_t nesting)
+{
+ int ret;
+ const char *length_name;
+ const struct lttng_type *elem_type;
+
+ WARN_ON_ONCE(field->type.atype != atype_sequence_nestable);
+
+ length_name = field->type.u.sequence_nestable.length_name;
+
+ if (field->type.u.sequence_nestable.alignment) {
+ ret = print_tabs(session, nesting);
+ if (ret)
+ return ret;
+ ret = lttng_metadata_printf(session,
+ "struct { } align(%u) _%s_padding;\n",
+ field->type.u.sequence_nestable.alignment * CHAR_BIT,
+ field->name);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Nested compound types: Only array of structures and variants are
+ * currently supported.
+ */
+ elem_type = field->type.u.sequence_nestable.elem_type;
+ switch (elem_type->atype) {
+ case atype_integer:
+ case atype_struct_nestable:
+ case atype_variant_nestable:
+ ret = _lttng_type_statedump(session, elem_type, nesting);
+ if (ret)
+ return ret;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ ret = lttng_metadata_printf(session,
+ " _%s[ _%s ];\n",
+ field->name,
+ field->type.u.sequence_nestable.length_name);
+ return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_enum_type_statedump(struct lttng_session *session,
+ const struct lttng_type *type,
+ size_t nesting)
+{
+ const struct lttng_enum_desc *enum_desc;
+ const struct lttng_type *container_type;
+ int ret;
+ unsigned int i, nr_entries;
+
+ container_type = type->u.enum_nestable.container_type;
+ if (container_type->atype != atype_integer) {
+ ret = -EINVAL;
+ goto end;
+ }
+ enum_desc = type->u.enum_nestable.desc;
+ nr_entries = enum_desc->nr_entries;
+
+ ret = print_tabs(session, nesting);
+ if (ret)
+ goto end;
+ ret = lttng_metadata_printf(session, "enum : ");
+ if (ret)
+ goto end;
+ ret = _lttng_integer_type_statedump(session, container_type, 0);
+ if (ret)
+ goto end;
+ ret = lttng_metadata_printf(session, " {\n");
+ if (ret)
+ goto end;
+ /* Dump all entries */
+ for (i = 0; i < nr_entries; i++) {
+ const struct lttng_enum_entry *entry = &enum_desc->entries[i];
+ int j, len;
+
+ ret = print_tabs(session, nesting + 1);
+ if (ret)
+ goto end;
+ ret = lttng_metadata_printf(session,
+ "\"");
+ if (ret)
+ goto end;
+ len = strlen(entry->string);
+ /* Escape the character '"' */
+ for (j = 0; j < len; j++) {
+ char c = entry->string[j];
+
+ switch (c) {
+ case '"':
+ ret = lttng_metadata_printf(session,
+ "\\\"");
+ break;
+ case '\\':
+ ret = lttng_metadata_printf(session,
+ "\\\\");
+ break;
+ default:
+ ret = lttng_metadata_printf(session,
+ "%c", c);
+ break;
+ }
+ if (ret)
+ goto end;
+ }
+ ret = lttng_metadata_printf(session, "\"");
+ if (ret)
+ goto end;
+
+ if (entry->options.is_auto) {
+ ret = lttng_metadata_printf(session, ",\n");
+ if (ret)
+ goto end;
+ } else {
+ ret = lttng_metadata_printf(session,
+ " = ");
+ if (ret)
+ goto end;
+ if (entry->start.signedness)
+ ret = lttng_metadata_printf(session,
+ "%lld", (long long) entry->start.value);
+ else
+ ret = lttng_metadata_printf(session,
+ "%llu", entry->start.value);
+ if (ret)
+ goto end;
+ if (entry->start.signedness == entry->end.signedness &&
+ entry->start.value
+ == entry->end.value) {
+ ret = lttng_metadata_printf(session,
+ ",\n");
+ } else {
+ if (entry->end.signedness) {
+ ret = lttng_metadata_printf(session,
+ " ... %lld,\n",
+ (long long) entry->end.value);
+ } else {
+ ret = lttng_metadata_printf(session,
+ " ... %llu,\n",
+ entry->end.value);
+ }
+ }
+ if (ret)
+ goto end;
+ }
+ }
+ ret = print_tabs(session, nesting);
+ if (ret)
+ goto end;
+ ret = lttng_metadata_printf(session, "}");
+end:
+ return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_enum_field_statedump(struct lttng_session *session,
+ const struct lttng_event_field *field,
+ size_t nesting)
+{
+ int ret;
+
+ ret = _lttng_enum_type_statedump(session, &field->type, nesting);
+ if (ret)
+ return ret;
+ return lttng_field_name_statedump(session, field, nesting);
+}
+
+static
+int _lttng_integer_field_statedump(struct lttng_session *session,
+ const struct lttng_event_field *field,
+ size_t nesting)
+{
+ int ret;
+
+ ret = _lttng_integer_type_statedump(session, &field->type, nesting);
+ if (ret)
+ return ret;
+ return lttng_field_name_statedump(session, field, nesting);
+}
+
+static
+int _lttng_string_type_statedump(struct lttng_session *session,
+ const struct lttng_type *type,
+ size_t nesting)
+{
+ int ret;
+
+ WARN_ON_ONCE(type->atype != atype_string);
+ /* Default encoding is UTF8 */
+ ret = print_tabs(session, nesting);
+ if (ret)
+ return ret;
+ ret = lttng_metadata_printf(session,
+ "string%s",
+ type->u.string.encoding == lttng_encode_ASCII ?
+ " { encoding = ASCII; }" : "");