2 * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
9 #include "lttng/domain.h"
10 #include <common/kernel-ctl/kernel-ctl.h>
11 #include <lttng/map/map.h>
12 #include <lttng/map/map-internal.h>
14 #include "lttng-sessiond.h"
15 #include "lttng-ust-error.h"
16 #include "notification-thread-commands.h"
17 #include "trace-kernel.h"
18 #include "trace-ust.h"
22 enum lttng_error_code
map_kernel_add(struct ltt_kernel_session
*ksession
,
23 struct lttng_map
*map
)
25 enum lttng_error_code ret
;
26 struct ltt_kernel_map
*kmap
;
27 enum lttng_map_status map_status
;
30 assert(lttng_map_get_domain(map
) == LTTNG_DOMAIN_KERNEL
);
32 map_status
= lttng_map_get_name(map
, &map_name
);
33 if (map_status
!= LTTNG_MAP_STATUS_OK
) {
34 ERR("Can't get map name");
39 kmap
= trace_kernel_get_map_by_name(map_name
, ksession
);
41 DBG("Kernel map named \"%s\" already present", map_name
);
46 kmap
= trace_kernel_create_map(map
);
49 ret
= kernctl_create_session_counter(ksession
->fd
,
52 PERROR("ioctl kernel create session counter");
58 /* Prevent fd duplication after execlp() */
59 ret
= fcntl(kmap
->fd
, F_SETFD
, FD_CLOEXEC
);
61 PERROR("fcntl session counter fd");
67 cds_list_add(&kmap
->list
, &ksession
->map_list
.head
);
68 ksession
->map_count
++;
70 DBG("Kernel session counter created (fd: %d)", kmap
->fd
);
72 ret
= kernctl_enable(kmap
->fd
);
74 PERROR("Enable kernel map");
82 enum lttng_error_code
map_kernel_enable(struct ltt_kernel_session
*ksess
,
83 struct ltt_kernel_map
*kmap
)
85 enum lttng_error_code ret
= LTTNG_OK
;
87 enum lttng_map_status map_status
;
93 map_status
= lttng_map_get_name(kmap
->map
, &map_name
);
94 if (map_status
!= LTTNG_MAP_STATUS_OK
) {
95 ERR("Error getting kernel map name");
100 /* If already enabled, everything is OK */
102 DBG3("Map %s already enabled. Skipping", map_name
);
103 ret
= LTTNG_ERR_UST_MAP_EXIST
;
107 lttng_map_set_is_enabled(kmap
->map
, true);
108 DBG2("Map %s enabled successfully", map_name
);
111 DBG2("Map %s being enabled in kernel domain", map_name
);
114 * Enable map for UST global domain on all applications. Ignore return
115 * value here since whatever error we got, it means that the map was
116 * not created on one or many registered applications and we can not report
117 * this to the user yet. However, at this stage, the map was
118 * successfully created on the session daemon side so the enable-map
119 * command is a success.
122 ret
= kernctl_enable(kmap
->fd
);
124 PERROR("Enable kernel map");
132 enum lttng_error_code
map_kernel_disable(struct ltt_kernel_session
*usess
,
133 struct ltt_kernel_map
*kmap
)
135 enum lttng_error_code ret
= LTTNG_OK
;
136 enum lttng_map_status map_status
;
137 const char *map_name
= NULL
;
142 map_status
= lttng_map_get_name(kmap
->map
, &map_name
);
143 if (map_status
!= LTTNG_MAP_STATUS_OK
) {
144 ERR("Error getting kernel map name");
149 /* Already disabled */
150 if (kmap
->enabled
== 0) {
151 DBG2("Map kernel %s already disabled", map_name
);
152 ret
= LTTNG_ERR_KERNEL_MAP_EXIST
;
157 lttng_map_set_is_enabled(kmap
->map
, false);
159 DBG2("Map %s being disabled in kernel global domain", map_name
);
161 /* Disable map for global domain */
162 ret
= kernctl_disable(kmap
->fd
);
164 ret
= LTTNG_ERR_KERNEL_MAP_DISABLE_FAIL
;
169 DBG2("Map %s disabled successfully", map_name
);
178 int map_ust_add(struct ltt_ust_session
*usession
, struct lttng_map
*map
)
181 struct ltt_ust_map
*umap
;
182 enum lttng_map_status map_status
;
183 const char *map_name
;
184 enum lttng_buffer_type buffer_type
;
186 assert(lttng_map_get_domain(map
) == LTTNG_DOMAIN_UST
);
188 map_status
= lttng_map_get_name(map
, &map_name
);
189 if (map_status
!= LTTNG_MAP_STATUS_OK
) {
190 ERR("Can't get map name");
195 umap
= trace_ust_find_map_by_name(usession
->domain_global
.maps
,
198 DBG("UST map named \"%s\" already present", map_name
);
203 buffer_type
= lttng_map_get_buffer_type(map
);
205 umap
= trace_ust_create_map(map
);
209 umap
->id
= trace_ust_get_next_chan_id(usession
);
213 lttng_map_set_is_enabled(umap
->map
, true);
215 DBG2("Map %s is being created for UST with buffer type %d and id %" PRIu64
,
216 umap
->name
, buffer_type
, umap
->id
);
218 /* Flag session buffer type. */
219 if (!usession
->buffer_type_changed
) {
220 usession
->buffer_type
= buffer_type
;
221 usession
->buffer_type_changed
= 1;
222 } else if (usession
->buffer_type
!= buffer_type
) {
223 /* Buffer type was already set. Refuse to create channel. */
224 ret
= LTTNG_ERR_BUFFER_TYPE_MISMATCH
;
230 /* Adding the map to the map hash table. */
231 lttng_ht_add_unique_str(usession
->domain_global
.maps
, &umap
->node
);
235 DBG2("Map %s created successfully", umap
->name
);
241 trace_ust_destroy_map(umap
);
247 * Enable UST map for session and domain.
249 int map_ust_enable(struct ltt_ust_session
*usess
,
250 struct ltt_ust_map
*umap
)
257 /* If already enabled, everything is OK */
259 DBG3("Map %s already enabled. Skipping", umap
->name
);
260 ret
= LTTNG_ERR_UST_MAP_EXIST
;
264 lttng_map_set_is_enabled(umap
->map
, true);
265 DBG2("Map %s enabled successfully", umap
->name
);
268 if (!usess
->active
) {
270 * The map will be activated against the apps
271 * when the session is started as part of the
272 * application map "synchronize" operation.
277 DBG2("Map %s being enabled in UST domain", umap
->name
);
280 * Enable map for UST global domain on all applications. Ignore return
281 * value here since whatever error we got, it means that the map was
282 * not created on one or many registered applications and we can not report
283 * this to the user yet. However, at this stage, the map was
284 * successfully created on the session daemon side so the enable-map
285 * command is a success.
287 (void) ust_app_enable_map_glb(usess
, umap
);
294 int map_ust_disable(struct ltt_ust_session
*usess
,
295 struct ltt_ust_map
*umap
)
302 /* Already disabled */
303 if (umap
->enabled
== 0) {
304 DBG2("Map UST %s already disabled", umap
->name
);
305 ret
= LTTNG_ERR_UST_MAP_EXIST
;
310 lttng_map_set_is_enabled(umap
->map
, false);
313 * If session is inactive we don't notify the tracer right away. We
314 * wait for the next synchronization.
316 if (!usess
->active
) {
320 DBG2("Map %s being disabled in UST global domain", umap
->name
);
322 /* Disable map for global domain */
323 ret
= ust_app_disable_map_glb(usess
, umap
);
324 if (ret
< 0 && ret
!= -LTTNG_UST_ERR_EXIST
) {
325 ret
= LTTNG_ERR_UST_MAP_DISABLE_FAIL
;
330 DBG2("Map %s disabled successfully", umap
->name
);
339 void map_add_or_increment_map_values(struct lttng_ht
*map_values
, const char *key
,
340 int64_t value
, bool has_underflowed
, bool has_overflowed
)
342 struct map_kv_ht_entry
*kv_entry
;
343 struct lttng_ht_node_str
*node
;
344 struct lttng_ht_iter ht_iter
;
346 lttng_ht_lookup(map_values
, (void *) key
, &ht_iter
);
347 node
= lttng_ht_iter_get_node_str(&ht_iter
);
350 * If the key is absent, the key value mapping.
352 kv_entry
= zmalloc(sizeof(*kv_entry
));
357 kv_entry
->key
= strdup(key
);
358 kv_entry
->value
= value
;
359 kv_entry
->has_underflowed
= has_underflowed
;
360 kv_entry
->has_overflowed
= has_overflowed
;
362 lttng_ht_node_init_str(&kv_entry
->node
, (char *) kv_entry
->key
);
363 lttng_ht_add_unique_str(map_values
, &kv_entry
->node
);
367 * If the key is already present, increment the current value with the
370 kv_entry
= caa_container_of(node
, typeof(*kv_entry
), node
);
371 kv_entry
->value
+= value
;
372 kv_entry
->has_underflowed
|= has_underflowed
;
373 kv_entry
->has_overflowed
|= has_overflowed
;
377 int map_new_content_section(struct lttng_map_content
*map_content
,
378 enum lttng_map_key_value_pair_list_type list_type
,
379 bool summed_all_cpus
, unsigned int identifier
,
380 int cpu
, struct lttng_ht
*values
)
383 struct lttng_map_key_value_pair_list
*kv_pair_list
;
384 enum lttng_map_status map_status
;
385 struct map_kv_ht_entry
*kv_entry
;
386 struct lttng_ht_iter key_iter
;
388 kv_pair_list
= lttng_map_key_value_pair_list_create(list_type
,
391 case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID
:
392 case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID
:
393 map_status
= lttng_map_key_value_pair_list_set_identifier(
394 kv_pair_list
, identifier
);
395 assert(map_status
== LTTNG_MAP_STATUS_OK
);
401 if (!summed_all_cpus
) {
402 map_status
= lttng_map_key_value_pair_list_set_cpu(kv_pair_list
,
406 cds_lfht_for_each_entry(values
->ht
, &key_iter
.iter
, kv_entry
, node
.node
) {
407 struct lttng_ht_iter entry_iter
;
409 struct lttng_map_key_value_pair
*pair
=
410 lttng_map_key_value_pair_create(kv_entry
->key
,
412 if (kv_entry
->has_overflowed
) {
413 lttng_map_key_value_pair_set_has_overflowed(pair
);
416 if (kv_entry
->has_underflowed
) {
417 lttng_map_key_value_pair_set_has_underflowed(pair
);
420 map_status
= lttng_map_key_value_pair_list_append_key_value(
423 entry_iter
.iter
.node
= &kv_entry
->node
.node
;
424 lttng_ht_del(values
, &entry_iter
);
430 map_status
= lttng_map_content_append_key_value_list(map_content
,
432 if (map_status
!= LTTNG_MAP_STATUS_OK
) {
433 lttng_map_key_value_pair_list_destroy(kv_pair_list
);
435 ERR("Error appending key-value pair list to map content object");