+ struct lttng_enabler_ref *enabler_ref;
+
+ list_for_each_entry(enabler_ref, enablers_ref_list, node) {
+ if (enabler_ref->ref == enabler)
+ return enabler_ref;
+ }
+ return NULL;
+}
+
+static
+void lttng_event_enabler_create_tracepoint_events_if_missing(struct lttng_event_enabler_common *event_enabler)
+{
+ struct lttng_event_ht *events_ht = lttng_get_event_ht_from_enabler(event_enabler);
+ struct lttng_kernel_probe_desc *probe_desc;
+ const struct lttng_kernel_event_desc *desc;
+ struct list_head *probe_list;
+ int i;
+
+ probe_list = lttng_get_probe_list_head();
+ /*
+ * For each probe event, if we find that a probe event matches
+ * our enabler, create an associated lttng_event if not
+ * already present.
+ */
+ list_for_each_entry(probe_desc, probe_list, head) {
+ for (i = 0; i < probe_desc->nr_events; i++) {
+ bool found = false;
+ struct hlist_head *head;
+ struct lttng_kernel_event_common *event;
+ struct lttng_kernel_event_common_private *event_priv;
+
+ desc = probe_desc->event_desc[i];
+ if (!lttng_desc_match_enabler(desc, event_enabler))
+ continue;
+
+ /*
+ * Check if already created.
+ */
+ head = utils_borrow_hash_table_bucket(events_ht->table, LTTNG_EVENT_HT_SIZE, desc->event_name);
+ lttng_hlist_for_each_entry(event_priv, head, hlist_node) {
+ if (lttng_event_enabler_desc_match_event(event_enabler, desc, event_priv->pub)) {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ /*
+ * We need to create an event for this event probe.
+ */
+ event = _lttng_kernel_event_create(event_enabler, desc);
+ if (IS_ERR(event)) {
+ printk(KERN_INFO "LTTng: Unable to create event %s\n",
+ probe_desc->event_desc[i]->event_name);
+ }
+ }
+ }
+}
+
+/*
+ * Create event if it is missing and present in the list of tracepoint probes.
+ * Should be called with sessions mutex held.
+ */
+static
+void lttng_event_enabler_create_events_if_missing(struct lttng_event_enabler_common *event_enabler)
+{
+ int ret;
+
+ switch (event_enabler->event_param.instrumentation) {
+ case LTTNG_KERNEL_ABI_TRACEPOINT:
+ lttng_event_enabler_create_tracepoint_events_if_missing(event_enabler);
+ break;
+
+ case LTTNG_KERNEL_ABI_SYSCALL:
+ ret = lttng_event_enabler_create_syscall_events_if_missing(event_enabler);
+ WARN_ON_ONCE(ret);
+ break;
+
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+}
+
+static
+void lttng_event_enabler_init_event_filter(struct lttng_event_enabler_common *event_enabler,
+ struct lttng_kernel_event_common *event)
+{
+ /* Link filter bytecodes if not linked yet. */
+ lttng_enabler_link_bytecode(event->priv->desc, lttng_static_ctx,
+ &event->priv->filter_bytecode_runtime_head, &event_enabler->filter_bytecode_head);
+}
+
+static
+void lttng_event_enabler_init_event_capture(struct lttng_event_enabler_common *event_enabler,
+ struct lttng_kernel_event_common *event)
+{
+ switch (event_enabler->enabler_type) {
+ case LTTNG_EVENT_ENABLER_TYPE_RECORDER:
+ break;
+ case LTTNG_EVENT_ENABLER_TYPE_NOTIFIER:
+ {
+ struct lttng_event_notifier_enabler *event_notifier_enabler =
+ container_of(event_enabler, struct lttng_event_notifier_enabler, parent);
+ struct lttng_kernel_event_notifier *event_notifier =
+ container_of(event, struct lttng_kernel_event_notifier, parent);
+
+ /* Link capture bytecodes if not linked yet. */
+ lttng_enabler_link_bytecode(event->priv->desc,
+ lttng_static_ctx, &event_notifier->priv->capture_bytecode_runtime_head,
+ &event_notifier_enabler->capture_bytecode_head);
+ event_notifier->priv->num_captures = event_notifier_enabler->num_captures;
+ break;
+ }
+ default:
+ WARN_ON_ONCE(1);
+ }
+}
+
+/*
+ * Create events associated with an event_enabler (if not already present),
+ * and add backward reference from the event to the enabler.
+ * Should be called with sessions mutex held.
+ */
+static
+int lttng_event_enabler_ref_events(struct lttng_event_enabler_common *event_enabler)
+{
+ struct list_head *event_list_head = lttng_get_event_list_head_from_enabler(event_enabler);
+ struct lttng_kernel_event_common_private *event_priv;
+
+ lttng_syscall_table_set_wildcard_all(event_enabler);
+
+ /* First ensure that probe events are created for this enabler. */
+ lttng_event_enabler_create_events_if_missing(event_enabler);
+
+ /* Link the created event with its associated enabler. */
+ list_for_each_entry(event_priv, event_list_head, node) {
+ struct lttng_kernel_event_common *event = event_priv->pub;
+ struct lttng_enabler_ref *enabler_ref;
+
+ if (!lttng_event_enabler_match_event(event_enabler, event))
+ continue;
+
+ enabler_ref = lttng_enabler_ref(&event_priv->enablers_ref_head, event_enabler);
+ if (!enabler_ref) {
+ /*
+ * If no backward ref, create it.
+ * Add backward ref from event_notifier to enabler.
+ */
+ enabler_ref = kzalloc(sizeof(*enabler_ref), GFP_KERNEL);
+ if (!enabler_ref)
+ return -ENOMEM;
+
+ enabler_ref->ref = event_enabler;
+ list_add(&enabler_ref->node, &event_priv->enablers_ref_head);
+ }
+
+ lttng_event_enabler_init_event_filter(event_enabler, event);
+ lttng_event_enabler_init_event_capture(event_enabler, event);
+ }
+ 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_kernel_session_private *session_priv;
+
+ list_for_each_entry(session_priv, &sessions, list)
+ lttng_session_lazy_sync_event_enablers(session_priv->pub);
+ return 0;
+}
+
+static bool lttng_event_notifier_group_has_active_event_notifiers(
+ struct lttng_event_notifier_group *event_notifier_group)
+{
+ struct lttng_event_enabler_common *event_enabler;
+
+ list_for_each_entry(event_enabler, &event_notifier_group->enablers_head, node) {
+ if (event_enabler->enabled)
+ return true;
+ }
+ return false;
+}
+
+bool lttng_event_notifier_active(void)
+{
+ struct lttng_event_notifier_group *event_notifier_group;
+
+ list_for_each_entry(event_notifier_group, &event_notifier_groups, node) {
+ if (lttng_event_notifier_group_has_active_event_notifiers(event_notifier_group))
+ return true;
+ }
+ return false;
+}
+
+int lttng_fix_pending_event_notifiers(void)
+{
+ struct lttng_event_notifier_group *event_notifier_group;
+
+ list_for_each_entry(event_notifier_group, &event_notifier_groups, node)
+ lttng_event_notifier_group_sync_enablers(event_notifier_group);
+ return 0;
+}
+
+struct lttng_event_recorder_enabler *lttng_event_recorder_enabler_create(
+ enum lttng_enabler_format_type format_type,
+ struct lttng_kernel_abi_event *event_param,
+ struct lttng_kernel_channel_buffer *chan)
+{
+ struct lttng_event_recorder_enabler *event_enabler;
+
+ event_enabler = kzalloc(sizeof(*event_enabler), GFP_KERNEL);
+ if (!event_enabler)
+ return NULL;
+ event_enabler->parent.enabler_type = LTTNG_EVENT_ENABLER_TYPE_RECORDER;
+ event_enabler->parent.format_type = format_type;
+ INIT_LIST_HEAD(&event_enabler->parent.filter_bytecode_head);
+ memcpy(&event_enabler->parent.event_param, event_param,
+ sizeof(event_enabler->parent.event_param));
+ event_enabler->chan = chan;
+ /* ctx left NULL */
+ event_enabler->parent.enabled = 0;
+ return event_enabler;
+}
+
+void lttng_event_enabler_session_add(struct lttng_kernel_session *session,
+ struct lttng_event_recorder_enabler *event_enabler)
+{
+ mutex_lock(&sessions_mutex);
+ list_add(&event_enabler->parent.node, &session->priv->enablers_head);
+ event_enabler->parent.published = true;
+ lttng_session_lazy_sync_event_enablers(session);
+ mutex_unlock(&sessions_mutex);
+}
+
+int lttng_event_enabler_enable(struct lttng_event_enabler_common *event_enabler)
+{
+ mutex_lock(&sessions_mutex);
+ event_enabler->enabled = 1;
+ lttng_event_enabler_sync(event_enabler);
+ mutex_unlock(&sessions_mutex);
+ return 0;
+}
+
+int lttng_event_enabler_disable(struct lttng_event_enabler_common *event_enabler)
+{
+ mutex_lock(&sessions_mutex);
+ event_enabler->enabled = 0;
+ lttng_event_enabler_sync(event_enabler);
+ mutex_unlock(&sessions_mutex);
+ return 0;
+}
+
+static
+int lttng_enabler_attach_filter_bytecode(struct lttng_event_enabler_common *enabler,
+ struct lttng_kernel_abi_filter_bytecode __user *bytecode)
+{
+ struct lttng_kernel_bytecode_node *bytecode_node;
+ uint32_t bytecode_len;
+ int ret;
+
+ ret = get_user(bytecode_len, &bytecode->len);
+ if (ret)
+ return ret;
+ bytecode_node = lttng_kvzalloc(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->type = LTTNG_KERNEL_BYTECODE_TYPE_FILTER;
+ 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:
+ lttng_kvfree(bytecode_node);
+ return ret;
+}
+
+int lttng_event_enabler_attach_filter_bytecode(struct lttng_event_enabler_common *event_enabler,
+ struct lttng_kernel_abi_filter_bytecode __user *bytecode)
+{
+ int ret;
+ ret = lttng_enabler_attach_filter_bytecode(event_enabler, bytecode);
+ if (ret)
+ goto error;
+ lttng_event_enabler_sync(event_enabler);
+ return 0;
+
+error:
+ return ret;