ust-app: implement event notifier support
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Mon, 13 Jan 2020 18:59:39 +0000 (13:59 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 18 Jan 2021 16:48:22 +0000 (11:48 -0500)
Event notifier support mostly resemble how it is done for regular event.

We end up implementing ust_app_synchronize_event_notifier_rules which is
used in a similar fashion to ust_app_synchronize minus the dependency on
a ltt_ust_session session.

The lttng_event_rule_generate_bytecode interface is modified to return a
status code since it could fail (return NULL) for reasons other than not
having exclusions (e.g. an allocation failure).

Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I2cde2b3d2530e2114bff99b1b26ac6d83f575ad9
Depends-on: lttng-ust: I5a800fc92e588c2a6a0e26282b0ad5f31c044479

include/lttng/event-rule/event-rule-internal.h
src/bin/lttng-sessiond/ust-app.c
src/bin/lttng-sessiond/ust-app.h
src/common/event-rule/event-rule.c
src/common/event-rule/kprobe.c
src/common/event-rule/syscall.c
src/common/event-rule/tracepoint.c
src/common/event-rule/uprobe.c

index ea0f46e480ec3f2d1454de147708a4607092d49e..31465c7694dc13b701bf3cdf45e3e3d170e0b629 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <common/macros.h>
 #include <common/credentials.h>
+#include <common/sessiond-comm/sessiond-comm.h>
 #include <lttng/domain.h>
 #include <lttng/event-rule/event-rule.h>
 #include <lttng/lttng-error.h>
 struct lttng_payload;
 struct lttng_payload_view;
 
+enum lttng_event_rule_generate_exclusions_status {
+       LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OK,
+       LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE,
+       LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_ERROR,
+       LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OUT_OF_MEMORY,
+};
+
 typedef void (*event_rule_destroy_cb)(struct lttng_event_rule *event_rule);
 typedef bool (*event_rule_validate_cb)(
                const struct lttng_event_rule *event_rule);
@@ -40,8 +48,10 @@ typedef const char *(*event_rule_get_filter_cb)(
 typedef const struct lttng_filter_bytecode *(
                *event_rule_get_filter_bytecode_cb)(
                const struct lttng_event_rule *event_rule);
-typedef struct lttng_event_exclusion *(*event_rule_generate_exclusions_cb)(
-               const struct lttng_event_rule *event_rule);
+typedef enum lttng_event_rule_generate_exclusions_status (
+               *event_rule_generate_exclusions_cb)(
+               const struct lttng_event_rule *event_rule,
+               struct lttng_event_exclusion **exclusions);
 typedef unsigned long (*event_rule_hash_cb)(
                const struct lttng_event_rule *event_rule);
 
@@ -120,8 +130,9 @@ const struct lttng_filter_bytecode *lttng_event_rule_get_filter_bytecode(
  * Caller OWNS the returned object.
  */
 LTTNG_HIDDEN
-struct lttng_event_exclusion *lttng_event_rule_generate_exclusions(
-               const struct lttng_event_rule *rule);
+enum lttng_event_rule_generate_exclusions_status
+lttng_event_rule_generate_exclusions(const struct lttng_event_rule *rule,
+               struct lttng_event_exclusion **exclusions);
 
 LTTNG_HIDDEN
 const char *lttng_event_rule_type_str(enum lttng_event_rule_type type);
index b30089dbc2fd6029f590adf8c05752ddda2d3225..3a899775dcb62f15f75964626932cc535a570a71 100644 (file)
 
 #include <common/compat/errno.h>
 #include <common/common.h>
+#include <common/hashtable/utils.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/tracepoint.h>
+#include <lttng/condition/condition.h>
+#include <lttng/condition/event-rule-internal.h>
+#include <lttng/condition/event-rule.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 
 #include "buffer-registry.h"
@@ -313,6 +320,51 @@ void delete_ust_app_event(int sock, struct ust_app_event *ua_event,
        free(ua_event);
 }
 
+/*
+ * Delayed reclaim of a ust_app_event_notifier_rule object. This MUST be called
+ * through a call_rcu().
+ */
+static
+void free_ust_app_event_notifier_rule_rcu(struct rcu_head *head)
+{
+       struct ust_app_event_notifier_rule *obj = caa_container_of(
+                       head, struct ust_app_event_notifier_rule, rcu_head);
+
+       free(obj);
+}
+
+/*
+ * Delete ust app event notifier rule safely.
+ */
+static void delete_ust_app_event_notifier_rule(int sock,
+               struct ust_app_event_notifier_rule *ua_event_notifier_rule,
+               struct ust_app *app)
+{
+       int ret;
+
+       assert(ua_event_notifier_rule);
+
+       if (ua_event_notifier_rule->exclusion != NULL) {
+               free(ua_event_notifier_rule->exclusion);
+       }
+
+       if (ua_event_notifier_rule->obj != NULL) {
+               pthread_mutex_lock(&app->sock_lock);
+               ret = ustctl_release_object(sock, ua_event_notifier_rule->obj);
+               pthread_mutex_unlock(&app->sock_lock);
+               if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("Failed to release event notifier object: app = '%s' (ppid %d), ret = %d",
+                                       app->name, (int) app->ppid, ret);
+               }
+
+               free(ua_event_notifier_rule->obj);
+       }
+
+       lttng_event_rule_put(ua_event_notifier_rule->event_rule);
+       call_rcu(&ua_event_notifier_rule->rcu_head,
+                       free_ust_app_event_notifier_rule_rcu);
+}
+
 /*
  * Release ust data object of the given stream.
  *
@@ -898,6 +950,8 @@ void delete_ust_app(struct ust_app *app)
 {
        int ret, sock;
        struct ust_app_session *ua_sess, *tmp_ua_sess;
+       struct lttng_ht_iter iter;
+       struct ust_app_event_notifier_rule *event_notifier_rule;
 
        /*
         * The session list lock must be held during this function to guarantee
@@ -917,9 +971,23 @@ void delete_ust_app(struct ust_app *app)
                rcu_read_unlock();
        }
 
+       /* Remove the event notifier rules associated with this app. */
+       rcu_read_lock();
+       cds_lfht_for_each_entry (app->token_to_event_notifier_rule_ht->ht,
+                       &iter.iter, event_notifier_rule, node.node) {
+               ret = lttng_ht_del(app->token_to_event_notifier_rule_ht, &iter);
+               assert(!ret);
+
+               delete_ust_app_event_notifier_rule(
+                               app->sock, event_notifier_rule, 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);
 
        /*
         * This could be NULL if the event notifier setup failed (e.g the app
@@ -1147,6 +1215,57 @@ error:
        return NULL;
 }
 
+/*
+ * Allocate a new UST app event notifier rule.
+ */
+static struct ust_app_event_notifier_rule *alloc_ust_app_event_notifier_rule(
+               struct lttng_event_rule *event_rule, uint64_t token)
+{
+       enum lttng_event_rule_generate_exclusions_status
+                       generate_exclusion_status;
+       struct ust_app_event_notifier_rule *ua_event_notifier_rule;
+
+       ua_event_notifier_rule = zmalloc(sizeof(struct ust_app_event_notifier_rule));
+       if (ua_event_notifier_rule == NULL) {
+               PERROR("Failed to allocate ust_app_event_notifier_rule structure");
+               goto error;
+       }
+
+       ua_event_notifier_rule->enabled = 1;
+       ua_event_notifier_rule->token = token;
+       lttng_ht_node_init_u64(&ua_event_notifier_rule->node, token);
+
+       /* Get reference of the event rule. */
+       if (!lttng_event_rule_get(event_rule)) {
+               abort();
+       }
+
+       ua_event_notifier_rule->event_rule = event_rule;
+       ua_event_notifier_rule->filter = lttng_event_rule_get_filter_bytecode(event_rule);
+       generate_exclusion_status = lttng_event_rule_generate_exclusions(
+                       event_rule, &ua_event_notifier_rule->exclusion);
+       switch (generate_exclusion_status) {
+       case LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OK:
+       case LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE:
+               break;
+       default:
+               /* Error occured. */
+               ERR("Failed to generate exclusions from event rule while allocating an event notifier rule");
+               goto error_put_event_rule;
+       }
+
+       DBG3("UST app event notifier rule allocated: token = %" PRIu64,
+                       ua_event_notifier_rule->token);
+
+       return ua_event_notifier_rule;
+
+error_put_event_rule:
+       lttng_event_rule_put(event_rule);
+error:
+       free(ua_event_notifier_rule);
+       return NULL;
+}
+
 /*
  * Alloc new UST app context.
  */
@@ -1319,6 +1438,35 @@ end:
        return event;
 }
 
+/*
+ * Look-up an event notifier rule based on its token id.
+ *
+ * Must be called with the RCU read lock held.
+ * Return an ust_app_event_notifier_rule object or NULL on error.
+ */
+static struct ust_app_event_notifier_rule *find_ust_app_event_notifier_rule(
+               struct lttng_ht *ht, uint64_t token)
+{
+       struct lttng_ht_iter iter;
+       struct lttng_ht_node_u64 *node;
+       struct ust_app_event_notifier_rule *event_notifier_rule = NULL;
+
+       assert(ht);
+
+       lttng_ht_lookup(ht, &token, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if (node == NULL) {
+               DBG2("UST app event notifier rule token not found: token = %" PRIu64,
+                               token);
+               goto end;
+       }
+
+       event_notifier_rule = caa_container_of(
+                       node, struct ust_app_event_notifier_rule, node);
+end:
+       return event_notifier_rule;
+}
+
 /*
  * Create the channel context on the tracer.
  *
@@ -1770,6 +1918,179 @@ error:
        return ret;
 }
 
+static int init_ust_event_notifier_from_event_rule(
+               const struct lttng_event_rule *rule,
+               struct lttng_ust_event_notifier *event_notifier)
+{
+       enum lttng_event_rule_status status;
+       enum lttng_loglevel_type loglevel_type;
+       enum lttng_ust_loglevel_type ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
+       int loglevel = -1, ret = 0;
+       const char *pattern;
+
+       /* For now only LTTNG_EVENT_RULE_TYPE_TRACEPOINT are supported. */
+       assert(lttng_event_rule_get_type(rule) ==
+                       LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
+
+       memset(event_notifier, 0, sizeof(*event_notifier));
+
+       status = lttng_event_rule_tracepoint_get_pattern(rule, &pattern);
+       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+               /* At this point, this is a fatal error. */
+               abort();
+       }
+
+       status = lttng_event_rule_tracepoint_get_log_level_type(
+                       rule, &loglevel_type);
+       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+               /* At this point, this is a fatal error. */
+               abort();
+       }
+
+       switch (loglevel_type) {
+       case LTTNG_EVENT_LOGLEVEL_ALL:
+               ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
+               break;
+       case LTTNG_EVENT_LOGLEVEL_RANGE:
+               ust_loglevel_type = LTTNG_UST_LOGLEVEL_RANGE;
+               break;
+       case LTTNG_EVENT_LOGLEVEL_SINGLE:
+               ust_loglevel_type = LTTNG_UST_LOGLEVEL_SINGLE;
+               break;
+       default:
+               /* Unknown log level specification type. */
+               abort();
+       }
+
+       if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
+               status = lttng_event_rule_tracepoint_get_log_level(
+                               rule, &loglevel);
+               assert(status == LTTNG_EVENT_RULE_STATUS_OK);
+       }
+
+       event_notifier->event.instrumentation = LTTNG_UST_TRACEPOINT;
+       ret = lttng_strncpy(event_notifier->event.name, pattern,
+                           LTTNG_UST_SYM_NAME_LEN - 1);
+       if (ret) {
+               ERR("Failed to copy event rule pattern to notifier: pattern = '%s' ",
+                               pattern);
+               goto end;
+       }
+
+       event_notifier->event.loglevel_type = ust_loglevel_type;
+       event_notifier->event.loglevel = loglevel;
+end:
+       return ret;
+}
+
+/*
+ * Create the specified event notifier against the user space tracer of a
+ * given application.
+ */
+static int create_ust_event_notifier(struct ust_app *app,
+               struct ust_app_event_notifier_rule *ua_event_notifier_rule)
+{
+       int ret = 0;
+       struct lttng_ust_event_notifier event_notifier;
+
+       health_code_update();
+       assert(app->event_notifier_group.object);
+
+       ret = init_ust_event_notifier_from_event_rule(
+                       ua_event_notifier_rule->event_rule, &event_notifier);
+       if (ret) {
+               ERR("Failed to initialize UST event notifier from event rule: app = '%s' (ppid: %d)",
+                               app->name, app->ppid);
+               goto error;
+       }
+
+       event_notifier.event.token = ua_event_notifier_rule->token;
+
+       /* Create UST event notifier against the tracer. */
+       pthread_mutex_lock(&app->sock_lock);
+       ret = ustctl_create_event_notifier(app->sock, &event_notifier,
+                       app->event_notifier_group.object,
+                       &ua_event_notifier_rule->obj);
+       pthread_mutex_unlock(&app->sock_lock);
+       if (ret < 0) {
+               if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("Error ustctl create event notifier: name = '%s', app = '%s' (ppid: %d), ret = %d",
+                                       event_notifier.event.name, app->name,
+                                       app->ppid, ret);
+               } else {
+                       /*
+                        * This is normal behavior, an application can die
+                        * during the creation process. Don't report an error so
+                        * the execution can continue normally.
+                        */
+                       ret = 0;
+                       DBG3("UST app create event notifier failed (application is dead): app = '%s' (ppid = %d)",
+                                       app->name, app->ppid);
+               }
+
+               goto error;
+       }
+
+       ua_event_notifier_rule->handle = ua_event_notifier_rule->obj->handle;
+
+       DBG2("UST app event notifier %s created successfully: app = '%s' (ppid: %d), object: %p",
+                       event_notifier.event.name, app->name, app->ppid,
+                       ua_event_notifier_rule->obj);
+
+       health_code_update();
+
+       /* Set filter if one is present. */
+       if (ua_event_notifier_rule->filter) {
+               ret = set_ust_object_filter(app, ua_event_notifier_rule->filter,
+                               ua_event_notifier_rule->obj);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       /* Set exclusions for the event. */
+       if (ua_event_notifier_rule->exclusion) {
+               ret = set_ust_object_exclusions(app,
+                               ua_event_notifier_rule->exclusion,
+                               ua_event_notifier_rule->obj);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       /*
+        * We now need to explicitly enable the event, since it
+        * is disabled at creation.
+        */
+       ret = enable_ust_object(app, ua_event_notifier_rule->obj);
+       if (ret < 0) {
+               /*
+                * If we hit an EPERM, something is wrong with our enable call.
+                * If we get an EEXIST, there is a problem on the tracer side
+                * since we just created it.
+                */
+               switch (ret) {
+               case -LTTNG_UST_ERR_PERM:
+                       /* Code flow problem. */
+                       abort();
+               case -LTTNG_UST_ERR_EXIST:
+                       /* It's OK for our use case. */
+                       ret = 0;
+                       break;
+               default:
+                       break;
+               }
+
+               goto error;
+       }
+
+       ua_event_notifier_rule->enabled = true;
+
+error:
+       health_code_update();
+       return ret;
+}
+
 /*
  * Copy data between an UST app event and a LTT event.
  */
@@ -3139,6 +3460,7 @@ error:
 /*
  * Create UST app event and create it on the tracer side.
  *
+ * Must be called with the RCU read side lock held.
  * Called with ust app session mutex held.
  */
 static
@@ -3178,8 +3500,8 @@ int create_ust_app_event(struct ust_app_session *ua_sess,
 
        add_unique_ust_app_event(ua_chan, ua_event);
 
-       DBG2("UST app create event %s for PID %d completed", ua_event->name,
-                       app->pid);
+       DBG2("UST app create event completed: app = '%s' (ppid: %d)",
+                       app->name, app->ppid);
 
 end:
        return ret;
@@ -3190,6 +3512,59 @@ error:
        return ret;
 }
 
+/*
+ * Create UST app event notifier rule and create it on the tracer side.
+ *
+ * Must be called with the RCU read side lock held.
+ * Called with ust app session mutex held.
+ */
+static
+int create_ust_app_event_notifier_rule(struct lttng_event_rule *rule,
+               struct ust_app *app, uint64_t token)
+{
+       int ret = 0;
+       struct ust_app_event_notifier_rule *ua_event_notifier_rule;
+
+       ua_event_notifier_rule = alloc_ust_app_event_notifier_rule(rule, token);
+       if (ua_event_notifier_rule == NULL) {
+               ret = -ENOMEM;
+               goto end;
+       }
+
+       /* Create it on the tracer side. */
+       ret = create_ust_event_notifier(app, ua_event_notifier_rule);
+       if (ret < 0) {
+               /*
+                * Not found previously means that it does not exist on the
+                * tracer. If the application reports that the event existed,
+                * it means there is a bug in the sessiond or lttng-ust
+                * (or corruption, etc.)
+                */
+               if (ret == -LTTNG_UST_ERR_EXIST) {
+                       ERR("Tracer for application reported that an event notifier being created already exists: "
+                                       "token = \"%" PRIu64 "\", pid = %d, ppid = %d, uid = %d, gid = %d",
+                                       token,
+                                       app->pid, app->ppid, app->uid,
+                                       app->gid);
+               }
+               goto error;
+       }
+
+       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' (ppid: %d), token = %" PRIu64,
+                       app->name, app->ppid, token);
+
+end:
+       return ret;
+
+error:
+       /* The RCU read side lock is already being held by the caller. */
+       delete_ust_app_event_notifier_rule(-1, ua_event_notifier_rule, app);
+       return ret;
+}
+
 /*
  * Create UST metadata and open it on the tracer side.
  *
@@ -3384,6 +3759,7 @@ struct ust_app *ust_app_create(struct ust_register_msg *msg, int sock)
        lta->ust_objd = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
        lta->ust_sessions_objd = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
        lta->notify_sock = -1;
+       lta->token_to_event_notifier_rule_ht = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
 
        /* Copy name and make sure it's NULL terminated. */
        strncpy(lta->name, msg->name, sizeof(lta->name));
