+ return 0;
+}
+
+/*
+ * Create struct lttng_trigger if it is missing and present in the list of
+ * tracepoint probes.
+ * Should be called with sessions mutex held.
+ */
+static
+void lttng_create_trigger_if_missing(struct lttng_trigger_enabler *trigger_enabler)
+{
+ switch (trigger_enabler->base.event_param.instrumentation) {
+ case LTTNG_KERNEL_TRACEPOINT:
+ lttng_create_tracepoint_trigger_if_missing(trigger_enabler);
+ break;
+ case LTTNG_KERNEL_SYSCALL:
+ lttng_create_syscall_trigger_if_missing(trigger_enabler);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+}
+
+/*
+ * Create triggers associated with a trigger enabler (if not already present).
+ */
+static
+int lttng_trigger_enabler_ref_triggers(struct lttng_trigger_enabler *trigger_enabler)
+{
+ struct lttng_trigger_group *trigger_group = trigger_enabler->group;
+ struct lttng_trigger *trigger;
+
+ /* First ensure that probe triggers are created for this enabler. */
+ lttng_create_trigger_if_missing(trigger_enabler);
+
+ /* Link the created trigger with its associated enabler. */
+ list_for_each_entry(trigger, &trigger_group->triggers_head, list) {
+ struct lttng_enabler_ref *enabler_ref;
+
+ if (!lttng_trigger_enabler_match_trigger(trigger_enabler, trigger))
+ continue;
+
+ enabler_ref = lttng_enabler_ref(&trigger->enablers_ref_head,
+ lttng_trigger_enabler_as_enabler(trigger_enabler));
+ if (!enabler_ref) {
+ /*
+ * If no backward ref, create it.
+ * Add backward ref from trigger to enabler.
+ */
+ enabler_ref = kzalloc(sizeof(*enabler_ref), GFP_KERNEL);
+ if (!enabler_ref)
+ return -ENOMEM;
+
+ enabler_ref->ref = lttng_trigger_enabler_as_enabler(
+ trigger_enabler);
+ list_add(&enabler_ref->node,
+ &trigger->enablers_ref_head);
+ }
+
+ /*
+ * Link filter bytecodes if not linked yet.
+ */
+ lttng_enabler_link_bytecode(trigger->desc,
+ trigger_group->ctx, &trigger->bytecode_runtime_head,
+ lttng_trigger_enabler_as_enabler(trigger_enabler));
+ }
+ 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_event_enablers(session);
+ return 0;
+}
+
+static bool lttng_trigger_group_has_active_triggers(
+ struct lttng_trigger_group *trigger_group)
+{
+ struct lttng_trigger_enabler *trigger_enabler;
+
+ list_for_each_entry(trigger_enabler, &trigger_group->enablers_head,
+ node) {
+ if (trigger_enabler->base.enabled)
+ return true;
+ }
+ return false;
+}
+
+bool lttng_trigger_active(void)
+{
+ struct lttng_trigger_group *trigger_group;
+
+ list_for_each_entry(trigger_group, &trigger_groups, node) {
+ if (lttng_trigger_group_has_active_triggers(trigger_group))
+ return true;
+ }
+ return false;
+}
+
+int lttng_fix_pending_triggers(void)
+{
+ struct lttng_trigger_group *trigger_group;
+
+ list_for_each_entry(trigger_group, &trigger_groups, node)
+ lttng_trigger_group_sync_enablers(trigger_group);
+ return 0;
+}
+
+struct lttng_event_enabler *lttng_event_enabler_create(
+ enum lttng_enabler_format_type format_type,
+ struct lttng_kernel_event *event_param,
+ struct lttng_channel *chan)
+{
+ struct lttng_event_enabler *event_enabler;
+
+ event_enabler = kzalloc(sizeof(*event_enabler), GFP_KERNEL);
+ if (!event_enabler)
+ return NULL;
+ event_enabler->base.format_type = format_type;
+ INIT_LIST_HEAD(&event_enabler->base.filter_bytecode_head);
+ memcpy(&event_enabler->base.event_param, event_param,
+ sizeof(event_enabler->base.event_param));
+ event_enabler->chan = chan;
+ /* ctx left NULL */
+ event_enabler->base.enabled = 0;
+ event_enabler->base.evtype = LTTNG_TYPE_ENABLER;
+ mutex_lock(&sessions_mutex);
+ list_add(&event_enabler->node, &event_enabler->chan->session->enablers_head);
+ lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
+ mutex_unlock(&sessions_mutex);
+ return event_enabler;
+}
+
+int lttng_event_enabler_enable(struct lttng_event_enabler *event_enabler)
+{
+ mutex_lock(&sessions_mutex);
+ lttng_event_enabler_as_enabler(event_enabler)->enabled = 1;
+ lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
+ mutex_unlock(&sessions_mutex);
+ return 0;
+}
+
+int lttng_event_enabler_disable(struct lttng_event_enabler *event_enabler)
+{
+ mutex_lock(&sessions_mutex);
+ lttng_event_enabler_as_enabler(event_enabler)->enabled = 0;
+ lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
+ mutex_unlock(&sessions_mutex);
+ return 0;
+}
+
+static
+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);
+
+ return 0;
+
+error_free:
+ kfree(bytecode_node);
+ return ret;
+}
+
+int lttng_event_enabler_attach_bytecode(struct lttng_event_enabler *event_enabler,
+ struct lttng_kernel_filter_bytecode __user *bytecode)
+{
+ int ret;
+ ret = lttng_enabler_attach_bytecode(
+ lttng_event_enabler_as_enabler(event_enabler), bytecode);
+ if (ret)
+ goto error;
+
+ lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
+ return 0;
+
+error:
+ 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_event_add_callsite(event, callsite);
+ default:
+ return -EINVAL;
+ }
+}
+
+int lttng_event_enabler_attach_context(struct lttng_event_enabler *event_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);
+ }