From 24f7193c9b918bf714a40e9fc908eeb4978ada1c Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Mon, 15 Jul 2024 17:41:32 -0400 Subject: [PATCH] Introduce extension points for trace hit counters Introduce two extension points for trace hit counters: 1) Future "actions" to perform other than "increment", 2) Future dimension indexing schemes (keys) other than tokens. Ensure the LTTng-UST protocol with session daemon has those extension points so we don't need to break ABI when we need to extend trace hit counters with those features. Also ensure the ABI between the tracepoint probe provider and the tracer passes all the relevant context for future features, e.g. tracepoint arguments and contexts. Change the layout of struct lttng_ust_abi_counter_key_dimension by adding a "key_type" field. A new struct lttng_ust_abi_counter_key_dimension_tokens inherits from struct lttng_ust_abi_counter_key_dimension, and contains the uint32_t nr_key_tokens field. The only currently supported key_type is LTTNG_UST_ABI_KEY_TYPE_TOKENS = 0. Change the layout of struct lttng_ust_abi_counter_event by adding an "action" field. The only currently supported action is LTTNG_UST_ABI_COUNTER_ACTION_INCREMENT = 0. Change the struct lttng_ust_abi_key_token_string so it inherits from struct lttng_ust_abi_key_token. The "len" field of struct lttng_ust_abi_key_token now includes the length of the entire child structure. Change the newly introduced ABI between probe providers to change the "event_counter_add" callback into a "counter_hit" callback, which takes one less argument (no integer value), but takes additional stack_data, probe_ctx, and event_counter_ctx arguments for future use. Introduce a new LTTNG_UST_CTL_NOTIFY_CMD_KEY notification command to separate key notifications from event notifications, given that they require different arguments. Revert back the register event notification to return a 32-bit event ID: there is no point in changing the pre-existing protocol for event registration now that key registration gets its own protocol commands. Note that the protocol major is left at 10 even though we revert the event ID change, because the protocol was bumped to 10 due to a different change: commit f63969cc383c ("dynamic-type: remove underscore prefix from mapping names") Signed-off-by: Mathieu Desnoyers Change-Id: I0ed00dacfdaf333ffad406f8d017ee21bcbc212b --- include/lttng/ust-abi.h | 69 +++++-- include/lttng/ust-ctl.h | 44 ++++- include/lttng/ust-events.h | 23 ++- include/lttng/ust-tracepoint-event.h | 13 +- .../counter-clients/percpu-32-modular.c | 20 ++- .../counter-clients/percpu-64-modular.c | 20 ++- src/common/events.h | 24 ++- src/common/ustcomm.c | 111 +++++++++++- src/common/ustcomm.h | 41 ++++- src/lib/lttng-ust-ctl/ustctl.c | 153 +++++++++++++++- src/lib/lttng-ust/lttng-events.c | 62 ++++++- src/lib/lttng-ust/lttng-ust-abi.c | 170 ++++++++++++------ 12 files changed, 654 insertions(+), 96 deletions(-) diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 7db52c4e..7cda357d 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -125,32 +125,80 @@ enum lttng_ust_abi_counter_bitness { LTTNG_UST_ABI_COUNTER_BITNESS_64 = 1, }; -struct lttng_ust_abi_counter_key_string { - uint32_t string_len; /* string length (includes \0) */ - char str[]; /* Null-terminated string. */ +struct lttng_ust_abi_key_token { + uint32_t len; /* length of child structure. */ + uint32_t type; /* enum lttng_ust_abi_key_token_type */ + /* + * The size of this structure is fixed because it is embedded into + * children structures. + */ } __attribute__((packed)); -struct lttng_ust_abi_key_token { - uint32_t len; /* length of this structure. */ - uint32_t type; /* enum lttng_ust_key_token_type */ +/* Length of this structure excludes the following string. */ +struct lttng_ust_abi_key_token_string { + struct lttng_ust_abi_key_token parent; + uint32_t string_len; /* string length (includes \0) */ - /* Followed by a struct lttng_ust_abi_counter_key_string for LTTNG_UST_ABI_KEY_TOKEN_STRING. */ + char str[]; /* Null-terminated string following this structure. */ } __attribute__((packed)); +/* + * token types event_name and provider_name don't have specific fields, + * so they do not need to derive their own specific child structure. + */ + +/* + * Dimension indexing: All events should use the same key type to index + * a given map dimension. + */ +enum lttng_ust_abi_key_type { + LTTNG_UST_ABI_KEY_TYPE_TOKENS = 0, /* Dimension key is a set of tokens. */ + LTTNG_UST_ABI_KEY_TYPE_INTEGER = 1, /* Dimension key is an integer value. */ +}; + struct lttng_ust_abi_counter_key_dimension { - uint32_t len; /* length of this structure */ + uint32_t len; /* length of child structure */ + uint32_t key_type; /* enum lttng_ust_abi_key_type */ + /* + * The size of this structure is fixed because it is embedded into + * children structures. + */ +} __attribute__((packed)); + +struct lttng_ust_abi_counter_key_dimension_tokens { + struct lttng_ust_abi_counter_key_dimension parent; uint32_t nr_key_tokens; - /* Followed by a variable-length array of key tokens */ + /* Followed by an array of nr_key_tokens struct lttng_ust_abi_key_token elements. */ } __attribute__((packed)); +/* + * The "integer" key type is not implemented yet, but when it will be + * introduced in the future, its specific key dimension will allow + * defining the function to apply over input argument, bytecode to run + * and so on. + */ + +enum lttng_ust_abi_counter_action { + LTTNG_UST_ABI_COUNTER_ACTION_INCREMENT = 0, + + /* + * Can be extended with additional actions, such as decrement, + * set value, run bytecode, and so on. + */ +}; + struct lttng_ust_abi_counter_event { uint32_t len; /* length of this structure */ + uint32_t action; /* enum lttng_ust_abi_counter_action */ struct lttng_ust_abi_event event; uint32_t number_key_dimensions; /* array of dimensions is an array of var. len. elements. */ - /* Followed by a variable-length array of key dimensions */ + /* + * Followed by additional data specific to the action, and by a + * variable-length array of key dimensions. + */ } __attribute__((packed)); enum lttng_ust_abi_counter_dimension_flags { @@ -159,6 +207,7 @@ enum lttng_ust_abi_counter_dimension_flags { }; struct lttng_ust_abi_counter_dimension { + uint32_t key_type; /* enum lttng_ust_abi_key_type */ uint32_t flags; /* enum lttng_ust_abi_counter_dimension_flags */ uint64_t size; /* dimension size */ uint64_t underflow_index; diff --git a/include/lttng/ust-ctl.h b/include/lttng/ust-ctl.h index 3c197394..0bae1eac 100644 --- a/include/lttng/ust-ctl.h +++ b/include/lttng/ust-ctl.h @@ -312,6 +312,7 @@ enum lttng_ust_ctl_notify_cmd { LTTNG_UST_CTL_NOTIFY_CMD_EVENT = 0, LTTNG_UST_CTL_NOTIFY_CMD_CHANNEL = 1, LTTNG_UST_CTL_NOTIFY_CMD_ENUM = 2, + LTTNG_UST_CTL_NOTIFY_CMD_KEY = 3, }; enum lttng_ust_ctl_channel_header { @@ -543,7 +544,42 @@ int lttng_ust_ctl_recv_register_event(int sock, * Returns 0 on success, negative error value on error. */ int lttng_ust_ctl_reply_register_event(int sock, - uint64_t id, /* id (input) */ + uint32_t id, /* id (input) */ + int ret_code); /* return code. 0 ok, negative error */ + +/* + * Returns 0 on success, negative UST or system error value on error. + */ +int lttng_ust_ctl_recv_register_key(int sock, + int *session_objd, /* session descriptor (output) */ + int *map_objd, /* map descriptor (output) */ + uint32_t *dimension, /* + * Against which dimension is + * this key expressed. (output) + */ + uint64_t **dimension_indexes, /* + * Indexes (output, + * dynamically + * allocated, must be + * free(3)'d by the + * caller if function + * returns success.) + * Contains @dimension + * elements. + */ + char **key_string, /* + * key string (output, + * dynamically allocated, must + * be free(3)'d by the caller if + * function returns success.) + */ + uint64_t *user_token); + +/* + * Returns 0 on success, negative error value on error. + */ +int lttng_ust_ctl_reply_register_key(int sock, + uint64_t index, /* Index within dimension (input) */ int ret_code); /* return code. 0 ok, negative error */ /* @@ -593,6 +629,11 @@ enum lttng_ust_ctl_counter_arithmetic { LTTNG_UST_CTL_COUNTER_ARITHMETIC_SATURATION = 1, }; +enum lttng_ust_ctl_key_type { + LTTNG_UST_CTL_KEY_TYPE_TOKENS = 0, + LTTNG_UST_CTL_KEY_TYPE_INTEGER = 1, +}; + /* Used as alloc flags. */ enum lttng_ust_ctl_counter_alloc { LTTNG_UST_CTL_COUNTER_ALLOC_PER_CPU = (1 << 0), @@ -607,6 +648,7 @@ struct lttng_ust_ctl_counter_dimension { uint64_t size; uint64_t underflow_index; uint64_t overflow_index; + enum lttng_ust_ctl_key_type key_type; uint8_t has_underflow; uint8_t has_overflow; }; diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index 36304bc4..10581459 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -433,6 +433,22 @@ struct lttng_ust_event_recorder { struct lttng_ust_event_counter_private; +/* + * IMPORTANT: this structure is part of the ABI between the probe and + * UST. Fields need to be only added at the end, never reordered, never + * removed. + * + * The field @struct_size should be used to determine the size of the + * structure. It should be queried before using additional fields added + * at the end of the structure. + */ +struct lttng_ust_event_counter_ctx { + uint32_t struct_size; /* Size of this structure. */ + int args_available; /* Input arguments are available. */ + + /* End of base ABI. Fields below should be used after checking struct_size. */ +}; + /* * IMPORTANT: this structure is part of the ABI between the probe and * UST. Fields need to be only added at the end, never reordered, never @@ -455,6 +471,8 @@ struct lttng_ust_event_counter { struct lttng_ust_channel_counter *chan; + int use_args; /* Use input arguments. */ + /* End of base ABI. Fields below should be used after checking struct_size. */ }; @@ -602,7 +620,10 @@ struct lttng_ust_channel_counter_ops { struct lttng_ust_channel_counter_ops_private *priv; /* Private channel counter ops interface */ - int (*event_counter_add)(struct lttng_ust_event_counter *event_counter, int64_t v); + int (*counter_hit)(struct lttng_ust_event_counter *event_counter, + const char *stack_data, + struct lttng_ust_probe_ctx *probe_ctx, + struct lttng_ust_event_counter_ctx *event_counter_ctx); /* End of base ABI. Fields below should be used after checking struct_size. */ }; diff --git a/include/lttng/ust-tracepoint-event.h b/include/lttng/ust-tracepoint-event.h index 1a7ea744..5cc69d85 100644 --- a/include/lttng/ust-tracepoint-event.h +++ b/include/lttng/ust-tracepoint-event.h @@ -1049,8 +1049,19 @@ void lttng_ust__event_probe__##_provider##___##_name(LTTNG_UST__TP_ARGS_DATA_PRO case LTTNG_UST_EVENT_TYPE_COUNTER: \ { \ struct lttng_ust_event_counter *__event_counter = (struct lttng_ust_event_counter *) __event->child; \ + struct lttng_ust_event_counter_ctx __event_counter_ctx; \ \ - (void) __event_counter->chan->ops->event_counter_add(__event_counter, 1); \ + __event_counter_ctx.struct_size = sizeof(struct lttng_ust_event_counter_ctx); \ + __event_counter_ctx.args_available = CMM_ACCESS_ONCE(__event_counter->use_args); \ + \ + if (caa_unlikely(!__interpreter_stack_prepared && __event_counter_ctx.args_available)) \ + lttng_ust__event_prepare_interpreter_stack__##_provider##___##_name(__stackvar.__interpreter_stack_data, \ + LTTNG_UST__TP_ARGS_DATA_VAR(_args)); \ + \ + (void) __event_counter->chan->ops->counter_hit(__event_counter, \ + __stackvar.__interpreter_stack_data, \ + &__probe_ctx, \ + &__event_counter_ctx); \ break; \ } \ } \ diff --git a/src/common/counter-clients/percpu-32-modular.c b/src/common/counter-clients/percpu-32-modular.c index 8675dc3d..38a5a4f1 100644 --- a/src/common/counter-clients/percpu-32-modular.c +++ b/src/common/counter-clients/percpu-32-modular.c @@ -49,6 +49,8 @@ static struct lttng_ust_channel_counter *counter_create(size_t nr_dimensions, if (!counter) goto error; lttng_chan_counter->priv->counter = counter; + for (i = 0; i < nr_dimensions; i++) + lttng_chan_counter->priv->dimension_key_types[i] = dimensions[i].key_type; return lttng_chan_counter; error: @@ -68,12 +70,22 @@ static int counter_add(struct lttng_ust_channel_counter *counter, return lttng_counter_add(&client_config, counter->priv->counter, dimension_indexes, v); } -static int event_counter_add(struct lttng_ust_event_counter *event_counter, int64_t v) +static int counter_hit(struct lttng_ust_event_counter *event_counter, + const char *stack_data __attribute__((unused)), + struct lttng_ust_probe_ctx *probe_ctx __attribute__((unused)), + struct lttng_ust_event_counter_ctx *event_counter_ctx __attribute__((unused))) { struct lttng_ust_channel_counter *counter = event_counter->chan; - size_t index = event_counter->priv->parent.id; - return counter_add(counter, &index, v); + switch (event_counter->priv->action) { + case LTTNG_EVENT_COUNTER_ACTION_INCREMENT: + { + size_t index = event_counter->priv->parent.id; + return counter_add(counter, &index, 1); + } + default: + return -ENOSYS; + } } static int counter_read(struct lttng_ust_channel_counter *counter, const size_t *dimension_indexes, int cpu, @@ -108,7 +120,7 @@ static struct lttng_counter_transport lttng_counter_transport = { .counter_aggregate = counter_aggregate, .counter_clear = counter_clear, }), - .event_counter_add = event_counter_add, + .counter_hit = counter_hit, }, .client_config = &client_config, }; diff --git a/src/common/counter-clients/percpu-64-modular.c b/src/common/counter-clients/percpu-64-modular.c index c73f8d99..20bf4bc1 100644 --- a/src/common/counter-clients/percpu-64-modular.c +++ b/src/common/counter-clients/percpu-64-modular.c @@ -49,6 +49,8 @@ static struct lttng_ust_channel_counter *counter_create(size_t nr_dimensions, if (!counter) goto error; lttng_chan_counter->priv->counter = counter; + for (i = 0; i < nr_dimensions; i++) + lttng_chan_counter->priv->dimension_key_types[i] = dimensions[i].key_type; return lttng_chan_counter; error: @@ -68,12 +70,22 @@ static int counter_add(struct lttng_ust_channel_counter *counter, return lttng_counter_add(&client_config, counter->priv->counter, dimension_indexes, v); } -static int event_counter_add(struct lttng_ust_event_counter *event_counter, int64_t v) +static int counter_hit(struct lttng_ust_event_counter *event_counter, + const char *stack_data __attribute__((unused)), + struct lttng_ust_probe_ctx *probe_ctx __attribute__((unused)), + struct lttng_ust_event_counter_ctx *event_counter_ctx __attribute__((unused))) { struct lttng_ust_channel_counter *counter = event_counter->chan; - size_t index = event_counter->priv->parent.id; - return counter_add(counter, &index, v); + switch (event_counter->priv->action) { + case LTTNG_EVENT_COUNTER_ACTION_INCREMENT: + { + size_t index = event_counter->priv->parent.id; + return counter_add(counter, &index, 1); + } + default: + return -ENOSYS; + } } static int counter_read(struct lttng_ust_channel_counter *counter, const size_t *dimension_indexes, int cpu, @@ -108,7 +120,7 @@ static struct lttng_counter_transport lttng_counter_transport = { .counter_aggregate = counter_aggregate, .counter_clear = counter_clear, }), - .event_counter_add = event_counter_add, + .counter_hit = counter_hit, }, .client_config = &client_config, }; diff --git a/src/common/events.h b/src/common/events.h index 2ac7a44e..d53a587b 100644 --- a/src/common/events.h +++ b/src/common/events.h @@ -86,10 +86,21 @@ struct lttng_key_token { } arg; }; +enum lttng_key_type { + LTTNG_KEY_TYPE_TOKENS = 0, + LTTNG_KEY_TYPE_INTEGER = 1, +}; + #define LTTNG_NR_KEY_TOKEN 8 struct lttng_counter_key_dimension { - size_t nr_key_tokens; - struct lttng_key_token key_tokens[LTTNG_NR_KEY_TOKEN]; + enum lttng_key_type key_type; + + union { + struct { + size_t nr_key_tokens; + struct lttng_key_token key_tokens[LTTNG_NR_KEY_TOKEN]; + } tokens; + } u; }; #define LTTNG_COUNTER_DIMENSION_MAX 4 @@ -102,6 +113,7 @@ struct lttng_counter_dimension { uint64_t size; uint64_t underflow_index; uint64_t overflow_index; + enum lttng_key_type key_type; uint8_t has_underflow; uint8_t has_overflow; }; @@ -143,10 +155,16 @@ struct lttng_event_recorder_enabler { struct lttng_ust_channel_buffer *chan; }; +enum lttng_event_counter_action { + LTTNG_EVENT_COUNTER_ACTION_INCREMENT = 0, +}; + struct lttng_event_counter_enabler { struct lttng_event_enabler_session_common parent; struct lttng_ust_channel_counter *chan; struct lttng_counter_key key; + + enum lttng_event_counter_action action; }; struct lttng_event_notifier_enabler { @@ -322,6 +340,7 @@ struct lttng_ust_event_counter_private { struct lttng_ust_event_session_common_private parent; struct lttng_ust_event_counter *pub; /* Public event interface */ + enum lttng_event_counter_action action; char key[LTTNG_KEY_TOKEN_STRING_LEN_MAX]; }; @@ -471,6 +490,7 @@ struct lttng_ust_channel_counter_private { struct lttng_session *session; struct cds_list_head node; /* Counter list (in session) */ size_t free_index; /* Next index to allocate */ + enum lttng_key_type dimension_key_types[LTTNG_COUNTER_DIMENSION_MAX]; }; /* diff --git a/src/common/ustcomm.c b/src/common/ustcomm.c index 1cf368b8..7bec2048 100644 --- a/src/common/ustcomm.c +++ b/src/common/ustcomm.c @@ -1370,7 +1370,7 @@ int ustcomm_register_event(int sock, const struct lttng_ust_event_field * const *lttng_fields, const char *model_emf_uri, uint64_t user_token, - uint64_t *id) /* event id (output) */ + uint32_t *id) /* event id (output) */ { ssize_t len; struct { @@ -1478,7 +1478,7 @@ int ustcomm_register_event(int sock, if (reply.r.ret_code < 0) return reply.r.ret_code; *id = reply.r.id; - DBG("Sent register event notification for name \"%s\": ret_code %d, id %" PRIu64 "\n", + DBG("Sent register event notification for name \"%s\": ret_code %d, id %" PRIu32 "\n", event_name, reply.r.ret_code, reply.r.id); return 0; default: @@ -1500,6 +1500,113 @@ error_fields: return ret; } +/* + * Returns 0 on success, negative error value on error. + * Returns -EPIPE or -ECONNRESET if other end has hung up. + */ +int ustcomm_register_key(int sock, + int session_objd, /* session descriptor */ + int map_objd, /* map descriptor */ + uint32_t dimension, + const uint64_t *dimension_indexes, + const char *key_string, /* key string (input) */ + uint64_t user_token, + uint64_t *index) /* (output) */ +{ + ssize_t len; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_key_msg m; + } msg; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_key_reply r; + } reply; + size_t dimension_indexes_len; + int ret; + + memset(&msg, 0, sizeof(msg)); + msg.header.notify_cmd = LTTNG_UST_CTL_NOTIFY_CMD_KEY; + msg.m.session_objd = session_objd; + msg.m.map_objd = map_objd; + msg.m.dimension = dimension; + dimension_indexes_len = sizeof(uint64_t) * dimension; + msg.m.key_string_len = strlen(key_string) + 1; + msg.m.user_token = user_token; + + len = ustcomm_send_unix_sock(sock, &msg, sizeof(msg)); + if (len > 0 && len != sizeof(msg)) { + ret = -EIO; + goto error_send; + } + if (len < 0) { + ret = len; + goto error_send; + } + + /* send dimension_indexes */ + if (dimension_indexes) { + len = ustcomm_send_unix_sock(sock, dimension_indexes, dimension_indexes_len); + if (len > 0 && len != dimension_indexes_len) { + ret = -EIO; + goto error_dimension_indexes; + } + if (len < 0) { + ret = len; + goto error_dimension_indexes; + } + } + + /* send key_string */ + len = ustcomm_send_unix_sock(sock, key_string, msg.m.key_string_len); + if (len > 0 && len != dimension_indexes_len) { + ret = -EIO; + goto error_dimension_indexes; + } + if (len < 0) { + ret = len; + goto error_dimension_indexes; + } + + /* receive reply */ + len = ustcomm_recv_unix_sock(sock, &reply, sizeof(reply)); + switch (len) { + case 0: /* orderly shutdown */ + return -EPIPE; + case sizeof(reply): + if (reply.header.notify_cmd != msg.header.notify_cmd) { + ERR("Unexpected result message command " + "expected: %u vs received: %u\n", + msg.header.notify_cmd, reply.header.notify_cmd); + return -EINVAL; + } + if (reply.r.ret_code > 0) + return -EINVAL; + if (reply.r.ret_code < 0) + return reply.r.ret_code; + *index = reply.r.index; + DBG("Sent register key notification for key \"%s\": ret_code %d, index %" PRIu64 "\n", + key_string, reply.r.ret_code, reply.r.index); + return 0; + default: + if (len < 0) { + /* Transport level error */ + if (errno == EPIPE || errno == ECONNRESET) + len = -errno; + return len; + } else { + ERR("incorrect message size: %zd\n", len); + return len; + } + } + /* Unreached. */ + + /* Error path only. */ +error_dimension_indexes: +error_send: + return ret; +} + /* * Returns 0 on success, negative error value on error. * Returns -EPIPE or -ECONNRESET if other end has hung up. diff --git a/src/common/ustcomm.h b/src/common/ustcomm.h index 6b555391..7ecb365b 100644 --- a/src/common/ustcomm.h +++ b/src/common/ustcomm.h @@ -144,16 +144,31 @@ struct ustcomm_notify_event_msg { /* followed by signature, fields, and model_emf_uri */ } __attribute__((packed)); -#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING 24 +#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING 32 struct ustcomm_notify_event_reply { int32_t ret_code; /* 0: ok, negative: error code */ - - /* 32-bit (lower bits) event id for backward compatibility with ABI major < 10 */ - uint32_t old_event_id; /* TODO: remove field on future protocol compatibility break. */ - uint64_t id; /* 64-bit event id. */ + uint32_t id; /* 32-bit event id. */ char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING]; } __attribute__((packed)); +#define USTCOMM_NOTIFY_KEY_MSG_PADDING 24 +struct ustcomm_notify_key_msg { + uint32_t session_objd; + uint32_t map_objd; + uint32_t dimension; + uint32_t key_string_len; + uint64_t user_token; + char padding[USTCOMM_NOTIFY_KEY_MSG_PADDING]; + /* followed by dimension_indexes (array of @dimension uint64_t items) and key_string. */ +} __attribute__((packed)); + +#define USTCOMM_NOTIFY_KEY_REPLY_PADDING 32 +struct ustcomm_notify_key_reply { + int32_t ret_code; /* 0: ok, negative: error code */ + uint64_t index; /* 64-bit key index. */ + char padding[USTCOMM_NOTIFY_KEY_REPLY_PADDING]; +} __attribute__((packed)); + #define USTCOMM_NOTIFY_ENUM_MSG_PADDING 32 struct ustcomm_notify_enum_msg { uint32_t session_objd; @@ -292,7 +307,21 @@ int ustcomm_register_event(int sock, const struct lttng_ust_event_field * const *fields, const char *model_emf_uri, uint64_t user_token, - uint64_t *id) /* (output) */ + uint32_t *id) /* (output) */ + __attribute__((visibility("hidden"))); + +/* + * Returns 0 on success, negative error value on error. + * Returns -EPIPE or -ECONNRESET if other end has hung up. + */ +int ustcomm_register_key(int sock, + int session_objd, /* session descriptor */ + int map_objd, /* map descriptor */ + uint32_t dimension, + const uint64_t *dimension_indexes, + const char *key_string, /* key string (input) */ + uint64_t user_token, + uint64_t *index) /* (output) */ __attribute__((visibility("hidden"))); /* diff --git a/src/lib/lttng-ust-ctl/ustctl.c b/src/lib/lttng-ust-ctl/ustctl.c index bf8c1373..92e52464 100644 --- a/src/lib/lttng-ust-ctl/ustctl.c +++ b/src/lib/lttng-ust-ctl/ustctl.c @@ -2548,6 +2548,9 @@ int lttng_ust_ctl_recv_notify(int sock, enum lttng_ust_ctl_notify_cmd *notify_cm case 2: *notify_cmd = LTTNG_UST_CTL_NOTIFY_CMD_ENUM; break; + case 3: + *notify_cmd = LTTNG_UST_CTL_NOTIFY_CMD_KEY; + break; default: return -EINVAL; } @@ -2681,7 +2684,7 @@ signature_error: * Returns 0 on success, negative error value on error. */ int lttng_ust_ctl_reply_register_event(int sock, - uint64_t id, + uint32_t id, int ret_code) { ssize_t len; @@ -2693,7 +2696,6 @@ int lttng_ust_ctl_reply_register_event(int sock, memset(&reply, 0, sizeof(reply)); reply.header.notify_cmd = LTTNG_UST_CTL_NOTIFY_CMD_EVENT; reply.r.ret_code = ret_code; - reply.r.old_event_id = (uint32_t) id; /* For backward compatibility */ reply.r.id = id; len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply)); if (len > 0 && len != sizeof(reply)) @@ -2703,6 +2705,134 @@ int lttng_ust_ctl_reply_register_event(int sock, return 0; } +/* + * Returns 0 on success, negative UST or system error value on error. + */ +int lttng_ust_ctl_recv_register_key(int sock, + int *session_objd, /* session descriptor (output) */ + int *map_objd, /* map descriptor (output) */ + uint32_t *dimension, /* + * Against which dimension is + * this key expressed. (output) + */ + uint64_t **dimension_indexes, /* + * Indexes (output, + * dynamically + * allocated, must be + * free(3)'d by the + * caller if function + * returns success.) + * Contains @dimension + * elements. + */ + char **key_string, /* + * key string (output, + * dynamically allocated, must + * be free(3)'d by the caller if + * function returns success.) + */ + uint64_t *user_token) +{ + ssize_t len; + struct ustcomm_notify_key_msg msg; + size_t dimension_indexes_len, key_string_len; + uint64_t *a_dimension_indexes = NULL; + char *a_key_string = NULL; + + len = ustcomm_recv_unix_sock(sock, &msg, sizeof(msg)); + if (len > 0 && len != sizeof(msg)) + return -EIO; + if (len == 0) + return -EPIPE; + if (len < 0) + return len; + + *session_objd = msg.session_objd; + *map_objd = msg.map_objd; + *dimension = msg.dimension; + dimension_indexes_len = msg.dimension * sizeof(uint64_t); + key_string_len = msg.key_string_len; + *user_token = msg.user_token; + + if (dimension_indexes_len) { + /* recv dimension_indexes */ + a_dimension_indexes = zmalloc(dimension_indexes_len); + if (!a_dimension_indexes) { + len = -ENOMEM; + goto error; + } + len = ustcomm_recv_unix_sock(sock, a_dimension_indexes, dimension_indexes_len); + if (len > 0 && len != dimension_indexes_len) { + len = -EIO; + goto error; + } + if (len == 0) { + len = -EPIPE; + goto error; + } + if (len < 0) { + goto error; + } + } + + if (key_string_len) { + /* recv key_string */ + a_key_string = zmalloc(key_string_len); + if (!a_key_string) { + len = -ENOMEM; + goto error; + } + len = ustcomm_recv_unix_sock(sock, a_key_string, key_string_len); + if (len > 0 && len != key_string_len) { + len = -EIO; + goto error; + } + if (len == 0) { + len = -EPIPE; + goto error; + } + if (len < 0) { + goto error; + } + /* Enforce end of string */ + a_key_string[key_string_len - 1] = '\0'; + } + + *dimension_indexes = a_dimension_indexes; + *key_string = a_key_string; + return 0; + +error: + free(a_key_string); + free(a_dimension_indexes); + return len; +} + +/* + * Returns 0 on success, negative error value on error. + */ +int lttng_ust_ctl_reply_register_key(int sock, + uint64_t index, /* Index within dimension (input) */ + int ret_code) /* return code. 0 ok, negative error */ +{ + ssize_t len; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_key_reply r; + } reply; + + memset(&reply, 0, sizeof(reply)); + reply.header.notify_cmd = LTTNG_UST_CTL_NOTIFY_CMD_KEY; + reply.r.ret_code = ret_code; + reply.r.index = index; + len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply)); + if (len > 0 && len != sizeof(reply)) + return -EIO; + if (len < 0) + return len; + return 0; +} + /* * Returns 0 on success, negative UST or system error value on error. */ @@ -2996,6 +3126,14 @@ struct lttng_ust_ctl_daemon_counter * ust_dim[i].overflow_index = dimensions[i].overflow_index; ust_dim[i].has_underflow = dimensions[i].has_underflow; ust_dim[i].has_overflow = dimensions[i].has_overflow; + switch (dimensions[i].key_type) { + case LTTNG_UST_CTL_KEY_TYPE_TOKENS: + ust_dim[i].key_type = LTTNG_KEY_TYPE_TOKENS; + break; + case LTTNG_UST_CTL_KEY_TYPE_INTEGER: /* Fall-through */ + default: + goto free_attr; + } } counter->counter = transport->ops.priv->counter_create(nr_dimensions, ust_dim, global_sum_step, global_counter_fd, @@ -3065,6 +3203,15 @@ int lttng_ust_ctl_create_counter_data(struct lttng_ust_ctl_daemon_counter *count dimension->size = counter->attr->dimensions[0].size; dimension->underflow_index = counter->attr->dimensions[0].underflow_index; dimension->overflow_index = counter->attr->dimensions[0].overflow_index; + switch (counter->attr->dimensions[0].key_type) { + case LTTNG_UST_CTL_KEY_TYPE_TOKENS: + dimension->key_type = LTTNG_UST_ABI_KEY_TYPE_TOKENS; + break; + case LTTNG_UST_CTL_KEY_TYPE_INTEGER: /* Fall-through */ + default: + ret = -EINVAL; + goto error; + } counter_data = zmalloc(sizeof(*counter_data)); if (!counter_data) { @@ -3180,6 +3327,8 @@ int lttng_ust_ctl_send_old_counter_data_to_ust(int sock, int parent_handle, old_counter_conf.dimensions[0].has_overflow = (dimension->flags & LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_OVERFLOW) ? 1 : 0; old_counter_conf.dimensions[0].underflow_index = dimension->underflow_index; old_counter_conf.dimensions[0].overflow_index = dimension->overflow_index; + if (dimension->key_type != LTTNG_UST_ABI_KEY_TYPE_TOKENS) + return -EINVAL; size = sizeof(old_counter_conf); lum.handle = parent_handle; diff --git a/src/lib/lttng-ust/lttng-events.c b/src/lib/lttng-ust/lttng-events.c index 88094fd7..2839d0c0 100644 --- a/src/lib/lttng-ust/lttng-events.c +++ b/src/lib/lttng-ust/lttng-events.c @@ -742,8 +742,11 @@ int format_event_key(struct lttng_event_enabler_common *event_enabler, char *key if (key->nr_dimensions != 1) return -EINVAL; dim = &key->key_dimensions[0]; - for (i = 0; i < dim->nr_key_tokens; i++) { - const struct lttng_key_token *token = &dim->key_tokens[i]; + /* Currently only tokens keys are supported. */ + if (dim->key_type != LTTNG_KEY_TYPE_TOKENS) + return -EINVAL; + for (i = 0; i < dim->u.tokens.nr_key_tokens; i++) { + const struct lttng_key_token *token = &dim->u.tokens.key_tokens[i]; size_t token_len; const char *str; @@ -950,6 +953,7 @@ struct lttng_ust_event_common *lttng_ust_event_alloc(struct lttng_event_enabler_ event_counter->priv->parent.parent.user_token = event_counter_enabler->parent.parent.user_token; event_counter->priv->parent.parent.desc = desc; strcpy(event_counter_priv->key, key_string); + event_counter_priv->action = event_counter_enabler->action; return event_counter->parent; } default: @@ -1005,7 +1009,6 @@ int lttng_event_register_to_sessiond(struct lttng_event_enabler_common *event_en { switch (event_enabler->enabler_type) { case LTTNG_EVENT_ENABLER_TYPE_RECORDER: /* Fall-through */ - case LTTNG_EVENT_ENABLER_TYPE_COUNTER: { struct lttng_event_enabler_session_common *event_enabler_session = caa_container_of(event_enabler, struct lttng_event_enabler_session_common, parent); @@ -1013,8 +1016,9 @@ int lttng_event_register_to_sessiond(struct lttng_event_enabler_common *event_en caa_container_of(event->priv, struct lttng_ust_event_session_common_private, parent); struct lttng_ust_session *session = event_enabler_session->chan->session; const struct lttng_ust_event_desc *desc = event->priv->desc; - int notify_socket, loglevel; + int notify_socket, loglevel, ret; const char *uri; + uint32_t id; if (desc->loglevel) loglevel = *(*desc->loglevel); @@ -1030,7 +1034,7 @@ int lttng_event_register_to_sessiond(struct lttng_event_enabler_common *event_en return notify_socket; /* Fetch event ID from sessiond */ - return ustcomm_register_event(notify_socket, + ret = ustcomm_register_event(notify_socket, session, session->priv->objd, event_enabler_session->chan->priv->objd, @@ -1041,7 +1045,39 @@ int lttng_event_register_to_sessiond(struct lttng_event_enabler_common *event_en desc->tp_class->fields, uri, event_enabler_session->parent.user_token, - &event_session_priv->id); + &id); + if (ret) + return ret; + event_session_priv->id = id; + return 0; + } + case LTTNG_EVENT_ENABLER_TYPE_COUNTER: + { + struct lttng_event_enabler_session_common *event_enabler_session = + caa_container_of(event_enabler, struct lttng_event_enabler_session_common, parent); + struct lttng_ust_event_session_common_private *event_session_priv = + caa_container_of(event->priv, struct lttng_ust_event_session_common_private, parent); + struct lttng_ust_session *session = event_enabler_session->chan->session; + uint64_t dimension_index[LTTNG_COUNTER_DIMENSION_MAX]; + int notify_socket, ret; + + notify_socket = lttng_get_notify_socket(session->priv->owner); + if (notify_socket < 0) + return notify_socket; + + /* Fetch key index from sessiond */ + ret = ustcomm_register_key(notify_socket, + session->priv->objd, + event_enabler_session->chan->priv->objd, + 0, /* target dimension */ + NULL, + name, + event_enabler_session->parent.user_token, + dimension_index); /* Filled up to target dimension. */ + if (ret) + return ret; + event_session_priv->id = dimension_index[0]; + return 0; } case LTTNG_EVENT_ENABLER_TYPE_NOTIFIER: @@ -1697,10 +1733,20 @@ struct lttng_event_counter_enabler *lttng_event_counter_enabler_create( struct lttng_ust_channel_counter *chan) { struct lttng_event_counter_enabler *event_enabler; + enum lttng_event_counter_action action; event_enabler = zmalloc(sizeof(*event_enabler)); if (!event_enabler) return NULL; + + switch (counter_event->action) { + case LTTNG_UST_ABI_COUNTER_ACTION_INCREMENT: + action = LTTNG_EVENT_COUNTER_ACTION_INCREMENT; + break; + default: + goto error; + } + event_enabler->action = action; event_enabler->parent.parent.enabler_type = LTTNG_EVENT_ENABLER_TYPE_COUNTER; event_enabler->parent.parent.format_type = format_type; CDS_INIT_LIST_HEAD(&event_enabler->parent.parent.filter_bytecode_head); @@ -1717,6 +1763,10 @@ struct lttng_event_counter_enabler *lttng_event_counter_enabler_create( lttng_session_lazy_sync_event_enablers(event_enabler->chan->parent->session); return event_enabler; + +error: + free(event_enabler); + return NULL; } struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create( diff --git a/src/lib/lttng-ust/lttng-ust-abi.c b/src/lib/lttng-ust/lttng-ust-abi.c index 63e21f21..2adb127e 100644 --- a/src/lib/lttng-ust/lttng-ust-abi.c +++ b/src/lib/lttng-ust/lttng-ust-abi.c @@ -701,6 +701,14 @@ long lttng_session_create_counter( dimensions[0].overflow_index = dimension.overflow_index; dimensions[0].has_underflow = dimension.flags & LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_UNDERFLOW; dimensions[0].has_overflow = dimension.flags & LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_OVERFLOW; + switch (dimension.key_type) { + case LTTNG_UST_ABI_KEY_TYPE_TOKENS: + dimensions[0].key_type = LTTNG_KEY_TYPE_TOKENS; + break; + case LTTNG_UST_ABI_KEY_TYPE_INTEGER: /* Fall-through */ + default: + return -EINVAL; + } counter_objd = objd_alloc(NULL, <tng_counter_ops, owner, "counter"); if (counter_objd < 0) { @@ -1374,79 +1382,110 @@ objd_error: return ret; } +static +int copy_counter_key_dimension_tokens(const struct lttng_ust_abi_counter_key_dimension_tokens *abi_dim_tokens, + const char *addr, size_t *offset, size_t arg_len, struct lttng_counter_key_dimension *internal_dim) +{ + struct lttng_ust_abi_counter_key_dimension_tokens dim_tokens; + size_t nr_key_tokens, j; + int ret; + + if (abi_dim_tokens->parent.len < sizeof(struct lttng_ust_abi_counter_key_dimension_tokens)) + return -EINVAL; + ret = copy_abi_struct(&dim_tokens, sizeof(dim_tokens), abi_dim_tokens, abi_dim_tokens->parent.len); + if (ret) + return ret; + nr_key_tokens = dim_tokens.nr_key_tokens; + if (!nr_key_tokens || nr_key_tokens > LTTNG_NR_KEY_TOKEN) + return -EINVAL; + internal_dim->key_type = LTTNG_KEY_TYPE_TOKENS; + internal_dim->u.tokens.nr_key_tokens = nr_key_tokens; + *offset += sizeof(struct lttng_ust_abi_counter_key_dimension_tokens); + for (j = 0; j < nr_key_tokens; j++) { + struct lttng_key_token *internal_token = &internal_dim->u.tokens.key_tokens[j]; + const struct lttng_ust_abi_key_token *abi_token; + + if (*offset + sizeof(struct lttng_ust_abi_key_token) > arg_len) + return -EINVAL; + abi_token = (const struct lttng_ust_abi_key_token *)(addr + *offset); + if (abi_token->len < sizeof(struct lttng_ust_abi_key_token)) + return -EINVAL; + if (*offset + abi_token->len > arg_len) + return -EINVAL; + switch (abi_token->type) { + case LTTNG_UST_ABI_KEY_TOKEN_STRING: + { + const struct lttng_ust_abi_key_token_string *abi_key_string; + struct lttng_ust_abi_key_token_string token_string; + + if (abi_token->len < sizeof(struct lttng_ust_abi_key_token_string)) + return -EINVAL; + abi_key_string = (const struct lttng_ust_abi_key_token_string *)(addr + *offset); + ret = copy_abi_struct(&token_string, sizeof(token_string), abi_key_string, abi_key_string->parent.len); + if (ret) + return ret; + *offset += abi_key_string->parent.len; + internal_token->type = LTTNG_KEY_TOKEN_STRING; + if (!abi_key_string->string_len || abi_key_string->string_len > LTTNG_KEY_TOKEN_STRING_LEN_MAX) + return -EINVAL; + *offset += abi_key_string->string_len; + if (*offset > arg_len) + return -EINVAL; + if (abi_key_string->str[abi_key_string->string_len - 1] != '\0' || + strlen(abi_key_string->str) + 1 != abi_key_string->string_len) + return -EINVAL; + memcpy(internal_token->arg.string, abi_key_string->str, abi_key_string->string_len); + break; + } + case LTTNG_UST_ABI_KEY_TOKEN_EVENT_NAME: + internal_token->type = LTTNG_KEY_TOKEN_EVENT_NAME; + *offset += abi_token->len; + break; + case LTTNG_UST_ABI_KEY_TOKEN_PROVIDER_NAME: + internal_token->type = LTTNG_KEY_TOKEN_PROVIDER_NAME; + *offset += abi_token->len; + break; + default: + return -EINVAL; + } + } + return 0; +} + static int copy_counter_key(struct lttng_counter_key *internal_key, - unsigned long arg, size_t arg_len, + unsigned long arg, size_t action_fields_len, size_t arg_len, const struct lttng_ust_abi_counter_event *counter_event) { - size_t i, j, nr_dimensions, offset = 0; - char *addr = (char *)arg; + size_t i, nr_dimensions, offset = 0; + const char *addr = (const char *)arg; int ret; nr_dimensions = counter_event->number_key_dimensions; if (nr_dimensions != 1) return -EINVAL; internal_key->nr_dimensions = nr_dimensions; - offset += counter_event->len; + offset += counter_event->len + action_fields_len; for (i = 0; i < nr_dimensions; i++) { - const struct lttng_ust_abi_counter_key_dimension *abi_dim; - struct lttng_ust_abi_counter_key_dimension dim; struct lttng_counter_key_dimension *internal_dim = &internal_key->key_dimensions[i]; - size_t nr_key_tokens; + const struct lttng_ust_abi_counter_key_dimension *abi_dim; abi_dim = (const struct lttng_ust_abi_counter_key_dimension *)(addr + offset); - offset += abi_dim->len; - if (offset > arg_len || abi_dim->len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_key_dimension, nr_key_tokens)) + if (offset + abi_dim->len > arg_len || abi_dim->len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_key_dimension, key_type)) return -EINVAL; - ret = copy_abi_struct(&dim, sizeof(dim), abi_dim, abi_dim->len); - if (ret) - return ret; - nr_key_tokens = dim.nr_key_tokens; - if (!nr_key_tokens || nr_key_tokens > LTTNG_NR_KEY_TOKEN) - return -EINVAL; - internal_dim->nr_key_tokens = nr_key_tokens; - for (j = 0; j < nr_key_tokens; j++) { - const struct lttng_ust_abi_key_token *abi_token; - struct lttng_ust_abi_key_token token; - struct lttng_key_token *internal_token = &internal_dim->key_tokens[j]; - - abi_token = (const struct lttng_ust_abi_key_token *)(addr + offset); - offset += abi_token->len; - if (offset > arg_len || abi_token->len < lttng_ust_offsetofend(struct lttng_ust_abi_key_token, type)) - return -EINVAL; - ret = copy_abi_struct(&token, sizeof(token), abi_token, abi_token->len); + switch (abi_dim->key_type) { + case LTTNG_UST_ABI_KEY_TYPE_TOKENS: + { + struct lttng_ust_abi_counter_key_dimension_tokens *dim_tokens = + caa_container_of(abi_dim, struct lttng_ust_abi_counter_key_dimension_tokens, parent); + ret = copy_counter_key_dimension_tokens(dim_tokens, addr, &offset, arg_len, + internal_dim); if (ret) return ret; - switch (token.type) { - case LTTNG_UST_ABI_KEY_TOKEN_STRING: - { - const struct lttng_ust_abi_counter_key_string *abi_key_string; - - abi_key_string = (const struct lttng_ust_abi_counter_key_string *)(addr + offset); - offset += sizeof(struct lttng_ust_abi_counter_key_string); - if (offset > arg_len) - return -EINVAL; - internal_token->type = LTTNG_KEY_TOKEN_STRING; - if (!abi_key_string->string_len || abi_key_string->string_len > LTTNG_KEY_TOKEN_STRING_LEN_MAX) - return -EINVAL; - offset += abi_key_string->string_len; - if (offset > arg_len) - return -EINVAL; - if (abi_key_string->str[abi_key_string->string_len - 1] != '\0' || - strlen(abi_key_string->str) + 1 != abi_key_string->string_len) - return -EINVAL; - memcpy(internal_token->arg.string, abi_key_string->str, abi_key_string->string_len); - break; - } - case LTTNG_UST_ABI_KEY_TOKEN_EVENT_NAME: - internal_token->type = LTTNG_KEY_TOKEN_EVENT_NAME; - break; - case LTTNG_UST_ABI_KEY_TOKEN_PROVIDER_NAME: - internal_token->type = LTTNG_KEY_TOKEN_PROVIDER_NAME; - break; - default: - return -EINVAL; - } + break; + } + default: + return -EINVAL; } } return 0; @@ -1462,7 +1501,9 @@ int lttng_abi_create_event_counter_enabler(int channel_objd, struct lttng_counter_key counter_key = {}; struct lttng_event_counter_enabler *enabler; enum lttng_enabler_format_type format_type; + size_t action_fields_len = 0; int event_objd, ret; + size_t i; if (arg_len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_event, number_key_dimensions)) { return -EINVAL; @@ -1476,16 +1517,31 @@ int lttng_abi_create_event_counter_enabler(int channel_objd, if (ret) { return ret; } + switch (counter_event.action) { + case LTTNG_UST_ABI_COUNTER_ACTION_INCREMENT: + /* No additional fields specific to this action. */ + break; + default: + return -EINVAL; + } counter_event.event.name[LTTNG_UST_ABI_SYM_NAME_LEN - 1] = '\0'; if (strutils_is_star_glob_pattern(counter_event.event.name)) { format_type = LTTNG_ENABLER_FORMAT_STAR_GLOB; } else { format_type = LTTNG_ENABLER_FORMAT_EVENT; } - ret = copy_counter_key(&counter_key, arg, arg_len, &counter_event); + ret = copy_counter_key(&counter_key, arg, action_fields_len, arg_len, &counter_event); if (ret) { return ret; } + /* + * Validate that each dimension counter key type match the map + * key type. + */ + for (i = 0; i < counter_key.nr_dimensions; i++) { + if (channel->priv->dimension_key_types[i] != counter_key.key_dimensions[i].key_type) + return -EINVAL; + } event_objd = objd_alloc(NULL, <tng_event_enabler_ops, owner, "event enabler"); if (event_objd < 0) { -- 2.34.1