Fix: data reception is called event when only FDS are expected for reception
[lttng-tools.git] / src / bin / lttng-sessiond / notification-thread-events.c
index 59b10e9db718f82c791abbddd4f8d1e4a8d20ded..655400f9484c790af2116f1855203a806f562e2d 100644 (file)
 #include <common/macros.h>
 #include <lttng/condition/condition.h>
 #include <lttng/action/action-internal.h>
-#include <lttng/action/group-internal.h>
+#include <lttng/action/list-internal.h>
 #include <lttng/domain-internal.h>
 #include <lttng/notification/notification-internal.h>
 #include <lttng/condition/condition-internal.h>
 #include <lttng/condition/buffer-usage-internal.h>
 #include <lttng/condition/session-consumed-size-internal.h>
 #include <lttng/condition/session-rotation-internal.h>
-#include <lttng/condition/on-event-internal.h>
+#include <lttng/condition/event-rule-matches-internal.h>
 #include <lttng/domain-internal.h>
 #include <lttng/notification/channel-internal.h>
 #include <lttng/trigger/trigger-internal.h>
@@ -353,6 +353,8 @@ const char *notification_command_type_str(
                return "REMOVE_TRACER_EVENT_SOURCE";
        case NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS:
                return "LIST_TRIGGERS";
+       case NOTIFICATION_COMMAND_TYPE_GET_TRIGGER:
+               return "GET_TRIGGER";
        case NOTIFICATION_COMMAND_TYPE_QUIT:
                return "QUIT";
        case NOTIFICATION_COMMAND_TYPE_CLIENT_COMMUNICATION_UPDATE:
@@ -371,7 +373,7 @@ int match_trigger_by_name_uid(struct cds_lfht_node *node,
                const void *key)
 {
        bool match = false;
-       const char *name;
+       const char *element_trigger_name;
        const char *key_name;
        enum lttng_trigger_status status;
        const struct lttng_credentials *key_creds;
@@ -383,14 +385,25 @@ int match_trigger_by_name_uid(struct cds_lfht_node *node,
                                struct lttng_trigger_ht_element,
                                node_by_name_uid);
 
-       status = lttng_trigger_get_name(trigger_ht_element->trigger, &name);
-       assert(status == LTTNG_TRIGGER_STATUS_OK);
+       status = lttng_trigger_get_name(trigger_ht_element->trigger,
+                       &element_trigger_name);
+       element_trigger_name = status == LTTNG_TRIGGER_STATUS_OK ?
+                       element_trigger_name : NULL;
 
        status = lttng_trigger_get_name(trigger_key, &key_name);
-       assert(status == LTTNG_TRIGGER_STATUS_OK);
+       key_name = status == LTTNG_TRIGGER_STATUS_OK ? key_name : NULL;
 
-       /* Compare the names. */
-       if (strcmp(name, key_name) != 0) {
+       /*
+        * Compare the names.
+        * Consider null names as not equal. This is to maintain backwards
+        * compatibility with pre-2.13 anonymous triggers. Multiples anonymous
+        * triggers are allowed for a given user.
+        */
+       if (!element_trigger_name || !key_name) {
+               goto end;
+       }
+
+       if (strcmp(element_trigger_name, key_name) != 0) {
                goto end;
        }
 
@@ -469,7 +482,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_ON_EVENT:
+       case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
                return LTTNG_OBJECT_TYPE_NONE;
        default:
                return LTTNG_OBJECT_TYPE_UNKNOWN;
@@ -1089,6 +1102,7 @@ int notification_thread_client_subscribe(struct notification_client *client,
        struct notification_client_list *client_list = NULL;
        struct lttng_condition_list_element *condition_list_element = NULL;
        struct notification_client_list_element *client_list_element = NULL;
+       struct lttng_trigger_ht_element *trigger_ht_element;
        enum lttng_notification_channel_status status =
                        LTTNG_NOTIFICATION_CHANNEL_STATUS_OK;
 
@@ -1120,9 +1134,11 @@ int notification_thread_client_subscribe(struct notification_client *client,
         */
        CDS_INIT_LIST_HEAD(&condition_list_element->node);
        condition_list_element->condition = condition;
+       condition = NULL;
        cds_list_add(&condition_list_element->node, &client->condition_list);
 
-       client_list = get_client_list_from_condition(state, condition);
+       client_list = get_client_list_from_condition(
+                       state, condition_list_element->condition);
        if (!client_list) {
                /*
                 * No notification-emiting trigger registered with this
@@ -1138,19 +1154,20 @@ int notification_thread_client_subscribe(struct notification_client *client,
         * at this point so that conditions that are already TRUE result
         * in a notification being sent out.
         *
-        * The client_list's trigger is used without locking the list itself.
-        * This is correct since the list doesn't own the trigger and the
-        * object is immutable.
+        * Note the iteration on all triggers which share an identical
+        * `condition` than the one to which the client is registering. This is
+        * done to ensure that the client receives a distinct notification for
+        * all triggers that have a `notify` action that have this condition.
         */
-       struct lttng_trigger_ht_element *trigger_ht_element;
        pthread_mutex_lock(&client_list->lock);
        cds_list_for_each_entry(trigger_ht_element,
                        &client_list->triggers_list, client_list_trigger_node) {
-               if (evaluate_condition_for_client(trigger_ht_element->trigger, condition,
+               if (evaluate_condition_for_client(trigger_ht_element->trigger, condition_list_element->condition,
                                client, state)) {
                        WARN("[notification-thread] Evaluation of a condition on client subscription failed, aborting.");
                        ret = -1;
                        free(client_list_element);
+                       pthread_mutex_unlock(&client_list->lock);
                        goto end;
                }
        }
@@ -1174,10 +1191,12 @@ end:
        if (client_list) {
                notification_client_list_put(client_list);
        }
+       lttng_condition_destroy(condition);
        return ret;
 error:
        free(condition_list_element);
        free(client_list_element);
+       lttng_condition_destroy(condition);
        return ret;
 }
 
@@ -1949,9 +1968,9 @@ int handle_notification_thread_command_session_rotation(
                 * Ownership of `evaluation` transferred to the action executor
                 * no matter the result.
                 */
-               executor_status = action_executor_enqueue(state->executor,
-                               trigger, evaluation, &session_creds,
-                               client_list);
+               executor_status = action_executor_enqueue_trigger(
+                               state->executor, trigger, evaluation,
+                               &session_creds, client_list);
                evaluation = NULL;
                switch (executor_status) {
                case ACTION_EXECUTOR_STATUS_OK:
@@ -2170,40 +2189,6 @@ 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)
@@ -2251,12 +2236,6 @@ static int handle_notification_thread_command_list_triggers(
                        continue;
                }
 
-               if (lttng_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) {
@@ -2278,6 +2257,69 @@ end:
        return ret;
 }
 
+static inline void get_trigger_info_for_log(const struct lttng_trigger *trigger,
+               const char **trigger_name,
+               uid_t *trigger_owner_uid)
+{
+       enum lttng_trigger_status trigger_status;
+
+       trigger_status = lttng_trigger_get_name(trigger, trigger_name);
+       switch (trigger_status) {
+       case LTTNG_TRIGGER_STATUS_OK:
+               break;
+       case LTTNG_TRIGGER_STATUS_UNSET:
+               *trigger_name = "(anonymous)";
+               break;
+       default:
+               abort();
+       }
+
+       trigger_status = lttng_trigger_get_owner_uid(trigger,
+                       trigger_owner_uid);
+       assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+}
+
+static int handle_notification_thread_command_get_trigger(
+               struct notification_thread_state *state,
+               const struct lttng_trigger *trigger,
+               struct lttng_trigger **registered_trigger,
+               enum lttng_error_code *_cmd_result)
+{
+       int ret = -1;
+       struct cds_lfht_iter iter;
+       struct lttng_trigger_ht_element *trigger_ht_element;
+       enum lttng_error_code cmd_result = LTTNG_ERR_TRIGGER_NOT_FOUND;
+       const char *trigger_name;
+       uid_t trigger_owner_uid;
+
+       rcu_read_lock();
+
+       cds_lfht_for_each_entry(
+                       state->triggers_ht, &iter, trigger_ht_element, node) {
+               if (lttng_trigger_is_equal(
+                                   trigger, trigger_ht_element->trigger)) {
+                       /* Take one reference on the return trigger. */
+                       *registered_trigger = trigger_ht_element->trigger;
+                       lttng_trigger_get(*registered_trigger);
+                       ret = 0;
+                       cmd_result = LTTNG_OK;
+                       goto end;
+               }
+       }
+
+       /* Not a fatal error if the trigger is not found. */
+       get_trigger_info_for_log(trigger, &trigger_name, &trigger_owner_uid);
+       DBG("Failed to retrieve registered version of trigger: trigger name = '%s', trigger owner uid = %d",
+                       trigger_name, (int) trigger_owner_uid);
+
+       ret = 0;
+
+end:
+       rcu_read_unlock();
+       *_cmd_result = cmd_result;
+       return ret;
+}
+
 static
 bool condition_is_supported(struct lttng_condition *condition)
 {
@@ -2309,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_ON_EVENT:
+       case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
        {
                const struct lttng_event_rule *event_rule;
                enum lttng_domain_type domain;
                const enum lttng_condition_status status =
-                               lttng_condition_on_event_get_rule(
+                               lttng_condition_event_rule_matches_get_rule(
                                                condition, &event_rule);
 
                assert(status == LTTNG_CONDITION_STATUS_OK);
@@ -2449,16 +2491,16 @@ bool is_trigger_action_notify(const struct lttng_trigger *trigger)
        if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
                is_notify = true;
                goto end;
-       } else if (action_type != LTTNG_ACTION_TYPE_GROUP) {
+       } else if (action_type != LTTNG_ACTION_TYPE_LIST) {
                goto end;
        }
 
-       action_status = lttng_action_group_get_count(action, &count);
+       action_status = lttng_action_list_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(
+                               lttng_action_list_get_at_index(
                                                action, i);
 
                action_type = lttng_action_get_type(inner_action);
@@ -2565,7 +2607,7 @@ enum lttng_error_code setup_tracer_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("Trigger group error accounting counter full.");
+                       DBG("Trigger list error accounting counter full.");
                        ret = LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING_FULL;
                } else {
                        ERR("Error registering trigger for error accounting");
@@ -2575,7 +2617,7 @@ enum lttng_error_code setup_tracer_notifier(
                goto error_remove_ht_element;
        }
 
-       lttng_condition_on_event_set_error_counter_index(
+       lttng_condition_event_rule_matches_set_error_counter_index(
                        condition, error_counter_index);
 
        ret = LTTNG_OK;
@@ -2608,6 +2650,7 @@ static
 int handle_notification_thread_command_register_trigger(
                struct notification_thread_state *state,
                struct lttng_trigger *trigger,
+               bool is_trigger_anonymous,
                enum lttng_error_code *cmd_result)
 {
        int ret = 0;
@@ -2630,22 +2673,27 @@ int handle_notification_thread_command_register_trigger(
        /* Set the trigger's tracer token. */
        lttng_trigger_set_tracer_token(trigger, trigger_tracer_token);
 
-       if (lttng_trigger_get_name(trigger, &trigger_name) ==
-                       LTTNG_TRIGGER_STATUS_UNSET) {
-               const enum lttng_error_code ret_code = generate_trigger_name(
-                               state, trigger, &trigger_name);
+       if (!is_trigger_anonymous) {
+               if (lttng_trigger_get_name(trigger, &trigger_name) ==
+                               LTTNG_TRIGGER_STATUS_UNSET) {
+                       const enum lttng_error_code ret_code =
+                                       generate_trigger_name(state, trigger,
+                                                       &trigger_name);
 
-               if (ret_code != LTTNG_OK) {
-                       /* Fatal error. */
-                       ret = -1;
-                       *cmd_result = ret_code;
+                       if (ret_code != LTTNG_OK) {
+                               /* Fatal error. */
+                               ret = -1;
+                               *cmd_result = ret_code;
+                               goto error;
+                       }
+               } else if (trigger_name_taken(state, trigger)) {
+                       /* Not a fatal error. */
+                       *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
+                       ret = 0;
                        goto error;
                }
-       } else if (trigger_name_taken(state, trigger)) {
-               /* Not a fatal error. */
-               *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
-               ret = 0;
-               goto error;
+       } else {
+               trigger_name = "(anonymous)";
        }
 
        condition = lttng_trigger_get_condition(trigger);
@@ -2685,12 +2733,14 @@ int handle_notification_thread_command_register_trigger(
                        trigger,
                        &trigger_ht_element->node_by_name_uid);
        if (node != &trigger_ht_element->node_by_name_uid) {
-               /* Not a fatal error, simply report it to the client. */
-               cds_lfht_del(state->triggers_ht, &trigger_ht_element->node);
-               *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
+               /* Internal error: add to triggers_ht should have failed. */
+               ret = -1;
                goto error_free_ht_element;
        }
 
+       /* From this point consider the trigger registered. */
+       lttng_trigger_set_as_registered(trigger);
+
        /*
         * Some triggers might need a tracer notifier depending on its
         * condition and actions.
@@ -2847,8 +2897,8 @@ int handle_notification_thread_command_register_trigger(
         * Ownership of `evaluation` transferred to the action executor
         * no matter the result.
         */
-       executor_status = action_executor_enqueue(state->executor, trigger,
-                       evaluation, &object_creds, client_list);
+       executor_status = action_executor_enqueue_trigger(state->executor,
+                       trigger, evaluation, &object_creds, client_list);
        evaluation = NULL;
        switch (executor_status) {
        case ACTION_EXECUTOR_STATUS_OK:
@@ -2890,6 +2940,11 @@ error_free_ht_element:
        }
 error:
        if (free_trigger) {
+               /*
+                * Other objects might have a reference to the trigger, mark it
+                * as unregistered.
+                */
+               lttng_trigger_set_as_unregistered(trigger);
                lttng_trigger_destroy(trigger);
        }
 end:
@@ -2971,6 +3026,9 @@ int handle_notification_thread_command_unregister_trigger(
                cmd_reply = LTTNG_OK;
        }
 
+       trigger_ht_element = caa_container_of(triggers_ht_node,
+                       struct lttng_trigger_ht_element, node);
+
        /* Remove trigger from channel_triggers_ht. */
        cds_lfht_for_each_entry(state->channel_triggers_ht, &iter, trigger_list,
                        channel_triggers_ht_node) {
@@ -2993,9 +3051,6 @@ int handle_notification_thread_command_unregister_trigger(
                teardown_tracer_notifier(state, trigger);
        }
 
-       trigger_ht_element = caa_container_of(triggers_ht_node,
-                       struct lttng_trigger_ht_element, node);
-
        if (is_trigger_action_notify(trigger)) {
                /*
                 * Remove and release the client list from
@@ -3056,6 +3111,7 @@ int handle_notification_thread_command(
        case NOTIFICATION_COMMAND_TYPE_REGISTER_TRIGGER:
                ret = handle_notification_thread_command_register_trigger(state,
                                cmd->parameters.register_trigger.trigger,
+                               cmd->parameters.register_trigger.is_trigger_anonymous,
                                &cmd->reply_code);
                break;
        case NOTIFICATION_COMMAND_TYPE_UNREGISTER_TRIGGER:
@@ -3125,6 +3181,16 @@ int handle_notification_thread_command(
                cmd->reply_code = LTTNG_OK;
                ret = 1;
                goto end;
+       case NOTIFICATION_COMMAND_TYPE_GET_TRIGGER:
+       {
+               struct lttng_trigger *trigger = NULL;
+
+               ret = handle_notification_thread_command_get_trigger(state,
+                               cmd->parameters.get_trigger.trigger, &trigger,
+                               &cmd->reply_code);
+               cmd->reply.get_trigger.trigger = trigger;
+               break;
+       }
        case NOTIFICATION_COMMAND_TYPE_CLIENT_COMMUNICATION_UPDATE:
        {
                const enum client_transmission_status client_status =
@@ -3800,6 +3866,7 @@ int client_handle_message_subscription(
                goto end;
        }
 
+       /* Ownership of condition is always transferred. */
        if (msg_type == LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_SUBSCRIBE) {
                ret = notification_thread_client_subscribe(
                                client, condition, state, &status);
@@ -3887,6 +3954,12 @@ int handle_notification_thread_client_in(
                goto end;
        }
 
+       if (client->communication.inbound.bytes_to_receive == 0 &&
+                       client->communication.inbound.fds_to_receive != 0) {
+               /* Only FDs left to receive. */
+               goto receive_fds;
+       }
+
        offset = client->communication.inbound.payload.buffer.size -
                        client->communication.inbound.bytes_to_receive;
        if (client->communication.inbound.expect_creds) {
@@ -3915,6 +3988,7 @@ int handle_notification_thread_client_in(
                goto end;
        }
 
+receive_fds:
        assert(client->communication.inbound.bytes_to_receive == 0);
 
        /* Receive fds. */
@@ -4333,7 +4407,7 @@ int notification_client_list_send_evaluation(
                        }
                }
 
-               if (client->uid != lttng_credentials_get_uid(trigger_creds) && client->gid != lttng_credentials_get_gid(trigger_creds)) {
+               if (client->uid != lttng_credentials_get_uid(trigger_creds)) {
                        DBG("[notification-thread] Skipping client at it does not have the permission to receive notification for this trigger");
                        goto skip_client;
                }
@@ -4492,11 +4566,9 @@ int dispatch_one_event_notifier_notification(struct notification_thread_state *s
        struct cds_lfht_node *node;
        struct cds_lfht_iter iter;
        struct notification_trigger_tokens_ht_element *element;
-       enum lttng_trigger_status trigger_status;
        struct lttng_evaluation *evaluation = NULL;
        enum action_executor_status executor_status;
        struct notification_client_list *client_list = NULL;
-       const char *trigger_name;
        int ret;
        unsigned int capture_count = 0;
 
@@ -4521,17 +4593,7 @@ int dispatch_one_event_notifier_notification(struct notification_thread_state *s
                        struct notification_trigger_tokens_ht_element,
                        node);
 
-       if (!lttng_trigger_should_fire(element->trigger)) {
-               ret = 0;
-               goto end_unlock;
-       }
-
-       lttng_trigger_fire(element->trigger);
-
-       trigger_status = lttng_trigger_get_name(element->trigger, &trigger_name);
-       assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       if (lttng_condition_on_event_get_capture_descriptor_count(
+       if (lttng_condition_event_rule_matches_get_capture_descriptor_count(
                            lttng_trigger_get_const_condition(element->trigger),
                            &capture_count) != LTTNG_CONDITION_STATUS_OK) {
                ERR("Failed to get capture count");
@@ -4545,12 +4607,11 @@ int dispatch_one_event_notifier_notification(struct notification_thread_state *s
                goto end;
        }
 
-       evaluation = lttng_evaluation_on_event_create(
+       evaluation = lttng_evaluation_event_rule_matches_create(
                        container_of(lttng_trigger_get_const_condition(
                                                     element->trigger),
-                                       struct lttng_condition_on_event,
+                                       struct lttng_condition_event_rule_matches,
                                        parent),
-                       trigger_name,
                        notification->capture_buffer,
                        notification->capture_buf_size, false);
 
@@ -4561,7 +4622,7 @@ int dispatch_one_event_notifier_notification(struct notification_thread_state *s
        }
        client_list = get_client_list_from_condition(state,
                        lttng_trigger_get_const_condition(element->trigger));
-       executor_status = action_executor_enqueue(state->executor,
+       executor_status = action_executor_enqueue_trigger(state->executor,
                        element->trigger, evaluation, NULL, client_list);
        switch (executor_status) {
        case ACTION_EXECUTOR_STATUS_OK:
@@ -4840,19 +4901,13 @@ int handle_notification_thread_channel_sample(
                        goto put_list;
                }
 
-               if (!lttng_trigger_should_fire(trigger)) {
-                       goto put_list;
-               }
-
-               lttng_trigger_fire(trigger);
-
                /*
                 * Ownership of `evaluation` transferred to the action executor
                 * no matter the result.
                 */
-               executor_status = action_executor_enqueue(state->executor,
-                               trigger, evaluation, &channel_creds,
-                               client_list);
+               executor_status = action_executor_enqueue_trigger(
+                               state->executor, trigger, evaluation,
+                               &channel_creds, client_list);
                evaluation = NULL;
                switch (executor_status) {
                case ACTION_EXECUTOR_STATUS_OK:
This page took 0.032837 seconds and 4 git commands to generate.