Implement event notifiers for tracepoints
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Wed, 5 Feb 2020 19:47:19 +0000 (14:47 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 18 Nov 2020 18:13:00 +0000 (13:13 -0500)
Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: I256cc2c54179255402c5b7bc7d439508f0a6adbf

include/lttng/events.h
src/lttng-abi.c
src/lttng-events.c
src/lttng-probes.c

index 37319ac92cc3288af78bc782a8b4566f793dd038..5fb7a7804a1807ba8d5f22e960c2b31ccae2d5e0 100644 (file)
@@ -656,7 +656,9 @@ int lttng_event_notifier_enabler_enable(
 int lttng_event_notifier_enabler_disable(
                struct lttng_event_notifier_enabler *event_notifier_enabler);
 int lttng_fix_pending_events(void);
+int lttng_fix_pending_event_notifiers(void);
 int lttng_session_active(void);
+bool lttng_event_notifier_active(void);
 
 struct lttng_session *lttng_session_create(void);
 int lttng_session_enable(struct lttng_session *session);
index c62e295e5fdea2f9ebb320fd8340cfb51e52314e..775f141714724224c4178e2288acda5da2c66101 100644 (file)
@@ -1804,6 +1804,7 @@ int lttng_abi_create_event_notifier(struct file *event_notifier_group_file,
 
        switch (event_notifier_param->event.instrumentation) {
        case LTTNG_KERNEL_TRACEPOINT:
+               break;
        case LTTNG_KERNEL_KPROBE:
        case LTTNG_KERNEL_UPROBE:
        case LTTNG_KERNEL_KRETPROBE:
index df834298a0dc24a624208da9eed020d66c1fc472..1338f1295e268ab6a2a150ec7346c5a59d1cf9ec 100644 (file)
@@ -62,6 +62,7 @@ static void lttng_session_lazy_sync_event_enablers(struct lttng_session *session
 static void lttng_session_sync_event_enablers(struct lttng_session *session);
 static void lttng_event_enabler_destroy(struct lttng_event_enabler *event_enabler);
 static void lttng_event_notifier_enabler_destroy(struct lttng_event_notifier_enabler *event_notifier_enabler);
+static void lttng_event_notifier_group_sync_enablers(struct lttng_event_notifier_group *event_notifier_group);
 
 static void _lttng_event_destroy(struct lttng_event *event);
 static void _lttng_event_notifier_destroy(struct lttng_event_notifier *event_notifier);
@@ -334,6 +335,9 @@ void lttng_event_notifier_group_destroy(
                WARN_ON(ret);
        }
 
+       /* Wait for in-flight event notifier to complete */
+       synchronize_trace();
+
        irq_work_sync(&event_notifier_group->wakeup_pending);
 
        list_for_each_entry_safe(event_notifier_enabler, tmp_event_notifier_enabler,
@@ -608,6 +612,8 @@ int lttng_event_notifier_enable(struct lttng_event_notifier *event_notifier)
        }
        switch (event_notifier->instrumentation) {
        case LTTNG_KERNEL_TRACEPOINT:
+               ret = -EINVAL;
+               break;
        case LTTNG_KERNEL_SYSCALL:
        case LTTNG_KERNEL_KPROBE:
        case LTTNG_KERNEL_FUNCTION:
@@ -634,6 +640,8 @@ int lttng_event_notifier_disable(struct lttng_event_notifier *event_notifier)
        }
        switch (event_notifier->instrumentation) {
        case LTTNG_KERNEL_TRACEPOINT:
+               ret = -EINVAL;
+               break;
        case LTTNG_KERNEL_SYSCALL:
        case LTTNG_KERNEL_KPROBE:
        case LTTNG_KERNEL_FUNCTION:
@@ -993,6 +1001,8 @@ struct lttng_event_notifier *_lttng_event_notifier_create(
 
        switch (itype) {
        case LTTNG_KERNEL_TRACEPOINT:
+               event_name = event_desc->name;
+               break;
        case LTTNG_KERNEL_KPROBE:
        case LTTNG_KERNEL_UPROBE:
        case LTTNG_KERNEL_KRETPROBE:
@@ -1181,8 +1191,7 @@ int _lttng_event_unregister(struct lttng_event *event)
 
 /* Only used for tracepoints for now. */
 static
-void __always_unused register_event_notifier(
-               struct lttng_event_notifier *event_notifier)
+void register_event_notifier(struct lttng_event_notifier *event_notifier)
 {
        const struct lttng_event_desc *desc;
        int ret = -EINVAL;
@@ -1193,6 +1202,10 @@ void __always_unused register_event_notifier(
        desc = event_notifier->desc;
        switch (event_notifier->instrumentation) {
        case LTTNG_KERNEL_TRACEPOINT:
+               ret = lttng_wrapper_tracepoint_probe_register(desc->kname,
+                                                 desc->event_notifier_callback,
+                                                 event_notifier);
+               break;
        case LTTNG_KERNEL_SYSCALL:
        case LTTNG_KERNEL_KPROBE:
        case LTTNG_KERNEL_UPROBE:
@@ -1219,6 +1232,10 @@ int _lttng_event_notifier_unregister(
        desc = event_notifier->desc;
        switch (event_notifier->instrumentation) {
        case LTTNG_KERNEL_TRACEPOINT:
+               ret = lttng_wrapper_tracepoint_probe_unregister(event_notifier->desc->kname,
+                                                 event_notifier->desc->event_notifier_callback,
+                                                 event_notifier);
+               break;
        case LTTNG_KERNEL_KPROBE:
        case LTTNG_KERNEL_KRETPROBE:
        case LTTNG_KERNEL_FUNCTION:
@@ -1275,6 +1292,8 @@ void _lttng_event_notifier_destroy(struct lttng_event_notifier *event_notifier)
 {
        switch (event_notifier->instrumentation) {
        case LTTNG_KERNEL_TRACEPOINT:
+               lttng_event_desc_put(event_notifier->desc);
+               break;
        case LTTNG_KERNEL_KPROBE:
        case LTTNG_KERNEL_KRETPROBE:
        case LTTNG_KERNEL_FUNCTION:
@@ -1667,6 +1686,23 @@ int lttng_event_enabler_match_event(struct lttng_event_enabler *event_enabler,
                return 0;
 }
 
+static
+int lttng_event_notifier_enabler_match_event_notifier(struct lttng_event_notifier_enabler *event_notifier_enabler,
+               struct lttng_event_notifier *event_notifier)
+{
+       struct lttng_enabler *base_enabler = lttng_event_notifier_enabler_as_enabler(
+               event_notifier_enabler);
+
+       if (base_enabler->event_param.instrumentation != event_notifier->instrumentation)
+               return 0;
+       if (lttng_desc_match_enabler(event_notifier->desc, base_enabler)
+                       && event_notifier->group == event_notifier_enabler->group
+                       && event_notifier->user_token == event_notifier_enabler->base.user_token)
+               return 1;
+       else
+               return 0;
+}
+
 static
 struct lttng_enabler_ref *lttng_enabler_ref(
                struct list_head *enablers_ref_list,
@@ -1736,6 +1772,61 @@ void lttng_create_tracepoint_event_if_missing(struct lttng_event_enabler *event_
        }
 }
 
+static
+void lttng_create_tracepoint_event_notifier_if_missing(struct lttng_event_notifier_enabler *event_notifier_enabler)
+{
+       struct lttng_event_notifier_group *event_notifier_group = event_notifier_enabler->group;
+       struct lttng_probe_desc *probe_desc;
+       const struct lttng_event_desc *desc;
+       int i;
+       struct list_head *probe_list;
+
+       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_notifier if not
+        * already present.
+        */
+       list_for_each_entry(probe_desc, probe_list, head) {
+               for (i = 0; i < probe_desc->nr_events; i++) {
+                       int found = 0;
+                       struct hlist_head *head;
+                       struct lttng_event_notifier *event_notifier;
+
+                       desc = probe_desc->event_desc[i];
+                       if (!lttng_desc_match_enabler(desc,
+                                       lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)))
+                               continue;
+
+                       /*
+                        * Check if already created.
+                        */
+                       head = utils_borrow_hash_table_bucket(
+                               event_notifier_group->event_notifiers_ht.table,
+                               LTTNG_EVENT_NOTIFIER_HT_SIZE, desc->name);
+                       lttng_hlist_for_each_entry(event_notifier, head, hlist) {
+                               if (event_notifier->desc == desc
+                                               && event_notifier->user_token == event_notifier_enabler->base.user_token)
+                                       found = 1;
+                       }
+                       if (found)
+                               continue;
+
+                       /*
+                        * We need to create a event_notifier for this event probe.
+                        */
+                       event_notifier = _lttng_event_notifier_create(desc,
+                               event_notifier_enabler->base.user_token,
+                               event_notifier_group, NULL, NULL,
+                               LTTNG_KERNEL_TRACEPOINT);
+                       if (IS_ERR(event_notifier)) {
+                               printk(KERN_INFO "Unable to create event_notifier %s\n",
+                                       probe_desc->event_desc[i]->name);
+                       }
+               }
+       }
+}
+
 static
 void lttng_create_syscall_event_if_missing(struct lttng_event_enabler *event_enabler)
 {
@@ -1827,6 +1918,70 @@ int lttng_event_enabler_ref_events(struct lttng_event_enabler *event_enabler)
        return 0;
 }
 
+/*
+ * Create struct lttng_event_notifier if it is missing and present in the list of
+ * tracepoint probes.
+ * Should be called with sessions mutex held.
+ */
+static
+void lttng_create_event_notifier_if_missing(struct lttng_event_notifier_enabler *event_notifier_enabler)
+{
+       switch (event_notifier_enabler->base.event_param.instrumentation) {
+       case LTTNG_KERNEL_TRACEPOINT:
+               lttng_create_tracepoint_event_notifier_if_missing(event_notifier_enabler);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               break;
+       }
+}
+
+/*
+ * Create event_notifiers associated with a event_notifier enabler (if not already present).
+ */
+static
+int lttng_event_notifier_enabler_ref_event_notifiers(struct lttng_event_notifier_enabler *event_notifier_enabler)
+{
+       struct lttng_event_notifier_group *event_notifier_group = event_notifier_enabler->group;
+       struct lttng_event_notifier *event_notifier;
+
+       /* First ensure that probe event_notifiers are created for this enabler. */
+       lttng_create_event_notifier_if_missing(event_notifier_enabler);
+
+       /* Link the created event_notifier with its associated enabler. */
+       list_for_each_entry(event_notifier, &event_notifier_group->event_notifiers_head, list) {
+               struct lttng_enabler_ref *enabler_ref;
+
+               if (!lttng_event_notifier_enabler_match_event_notifier(event_notifier_enabler, event_notifier))
+                       continue;
+
+               enabler_ref = lttng_enabler_ref(&event_notifier->enablers_ref_head,
+                       lttng_event_notifier_enabler_as_enabler(event_notifier_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 = lttng_event_notifier_enabler_as_enabler(
+                               event_notifier_enabler);
+                       list_add(&enabler_ref->node,
+                               &event_notifier->enablers_ref_head);
+               }
+
+               /*
+                * Link filter bytecodes if not linked yet.
+                */
+               lttng_enabler_link_bytecode(event_notifier->desc,
+                       lttng_static_ctx, &event_notifier->bytecode_runtime_head,
+                       lttng_event_notifier_enabler_as_enabler(event_notifier_enabler));
+       }
+       return 0;
+}
+
 /*
  * Called at module load: connect the probe on all enablers matching
  * this event.
@@ -1841,6 +1996,39 @@ int lttng_fix_pending_events(void)
        return 0;
 }
 
+static bool lttng_event_notifier_group_has_active_event_notifiers(
+               struct lttng_event_notifier_group *event_notifier_group)
+{
+       struct lttng_event_notifier_enabler *event_notifier_enabler;
+
+       list_for_each_entry(event_notifier_enabler, &event_notifier_group->enablers_head,
+                       node) {
+               if (event_notifier_enabler->base.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_enabler *lttng_event_enabler_create(
                enum lttng_enabler_format_type format_type,
                struct lttng_kernel_event *event_param,
@@ -1999,6 +2187,7 @@ struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create(
 
        mutex_lock(&sessions_mutex);
        list_add(&event_notifier_enabler->node, &event_notifier_enabler->group->enablers_head);
+       lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group);
 
        mutex_unlock(&sessions_mutex);
 
@@ -2010,6 +2199,7 @@ int lttng_event_notifier_enabler_enable(
 {
        mutex_lock(&sessions_mutex);
        lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)->enabled = 1;
+       lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group);
        mutex_unlock(&sessions_mutex);
        return 0;
 }
@@ -2019,6 +2209,7 @@ int lttng_event_notifier_enabler_disable(
 {
        mutex_lock(&sessions_mutex);
        lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)->enabled = 0;
+       lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group);
        mutex_unlock(&sessions_mutex);
        return 0;
 }
@@ -2035,6 +2226,7 @@ int lttng_event_notifier_enabler_attach_bytecode(
        if (ret)
                goto error;
 
+       lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group);
        return 0;
 
 error:
@@ -2154,6 +2346,73 @@ void lttng_session_lazy_sync_event_enablers(struct lttng_session *session)
        lttng_session_sync_event_enablers(session);
 }
 
+static
+void lttng_event_notifier_group_sync_enablers(struct lttng_event_notifier_group *event_notifier_group)
+{
+       struct lttng_event_notifier_enabler *event_notifier_enabler;
+       struct lttng_event_notifier *event_notifier;
+
+       list_for_each_entry(event_notifier_enabler, &event_notifier_group->enablers_head, node)
+               lttng_event_notifier_enabler_ref_event_notifiers(event_notifier_enabler);
+
+       /*
+        * For each event_notifier, if at least one of its enablers is enabled,
+        * we enable the event_notifier, else we disable it.
+        */
+       list_for_each_entry(event_notifier, &event_notifier_group->event_notifiers_head, list) {
+               struct lttng_enabler_ref *enabler_ref;
+               struct lttng_bytecode_runtime *runtime;
+               int enabled = 0, has_enablers_without_bytecode = 0;
+
+               switch (event_notifier->instrumentation) {
+               case LTTNG_KERNEL_TRACEPOINT:
+               case LTTNG_KERNEL_SYSCALL:
+                       /* Enable event_notifiers */
+                       list_for_each_entry(enabler_ref,
+                                       &event_notifier->enablers_ref_head, node) {
+                               if (enabler_ref->ref->enabled) {
+                                       enabled = 1;
+                                       break;
+                               }
+                       }
+                       break;
+               default:
+                       /* Not handled with sync. */
+                       continue;
+               }
+
+               WRITE_ONCE(event_notifier->enabled, enabled);
+               /*
+                * Sync tracepoint registration with event_notifier enabled
+                * state.
+                */
+               if (enabled) {
+                       if (!event_notifier->registered)
+                               register_event_notifier(event_notifier);
+               } else {
+                       if (event_notifier->registered)
+                               _lttng_event_notifier_unregister(event_notifier);
+               }
+
+               /* Check if has enablers without bytecode enabled */
+               list_for_each_entry(enabler_ref,
+                               &event_notifier->enablers_ref_head, node) {
+                       if (enabler_ref->ref->enabled
+                                       && list_empty(&enabler_ref->ref->filter_bytecode_head)) {
+                               has_enablers_without_bytecode = 1;
+                               break;
+                       }
+               }
+               event_notifier->has_enablers_without_bytecode =
+                       has_enablers_without_bytecode;
+
+               /* Enable filters */
+               list_for_each_entry(runtime,
+                               &event_notifier->bytecode_runtime_head, node)
+                       lttng_filter_sync_state(runtime);
+       }
+}
+
 /*
  * Serialize at most one packet worth of metadata into a metadata
  * channel.
index 8ac061e70e6721a45704f7aa3654b583faad5c13..00f39112f04d84485bc9d482aad9c632c92dab6b 100644 (file)
@@ -25,7 +25,7 @@ static LIST_HEAD(_probe_list);
 static LIST_HEAD(lazy_probe_init);
 
 /*
- * lazy_nesting counter ensures we don't trigger lazy probe registration
+ * lazy_nesting counter ensures we don't event_notifier lazy probe registration
  * fixup while we are performing the fixup. It is protected by the
  * sessions lock.
  */
@@ -124,6 +124,8 @@ void fixup_lazy_probes(void)
        }
        ret = lttng_fix_pending_events();
        WARN_ON_ONCE(ret);
+       ret = lttng_fix_pending_event_notifiers();
+       WARN_ON_ONCE(ret);
        lazy_nesting--;
 }
 
@@ -173,7 +175,7 @@ int lttng_probe_register(struct lttng_probe_desc *desc)
         * the probe immediately, since we cannot delay event
         * registration because they are needed ASAP.
         */
-       if (lttng_session_active())
+       if (lttng_session_active() || lttng_event_notifier_active())
                fixup_lazy_probes();
 end:
        lttng_unlock_sessions();
This page took 0.032968 seconds and 4 git commands to generate.