X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fnotification-thread-events.c;h=23e1c13af67281006acdf50d8a627692c363992f;hb=2758e38b1a5f82fd7e4ea621b1a3ea53187034c0;hp=6bd799279b3ff6cead92c77bb2553c6117ed5afc;hpb=8b5240601e4ddf6127e4291b7194dd5179cb35b5;p=lttng-tools.git diff --git a/src/bin/lttng-sessiond/notification-thread-events.c b/src/bin/lttng-sessiond/notification-thread-events.c index 6bd799279..23e1c13af 100644 --- a/src/bin/lttng-sessiond/notification-thread-events.c +++ b/src/bin/lttng-sessiond/notification-thread-events.c @@ -21,12 +21,14 @@ #include #include #include +#include +#include #include #include #include #include #include -#include +#include #include #include #include @@ -39,6 +41,7 @@ #include #include "condition-internal.h" +#include "event-notifier-error-accounting.h" #include "notification-thread.h" #include "notification-thread-events.h" #include "notification-thread-commands.h" @@ -48,6 +51,9 @@ #define CLIENT_POLL_MASK_IN (LPOLLIN | LPOLLERR | LPOLLHUP | LPOLLRDHUP) #define CLIENT_POLL_MASK_IN_OUT (CLIENT_POLL_MASK_IN | LPOLLOUT) +/* The tracers currently limit the capture size to PIPE_BUF (4kb on linux). */ +#define MAX_CAPTURE_SIZE (PIPE_BUF) + enum lttng_object_type { LTTNG_OBJECT_TYPE_UNKNOWN, LTTNG_OBJECT_TYPE_NONE, @@ -462,7 +468,7 @@ 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: + case LTTNG_CONDITION_TYPE_ON_EVENT: return LTTNG_OBJECT_TYPE_NONE; default: return LTTNG_OBJECT_TYPE_UNKNOWN; @@ -2017,7 +2023,7 @@ int drain_event_notifier_notification_pipe( * the pipe is closed but empty. */ ret = lttng_poll_wait_interruptible(&events, 0); - if (ret == 0 || (LTTNG_POLL_GETEV(&events, 1) & LPOLLIN) == 0) { + if (ret == 0 || (LTTNG_POLL_GETEV(&events, 0) & LPOLLIN) == 0) { /* No more notification to be read on this pipe. */ ret = 0; goto end; @@ -2118,6 +2124,40 @@ end: return ret; } +static +int condition_on_event_update_error_count(struct lttng_trigger *trigger) +{ + int ret = 0; + uint64_t error_count = 0; + struct lttng_condition *condition; + enum event_notifier_error_accounting_status status; + + condition = lttng_trigger_get_condition(trigger); + assert(lttng_condition_get_type(condition) == + LTTNG_CONDITION_TYPE_ON_EVENT); + + status = event_notifier_error_accounting_get_count(trigger, &error_count); + if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) { + uid_t trigger_owner_uid; + const char *trigger_name; + const enum lttng_trigger_status trigger_status = + lttng_trigger_get_owner_uid( + trigger, &trigger_owner_uid); + + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + if (lttng_trigger_get_name(trigger, &trigger_name) != LTTNG_TRIGGER_STATUS_OK) { + trigger_name = "(unnamed)"; + } + + ERR("Failed to get event notifier error count of trigger for update: trigger owner = %d, trigger name = '%s'", + trigger_owner_uid, trigger_name); + ret = -1; + } + + lttng_condition_on_event_set_error_count(condition, error_count); + return ret; +} + int handle_notification_thread_remove_tracer_event_source_no_result( struct notification_thread_state *state, int tracer_event_source_fd) @@ -2131,6 +2171,94 @@ int handle_notification_thread_remove_tracer_event_source_no_result( return ret; } +static +bool action_type_needs_tracer_notifier(enum lttng_action_type action_type) +{ + switch (action_type) { + case LTTNG_ACTION_TYPE_NOTIFY: + case LTTNG_ACTION_TYPE_START_SESSION: + case LTTNG_ACTION_TYPE_STOP_SESSION: + case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION: + case LTTNG_ACTION_TYPE_ROTATE_SESSION: + return true; + case LTTNG_ACTION_TYPE_GROUP: + case LTTNG_ACTION_TYPE_UNKNOWN: + default: + abort(); + } +} + +static +bool action_needs_tracer_notifier(const struct lttng_action *action) +{ + bool needs_tracer_notifier = false; + unsigned int i, count; + enum lttng_action_status action_status; + enum lttng_action_type action_type; + + assert(action); + /* If there is only one action. Check if it needs a tracer notifier. */ + action_type = lttng_action_get_type(action); + if (action_type != LTTNG_ACTION_TYPE_GROUP) { + needs_tracer_notifier = action_type_needs_tracer_notifier( + action_type); + goto end; + } + + /* + * Iterate over all the actions of the action group and check if any of + * them needs a tracer notifier. + */ + action_status = lttng_action_group_get_count(action, &count); + assert(action_status == LTTNG_ACTION_STATUS_OK); + for (i = 0; i < count; i++) { + const struct lttng_action *inner_action = + lttng_action_group_get_at_index(action, i); + + action_type = lttng_action_get_type(inner_action); + if (action_type_needs_tracer_notifier(action_type)) { + needs_tracer_notifier = true; + goto end; + } + } + +end: + return needs_tracer_notifier; +} + +/* + * A given trigger needs a tracer notifier if + * it has an event-rule condition, + * AND + * it has one or more sessiond-execution action. + */ +static +bool trigger_needs_tracer_notifier(const struct lttng_trigger *trigger) +{ + bool needs_tracer_notifier = false; + const struct lttng_condition *condition = + lttng_trigger_get_const_condition(trigger); + const struct lttng_action *action = + lttng_trigger_get_const_action(trigger); + + switch (lttng_condition_get_type(condition)) { + case LTTNG_CONDITION_TYPE_ON_EVENT: + needs_tracer_notifier = action_needs_tracer_notifier(action); + goto end; + case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE: + case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH: + case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW: + case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING: + case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED: + goto end; + case LTTNG_CONDITION_TYPE_UNKNOWN: + default: + abort(); + } +end: + return needs_tracer_notifier; +} + static int handle_notification_thread_command_list_triggers( struct notification_thread_handle *handle, struct notification_thread_state *state, @@ -2165,6 +2293,12 @@ static int handle_notification_thread_command_list_triggers( continue; } + if (trigger_needs_tracer_notifier(trigger_ht_element->trigger)) { + ret = condition_on_event_update_error_count( + trigger_ht_element->trigger); + assert(!ret); + } + ret = lttng_triggers_add(local_triggers, trigger_ht_element->trigger); if (ret < 0) { @@ -2217,12 +2351,12 @@ bool condition_is_supported(struct lttng_condition *condition) is_supported = kernel_supports_ring_buffer_snapshot_sample_positions() == 1; break; } - case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT: + case LTTNG_CONDITION_TYPE_ON_EVENT: { const struct lttng_event_rule *event_rule; enum lttng_domain_type domain; const enum lttng_condition_status status = - lttng_condition_event_rule_get_rule( + lttng_condition_on_event_get_rule( condition, &event_rule); assert(status == LTTNG_CONDITION_STATUS_OK); @@ -2424,6 +2558,18 @@ enum lttng_error_code generate_trigger_name( return ret_code; } +static inline +void notif_thread_state_remove_trigger_ht_elem( + struct notification_thread_state *state, + struct lttng_trigger_ht_element *trigger_ht_element) +{ + assert(state); + assert(trigger_ht_element); + + cds_lfht_del(state->triggers_ht, &trigger_ht_element->node); + cds_lfht_del(state->triggers_by_name_uid_ht, &trigger_ht_element->node_by_name_uid); +} + /* * FIXME A client's credentials are not checked when registering a trigger. * @@ -2530,15 +2676,13 @@ int handle_notification_thread_command_register_trigger( goto error_free_ht_element; } - if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) { + if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_ON_EVENT) { trigger_tokens_ht_element = zmalloc(sizeof(*trigger_tokens_ht_element)); if (!trigger_tokens_ht_element) { /* Fatal error. */ ret = -1; - cds_lfht_del(state->triggers_ht, - &trigger_ht_element->node); - cds_lfht_del(state->triggers_by_name_uid_ht, - &trigger_ht_element->node_by_name_uid); + notif_thread_state_remove_trigger_ht_elem(state, + trigger_ht_element); goto error_free_ht_element; } @@ -2558,12 +2702,37 @@ int handle_notification_thread_command_register_trigger( /* Internal corruption, fatal error. */ ret = -1; *cmd_result = LTTNG_ERR_TRIGGER_EXISTS; - cds_lfht_del(state->triggers_ht, - &trigger_ht_element->node); - cds_lfht_del(state->triggers_by_name_uid_ht, - &trigger_ht_element->node_by_name_uid); + notif_thread_state_remove_trigger_ht_elem(state, + trigger_ht_element); goto error_free_ht_element; } + + if (trigger_needs_tracer_notifier(trigger)) { + uint64_t error_counter_index = 0; + enum event_notifier_error_accounting_status error_accounting_status; + + error_accounting_status = event_notifier_error_accounting_register_event_notifier( + trigger, &error_counter_index); + if (error_accounting_status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) { + if (error_accounting_status == EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE) { + DBG("Event notifier group error accounting map is full"); + *cmd_result = LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING_FULL; + } else { + ERR("Failed to register event notifier for error accounting"); + *cmd_result = LTTNG_ERR_EVENT_NOTIFIER_REGISTRATION; + } + + cds_lfht_del(state->trigger_tokens_ht, + &trigger_tokens_ht_element->node); + notif_thread_state_remove_trigger_ht_elem(state, + trigger_ht_element); + goto error_free_ht_element; + } + + lttng_condition_on_event_set_error_counter_index( + condition, error_counter_index); + } + } /* @@ -2825,7 +2994,7 @@ int handle_notification_thread_command_unregister_trigger( } if (lttng_condition_get_type(condition) == - LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) { + LTTNG_CONDITION_TYPE_ON_EVENT) { struct notification_trigger_tokens_ht_element *trigger_tokens_ht_element; @@ -2836,6 +3005,11 @@ int handle_notification_thread_command_unregister_trigger( continue; } + if (trigger_needs_tracer_notifier(trigger_tokens_ht_element->trigger)) { + event_notifier_error_accounting_unregister_event_notifier( + trigger_tokens_ht_element->trigger); + } + DBG("[notification-thread] Removed trigger from tokens_ht"); cds_lfht_del(state->trigger_tokens_ht, &trigger_tokens_ht_element->node); @@ -2860,11 +3034,11 @@ int handle_notification_thread_command_unregister_trigger( client_list = NULL; } - /* Remove trigger from triggers_ht. */ trigger_ht_element = caa_container_of(triggers_ht_node, struct lttng_trigger_ht_element, node); - cds_lfht_del(state->triggers_by_name_uid_ht, &trigger_ht_element->node_by_name_uid); - cds_lfht_del(state->triggers_ht, triggers_ht_node); + + /* Remove trigger from triggers_ht. */ + notif_thread_state_remove_trigger_ht_elem(state, trigger_ht_element); /* Release the ownership of the trigger. */ lttng_trigger_destroy(trigger_ht_element->trigger); @@ -4244,10 +4418,12 @@ struct lttng_event_notifier_notification *recv_one_event_notifier_notification( int ret; uint64_t token; struct lttng_event_notifier_notification *notification = NULL; + char *capture_buffer = NULL; + size_t capture_buffer_size; void *reception_buffer; size_t reception_size; - struct lttng_ust_event_notifier_notification ust_notification; + struct lttng_ust_abi_event_notifier_notification ust_notification; struct lttng_kernel_event_notifier_notification kernel_notification; /* Init lttng_event_notifier_notification */ @@ -4280,17 +4456,55 @@ struct lttng_event_notifier_notification *recv_one_event_notifier_notification( switch(domain) { case LTTNG_DOMAIN_UST: token = ust_notification.token; + capture_buffer_size = ust_notification.capture_buf_size; break; case LTTNG_DOMAIN_KERNEL: token = kernel_notification.token; + capture_buffer_size = kernel_notification.capture_buf_size; break; default: abort(); } - notification = lttng_event_notifier_notification_create( - token, domain); + if (capture_buffer_size == 0) { + capture_buffer = NULL; + goto skip_capture; + } + + if (capture_buffer_size > MAX_CAPTURE_SIZE) { + ERR("[notification-thread] Event notifier has a capture payload size which exceeds the maximum allowed size: capture_payload_size = %zu bytes, max allowed size = %d bytes", + capture_buffer_size, MAX_CAPTURE_SIZE); + goto end; + } + + capture_buffer = zmalloc(capture_buffer_size); + if (!capture_buffer) { + ERR("[notification-thread] Failed to allocate capture buffer"); + goto end; + } + + /* Fetch additional payload (capture). */ + ret = lttng_read(notification_pipe_read_fd, capture_buffer, capture_buffer_size); + if (ret != capture_buffer_size) { + ERR("[notification-thread] Failed to read from event source pipe (fd = %i)", + notification_pipe_read_fd); + goto end; + } + +skip_capture: + notification = lttng_event_notifier_notification_create(token, domain, + capture_buffer, capture_buffer_size); + if (notification == NULL) { + goto end; + } + + /* + * Ownership transfered to the lttng_event_notifier_notification object. + */ + capture_buffer = NULL; + end: + free(capture_buffer); return notification; } @@ -4307,6 +4521,7 @@ int dispatch_one_event_notifier_notification(struct notification_thread_state *s struct notification_client_list *client_list = NULL; const char *trigger_name; int ret; + unsigned int capture_count = 0; /* Find triggers associated with this token. */ rcu_read_lock(); @@ -4339,14 +4554,34 @@ int dispatch_one_event_notifier_notification(struct notification_thread_state *s trigger_status = lttng_trigger_get_name(element->trigger, &trigger_name); assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); - evaluation = lttng_evaluation_event_rule_create( - trigger_name); + if (lttng_condition_on_event_get_capture_descriptor_count( + lttng_trigger_get_const_condition(element->trigger), + &capture_count) != LTTNG_CONDITION_STATUS_OK) { + ERR("Failed to get capture count"); + ret = -1; + goto end; + } + + if (!notification->capture_buffer && capture_count != 0) { + ERR("Expected capture but capture buffer is null"); + ret = -1; + goto end; + } + + evaluation = lttng_evaluation_on_event_create( + container_of(lttng_trigger_get_const_condition( + element->trigger), + struct lttng_condition_on_event, + parent), + trigger_name, + notification->capture_buffer, + notification->capture_buf_size, false); + if (evaluation == NULL) { ERR("[notification-thread] Failed to create event rule hit evaluation while creating and enqueuing action executor job"); ret = -1; goto end_unlock; } - client_list = get_client_list_from_condition(state, lttng_trigger_get_const_condition(element->trigger)); executor_status = action_executor_enqueue(state->executor, @@ -4404,6 +4639,7 @@ next_client: pthread_mutex_unlock(&client_list->lock); break; } + case ACTION_EXECUTOR_STATUS_INVALID: case ACTION_EXECUTOR_STATUS_ERROR: /* Fatal error, shut down everything. */ ERR("Fatal error encoutered while enqueuing action to the action executor"); @@ -4417,6 +4653,7 @@ next_client: end_unlock: notification_client_list_put(client_list); rcu_read_unlock(); +end: return ret; } @@ -4425,14 +4662,14 @@ int handle_one_event_notifier_notification( struct notification_thread_state *state, int pipe, enum lttng_domain_type domain) { - int ret; + int ret = 0; struct lttng_event_notifier_notification *notification = NULL; notification = recv_one_event_notifier_notification(pipe, domain); if (notification == NULL) { + /* Reception failed, don't consider it fatal. */ ERR("[notification-thread] Error receiving an event notifier notification from tracer: fd = %i, domain = %s", pipe, lttng_domain_type_str(domain)); - ret = -1; goto end; }