From 588c4b0d153e8919b8d9159b69ce0db8fbe52af0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Thu, 15 Apr 2021 13:11:09 -0400 Subject: [PATCH] sessiond: implement EXECUTE_ERROR_QUERY command MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau Change-Id: I3404e85e18b0b4e5d51b620c3a082736d3190066 --- include/lttng/action/action-internal.h | 31 ++- include/lttng/error-query-internal.h | 4 +- include/lttng/trigger/trigger-internal.h | 12 +- src/bin/lttng-sessiond/Makefile.am | 3 +- src/bin/lttng-sessiond/client.c | 145 +++++++++++++- src/bin/lttng-sessiond/cmd.c | 187 ++++++++++++++++--- src/bin/lttng-sessiond/cmd.h | 4 + src/bin/lttng-sessiond/trigger-error-query.c | 96 ++++++++++ src/common/actions/action.c | 48 ++++- src/common/actions/group.c | 31 ++- src/common/actions/notify.c | 3 +- src/common/actions/rotate-session.c | 3 +- src/common/actions/snapshot-session.c | 3 +- src/common/actions/start-session.c | 3 +- src/common/actions/stop-session.c | 3 +- src/common/error-query.c | 14 +- tests/unit/Makefile.am | 1 + 17 files changed, 528 insertions(+), 63 deletions(-) create mode 100644 src/bin/lttng-sessiond/trigger-error-query.c diff --git a/include/lttng/action/action-internal.h b/include/lttng/action/action-internal.h index 12029e42f..55e34163b 100644 --- a/include/lttng/action/action-internal.h +++ b/include/lttng/action/action-internal.h @@ -8,12 +8,13 @@ #ifndef LTTNG_ACTION_INTERNAL_H #define LTTNG_ACTION_INTERNAL_H -#include -#include #include #include +#include #include #include +#include +#include #include #include #include @@ -31,6 +32,9 @@ typedef ssize_t (*action_create_from_payload_cb)( struct lttng_action **action); typedef const struct lttng_rate_policy *(*action_get_rate_policy_cb)( const struct lttng_action *action); +typedef enum lttng_action_status (*action_add_error_query_results_cb)( + const struct lttng_action *action, + struct lttng_error_query_results *results); struct lttng_action { struct urcu_ref ref; @@ -40,6 +44,7 @@ struct lttng_action { action_equal_cb equal; action_destroy_cb destroy; action_get_rate_policy_cb get_rate_policy; + action_add_error_query_results_cb add_error_query_results; /* Internal use only. */ @@ -52,8 +57,10 @@ struct lttng_action { uint64_t execution_counter; /* * The number of time the action execution failed. + * An unsigned long is used to use a type which makes atomic + * operations possible. */ - uint64_t execution_failure_counter; + unsigned long execution_failure_counter; }; struct lttng_action_comm { @@ -68,7 +75,8 @@ void lttng_action_init(struct lttng_action *action, action_serialize_cb serialize, action_equal_cb equal, action_destroy_cb destroy, - action_get_rate_policy_cb get_rate_policy); + action_get_rate_policy_cb get_rate_policy, + action_add_error_query_results_cb add_error_query_results); LTTNG_HIDDEN bool lttng_action_validate(struct lttng_action *action); @@ -106,4 +114,19 @@ void lttng_action_increase_execution_failure_count(struct lttng_action *action); LTTNG_HIDDEN bool lttng_action_should_execute(const struct lttng_action *action); +LTTNG_HIDDEN +enum lttng_action_status lttng_action_add_error_query_results( + const struct lttng_action *action, + struct lttng_error_query_results *results); + +/* + * For use by the various lttng_action implementation. Implements the default + * behavior to the generic error "execution failure counter" that all actions + * (except group, which passes-through) provide. + */ +LTTNG_HIDDEN +enum lttng_action_status lttng_action_generic_add_error_query_results( + const struct lttng_action *action, + struct lttng_error_query_results *results); + #endif /* LTTNG_ACTION_INTERNAL_H */ diff --git a/include/lttng/error-query-internal.h b/include/lttng/error-query-internal.h index 24216f964..b5578d44d 100644 --- a/include/lttng/error-query-internal.h +++ b/include/lttng/error-query-internal.h @@ -33,9 +33,9 @@ const struct lttng_trigger *lttng_error_query_action_borrow_trigger_target( const struct lttng_error_query *query); LTTNG_HIDDEN -const struct lttng_action *lttng_error_query_action_borrow_action_target( +struct lttng_action *lttng_error_query_action_borrow_action_target( const struct lttng_error_query *query, - const struct lttng_trigger *trigger); + struct lttng_trigger *trigger); LTTNG_HIDDEN int lttng_error_query_serialize(const struct lttng_error_query *query, diff --git a/include/lttng/trigger/trigger-internal.h b/include/lttng/trigger/trigger-internal.h index f16b68d00..5bab4c763 100644 --- a/include/lttng/trigger/trigger-internal.h +++ b/include/lttng/trigger/trigger-internal.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -226,4 +226,14 @@ void lttng_trigger_lock(struct lttng_trigger *trigger); LTTNG_HIDDEN void lttng_trigger_unlock(struct lttng_trigger *trigger); +LTTNG_HIDDEN +enum lttng_trigger_status lttng_trigger_add_error_results( + const struct lttng_trigger *trigger, + struct lttng_error_query_results *results); + +LTTNG_HIDDEN +enum lttng_trigger_status lttng_trigger_add_action_error_query_results( + struct lttng_trigger *trigger, + struct lttng_error_query_results *results); + #endif /* LTTNG_TRIGGER_INTERNAL_H */ diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am index 8a299fab8..07aaa821c 100644 --- a/src/bin/lttng-sessiond/Makefile.am +++ b/src/bin/lttng-sessiond/Makefile.am @@ -56,7 +56,8 @@ lttng_sessiond_SOURCES = utils.c utils.h \ clear.c clear.h \ tracker.c tracker.h \ event-notifier-error-accounting.c event-notifier-error-accounting.h \ - action-executor.c action-executor.h + action-executor.c action-executor.h\ + trigger-error-query.c lttng_sessiond_LDFLAGS = -rdynamic diff --git a/src/bin/lttng-sessiond/client.c b/src/bin/lttng-sessiond/client.c index d83bee8e6..6943a776e 100644 --- a/src/bin/lttng-sessiond/client.c +++ b/src/bin/lttng-sessiond/client.c @@ -9,20 +9,19 @@ #include "common/buffer-view.h" #include "common/compat/socket.h" -#include "common/dynamic-buffer.h" #include "common/dynamic-array.h" -#include "common/payload.h" -#include "common/payload-view.h" +#include "common/dynamic-buffer.h" #include "common/fd-handle.h" -#include "common/sessiond-comm/sessiond-comm.h" -#include "common/payload.h" #include "common/payload-view.h" +#include "common/payload.h" +#include "common/sessiond-comm/sessiond-comm.h" #include "lttng/lttng-error.h" #include "lttng/tracker.h" #include #include #include #include +#include #include #include #include @@ -33,17 +32,17 @@ #include #include +#include "agent-thread.h" +#include "clear.h" #include "client.h" -#include "lttng-sessiond.h" #include "cmd.h" +#include "health-sessiond.h" #include "kernel.h" +#include "lttng-sessiond.h" +#include "manage-consumer.h" #include "save.h" -#include "health-sessiond.h" #include "testpoint.h" #include "utils.h" -#include "manage-consumer.h" -#include "clear.h" -#include "agent-thread.h" static bool is_root; @@ -780,6 +779,77 @@ end: return ret_code; } +static enum lttng_error_code receive_lttng_error_query(struct command_ctx *cmd_ctx, + int sock, + int *sock_error, + struct lttng_error_query **_query) +{ + int ret; + size_t query_len; + ssize_t sock_recv_len; + enum lttng_error_code ret_code; + struct lttng_payload query_payload; + struct lttng_error_query *query = NULL; + + lttng_payload_init(&query_payload); + query_len = (size_t) cmd_ctx->lsm.u.error_query.length; + ret = lttng_dynamic_buffer_set_size(&query_payload.buffer, query_len); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + sock_recv_len = lttcomm_recv_unix_sock( + sock, query_payload.buffer.data, query_len); + if (sock_recv_len < 0 || sock_recv_len != query_len) { + ERR("Failed to receive error query in command payload"); + *sock_error = 1; + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + goto end; + } + + /* Receive fds, if any. */ + if (cmd_ctx->lsm.fd_count > 0) { + sock_recv_len = lttcomm_recv_payload_fds_unix_sock( + sock, cmd_ctx->lsm.fd_count, &query_payload); + if (sock_recv_len > 0 && + sock_recv_len != cmd_ctx->lsm.fd_count * sizeof(int)) { + ERR("Failed to receive all file descriptors for error query in command payload: expected fd count = %u, ret = %d", + cmd_ctx->lsm.fd_count, (int) ret); + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + *sock_error = 1; + goto end; + } else if (sock_recv_len <= 0) { + ERR("Failed to receive file descriptors for error query in command payload: expected fd count = %u, ret = %d", + cmd_ctx->lsm.fd_count, (int) ret); + ret_code = LTTNG_ERR_FATAL; + *sock_error = 1; + goto end; + } + } + + /* Deserialize error query. */ + { + struct lttng_payload_view view = + lttng_payload_view_from_payload( + &query_payload, 0, -1); + + if (lttng_error_query_create_from_payload(&view, &query) != + query_len) { + ERR("Invalid error query received as part of command payload"); + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + goto end; + } + } + + *_query = query; + ret_code = LTTNG_OK; + +end: + lttng_payload_reset(&query_payload); + return ret_code; +} + /* * Version of setup_lttng_msg() without command header. */ @@ -890,6 +960,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: case LTTNG_CLEAR_SESSION: case LTTNG_LIST_TRIGGERS: + case LTTNG_EXECUTE_ERROR_QUERY: need_domain = false; break; default: @@ -900,6 +971,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, switch (cmd_ctx->lsm.cmd_type) { case LTTNG_REGISTER_TRIGGER: case LTTNG_UNREGISTER_TRIGGER: + case LTTNG_EXECUTE_ERROR_QUERY: need_consumerd = false; break; default: @@ -949,6 +1021,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, case LTTNG_ROTATION_GET_INFO: case LTTNG_REGISTER_TRIGGER: case LTTNG_LIST_TRIGGERS: + case LTTNG_EXECUTE_ERROR_QUERY: break; default: /* Setup lttng message with no payload */ @@ -970,6 +1043,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, case LTTNG_REGISTER_TRIGGER: case LTTNG_UNREGISTER_TRIGGER: case LTTNG_LIST_TRIGGERS: + case LTTNG_EXECUTE_ERROR_QUERY: need_tracing_session = false; break; default: @@ -2356,6 +2430,57 @@ error_add_context: ret = LTTNG_OK; break; } + case LTTNG_EXECUTE_ERROR_QUERY: + { + struct lttng_error_query *query; + const struct lttng_credentials cmd_creds = { + .uid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.uid), + .gid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.gid), + }; + struct lttng_error_query_results *results = NULL; + size_t original_payload_size; + size_t payload_size; + + ret = setup_empty_lttng_msg(cmd_ctx); + if (ret) { + ret = LTTNG_ERR_NOMEM; + goto setup_error; + } + + original_payload_size = cmd_ctx->reply_payload.buffer.size; + + ret = receive_lttng_error_query( + cmd_ctx, *sock, sock_error, &query); + if (ret != LTTNG_OK) { + goto error; + } + + ret = cmd_execute_error_query(&cmd_creds, query, &results, + the_notification_thread_handle); + lttng_error_query_destroy(query); + if (ret != LTTNG_OK) { + goto error; + } + + assert(results); + ret = lttng_error_query_results_serialize( + results, &cmd_ctx->reply_payload); + lttng_error_query_results_destroy(results); + if (ret) { + ERR("Failed to serialize error query result set in reply to `execute error query` command"); + ret = LTTNG_ERR_NOMEM; + goto error; + } + + payload_size = cmd_ctx->reply_payload.buffer.size - + original_payload_size; + + update_lttng_msg(cmd_ctx, 0, payload_size); + + ret = LTTNG_OK; + + break; + } default: ret = LTTNG_ERR_UND; break; diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index c7745abf1..3fab5af02 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -6,67 +6,69 @@ * */ -#include "bin/lttng-sessiond/session.h" + #define _LGPL_SOURCE #include #include +#include +#include #include #include -#include -#include -#include +#include #include -#include -#include -#include #include -#include +#include #include -#include -#include +#include #include +#include +#include +#include +#include #include -#include -#include -#include +#include +#include +#include +#include +#include #include -#include +#include #include -#include +#include +#include #include -#include -#include -#include -#include +#include #include -#include -#include -#include #include +#include +#include +#include #include -#include +#include +#include +#include "agent-thread.h" +#include "agent.h" +#include "buffer-registry.h" #include "channel.h" +#include "cmd.h" #include "consumer.h" +#include "event-notifier-error-accounting.h" #include "event.h" #include "health-sessiond.h" -#include "kernel.h" #include "kernel-consumer.h" +#include "kernel.h" #include "lttng-sessiond.h" -#include "utils.h" #include "lttng-syscall.h" -#include "agent.h" -#include "buffer-registry.h" -#include "notification-thread.h" #include "notification-thread-commands.h" +#include "notification-thread.h" #include "rotate.h" #include "rotation-thread.h" +#include "session.h" #include "timer.h" -#include "agent-thread.h" #include "tracker.h" - -#include "cmd.h" +#include "utils.h" /* Sleep for 100ms between each check for the shm path's deletion. */ #define SESSION_DESTROY_SHM_PATH_CHECK_DELAY_US 100000 @@ -4650,6 +4652,129 @@ end: lttng_triggers_destroy(triggers); return ret; } + +enum lttng_error_code cmd_execute_error_query(const struct lttng_credentials *cmd_creds, + const struct lttng_error_query *query, + struct lttng_error_query_results **_results, + struct notification_thread_handle *notification_thread) +{ + enum lttng_error_code ret_code; + const struct lttng_trigger *query_target_trigger; + struct lttng_action *query_target_action; + struct lttng_trigger *matching_trigger = NULL; + const char *trigger_name; + uid_t trigger_owner; + enum lttng_trigger_status trigger_status; + struct lttng_error_query_results *results = NULL; + + switch (lttng_error_query_get_target_type(query)) { + case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER: + query_target_trigger = lttng_error_query_trigger_borrow_target(query); + break; + case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION: + query_target_trigger = lttng_error_query_action_borrow_trigger_target( + query); + break; + default: + abort(); + } + + assert(query_target_trigger); + + ret_code = notification_thread_command_get_trigger(notification_thread, + query_target_trigger, &matching_trigger); + if (ret_code != LTTNG_OK) { + goto end; + } + + /* No longer needed. */ + query_target_trigger = NULL; + + if (lttng_error_query_get_target_type(query) == + LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION) { + /* Get the sessiond-side version of the target action. */ + query_target_action = + lttng_error_query_action_borrow_action_target( + query, matching_trigger); + } + + trigger_status = lttng_trigger_get_name(matching_trigger, &trigger_name); + trigger_name = trigger_status == LTTNG_TRIGGER_STATUS_OK ? + trigger_name : "(unnamed)"; + trigger_status = lttng_trigger_get_owner_uid(matching_trigger, + &trigger_owner); + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + results = lttng_error_query_results_create(); + if (!results) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + DBG("Running \"execute error query\" command: trigger name = '%s', trigger owner uid = %d, command creds uid = %d", + trigger_name, (int) trigger_owner, + (int) lttng_credentials_get_uid(cmd_creds)); + + /* + * Validate the trigger credentials against the command credentials. + * Only the root user can target a trigger with non-matching + * credentials. + */ + if (!lttng_credentials_is_equal_uid( + lttng_trigger_get_credentials(matching_trigger), + cmd_creds)) { + if (lttng_credentials_get_uid(cmd_creds) != 0) { + ERR("Trigger credentials do not match the command credentials: trigger name = '%s', trigger owner uid = %d, command creds uid = %d", + trigger_name, (int) trigger_owner, + (int) lttng_credentials_get_uid(cmd_creds)); + ret_code = LTTNG_ERR_INVALID_TRIGGER; + goto end; + } + } + + switch (lttng_error_query_get_target_type(query)) { + case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER: + trigger_status = lttng_trigger_add_error_results( + matching_trigger, results); + + switch (trigger_status) { + case LTTNG_TRIGGER_STATUS_OK: + break; + default: + ret_code = LTTNG_ERR_UNK; + goto end; + } + + break; + case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION: + { + const enum lttng_action_status action_status = + lttng_action_add_error_query_results( + query_target_action, results); + + switch (action_status) { + case LTTNG_ACTION_STATUS_OK: + break; + default: + ret_code = LTTNG_ERR_UNK; + goto end; + } + + break; + } + default: + break; + } + + *_results = results; + results = NULL; + ret_code = LTTNG_OK; +end: + lttng_trigger_put(matching_trigger); + lttng_error_query_results_destroy(results); + return ret_code; +} + /* * Send relayd sockets from snapshot output to consumer. Ignore request if the * snapshot output is *not* set with a remote destination. diff --git a/src/bin/lttng-sessiond/cmd.h b/src/bin/lttng-sessiond/cmd.h index dcda2365d..9aa13ff22 100644 --- a/src/bin/lttng-sessiond/cmd.h +++ b/src/bin/lttng-sessiond/cmd.h @@ -154,6 +154,10 @@ enum lttng_error_code cmd_unregister_trigger( int cmd_list_triggers(struct command_ctx *cmd_ctx, struct notification_thread_handle *notification_thread_handle, struct lttng_triggers **return_triggers); +enum lttng_error_code cmd_execute_error_query(const struct lttng_credentials *cmd_creds, + const struct lttng_error_query *query, + struct lttng_error_query_results **_results, + struct notification_thread_handle *notification_thread); int cmd_rotate_session(struct ltt_session *session, struct lttng_rotate_session_return *rotate_return, diff --git a/src/bin/lttng-sessiond/trigger-error-query.c b/src/bin/lttng-sessiond/trigger-error-query.c new file mode 100644 index 000000000..bc8e7f688 --- /dev/null +++ b/src/bin/lttng-sessiond/trigger-error-query.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2021 Jérémie Galarneau + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + +#include "event-notifier-error-accounting.h" +#include +#include +#include + +LTTNG_HIDDEN +enum lttng_trigger_status lttng_trigger_add_error_results( + const struct lttng_trigger *trigger, + struct lttng_error_query_results *results) +{ + enum lttng_trigger_status status; + uint64_t discarded_tracer_messages_count; + enum event_notifier_error_accounting_status error_accounting_status; + struct lttng_error_query_result *discarded_tracer_messages_counter = NULL; + const char *trigger_name; + uid_t trigger_owner; + + status = lttng_trigger_get_name(trigger, &trigger_name); + trigger_name = status == LTTNG_TRIGGER_STATUS_OK ? + trigger_name : "(unnamed)"; + status = lttng_trigger_get_owner_uid(trigger, + &trigger_owner); + assert(status == LTTNG_TRIGGER_STATUS_OK); + + error_accounting_status = event_notifier_error_accounting_get_count( + trigger, &discarded_tracer_messages_count); + if (error_accounting_status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) { + ERR("Failed to retrieve tracer discarded messages count for triger: triggger name = '%s', trigger owner uid = %d", + trigger_name, (int) trigger_owner); + status = LTTNG_TRIGGER_STATUS_ERROR; + goto end; + } + + discarded_tracer_messages_counter = lttng_error_query_result_counter_create( + "discarded tracer messages", + "Count of messages discarded by the tracer due to a communication error with the session daemon", + discarded_tracer_messages_count); + if (!discarded_tracer_messages_counter) { + status = LTTNG_TRIGGER_STATUS_ERROR; + goto end; + } + + if (lttng_error_query_results_add_result( + results, discarded_tracer_messages_counter)) { + status = LTTNG_TRIGGER_STATUS_ERROR; + goto end; + } + + /* Ownership transferred to the results. */ + discarded_tracer_messages_counter = NULL; + + status = LTTNG_TRIGGER_STATUS_OK; +end: + lttng_error_query_result_destroy(discarded_tracer_messages_counter); + return status; +} + +LTTNG_HIDDEN +enum lttng_trigger_status lttng_trigger_add_action_error_query_results( + struct lttng_trigger *trigger, + struct lttng_error_query_results *results) +{ + enum lttng_trigger_status status; + const char *trigger_name; + uid_t trigger_owner; + enum lttng_action_status action_status; + + status = lttng_trigger_get_name(trigger, &trigger_name); + trigger_name = status == LTTNG_TRIGGER_STATUS_OK ? + trigger_name : "(unnamed)"; + status = lttng_trigger_get_owner_uid(trigger, + &trigger_owner); + assert(status == LTTNG_TRIGGER_STATUS_OK); + + action_status = lttng_action_add_error_query_results( + lttng_trigger_get_action(trigger), results); + switch (action_status) { + case LTTNG_ACTION_STATUS_OK: + status = LTTNG_TRIGGER_STATUS_OK; + goto end; + default: + status = LTTNG_TRIGGER_STATUS_ERROR; + goto end; + } + + status = LTTNG_TRIGGER_STATUS_OK; +end: + return status; +} diff --git a/src/common/actions/action.c b/src/common/actions/action.c index 64864a627..d4b9c09eb 100644 --- a/src/common/actions/action.c +++ b/src/common/actions/action.c @@ -15,6 +15,7 @@ #include #include #include +#include LTTNG_HIDDEN const char *lttng_action_type_string(enum lttng_action_type action_type) @@ -51,7 +52,8 @@ void lttng_action_init(struct lttng_action *action, action_serialize_cb serialize, action_equal_cb equal, action_destroy_cb destroy, - action_get_rate_policy_cb get_rate_policy) + action_get_rate_policy_cb get_rate_policy, + action_add_error_query_results_cb add_error_query_results) { urcu_ref_init(&action->ref); action->type = type; @@ -60,6 +62,7 @@ void lttng_action_init(struct lttng_action *action, action->equal = equal; action->destroy = destroy; action->get_rate_policy = get_rate_policy; + action->add_error_query_results = add_error_query_results; action->execution_request_counter = 0; action->execution_counter = 0; @@ -265,7 +268,7 @@ void lttng_action_increase_execution_count(struct lttng_action *action) LTTNG_HIDDEN void lttng_action_increase_execution_failure_count(struct lttng_action *action) { - action->execution_failure_counter++; + uatomic_inc(&action->execution_failure_counter); } LTTNG_HIDDEN @@ -290,3 +293,44 @@ bool lttng_action_should_execute(const struct lttng_action *action) end: return execute; } + +LTTNG_HIDDEN +enum lttng_action_status lttng_action_add_error_query_results( + const struct lttng_action *action, + struct lttng_error_query_results *results) +{ + return action->add_error_query_results(action, results); +} + +LTTNG_HIDDEN +enum lttng_action_status lttng_action_generic_add_error_query_results( + const struct lttng_action *action, + struct lttng_error_query_results *results) +{ + enum lttng_action_status action_status; + struct lttng_error_query_result *error_counter = NULL; + const uint64_t execution_failure_counter = + uatomic_read(&action->execution_failure_counter); + + error_counter = lttng_error_query_result_counter_create( + "total execution failures", + "Aggregated count of errors encountered when executing the action", + execution_failure_counter); + if (!error_counter) { + action_status = LTTNG_ACTION_STATUS_ERROR; + goto end; + } + + if (lttng_error_query_results_add_result( + results, error_counter)) { + action_status = LTTNG_ACTION_STATUS_ERROR; + goto end; + } + + /* Ownership transferred to the results. */ + error_counter = NULL; + action_status = LTTNG_ACTION_STATUS_OK; +end: + lttng_error_query_result_destroy(error_counter); + return action_status; +} diff --git a/src/common/actions/group.c b/src/common/actions/group.c index afb832ee6..3effa8715 100644 --- a/src/common/actions/group.c +++ b/src/common/actions/group.c @@ -250,6 +250,34 @@ end: return consumed_len; } +static enum lttng_action_status lttng_action_group_add_error_query_results( + const struct lttng_action *action, + struct lttng_error_query_results *results) +{ + unsigned int i, count; + enum lttng_action_status action_status; + const struct lttng_action_group *group = + container_of(action, typeof(*group), parent); + + action_status = lttng_action_group_get_count(action, &count); + if (action_status != LTTNG_ACTION_STATUS_OK) { + goto end; + } + + for (i = 0; i < count; i++) { + struct lttng_action *inner_action = + lttng_action_group_borrow_mutable_at_index(action, i); + + action_status = lttng_action_add_error_query_results( + inner_action, results); + if (action_status != LTTNG_ACTION_STATUS_OK) { + goto end; + } + } +end: + return action_status; +} + struct lttng_action *lttng_action_group_create(void) { struct lttng_action_group *action_group; @@ -267,7 +295,8 @@ struct lttng_action *lttng_action_group_create(void) lttng_action_group_validate, lttng_action_group_serialize, lttng_action_group_is_equal, lttng_action_group_destroy, - NULL); + NULL, + lttng_action_group_add_error_query_results); lttng_dynamic_pointer_array_init(&action_group->actions, destroy_lttng_action_group_element); diff --git a/src/common/actions/notify.c b/src/common/actions/notify.c index 0ab88be44..646bffe9d 100644 --- a/src/common/actions/notify.c +++ b/src/common/actions/notify.c @@ -103,7 +103,8 @@ struct lttng_action *lttng_action_notify_create(void) lttng_action_notify_serialize, lttng_action_notify_is_equal, lttng_action_notify_destroy, - lttng_action_notify_internal_get_rate_policy); + lttng_action_notify_internal_get_rate_policy, + lttng_action_generic_add_error_query_results); notify->policy = policy; policy = NULL; diff --git a/src/common/actions/rotate-session.c b/src/common/actions/rotate-session.c index 3d5a61709..c8dadd119 100644 --- a/src/common/actions/rotate-session.c +++ b/src/common/actions/rotate-session.c @@ -252,7 +252,8 @@ struct lttng_action *lttng_action_rotate_session_create(void) lttng_action_rotate_session_serialize, lttng_action_rotate_session_is_equal, lttng_action_rotate_session_destroy, - lttng_action_rotate_session_internal_get_rate_policy); + lttng_action_rotate_session_internal_get_rate_policy, + lttng_action_generic_add_error_query_results); status = lttng_action_rotate_session_set_rate_policy(action, policy); if (status != LTTNG_ACTION_STATUS_OK) { diff --git a/src/common/actions/snapshot-session.c b/src/common/actions/snapshot-session.c index 239cf5e73..776615003 100644 --- a/src/common/actions/snapshot-session.c +++ b/src/common/actions/snapshot-session.c @@ -395,7 +395,8 @@ struct lttng_action *lttng_action_snapshot_session_create(void) lttng_action_snapshot_session_serialize, lttng_action_snapshot_session_is_equal, lttng_action_snapshot_session_destroy, - lttng_action_snapshot_session_internal_get_rate_policy); + lttng_action_snapshot_session_internal_get_rate_policy, + lttng_action_generic_add_error_query_results); status = lttng_action_snapshot_session_set_rate_policy(action, policy); if (status != LTTNG_ACTION_STATUS_OK) { diff --git a/src/common/actions/start-session.c b/src/common/actions/start-session.c index 8ed8068dd..e5cbac726 100644 --- a/src/common/actions/start-session.c +++ b/src/common/actions/start-session.c @@ -255,7 +255,8 @@ struct lttng_action *lttng_action_start_session_create(void) lttng_action_start_session_serialize, lttng_action_start_session_is_equal, lttng_action_start_session_destroy, - lttng_action_start_session_internal_get_rate_policy); + lttng_action_start_session_internal_get_rate_policy, + lttng_action_generic_add_error_query_results); status = lttng_action_start_session_set_rate_policy(action, policy); if (status != LTTNG_ACTION_STATUS_OK) { diff --git a/src/common/actions/stop-session.c b/src/common/actions/stop-session.c index 9f74bf884..ec167d1ed 100644 --- a/src/common/actions/stop-session.c +++ b/src/common/actions/stop-session.c @@ -255,7 +255,8 @@ struct lttng_action *lttng_action_stop_session_create(void) lttng_action_stop_session_serialize, lttng_action_stop_session_is_equal, lttng_action_stop_session_destroy, - lttng_action_stop_session_internal_get_rate_policy); + lttng_action_stop_session_internal_get_rate_policy, + lttng_action_generic_add_error_query_results); status = lttng_action_stop_session_set_rate_policy(action, policy); if (status != LTTNG_ACTION_STATUS_OK) { diff --git a/src/common/error-query.c b/src/common/error-query.c index 17fd5ffae..d353c5a8f 100644 --- a/src/common/error-query.c +++ b/src/common/error-query.c @@ -351,6 +351,7 @@ lttng_error_query_result_counter_create( goto error; } + counter->value = value; goto end; error: lttng_error_query_result_destroy(&counter->parent); @@ -659,15 +660,15 @@ const struct lttng_trigger *lttng_error_query_action_borrow_trigger_target( } LTTNG_HIDDEN -const struct lttng_action *lttng_error_query_action_borrow_action_target( +struct lttng_action *lttng_error_query_action_borrow_action_target( const struct lttng_error_query *query, - const struct lttng_trigger *trigger) + struct lttng_trigger *trigger) { - const struct lttng_action *target_action = NULL; + struct lttng_action *target_action = NULL; const struct lttng_error_query_action *query_action = container_of(query, typeof(*query_action), parent); - const struct lttng_action *trigger_action = - lttng_trigger_get_const_action(trigger); + struct lttng_action *trigger_action = + lttng_trigger_get_action(trigger); if (!query_action->action_index.is_set) { target_action = trigger_action; @@ -678,7 +679,8 @@ const struct lttng_action *lttng_error_query_action_borrow_action_target( goto end; } - target_action = lttng_action_group_get_at_index(trigger_action, + target_action = lttng_action_group_borrow_mutable_at_index( + trigger_action, LTTNG_OPTIONAL_GET(query_action->action_index)); } diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 2a0f3c9fb..401e89f25 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -114,6 +114,7 @@ SESSIOND_OBJS = $(top_builddir)/src/bin/lttng-sessiond/buffer-registry.$(OBJEXT) $(top_builddir)/src/bin/lttng-sessiond/process-utils.$(OBJEXT) \ $(top_builddir)/src/bin/lttng-sessiond/thread.$(OBJEXT) \ $(top_builddir)/src/bin/lttng-sessiond/tracker.$(OBJEXT) \ + $(top_builddir)/src/bin/lttng-sessiond/trigger-error-query.$(OBJEXT) \ $(top_builddir)/src/common/libcommon.la \ $(top_builddir)/src/common/testpoint/libtestpoint.la \ $(top_builddir)/src/common/compat/libcompat.la \ -- 2.34.1