@@ -5074,6 +5450,149 @@ end:
        return ret;
 }
 
+/* Called with RCU read-side lock held. */
+static
+void ust_app_synchronize_event_notifier_rules(struct ust_app *app)
+{
+       int ret = 0;
+       enum lttng_error_code ret_code;
+       enum lttng_trigger_status t_status;
+       struct lttng_ht_iter app_trigger_iter;
+       struct lttng_triggers *triggers = NULL;
+       struct ust_app_event_notifier_rule *event_notifier_rule;
+       unsigned int count, i;
+
+       /*
+        * Currrently, registering or unregistering a trigger with an
+        * event rule condition causes a full synchronization of the event
+        * notifiers.
+        *
+        * The first step attempts to add an event notifier for all registered
+        * triggers that apply to the user space tracers. Then, the
+        * application's event notifiers rules are all checked against the list
+        * of registered triggers. Any event notifier that doesn't have a
+        * matching trigger can be assumed to have been disabled.
+        *
+        * All of this is inefficient, but is put in place to get the feature
+        * rolling as it is simpler at this moment. It will be optimized Soon™
+        * to allow the state of enabled
+        * event notifiers to be synchronized in a piece-wise way.
+        */
+
+       /* Get all triggers using uid 0 (root) */
+       ret_code = notification_thread_command_list_triggers(
+                       notification_thread_handle, 0, &triggers);
+       if (ret_code != LTTNG_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       assert(triggers);
+
+       t_status = lttng_triggers_get_count(triggers, &count);
+       if (t_status != LTTNG_TRIGGER_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               struct lttng_condition *condition;
+               struct lttng_event_rule *event_rule;
+               struct lttng_trigger *trigger;
+               const struct ust_app_event_notifier_rule *looked_up_event_notifier_rule;
+               enum lttng_condition_status condition_status;
+               uint64_t token;
+
+               trigger = lttng_triggers_borrow_mutable_at_index(triggers, i);
+               assert(trigger);
+
+               token = lttng_trigger_get_tracer_token(trigger);
+               condition = lttng_trigger_get_condition(trigger);
+
+               if (lttng_condition_get_type(condition) != LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+                       /* Does not apply */
+                       continue;
+               }
+
+               condition_status = lttng_condition_event_rule_borrow_rule_mutable(condition, &event_rule);
+               assert(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+               if (lttng_event_rule_get_domain_type(event_rule) == LTTNG_DOMAIN_KERNEL) {
+                       /* Skip kernel related triggers. */
+                       continue;
+               }
+
+               /*
+                * Find or create the associated token event rule. The caller
+                * holds the RCU read lock, so this is safe to call without
+                * explicitly acquiring it here.
+                */
+               looked_up_event_notifier_rule = find_ust_app_event_notifier_rule(
+                               app->token_to_event_notifier_rule_ht, token);
+               if (!looked_up_event_notifier_rule) {
+                       ret = create_ust_app_event_notifier_rule(event_rule, app, token);
+                       if (ret < 0) {
+                               goto end;
+                       }
+               }
+       }
+
+       rcu_read_lock();
+       /* Remove all unknown event sources from the app. */
+       cds_lfht_for_each_entry (app->token_to_event_notifier_rule_ht->ht,
+                       &app_trigger_iter.iter, event_notifier_rule,
+                       node.node) {
+               const uint64_t app_token = event_notifier_rule->token;
+               bool found = false;
+
+               /*
+                * Check if the app event trigger still exists on the
+                * notification side.
+                */
+               for (i = 0; i < count; i++) {
+                       uint64_t notification_thread_token;
+                       const struct lttng_trigger *trigger =
+                                       lttng_triggers_get_at_index(
+                                                       triggers, i);
+
+                       assert(trigger);
+
+                       notification_thread_token =
+                                       lttng_trigger_get_tracer_token(trigger);
+
+                       if (notification_thread_token == app_token) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (found) {
+                       /* Still valid. */
+                       continue;
+               }
+
+               /*
+                * This trigger was unregistered, disable it on the tracer's
+                * side.
+                */
+               ret = lttng_ht_del(app->token_to_event_notifier_rule_ht,
+                               &app_trigger_iter);
+               assert(ret == 0);
+
+               /* Callee logs errors. */
+               (void) disable_ust_object(app, event_notifier_rule->obj);
+
+               delete_ust_app_event_notifier_rule(
+                               app->sock, event_notifier_rule, app);
+       }
+
+       rcu_read_unlock();
+
+end:
+       lttng_triggers_destroy(triggers);
+       return;
+}
+
 /*
  * The caller must ensure that the application is compatible and is tracked
  * by the process attribute trackers.
@@ -5231,6 +5750,30 @@ void ust_app_global_update(struct ltt_ust_session *usess, struct ust_app *app)
        }
 }
 
+/*
+ * Add all event notifiers to an application.
+ *
+ * Called with session lock held.
+ * Called with RCU read-side lock held.
+ */
+void ust_app_global_update_event_notifier_rules(struct ust_app *app)
+{
+       DBG2("UST application global event notifier rules update: app = '%s' (ppid: %d)",
+                       app->name, app->ppid);
+
+       if (!app->compatible) {
+               return;
+       }
+
+       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' (ppid: %d)",
+                               app->name, app->ppid);
+               return;
+       }
+
+       ust_app_synchronize_event_notifier_rules(app);
+}
+
 /*
  * Called with session lock held.
  */
@@ -5246,6 +5789,19 @@ void ust_app_global_update_all(struct ltt_ust_session *usess)
        rcu_read_unlock();
 }
 
