+static
+bool lttng_event_container_current_id_full(struct lttng_event_container *container)
+{
+ switch (container->type) {
+ case LTTNG_EVENT_CONTAINER_CHANNEL:
+ {
+ struct lttng_channel *channel = lttng_event_container_get_channel(container);
+
+ return channel->free_event_id == -1U;
+ }
+ case LTTNG_EVENT_CONTAINER_COUNTER:
+ {
+ struct lttng_counter *counter = lttng_event_container_get_counter(container);
+ size_t nr_dimensions, max_nr_elem;
+
+ if (lttng_counter_get_nr_dimensions(&counter->counter->config,
+ counter->counter, &nr_dimensions))
+ return true;
+ WARN_ON_ONCE(nr_dimensions != 1);
+ if (nr_dimensions != 1)
+ return true;
+ if (lttng_counter_get_max_nr_elem(&counter->counter->config,
+ counter->counter, &max_nr_elem))
+ return true;
+ return counter->free_index >= max_nr_elem;
+ }
+ default:
+ WARN_ON_ONCE(1);
+ return true;
+ }
+}
+
+
+static
+int lttng_event_container_allocate_id(struct lttng_event_container *container,
+ const char *key_string, size_t *id)
+{
+ struct lttng_session *session = container->session;
+ struct lttng_event *event;
+
+ if (key_string[0]) {
+ struct hlist_head *head;
+
+ head = utils_borrow_hash_table_bucket(session->events_key_ht.table,
+ LTTNG_EVENT_HT_SIZE, key_string);
+ lttng_hlist_for_each_entry(event, head, key_hlist) {
+ if (!strcmp(key_string, event->key)) {
+ /* Same key, use same id. */
+ *id = event->id;
+ return 0;
+ }
+ }
+ }
+
+ if (lttng_event_container_current_id_full(container)) {
+ return -EMFILE;
+ }
+
+ switch (container->type) {
+ case LTTNG_EVENT_CONTAINER_CHANNEL:
+ {
+ struct lttng_channel *channel = lttng_event_container_get_channel(container);
+ *id = channel->free_event_id++;
+ break;
+ }
+ case LTTNG_EVENT_CONTAINER_COUNTER:
+ {
+ struct lttng_counter *counter = lttng_event_container_get_counter(container);
+ *id = counter->free_index++;
+ break;
+ }
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+
+ return 0;
+}
+
+static
+int format_event_key(char *key_string, const struct lttng_counter_key *key,
+ const char *event_name)
+{
+ const struct lttng_counter_key_dimension *dim;
+ size_t i, left = LTTNG_KEY_TOKEN_STRING_LEN_MAX;
+
+ key_string[0] = '\0';
+ if (!key || !key->nr_dimensions)
+ return 0;
+ /* Currently event keys can only be specified on a single dimension. */
+ 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];
+ size_t token_len;
+ const char *str;
+
+ switch (token->type) {
+ case LTTNG_KEY_TOKEN_STRING:
+ str = token->arg.string;
+ break;
+ case LTTNG_KEY_TOKEN_EVENT_NAME:
+ str = event_name;
+ break;
+ default:
+ return -EINVAL;
+ }
+ token_len = strlen(str);
+ if (token_len >= left)
+ return -EINVAL;
+ strcat(key_string, str);
+ left -= token_len;
+ }
+ return 0;
+}
+
+static
+bool match_event_token(struct lttng_event_container *container,
+ struct lttng_event *event, uint64_t token)
+{
+ if (container->coalesce_hits)
+ return true;
+ if (event->user_token == token)
+ return true;
+ return false;
+}
+
+static
+int lttng_counter_append_descriptor(struct lttng_counter *counter,
+ uint64_t user_token,
+ size_t index,
+ const char *key)
+{
+ struct lttng_counter_map *map = &counter->map;
+ struct lttng_counter_map_descriptor *last;
+ int ret = 0;
+
+ if (strlen(key) >= LTTNG_KERNEL_COUNTER_KEY_LEN) {
+ WARN_ON_ONCE(1);
+ return -EOVERFLOW;
+ }
+ mutex_lock(&map->lock);
+ if (map->nr_descriptors == map->alloc_len) {
+ struct lttng_counter_map_descriptor *new_table, *old_table;
+ size_t old_len = map->nr_descriptors;
+ size_t new_len = max_t(size_t, old_len + 1, map->alloc_len * 2);
+
+ old_table = map->descriptors;
+ new_table = lttng_kvzalloc(sizeof(struct lttng_counter_map_descriptor) * new_len,
+ GFP_KERNEL);
+ if (!new_table) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ if (old_table)
+ memcpy(new_table, old_table, old_len * sizeof(struct lttng_counter_map_descriptor));
+
+ map->descriptors = new_table;
+ map->alloc_len = new_len;
+ lttng_kvfree(old_table);
+ }
+ last = &map->descriptors[map->nr_descriptors++];
+ last->user_token = user_token;
+ last->array_index = index;
+ strcpy(last->key, key);
+unlock:
+ mutex_unlock(&map->lock);
+ return ret;
+}