2 * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
12 #include <urcu/compiler.h>
15 #include <common/error.h>
16 #include <common/hashtable/hashtable.h>
17 #include <common/index-allocator.h>
18 #include <common/kernel-ctl/kernel-ctl.h>
19 #include <common/shm.h>
20 #include <lttng/trigger/trigger-internal.h>
22 #include "event-notifier-error-accounting.h"
23 #include "lttng-ust-error.h"
26 #define ERROR_COUNTER_INDEX_HT_INITIAL_SIZE 16
28 struct index_ht_entry
{
29 struct lttng_ht_node_u64 node
;
30 uint64_t error_counter_index
;
31 struct rcu_head rcu_head
;
34 struct ust_error_accounting_entry
{
36 struct lttng_ht_node_u64 node
;
37 struct rcu_head rcu_head
;
38 struct ustctl_daemon_counter
*daemon_counter
;
40 * Those `lttng_ust_abi_object_data` are anonymous handles to the counters
42 * They are only used to be duplicated for each new applications of the
43 * user. To destroy them, call with the `sock` parameter set to -1.
44 * e.g. `ustctl_release_object(-1, data)`;
46 struct lttng_ust_abi_object_data
*counter
;
47 struct lttng_ust_abi_object_data
**cpu_counters
;
48 int nr_counter_cpu_fds
;
51 struct kernel_error_accounting_entry
{
52 int kernel_event_notifier_error_counter_fd
;
55 static struct kernel_error_accounting_entry kernel_error_accountant
;
57 /* Hashtable mapping uid to error_account_entry. */
58 static struct lttng_ht
*error_counter_uid_ht
;
60 struct error_accounting_state
{
61 struct lttng_index_allocator
*index_allocator
;
62 /* Hashtable mapping event notifier token to index_ht_entry. */
63 struct lttng_ht
*indices_ht
;
64 uint64_t number_indices
;
67 static struct error_accounting_state ust_state
;
68 static struct error_accounting_state kernel_state
;
70 static inline void get_trigger_info_for_log(const struct lttng_trigger
*trigger
,
71 const char **trigger_name
,
72 uid_t
*trigger_owner_uid
)
74 enum lttng_trigger_status trigger_status
;
76 trigger_status
= lttng_trigger_get_name(trigger
, trigger_name
);
77 switch (trigger_status
) {
78 case LTTNG_TRIGGER_STATUS_OK
:
80 case LTTNG_TRIGGER_STATUS_UNSET
:
81 *trigger_name
= "(unset)";
87 trigger_status
= lttng_trigger_get_owner_uid(trigger
,
89 assert(trigger_status
== LTTNG_TRIGGER_STATUS_OK
);
93 const char *error_accounting_status_str(
94 enum event_notifier_error_accounting_status status
)
97 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
:
99 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
:
101 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND
:
103 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
:
105 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE
:
106 return "NO_INDEX_AVAILABLE";
107 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD
:
115 enum event_notifier_error_accounting_status
116 init_error_accounting_state(struct error_accounting_state
*state
,
117 uint64_t index_count
)
119 enum event_notifier_error_accounting_status status
;
123 state
->number_indices
= index_count
;
125 state
->index_allocator
= lttng_index_allocator_create(index_count
);
126 if (!state
->index_allocator
) {
127 ERR("Failed to allocate event notifier error counter index allocator");
128 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
132 state
->indices_ht
= lttng_ht_new(ERROR_COUNTER_INDEX_HT_INITIAL_SIZE
,
134 if (!state
->indices_ht
) {
135 ERR("Failed to allocate error counter indices hash table");
136 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
137 goto error_indices_ht
;
140 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
144 lttng_index_allocator_destroy(state
->index_allocator
);
145 state
->index_allocator
= NULL
;
151 void fini_error_accounting_state(struct error_accounting_state
*state
)
156 * Will assert if some error counter indices were not released (an
159 lttng_ht_destroy(state
->indices_ht
);
160 lttng_index_allocator_destroy(state
->index_allocator
);
163 enum event_notifier_error_accounting_status
164 event_notifier_error_accounting_init(uint64_t buffer_size_kernel
,
165 uint64_t buffer_size_ust
)
167 enum event_notifier_error_accounting_status status
;
169 status
= init_error_accounting_state(&kernel_state
, buffer_size_kernel
);
170 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
171 ERR("Failed to initialize kernel event notifier accounting state: status = %s",
172 error_accounting_status_str(status
));
176 status
= init_error_accounting_state(&ust_state
, buffer_size_ust
);
177 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
178 ERR("Failed to initialize UST event notifier accounting state: status = %s",
179 error_accounting_status_str(status
));
180 goto error_ust_state
;
183 error_counter_uid_ht
= lttng_ht_new(
184 ERROR_COUNTER_INDEX_HT_INITIAL_SIZE
, LTTNG_HT_TYPE_U64
);
185 if (!error_counter_uid_ht
) {
186 ERR("Failed to allocate UID to error counter accountant hash table");
187 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
191 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
195 fini_error_accounting_state(&ust_state
);
197 fini_error_accounting_state(&kernel_state
);
203 enum event_notifier_error_accounting_status
get_error_counter_index_for_token(
204 struct error_accounting_state
*state
, uint64_t tracer_token
,
205 uint64_t *error_counter_index
)
207 struct lttng_ht_node_u64
*node
;
208 struct lttng_ht_iter iter
;
209 const struct index_ht_entry
*index_entry
;
210 enum event_notifier_error_accounting_status status
;
213 lttng_ht_lookup(state
->indices_ht
, &tracer_token
, &iter
);
214 node
= lttng_ht_iter_get_node_u64(&iter
);
216 index_entry
= caa_container_of(
217 node
, const struct index_ht_entry
, node
);
218 *error_counter_index
= index_entry
->error_counter_index
;
219 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
221 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND
;
228 #ifdef HAVE_LIBLTTNG_UST_CTL
230 struct ust_error_accounting_entry
*get_uid_accounting_entry(const struct ust_app
*app
)
232 struct ust_error_accounting_entry
*entry
;
233 struct lttng_ht_node_u64
*node
;
234 struct lttng_ht_iter iter
;
235 uint64_t key
= app
->uid
;
237 lttng_ht_lookup(error_counter_uid_ht
, &key
, &iter
);
238 node
= lttng_ht_iter_get_node_u64(&iter
);
242 entry
= caa_container_of(node
, struct ust_error_accounting_entry
, node
);
249 struct ust_error_accounting_entry
*create_uid_accounting_entry(
250 const struct ust_app
*app
)
253 struct ustctl_daemon_counter
*daemon_counter
;
254 struct lttng_ust_abi_object_data
*counter
, **cpu_counters
;
255 int *cpu_counter_fds
= NULL
;
256 struct ust_error_accounting_entry
*entry
= NULL
;
257 const struct ustctl_counter_dimension dimension
= {
258 .size
= ust_state
.number_indices
,
259 .has_underflow
= false,
260 .has_overflow
= false,
263 entry
= zmalloc(sizeof(struct ust_error_accounting_entry
));
265 PERROR("Failed to allocate event notifier error acounting entry")
269 entry
->uid
= app
->uid
;
270 entry
->nr_counter_cpu_fds
= ustctl_get_nr_cpu_per_counter();
272 cpu_counter_fds
= zmalloc(entry
->nr_counter_cpu_fds
* sizeof(*cpu_counter_fds
));
273 if (!cpu_counter_fds
) {
274 PERROR("Failed to allocate event notifier error counter file descriptors array: application uid = %d, application name = '%s', pid = %d, allocation size = %zu",
275 (int) app
->uid
, app
->name
, (int) app
->pid
,
276 entry
->nr_counter_cpu_fds
* sizeof(*cpu_counter_fds
));
278 goto error_counter_cpu_fds_alloc
;
281 /* Initialize to an invalid fd value to closes fds in case of error. */
282 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
283 cpu_counter_fds
[i
] = -1;
286 cpu_counters
= zmalloc(entry
->nr_counter_cpu_fds
* sizeof(struct lttng_ust_abi_object_data
*));
288 PERROR("Failed to allocate event notifier error counter lttng_ust_abi_object_data array: application uid = %d, application name = '%s', pid = %d, allocation size = %zu",
289 (int) app
->uid
, app
->name
, (int) app
->pid
,
290 entry
->nr_counter_cpu_fds
* sizeof(struct lttng_ust_abi_object_data
*));
292 goto error_counter_cpus_alloc
;
295 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
296 cpu_counter_fds
[i
] = shm_create_anonymous("event-notifier-error-accounting");
297 if (cpu_counter_fds
[i
] == -1) {
298 ERR("Failed to create event notifier error accounting shared memory for application user: application uid = %d, pid = %d, application name = '%s'",
299 (int) app
->uid
, (int) app
->pid
, app
->name
);
300 goto error_shm_alloc
;
305 * Ownership of the file descriptors transferred to the ustctl object.
307 daemon_counter
= ustctl_create_counter(1, &dimension
, 0, -1,
308 entry
->nr_counter_cpu_fds
, cpu_counter_fds
,
309 USTCTL_COUNTER_BITNESS_32
,
310 USTCTL_COUNTER_ARITHMETIC_MODULAR
,
311 USTCTL_COUNTER_ALLOC_PER_CPU
,
313 if (!daemon_counter
) {
314 goto error_create_daemon_counter
;
317 ret
= ustctl_create_counter_data(daemon_counter
, &counter
);
319 ERR("Failed to create userspace tracer counter data for application user: uid = %d, pid = %d, application name = '%s'",
320 (int) app
->uid
, (int) app
->pid
, app
->name
);
321 goto error_create_counter_data
;
324 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
325 ret
= ustctl_create_counter_cpu_data(daemon_counter
, i
,
328 ERR("Failed to create userspace tracer counter cpu data for application user: uid = %d, pid = %d, application name = '%s'",
329 (int) app
->uid
, (int) app
->pid
,
331 goto error_create_counter_cpu_data
;
335 entry
->daemon_counter
= daemon_counter
;
336 entry
->counter
= counter
;
337 entry
->cpu_counters
= cpu_counters
;
339 lttng_ht_node_init_u64(&entry
->node
, app
->uid
);
340 lttng_ht_add_unique_u64(error_counter_uid_ht
, &entry
->node
);
344 error_create_counter_cpu_data
:
345 /* Teardown any allocated cpu counters. */
346 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
347 if (!cpu_counters
[i
]) {
349 * Early-exit when error occurred before all cpu
350 * counters could be initialized.
355 ustctl_release_object(-1, cpu_counters
[i
]);
356 free(cpu_counters
[i
]);
359 ustctl_release_object(-1, entry
->counter
);
360 free(entry
->counter
);
361 error_create_counter_data
:
362 ustctl_destroy_counter(daemon_counter
);
363 error_create_daemon_counter
:
365 /* Error occured before per-cpu SHMs were handed-off to ustctl. */
366 if (cpu_counter_fds
) {
367 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
368 if (cpu_counter_fds
[i
] < 0) {
370 * Early-exit when error occurred before all cpu
371 * counter shm fds could be initialized.
376 ret
= close(cpu_counter_fds
[i
]);
378 PERROR("Failed to close error counter per-CPU shm file descriptor: fd = %d", cpu_counter_fds
[i
]);
384 error_counter_cpus_alloc
:
385 error_counter_cpu_fds_alloc
:
390 free(cpu_counter_fds
);
395 enum event_notifier_error_accounting_status
send_counter_data_to_ust(
397 struct lttng_ust_abi_object_data
*new_counter
)
400 enum event_notifier_error_accounting_status status
;
402 /* Attach counter to trigger group. */
403 pthread_mutex_lock(&app
->sock_lock
);
404 ret
= ustctl_send_counter_data_to_ust(app
->sock
,
405 app
->event_notifier_group
.object
->handle
, new_counter
);
406 pthread_mutex_unlock(&app
->sock_lock
);
408 if (ret
!= -EPIPE
&& ret
!= -LTTNG_UST_ERR_EXITING
) {
409 ERR("Failed to send counter data to application: application name = '%s', pid = %d, ret = %d",
410 app
->name
, app
->pid
, ret
);
411 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
413 DBG3("Failed to send counter data to application (application is dead): application name = '%s', pid = %d, ret = %d",
414 app
->name
, app
->pid
, ret
);
415 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD
;
421 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
427 enum event_notifier_error_accounting_status
send_counter_cpu_data_to_ust(
429 struct lttng_ust_abi_object_data
*counter
,
430 struct lttng_ust_abi_object_data
*counter_cpu
)
433 enum event_notifier_error_accounting_status status
;
435 pthread_mutex_lock(&app
->sock_lock
);
436 ret
= ustctl_send_counter_cpu_data_to_ust(app
->sock
,
437 counter
, counter_cpu
);
438 pthread_mutex_unlock(&app
->sock_lock
);
440 if (ret
!= -EPIPE
&& ret
!= -LTTNG_UST_ERR_EXITING
) {
441 ERR("Failed to send counter CPU data to application: application name = '%s', pid = %d, ret = %d",
442 app
->name
, app
->pid
, ret
);
443 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
445 DBG3("Failed to send counter CPU data to application: application name = '%s', pid = %d, ret = %d",
446 app
->name
, app
->pid
, ret
);
447 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD
;
453 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
458 enum event_notifier_error_accounting_status
459 event_notifier_error_accounting_register_app(struct ust_app
*app
)
463 struct lttng_ust_abi_object_data
*new_counter
;
464 struct ust_error_accounting_entry
*entry
;
465 enum event_notifier_error_accounting_status status
;
466 struct lttng_ust_abi_object_data
**cpu_counters
;
469 * Check if we already have a error counter for the user id of this
470 * app. If not, create one.
473 entry
= get_uid_accounting_entry(app
);
475 entry
= create_uid_accounting_entry(app
);
477 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
482 /* Duplicate counter object data. */
483 ret
= ustctl_duplicate_ust_object_data(&new_counter
,
486 ERR("Failed to duplicate event notifier error accounting counter for application user: application uid = %d, pid = %d, application name = '%s'",
487 (int) app
->uid
, (int) app
->pid
, app
->name
);
488 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
492 status
= send_counter_data_to_ust(app
, new_counter
);
493 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
494 if (status
== EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD
) {
495 goto error_send_counter_data
;
498 ERR("Failed to send counter data to application tracer: status = %s, application uid = %d, pid = %d, application name = '%s'",
499 error_accounting_status_str(status
),
500 (int) app
->uid
, (int) app
->pid
, app
->name
);
501 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
502 goto error_send_counter_data
;
505 cpu_counters
= zmalloc(entry
->nr_counter_cpu_fds
* sizeof(struct lttng_ust_abi_object_data
*));
507 PERROR("Failed to allocate event notifier error counter lttng_ust_abi_object_data array: application uid = %d, application name = '%s', pid = %d, allocation size = %zu",
508 (int) app
->uid
, app
->name
, (int) app
->pid
,
509 entry
->nr_counter_cpu_fds
* sizeof(**cpu_counters
));
510 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
511 goto error_allocate_cpu_counters
;
514 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
515 struct lttng_ust_abi_object_data
*new_counter_cpu
= NULL
;
517 ret
= ustctl_duplicate_ust_object_data(&new_counter_cpu
,
518 entry
->cpu_counters
[i
]);
520 ERR("Failed to duplicate userspace tracer counter cpu data for application user: uid = %d, pid = %d, application name = '%s'",
521 (int) app
->uid
, (int) app
->pid
,
523 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
524 goto error_duplicate_cpu_counter
;
527 cpu_counters
[i
] = new_counter_cpu
;
529 status
= send_counter_cpu_data_to_ust(app
, new_counter
,
531 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
532 if (status
== EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD
) {
533 goto error_send_cpu_counter_data
;
536 ERR("Failed to send counter cpu data to application tracer: status = %s, application uid = %d, pid = %d, application name = '%s'",
537 error_accounting_status_str(status
),
538 (int) app
->uid
, (int) app
->pid
,
540 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
541 goto error_send_cpu_counter_data
;
545 app
->event_notifier_group
.counter
= new_counter
;
547 app
->event_notifier_group
.nr_counter_cpu
= entry
->nr_counter_cpu_fds
;
548 app
->event_notifier_group
.counter_cpu
= cpu_counters
;
552 error_send_cpu_counter_data
:
553 error_duplicate_cpu_counter
:
554 /* Teardown any duplicated cpu counters. */
555 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
556 if (!cpu_counters
[i
]) {
558 * Early-exit when error occurred before all cpu
559 * counters could be initialized.
564 ustctl_release_object(-1, cpu_counters
[i
]);
565 free(cpu_counters
[i
]);
570 error_allocate_cpu_counters
:
571 error_send_counter_data
:
572 ustctl_release_object(-1, new_counter
);
579 enum event_notifier_error_accounting_status
580 event_notifier_error_accounting_unregister_app(struct ust_app
*app
)
582 enum event_notifier_error_accounting_status status
;
583 struct ust_error_accounting_entry
*entry
;
587 entry
= get_uid_accounting_entry(app
);
589 ERR("Failed to find event notitifier error accounting entry on application teardown: pid = %d, application name = '%s'",
590 app
->pid
, app
->name
);
591 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
595 for (i
= 0; i
< app
->event_notifier_group
.nr_counter_cpu
; i
++) {
596 ustctl_release_object(app
->sock
,
597 app
->event_notifier_group
.counter_cpu
[i
]);
598 free(app
->event_notifier_group
.counter_cpu
[i
]);
601 free(app
->event_notifier_group
.counter_cpu
);
603 ustctl_release_object(app
->sock
, app
->event_notifier_group
.counter
);
604 free(app
->event_notifier_group
.counter
);
606 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
613 enum event_notifier_error_accounting_status
614 event_notifier_error_accounting_ust_get_count(
615 const struct lttng_trigger
*trigger
, uint64_t *count
)
617 struct lttng_ht_iter iter
;
618 struct ust_error_accounting_entry
*uid_entry
;
619 uint64_t error_counter_index
, global_sum
= 0;
620 enum event_notifier_error_accounting_status status
;
621 size_t dimension_indexes
[1];
622 const uint64_t tracer_token
= lttng_trigger_get_tracer_token(trigger
);
623 uid_t trigger_owner_uid
;
624 const char *trigger_name
;
629 get_trigger_info_for_log(trigger
, &trigger_name
, &trigger_owner_uid
);
632 * At the moment, the error counter index is domain wide. This means
633 * that if UID 1000 registers a event notifier and is allocated index 0
634 * in it's error counter, index zero will be unused in error counter of
637 status
= get_error_counter_index_for_token(
640 &error_counter_index
);
641 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
643 ERR("Failed to retrieve index for tracer token: token = %" PRIu64
", trigger name = '%s', trigger owner uid = %d, status = %s",
644 tracer_token
, trigger_name
,
645 (int) trigger_owner_uid
,
646 error_accounting_status_str(status
));
650 dimension_indexes
[0] = error_counter_index
;
653 * Iterate over all the UID entries.
654 * We aggregate the value of all uid entries regardless of if the uid
655 * matches the trigger's uid because a user that is allowed to register
656 * a trigger to a given sessiond is also allowed to create an event
657 * notifier on all apps that this sessiond is aware of.
659 cds_lfht_for_each_entry(error_counter_uid_ht
->ht
, &iter
.iter
,
660 uid_entry
, node
.node
) {
662 int64_t local_value
= 0;
663 bool overflow
= false, underflow
= false;
665 ret
= ustctl_counter_aggregate(uid_entry
->daemon_counter
,
666 dimension_indexes
, &local_value
, &overflow
,
668 if (ret
|| local_value
< 0) {
670 ERR("Failed to aggregate event notifier error counter values of trigger: trigger name = '%s', trigger owner uid = %d",
672 (int) trigger_owner_uid
);
673 } else if (local_value
< 0) {
674 ERR("Negative event notifier error counter value encountered during aggregation: trigger name = '%s', trigger owner uid = %d, value = %" PRId64
,
676 (int) trigger_owner_uid
,
682 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
686 /* Cast is safe as negative values are checked-for above. */
687 global_sum
+= (uint64_t) local_value
;
691 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
699 enum event_notifier_error_accounting_status
event_notifier_error_accounting_ust_clear(
700 const struct lttng_trigger
*trigger
)
702 struct lttng_ht_iter iter
;
703 struct ust_error_accounting_entry
*uid_entry
;
704 uint64_t error_counter_index
;
705 enum event_notifier_error_accounting_status status
;
706 size_t dimension_index
;
707 const uint64_t tracer_token
= lttng_trigger_get_tracer_token(trigger
);
710 * Go over all error counters (ignoring uid) as a trigger (and trigger
711 * errors) can be generated from any applications that this session
712 * daemon is managing.
716 status
= get_error_counter_index_for_token(
719 &error_counter_index
);
720 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
721 uid_t trigger_owner_uid
;
722 const char *trigger_name
;
724 get_trigger_info_for_log(trigger
, &trigger_name
,
727 ERR("Failed to retrieve index for tracer token: token = %" PRIu64
", trigger name = '%s', trigger owner uid = %d, status = %s",
728 tracer_token
, trigger_name
,
729 (int) trigger_owner_uid
,
730 error_accounting_status_str(status
));
734 dimension_index
= error_counter_index
;
736 cds_lfht_for_each_entry(error_counter_uid_ht
->ht
, &iter
.iter
,
737 uid_entry
, node
.node
) {
738 const int ret
= ustctl_counter_clear(uid_entry
->daemon_counter
,
742 uid_t trigger_owner_uid
;
743 const char *trigger_name
;
745 get_trigger_info_for_log(trigger
, &trigger_name
,
747 ERR("Failed to clear event notifier counter value for trigger: counter uid = %d, trigger name = '%s', trigger owner uid = %d",
748 (int) uid_entry
->node
.key
, trigger_name
,
749 (int) trigger_owner_uid
);
750 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
755 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
760 #endif /* HAVE_LIBLTTNG_UST_CTL */
763 enum event_notifier_error_accounting_status
764 event_notifier_error_accounting_kernel_clear(
765 const struct lttng_trigger
*trigger
)
768 uint64_t error_counter_index
;
769 enum event_notifier_error_accounting_status status
;
770 struct lttng_kernel_counter_clear counter_clear
= {};
772 status
= get_error_counter_index_for_token(
774 lttng_trigger_get_tracer_token(trigger
),
775 &error_counter_index
);
776 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
777 uid_t trigger_owner_uid
;
778 const char *trigger_name
;
780 get_trigger_info_for_log(
781 trigger
, &trigger_name
, &trigger_owner_uid
);
783 ERR("Failed to get event notifier error counter index: trigger owner uid = %d, trigger name = '%s', status = '%s'",
784 trigger_owner_uid
, trigger_name
,
785 error_accounting_status_str(status
));
789 counter_clear
.index
.number_dimensions
= 1;
790 counter_clear
.index
.dimension_indexes
[0] = error_counter_index
;
792 ret
= kernctl_counter_clear(
793 kernel_error_accountant
.kernel_event_notifier_error_counter_fd
,
796 uid_t trigger_owner_uid
;
797 const char *trigger_name
;
799 get_trigger_info_for_log(
800 trigger
, &trigger_name
, &trigger_owner_uid
);
802 ERR("Failed to clear kernel event notifier error counter: trigger owner uid = %d, trigger name = '%s'",
803 trigger_owner_uid
, trigger_name
);
804 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
808 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
813 enum event_notifier_error_accounting_status
814 event_notifier_error_accounting_register_kernel(
815 int kernel_event_notifier_group_fd
)
817 int error_counter_fd
= -1, ret
;
818 enum event_notifier_error_accounting_status status
;
819 const struct lttng_kernel_counter_conf error_counter_conf
= {
820 .arithmetic
= LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR
,
821 .bitness
= sizeof(void *) == sizeof(uint32_t) ?
822 LTTNG_KERNEL_COUNTER_BITNESS_32
:
823 LTTNG_KERNEL_COUNTER_BITNESS_64
,
824 .global_sum_step
= 0,
825 .number_dimensions
= 1,
826 .dimensions
[0].size
= kernel_state
.number_indices
,
827 .dimensions
[0].has_underflow
= false,
828 .dimensions
[0].has_overflow
= false,
831 ret
= kernctl_create_event_notifier_group_error_counter(
832 kernel_event_notifier_group_fd
, &error_counter_conf
);
834 PERROR("Failed to create event notifier group error counter through kernel ioctl: kernel_event_notifier_group_fd = %d",
835 kernel_event_notifier_group_fd
);
836 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
840 error_counter_fd
= ret
;
842 /* Prevent fd duplication after execlp(). */
843 ret
= fcntl(error_counter_fd
, F_SETFD
, FD_CLOEXEC
);
845 PERROR("Failed to set FD_CLOEXEC flag on event notifier error counter file descriptor: error_counter_fd = %d",
847 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
851 DBG("Created kernel event notifier group error counter: fd = %d",
854 kernel_error_accountant
.kernel_event_notifier_error_counter_fd
=
856 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
863 enum event_notifier_error_accounting_status
create_error_counter_index_for_token(
864 struct error_accounting_state
*state
, uint64_t tracer_token
,
865 uint64_t *error_counter_index
)
867 struct index_ht_entry
*index_entry
;
868 enum lttng_index_allocator_status index_alloc_status
;
869 uint64_t local_error_counter_index
;
870 enum event_notifier_error_accounting_status status
;
874 /* Allocate a new index for that counter. */
875 index_alloc_status
= lttng_index_allocator_alloc(state
->index_allocator
,
876 &local_error_counter_index
);
877 switch (index_alloc_status
) {
878 case LTTNG_INDEX_ALLOCATOR_STATUS_EMPTY
:
879 DBG("No indices left in the configured event notifier error counter: "
880 "number-of-indices = %"PRIu64
,
881 lttng_index_allocator_get_index_count(
882 state
->index_allocator
));
883 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE
;
885 case LTTNG_INDEX_ALLOCATOR_STATUS_OK
:
888 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
892 index_entry
= zmalloc(sizeof(*index_entry
));
893 if (index_entry
== NULL
) {
894 PERROR("Failed to allocate event notifier error counter hash table entry");
895 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
899 index_entry
->error_counter_index
= local_error_counter_index
;
900 lttng_ht_node_init_u64(&index_entry
->node
, tracer_token
);
901 lttng_ht_add_unique_u64(state
->indices_ht
, &index_entry
->node
);
903 DBG("Allocated error counter index for tracer token: tracer token = %" PRIu64
", index = %" PRIu64
,
904 tracer_token
, local_error_counter_index
);
905 *error_counter_index
= local_error_counter_index
;
906 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
911 enum event_notifier_error_accounting_status
912 event_notifier_error_accounting_register_event_notifier(
913 const struct lttng_trigger
*trigger
,
914 uint64_t *error_counter_index
)
916 enum event_notifier_error_accounting_status status
;
917 uint64_t local_error_counter_index
;
918 struct error_accounting_state
*state
;
920 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger
)) {
921 case LTTNG_DOMAIN_KERNEL
:
922 state
= &kernel_state
;
924 case LTTNG_DOMAIN_UST
:
932 * Check if this event notifier already has a error counter index
935 status
= get_error_counter_index_for_token(state
,
936 lttng_trigger_get_tracer_token(trigger
),
937 &local_error_counter_index
);
939 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND
:
941 uid_t trigger_owner_uid
;
942 const char *trigger_name
;
944 get_trigger_info_for_log(
945 trigger
, &trigger_name
, &trigger_owner_uid
);
947 DBG("Event notifier error counter index not found for tracer token (allocating a new one): trigger name = '%s', trigger owner uid = %d, tracer token = %" PRIu64
,
948 trigger_name
, trigger_owner_uid
,
949 lttng_trigger_get_tracer_token(trigger
));
951 status
= create_error_counter_index_for_token(state
,
952 lttng_trigger_get_tracer_token(trigger
),
953 &local_error_counter_index
);
954 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
955 ERR("Error creating index for token: status = %s, trigger name = '%s', trigger owner uid = %d",
956 error_accounting_status_str(status
),
957 trigger_name
, trigger_owner_uid
);
962 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
:
963 *error_counter_index
= local_error_counter_index
;
964 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
975 enum event_notifier_error_accounting_status
976 event_notifier_error_accounting_kernel_get_count(
977 const struct lttng_trigger
*trigger
, uint64_t *count
)
979 struct lttng_kernel_counter_aggregate counter_aggregate
= {};
980 enum event_notifier_error_accounting_status status
;
981 uint64_t error_counter_index
;
984 status
= get_error_counter_index_for_token(
986 lttng_trigger_get_tracer_token(trigger
),
987 &error_counter_index
);
988 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
989 ERR("Error getting index for token: status=%s",
990 error_accounting_status_str(status
));
994 counter_aggregate
.index
.number_dimensions
= 1;
995 counter_aggregate
.index
.dimension_indexes
[0] = error_counter_index
;
997 assert(kernel_error_accountant
.kernel_event_notifier_error_counter_fd
);
999 ret
= kernctl_counter_get_aggregate_value(
1000 kernel_error_accountant
.kernel_event_notifier_error_counter_fd
,
1001 &counter_aggregate
);
1002 if (ret
|| counter_aggregate
.value
.value
< 0) {
1003 uid_t trigger_owner_uid
;
1004 const char *trigger_name
;
1006 get_trigger_info_for_log(trigger
, &trigger_name
,
1007 &trigger_owner_uid
);
1009 if (counter_aggregate
.value
.value
< 0) {
1010 ERR("Invalid negative event notifier error counter value: trigger owner = %d, trigger name = '%s', value = %" PRId64
,
1011 trigger_owner_uid
, trigger_name
,
1012 counter_aggregate
.value
.value
);
1014 ERR("Failed to getting event notifier error count: trigger owner = %d, trigger name = '%s', ret = %d",
1015 trigger_owner_uid
, trigger_name
, ret
);
1018 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
1022 /* Error count can't be negative. */
1023 assert(counter_aggregate
.value
.value
>= 0);
1024 *count
= (uint64_t) counter_aggregate
.value
.value
;
1026 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
1032 enum event_notifier_error_accounting_status
1033 event_notifier_error_accounting_get_count(
1034 const struct lttng_trigger
*trigger
, uint64_t *count
)
1036 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger
)) {
1037 case LTTNG_DOMAIN_KERNEL
:
1038 return event_notifier_error_accounting_kernel_get_count(
1040 case LTTNG_DOMAIN_UST
:
1041 #ifdef HAVE_LIBLTTNG_UST_CTL
1042 return event_notifier_error_accounting_ust_get_count(trigger
,
1045 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
1046 #endif /* HAVE_LIBLTTNG_UST_CTL */
1053 enum event_notifier_error_accounting_status
1054 event_notifier_error_accounting_clear(const struct lttng_trigger
*trigger
)
1056 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger
)) {
1057 case LTTNG_DOMAIN_KERNEL
:
1058 return event_notifier_error_accounting_kernel_clear(trigger
);
1059 case LTTNG_DOMAIN_UST
:
1060 #ifdef HAVE_LIBLTTNG_UST_CTL
1061 return event_notifier_error_accounting_ust_clear(trigger
);
1063 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
1064 #endif /* HAVE_LIBLTTNG_UST_CTL */
1070 static void free_index_ht_entry(struct rcu_head
*head
)
1072 struct index_ht_entry
*entry
= caa_container_of(head
,
1073 struct index_ht_entry
, rcu_head
);
1078 void event_notifier_error_accounting_unregister_event_notifier(
1079 const struct lttng_trigger
*trigger
)
1081 struct lttng_ht_iter iter
;
1082 struct lttng_ht_node_u64
*node
;
1083 const uint64_t tracer_token
= lttng_trigger_get_tracer_token(trigger
);
1084 enum event_notifier_error_accounting_status status
;
1085 struct error_accounting_state
*state
;
1087 status
= event_notifier_error_accounting_clear(trigger
);
1088 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
1089 /* Trigger details already logged by callee on error. */
1090 ERR("Failed to clear event notifier error counter during unregistration of event notifier: status = '%s'",
1091 error_accounting_status_str(status
));
1094 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger
)) {
1095 case LTTNG_DOMAIN_KERNEL
:
1096 state
= &kernel_state
;
1098 case LTTNG_DOMAIN_UST
:
1106 lttng_ht_lookup(state
->indices_ht
, &tracer_token
, &iter
);
1107 node
= lttng_ht_iter_get_node_u64(&iter
);
1110 struct index_ht_entry
*index_entry
= caa_container_of(
1111 node
, typeof(*index_entry
), node
);
1112 enum lttng_index_allocator_status index_alloc_status
;
1114 index_alloc_status
= lttng_index_allocator_release(
1115 state
->index_allocator
,
1116 index_entry
->error_counter_index
);
1117 if (index_alloc_status
!= LTTNG_INDEX_ALLOCATOR_STATUS_OK
) {
1118 uid_t trigger_owner_uid
;
1119 const char *trigger_name
;
1121 get_trigger_info_for_log(trigger
, &trigger_name
,
1122 &trigger_owner_uid
);
1124 ERR("Failed to release event notifier error counter index: index = %" PRIu64
", trigger name = '%s', trigger owner uid = %d",
1125 index_entry
->error_counter_index
,
1126 trigger_name
, (int) trigger_owner_uid
);
1127 /* Don't exit, perform the rest of the clean-up. */
1130 del_ret
= lttng_ht_del(state
->indices_ht
, &iter
);
1132 call_rcu(&index_entry
->rcu_head
, free_index_ht_entry
);
1138 #ifdef HAVE_LIBLTTNG_UST_CTL
1139 static void free_error_account_entry(struct rcu_head
*head
)
1142 struct ust_error_accounting_entry
*entry
=
1143 caa_container_of(head
, typeof(*entry
), rcu_head
);
1145 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
1146 ustctl_release_object(-1, entry
->cpu_counters
[i
]);
1147 free(entry
->cpu_counters
[i
]);
1150 free(entry
->cpu_counters
);
1152 ustctl_release_object(-1, entry
->counter
);
1153 free(entry
->counter
);
1155 ustctl_destroy_counter(entry
->daemon_counter
);
1160 /* Not called without UST support. */
1161 static void free_error_account_entry(struct rcu_head
*head
) {}
1162 #endif /* HAVE_LIBLTTNG_UST_CTL */
1164 void event_notifier_error_accounting_fini(void)
1166 struct lttng_ht_iter iter
;
1167 struct ust_error_accounting_entry
*uid_entry
;
1169 if (kernel_error_accountant
.kernel_event_notifier_error_counter_fd
) {
1170 const int ret
= close(kernel_error_accountant
.kernel_event_notifier_error_counter_fd
);
1173 PERROR("Failed to close kernel event notifier error counter");
1178 * FIXME error account entries are not reference-counted and torn
1179 * down on last use. They exist from the moment of their first use
1180 * up until the teardown of the session daemon.
1183 cds_lfht_for_each_entry(error_counter_uid_ht
->ht
, &iter
.iter
,
1184 uid_entry
, node
.node
) {
1185 cds_lfht_del(error_counter_uid_ht
->ht
, &uid_entry
->node
.node
);
1186 call_rcu(&uid_entry
->rcu_head
, free_error_account_entry
);
1190 lttng_ht_destroy(error_counter_uid_ht
);
1192 fini_error_accounting_state(&kernel_state
);
1193 fini_error_accounting_state(&ust_state
);