+void ust_app_global_update_all_event_notifier_rules(void)
+{
+       struct lttng_ht_iter iter;
+       struct ust_app *app;
+
+       rcu_read_lock();
+       cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+               ust_app_global_update_event_notifier_rules(app);
+       }
+
+       rcu_read_unlock();
+}
+
 /*
  * Add context to a specific channel for global UST domain.
  */
index 449173cd36a94a2f965a6a31c2ee351732e8fc22..65ed6a2551eb96c63db64c900032a8faed233da3 100644 (file)
@@ -112,6 +112,23 @@ struct ust_app_event {
        struct lttng_event_exclusion *exclusion;
 };
 
+struct ust_app_event_notifier_rule {
+       int enabled;
+       int handle;
+       struct lttng_ust_object_data *obj;
+       /* Holds a strong reference. */
+       struct lttng_event_rule *event_rule;
+       /* Unique ID returned by the tracer to identify this event notifier. */
+       uint64_t token;
+       struct lttng_ht_node_u64 node;
+       /* The event_rule object owns the filter. */
+       const struct lttng_filter_bytecode *filter;
+       /* Owned by this. */
+       struct lttng_event_exclusion *exclusion;
+       /* For delayed reclaim. */
+       struct rcu_head rcu_head;
+};
+
 struct ust_app_stream {
        int handle;
        char pathname[PATH_MAX];
@@ -303,6 +320,11 @@ struct ust_app {
                struct lttng_ust_object_data *object;
                struct lttng_pipe *event_pipe;
        } event_notifier_group;
+       /*
+        * Hashtable indexing the application's event notifier rule's
+        * (ust_app_event_notifier_rule) by their token's value.
+        */
+       struct lttng_ht *token_to_event_notifier_rule_ht;
 };
 
 #ifdef HAVE_LIBLTTNG_UST_CTL
