X-Git-Url: http://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fnotification-thread-events.c;h=5956d53ca9e6f0c4e3006ac456979a621bf5f7e6;hp=40450304297230b96cdf980afde1b516dc6c02c9;hb=959e3c66727698e58a8788aceeda5820b3c938ba;hpb=f8522f5cc357c0d80257d5ace1cd556a88305c0c diff --git a/src/bin/lttng-sessiond/notification-thread-events.c b/src/bin/lttng-sessiond/notification-thread-events.c index 404503042..5956d53ca 100644 --- a/src/bin/lttng-sessiond/notification-thread-events.c +++ b/src/bin/lttng-sessiond/notification-thread-events.c @@ -26,8 +26,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -444,6 +446,24 @@ unsigned long lttng_condition_session_rotation_hash( return hash; } +static +unsigned long lttng_condition_event_rule_hash( + const struct lttng_condition *condition) +{ + unsigned long hash, condition_type; + enum lttng_condition_status condition_status; + const struct lttng_event_rule *event_rule; + + condition_type = (unsigned long) condition->type; + + condition_status = lttng_condition_event_rule_get_rule(condition, + &event_rule); + assert(condition_status == LTTNG_CONDITION_STATUS_OK); + + hash = hash_key_ulong((void *) condition_type, lttng_ht_seed); + return hash ^ lttng_event_rule_hash(event_rule); +} + /* * The lttng_condition hashing code is kept in this file (rather than * condition.c) since it makes use of GPLv2 code (hashtable utils), which we @@ -461,6 +481,8 @@ unsigned long lttng_condition_hash(const struct lttng_condition *condition) case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING: case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED: return lttng_condition_session_rotation_hash(condition); + case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT: + return lttng_condition_event_rule_hash(condition); default: ERR("[notification-thread] Unexpected condition type caught"); abort(); @@ -509,6 +531,8 @@ enum lttng_object_type get_condition_binding_object( case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING: case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED: return LTTNG_OBJECT_TYPE_SESSION; + case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT: + return LTTNG_OBJECT_TYPE_NONE; default: return LTTNG_OBJECT_TYPE_UNKNOWN; } @@ -1984,26 +2008,79 @@ end: return ret; } +static int handle_notification_thread_command_list_triggers( + struct notification_thread_handle *handle, + struct notification_thread_state *state, + uid_t client_uid, + struct lttng_triggers **triggers, + enum lttng_error_code *_cmd_result) +{ + int ret = 0; + enum lttng_error_code cmd_result = LTTNG_OK; + struct cds_lfht_iter iter; + struct lttng_trigger_ht_element *trigger_ht_element; + struct lttng_triggers *local_triggers = NULL; + const struct lttng_credentials *creds; + + rcu_read_lock(); + + local_triggers = lttng_triggers_create(); + if (!local_triggers) { + /* Not a fatal error. */ + cmd_result = LTTNG_ERR_NOMEM; + goto end; + } + + cds_lfht_for_each_entry(state->triggers_ht, &iter, + trigger_ht_element, node) { + /* + * Only return the triggers to which the client has access. + * The root user has visibility over all triggers. + */ + creds = lttng_trigger_get_credentials(trigger_ht_element->trigger); + if (client_uid != lttng_credentials_get_uid(creds) && client_uid != 0) { + continue; + } + + ret = lttng_triggers_add(local_triggers, + trigger_ht_element->trigger); + if (ret < 0) { + /* Not a fatal error. */ + ret = 0; + cmd_result = LTTNG_ERR_NOMEM; + goto end; + } + } + + /* Transferring ownership to the caller. */ + *triggers = local_triggers; + local_triggers = NULL; + +end: + rcu_read_unlock(); + lttng_triggers_destroy(local_triggers); + *_cmd_result = cmd_result; + return ret; +} + static -int condition_is_supported(struct lttng_condition *condition) +bool condition_is_supported(struct lttng_condition *condition) { - int ret; + bool is_supported; switch (lttng_condition_get_type(condition)) { case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW: case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH: { + int ret; enum lttng_domain_type domain; ret = lttng_condition_buffer_usage_get_domain_type(condition, &domain); - if (ret) { - ret = -1; - goto end; - } + assert(ret == 0); if (domain != LTTNG_DOMAIN_KERNEL) { - ret = 1; + is_supported = true; goto end; } @@ -2011,15 +2088,43 @@ int condition_is_supported(struct lttng_condition *condition) * Older kernel tracers don't expose the API to monitor their * buffers. Therefore, we reject triggers that require that * mechanism to be available to be evaluated. + * + * Assume unsupported on error. + */ + is_supported = kernel_supports_ring_buffer_snapshot_sample_positions() == 1; + break; + } + case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT: + { + const struct lttng_event_rule *event_rule; + enum lttng_domain_type domain; + const enum lttng_condition_status status = + lttng_condition_event_rule_get_rule( + condition, &event_rule); + + assert(status == LTTNG_CONDITION_STATUS_OK); + + domain = lttng_event_rule_get_domain_type(event_rule); + if (domain != LTTNG_DOMAIN_KERNEL) { + is_supported = true; + goto end; + } + + /* + * Older kernel tracers can't emit notification. Therefore, we + * reject triggers that require that mechanism to be available + * to be evaluated. + * + * Assume unsupported on error. */ - ret = kernel_supports_ring_buffer_snapshot_sample_positions(); + is_supported = kernel_supports_event_notifiers() == 1; break; } default: - ret = 1; + is_supported = true; } end: - return ret; + return is_supported; } /* Must be called with RCU read lock held. */ @@ -2261,15 +2366,10 @@ int handle_notification_thread_command_register_trigger( condition = lttng_trigger_get_condition(trigger); assert(condition); - ret = condition_is_supported(condition); - if (ret < 0) { - goto error; - } else if (ret == 0) { + /* Some conditions require tracers to implement a minimal ABI version. */ + if (!condition_is_supported(condition)) { *cmd_result = LTTNG_ERR_NOT_SUPPORTED; goto error; - } else { - /* Feature is supported, continue. */ - ret = 0; } trigger_ht_element = zmalloc(sizeof(*trigger_ht_element)); @@ -2543,13 +2643,7 @@ int handle_notification_thread_command_unregister_trigger( cds_list_for_each_entry_safe(trigger_element, tmp, &trigger_list->list, node) { - const struct lttng_condition *current_condition = - lttng_trigger_get_const_condition( - trigger_element->trigger); - - assert(current_condition); - if (!lttng_condition_is_equal(condition, - current_condition)) { + if (!lttng_trigger_is_equal(trigger, trigger_element->trigger)) { continue; } @@ -2560,17 +2654,19 @@ int handle_notification_thread_command_unregister_trigger( } } - /* - * Remove and release the client list from - * notification_trigger_clients_ht. - */ - client_list = get_client_list_from_condition(state, condition); - assert(client_list); + if (is_trigger_action_notify(trigger)) { + /* + * Remove and release the client list from + * notification_trigger_clients_ht. + */ + client_list = get_client_list_from_condition(state, condition); + assert(client_list); - /* Put new reference and the hashtable's reference. */ - notification_client_list_put(client_list); - notification_client_list_put(client_list); - client_list = NULL; + /* Put new reference and the hashtable's reference. */ + notification_client_list_put(client_list); + notification_client_list_put(client_list); + client_list = NULL; + } /* Remove trigger from triggers_ht. */ trigger_ht_element = caa_container_of(triggers_ht_node, @@ -2658,6 +2754,20 @@ int handle_notification_thread_command( cmd->parameters.session_rotation.location, &cmd->reply_code); break; + case NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS: + { + struct lttng_triggers *triggers = NULL; + + ret = handle_notification_thread_command_list_triggers( + handle, + state, + cmd->parameters.list_triggers.uid, + &triggers, + &cmd->reply_code); + cmd->reply.list_triggers.triggers = triggers; + ret = 0; + break; + } case NOTIFICATION_COMMAND_TYPE_QUIT: DBG("[notification-thread] Received quit command"); cmd->reply_code = LTTNG_OK;