From 993578ff7c4fce4d9a834918d192f896ba3021c7 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Mon, 13 Jan 2020 13:59:39 -0500 Subject: [PATCH] ust-app: implement event notifier support MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Jérémie Galarneau Change-Id: I2cde2b3d2530e2114bff99b1b26ac6d83f575ad9 Depends-on: lttng-ust: I5a800fc92e588c2a6a0e26282b0ad5f31c044479 --- .../lttng/event-rule/event-rule-internal.h | 19 +- src/bin/lttng-sessiond/ust-app.c | 560 +++++++++++++++++- src/bin/lttng-sessiond/ust-app.h | 29 +- src/common/event-rule/event-rule.c | 7 +- src/common/event-rule/kprobe.c | 8 +- src/common/event-rule/syscall.c | 11 +- src/common/event-rule/tracepoint.c | 77 ++- src/common/event-rule/uprobe.c | 8 +- 8 files changed, 666 insertions(+), 53 deletions(-) diff --git a/include/lttng/event-rule/event-rule-internal.h b/include/lttng/event-rule/event-rule-internal.h index ea0f46e48..31465c769 100644 --- a/include/lttng/event-rule/event-rule-internal.h +++ b/include/lttng/event-rule/event-rule-internal.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,13 @@ 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); diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c index b30089dbc..3a899775d 100644 --- a/src/bin/lttng-sessiond/ust-app.c +++ b/src/bin/lttng-sessiond/ust-app.c @@ -20,6 +20,13 @@ #include #include +#include +#include +#include +#include +#include +#include +#include #include #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. */ diff --git a/src/bin/lttng-sessiond/ust-app.h b/src/bin/lttng-sessiond/ust-app.h index 449173cd3..65ed6a255 100644 --- a/src/bin/lttng-sessiond/ust-app.h +++ b/src/bin/lttng-sessiond/ust-app.h @@ -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) diff --git a/src/common/event-rule/event-rule.c b/src/common/event-rule/event-rule.c index a42d5555c..a37559c70 100644 --- a/src/common/event-rule/event-rule.c +++ b/src/common/event-rule/event-rule.c @@ -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 diff --git a/src/common/event-rule/kprobe.c b/src/common/event-rule/kprobe.c index 6ec5cd402..01699caf1 100644 --- a/src/common/event-rule/kprobe.c +++ b/src/common/event-rule/kprobe.c @@ -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 diff --git a/src/common/event-rule/syscall.c b/src/common/event-rule/syscall.c index fde01019e..98c272d40 100644 --- a/src/common/event-rule/syscall.c +++ b/src/common/event-rule/syscall.c @@ -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 diff --git a/src/common/event-rule/tracepoint.c b/src/common/event-rule/tracepoint.c index a82151a25..6bdb754bc 100644 --- a/src/common/event-rule/tracepoint.c +++ b/src/common/event-rule/tracepoint.c @@ -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) diff --git a/src/common/event-rule/uprobe.c b/src/common/event-rule/uprobe.c index 09434b6d4..de4ee1cb0 100644 --- a/src/common/event-rule/uprobe.c +++ b/src/common/event-rule/uprobe.c @@ -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 -- 2.34.1