@@ -330,6 +352,8 @@ int ust_app_add_ctx_channel_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_context *uctx);
 void ust_app_global_update(struct ltt_ust_session *usess, struct ust_app *app);
 void ust_app_global_update_all(struct ltt_ust_session *usess);
+void ust_app_global_update_event_notifier_rules(struct ust_app *app);
+void ust_app_global_update_all_event_notifier_rules(void);
 
 void ust_app_clean_list(void);
 int ust_app_ht_alloc(void);
@@ -457,7 +481,10 @@ static inline
 void ust_app_global_update(struct ltt_ust_session *usess, struct ust_app *app)
 {}
 static inline
-void ust_app_global_update_tokens(struct ust_app *app)
+void ust_app_global_update_event_notifier_rules(struct ust_app *app)
+{}
+static inline
+void ust_app_global_update_all_event_notifier_rules(void)
 {}
 static inline
 int ust_app_setup_event_notifier_group(struct ust_app *app)
index a42d5555c409eff5e0693becd92b55a6ea1cb2dc..a37559c70608cf174a5401854031521e0a506409 100644 (file)
@@ -267,11 +267,12 @@ const struct lttng_filter_bytecode *lttng_event_rule_get_filter_bytecode(
 }
 
 LTTNG_HIDDEN
-struct lttng_event_exclusion *lttng_event_rule_generate_exclusions(
-               const struct lttng_event_rule *rule)
+enum lttng_event_rule_generate_exclusions_status
+lttng_event_rule_generate_exclusions(const struct lttng_event_rule *rule,
+               struct lttng_event_exclusion **exclusions)
 {
        assert(rule->generate_exclusions);
-       return rule->generate_exclusions(rule);
+       return rule->generate_exclusions(rule, exclusions);
 }
 
 LTTNG_HIDDEN
index 6ec5cd402df5c590ab115a1384d6e5e34ec161b9..01699caf1ade9407948e8024889095954d3948c9 100644 (file)
@@ -170,11 +170,13 @@ lttng_event_rule_kprobe_get_filter_bytecode(const struct lttng_event_rule *rule)
        return NULL;
 }
 
-static struct lttng_event_exclusion *
-lttng_event_rule_kprobe_generate_exclusions(const struct lttng_event_rule *rule)
+static enum lttng_event_rule_generate_exclusions_status
+lttng_event_rule_kprobe_generate_exclusions(const struct lttng_event_rule *rule,
+               struct lttng_event_exclusion **exclusions)
 {
        /* Not supported. */
-       return NULL;
+       *exclusions = NULL;
+       return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
 }
 
 static unsigned long
index fde01019e0416c93c25afc75b10988087687ccc7..98c272d40c8ece449793c6a9e7d60beeea90bbcf 100644 (file)
@@ -217,12 +217,13 @@ lttng_event_rule_syscall_get_internal_filter_bytecode(
        return syscall->internal_filter.bytecode;
 }
 
-static struct lttng_event_exclusion *
-lttng_event_rule_syscall_generate_exclusions(
-               const struct lttng_event_rule *rule)
+static enum lttng_event_rule_generate_exclusions_status
+lttng_event_rule_syscall_generate_exclusions(const struct lttng_event_rule *rule,
+               struct lttng_event_exclusion **exclusions)
 {
-       /* Not supported. */
-       return NULL;
+       /* Unsupported. */
+       *exclusions = NULL;
+       return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
 }
 
 static unsigned long
index a82151a254c6db6d5118754911fef55bfb55b8b4..6bdb754bc98f5f7917dbeb93bd59f0b10f8b663b 100644 (file)
@@ -473,19 +473,22 @@ lttng_event_rule_tracepoint_get_internal_filter_bytecode(
        return tracepoint->internal_filter.bytecode;
 }
 
-static struct lttng_event_exclusion *
+static enum lttng_event_rule_generate_exclusions_status
 lttng_event_rule_tracepoint_generate_exclusions(
-               const struct lttng_event_rule *rule)
+               const struct lttng_event_rule *rule,
+               struct lttng_event_exclusion **_exclusions)
 {
-       enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
-       enum lttng_event_rule_status status;
-       struct lttng_event_exclusion *local_exclusions = NULL;
-       struct lttng_event_exclusion *ret_exclusions = NULL;
-       unsigned int nb_exclusions = 0;
-       unsigned int i;
+       unsigned int nb_exclusions = 0, i;
+       enum lttng_domain_type domain_type;
+       struct lttng_event_exclusion *exclusions;
+       enum lttng_event_rule_status event_rule_status;
+       enum lttng_event_rule_generate_exclusions_status ret_status;
 
-       status = lttng_event_rule_tracepoint_get_domain_type(rule, &domain_type);
-       assert(status == LTTNG_EVENT_RULE_STATUS_OK);
+       assert(_exclusions);
+
+       event_rule_status = lttng_event_rule_tracepoint_get_domain_type(
+                       rule, &domain_type);
+       assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
 
        switch (domain_type) {
        case LTTNG_DOMAIN_KERNEL:
@@ -493,50 +496,60 @@ lttng_event_rule_tracepoint_generate_exclusions(
        case LTTNG_DOMAIN_LOG4J:
        case LTTNG_DOMAIN_PYTHON:
                /* Not supported. */
-               ret_exclusions = NULL;
+               exclusions = NULL;
+               ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
                goto end;
        case LTTNG_DOMAIN_UST:
                /* Exclusions supported. */
                break;
        default:
+               /* Unknown domain. */
                abort();
        }
 
-       status = lttng_event_rule_tracepoint_get_exclusions_count(
+       event_rule_status = lttng_event_rule_tracepoint_get_exclusions_count(
                        rule, &nb_exclusions);
-       assert(status == LTTNG_EVENT_RULE_STATUS_OK);
+       assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
        if (nb_exclusions == 0) {
                /* Nothing to do. */
-               ret_exclusions = NULL;
+               exclusions = NULL;
+               ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
                goto end;
        }
 
-       local_exclusions = zmalloc(sizeof(struct lttng_event_exclusion) +
-                                  (LTTNG_SYMBOL_NAME_LEN * nb_exclusions));
-       if (!local_exclusions) {
+       exclusions = zmalloc(sizeof(struct lttng_event_exclusion) +
+                       (LTTNG_SYMBOL_NAME_LEN * nb_exclusions));
+       if (!exclusions) {
                PERROR("Failed to allocate exclusions buffer");
-               ret_exclusions = NULL;
+               ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OUT_OF_MEMORY;
                goto end;
        }
 
-       local_exclusions->count = nb_exclusions;
+       exclusions->count = nb_exclusions;
        for (i = 0; i < nb_exclusions; i++) {
-               /* Truncation is already checked at the setter level. */
-               const char *tmp;
-
-               status = lttng_event_rule_tracepoint_get_exclusion_at_index(
-                               rule, i, &tmp);
-               assert(status == LTTNG_EVENT_RULE_STATUS_OK);
-               strncpy(local_exclusions->names[i], tmp, LTTNG_SYMBOL_NAME_LEN);
-               local_exclusions->names[i][LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
+               int copy_ret;
+               const char *exclusion_str;
+
+               event_rule_status =
+                               lttng_event_rule_tracepoint_get_exclusion_at_index(
+                                               rule, i, &exclusion_str);
+               assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
+
+               copy_ret = lttng_strncpy(exclusions->names[i], exclusion_str,
+                               LTTNG_SYMBOL_NAME_LEN);
+               if (copy_ret) {
+                       free(exclusions);
+                       exclusions = NULL;
+                       ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_ERROR;
+                       goto end;
+               }
        }
 
-       /* Pass ownership. */
-       ret_exclusions = local_exclusions;
-       local_exclusions = NULL;
+       ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OK;
+
 end:
-       free(local_exclusions);
-       return ret_exclusions;
+       *_exclusions = exclusions;
+       return ret_status;
 }
 
 static void destroy_lttng_exclusions_element(void *ptr)
index 09434b6d41f8ab965542b5731432423cce68bdfd..de4ee1cb0add4efa908cbc57fcd46d86f8b02cde 100644 (file)
@@ -162,11 +162,13 @@ lttng_event_rule_uprobe_get_filter_bytecode(const struct lttng_event_rule *rule)
        return NULL;
 }
 
-static struct lttng_event_exclusion *
-lttng_event_rule_uprobe_generate_exclusions(const struct lttng_event_rule *rule)
+static enum lttng_event_rule_generate_exclusions_status
+lttng_event_rule_uprobe_generate_exclusions(const struct lttng_event_rule *rule,
+               struct lttng_event_exclusion **exclusions)
 {
        /* Unsupported. */
-       return NULL;
+       *exclusions = NULL;
+       return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
 }
 
 static unsigned long
This page took 0.041369 seconds and 5 git commands to generate.