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 error_account_entry
{
35 struct lttng_ht_node_u64 node
;
36 struct rcu_head rcu_head
;
37 struct ustctl_daemon_counter
*daemon_counter
;
39 * Those `lttng_ust_abi_object_data` are anonymous handles to the counters
41 * They are only used to be duplicated for each new applications of the
42 * user. To destroy them, call with the `sock` parameter set to -1.
43 * e.g. `ustctl_release_object(-1, data)`;
45 struct lttng_ust_abi_object_data
*counter
;
46 struct lttng_ust_abi_object_data
**cpu_counters
;
47 int nr_counter_cpu_fds
;
50 struct kernel_error_account_entry
{
51 int kernel_event_notifier_error_counter_fd
;
54 static struct kernel_error_account_entry kernel_error_accountant
;
56 /* Hashtable mapping event notifier token to index_ht_entry. */
57 static struct lttng_ht
*error_counter_indexes_ht
;
59 /* Hashtable mapping uid to error_account_entry. */
60 static struct lttng_ht
*error_counter_uid_ht
;
62 static uint64_t error_counter_size
;
63 static struct lttng_index_allocator
*index_allocator
;
65 static inline void get_trigger_info_for_log(const struct lttng_trigger
*trigger
,
66 const char **trigger_name
,
67 uid_t
*trigger_owner_uid
)
69 enum lttng_trigger_status trigger_status
;
71 trigger_status
= lttng_trigger_get_name(trigger
, trigger_name
);
72 switch (trigger_status
) {
73 case LTTNG_TRIGGER_STATUS_OK
:
75 case LTTNG_TRIGGER_STATUS_UNSET
:
76 *trigger_name
= "(unset)";
82 trigger_status
= lttng_trigger_get_owner_uid(trigger
,
84 assert(trigger_status
== LTTNG_TRIGGER_STATUS_OK
);
88 const char *error_accounting_status_str(
89 enum event_notifier_error_accounting_status status
)
92 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
:
94 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
:
96 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND
:
98 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
:
100 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE
:
101 return "NO_INDEX_AVAILABLE";
102 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD
:
109 enum event_notifier_error_accounting_status
110 event_notifier_error_accounting_init(uint64_t nb_bucket
)
112 enum event_notifier_error_accounting_status status
;
114 index_allocator
= lttng_index_allocator_create(nb_bucket
);
115 if (!index_allocator
) {
116 ERR("Failed to allocate event notifier error counter index");
117 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
118 goto error_index_allocator
;
121 error_counter_indexes_ht
= lttng_ht_new(
122 ERROR_COUNTER_INDEX_HT_INITIAL_SIZE
, LTTNG_HT_TYPE_U64
);
123 if (!error_counter_indexes_ht
) {
124 ERR("Failed to allocate error counter indices hash table");
125 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
126 goto error_index_allocator
;
129 error_counter_uid_ht
= lttng_ht_new(
130 ERROR_COUNTER_INDEX_HT_INITIAL_SIZE
, LTTNG_HT_TYPE_U64
);
131 if (!error_counter_uid_ht
) {
132 ERR("Failed to allocate UID to error counter accountant hash table");
133 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
134 goto error_index_allocator
;
137 error_counter_size
= nb_bucket
;
139 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
141 error_index_allocator
:
146 enum event_notifier_error_accounting_status
get_error_counter_index_for_token(
147 uint64_t tracer_token
, uint64_t *error_counter_index
)
149 struct lttng_ht_node_u64
*node
;
150 struct lttng_ht_iter iter
;
151 const struct index_ht_entry
*index_entry
;
152 enum event_notifier_error_accounting_status status
;
155 lttng_ht_lookup(error_counter_indexes_ht
, &tracer_token
, &iter
);
156 node
= lttng_ht_iter_get_node_u64(&iter
);
158 index_entry
= caa_container_of(
159 node
, const struct index_ht_entry
, node
);
160 *error_counter_index
= index_entry
->error_counter_index
;
161 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
163 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND
;
170 #ifdef HAVE_LIBLTTNG_UST_CTL
172 struct error_account_entry
*get_uid_accounting_entry(const struct ust_app
*app
)
174 struct error_account_entry
*entry
;
175 struct lttng_ht_node_u64
*node
;
176 struct lttng_ht_iter iter
;
177 uint64_t key
= app
->uid
;
179 lttng_ht_lookup(error_counter_uid_ht
, &key
, &iter
);
180 node
= lttng_ht_iter_get_node_u64(&iter
);
184 entry
= caa_container_of(node
, struct error_account_entry
, node
);
191 struct error_account_entry
*create_uid_accounting_entry(
192 const struct ust_app
*app
)
195 struct ustctl_daemon_counter
*daemon_counter
;
196 struct lttng_ust_abi_object_data
*counter
, **cpu_counters
;
197 int *cpu_counter_fds
= NULL
;
198 struct error_account_entry
*entry
= NULL
;
199 const struct ustctl_counter_dimension dimension
= {
200 .size
= error_counter_size
,
201 .has_underflow
= false,
202 .has_overflow
= false,
205 entry
= zmalloc(sizeof(struct error_account_entry
));
207 PERROR("Failed to allocate event notifier error acounting entry")
211 entry
->nr_counter_cpu_fds
= ustctl_get_nr_cpu_per_counter();
212 cpu_counter_fds
= zmalloc(entry
->nr_counter_cpu_fds
* sizeof(*cpu_counter_fds
));
213 if (!cpu_counter_fds
) {
214 PERROR("Failed to allocate event notifier error counter file descriptors array: application uid = %d, application name = '%s', pid = %d, allocation size = %zu",
215 (int) app
->uid
, app
->name
, (int) app
->pid
,
216 entry
->nr_counter_cpu_fds
* sizeof(*cpu_counter_fds
));
218 goto error_counter_cpu_fds_alloc
;
221 /* Initialize to an invalid fd value to closes fds in case of error. */
222 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
223 cpu_counter_fds
[i
] = -1;
226 cpu_counters
= zmalloc(entry
->nr_counter_cpu_fds
* sizeof(**cpu_counters
));
228 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",
229 (int) app
->uid
, app
->name
, (int) app
->pid
,
230 entry
->nr_counter_cpu_fds
* sizeof(**cpu_counters
));
232 goto error_counter_cpus_alloc
;
235 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
236 cpu_counter_fds
[i
] = shm_create_anonymous("event-notifier-error-accounting");
237 if (cpu_counter_fds
[i
] == -1) {
238 ERR("Failed to create event notifier error accounting shared memory for application user: application uid = %d, pid = %d, application name = '%s'",
239 (int) app
->uid
, (int) app
->pid
, app
->name
);
240 goto error_shm_alloc
;
245 * Ownership of the file descriptors transferred to the ustctl object.
247 daemon_counter
= ustctl_create_counter(1, &dimension
, 0, -1,
248 entry
->nr_counter_cpu_fds
, cpu_counter_fds
,
249 USTCTL_COUNTER_BITNESS_32
,
250 USTCTL_COUNTER_ARITHMETIC_MODULAR
,
251 USTCTL_COUNTER_ALLOC_PER_CPU
,
253 if (!daemon_counter
) {
254 goto error_create_daemon_counter
;
257 ret
= ustctl_create_counter_data(daemon_counter
, &counter
);
259 ERR("Failed to create userspace tracer counter data for application user: uid = %d, pid = %d, application name = '%s'",
260 (int) app
->uid
, (int) app
->pid
, app
->name
);
261 goto error_create_counter_data
;
264 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
265 ret
= ustctl_create_counter_cpu_data(daemon_counter
, i
,
268 ERR("Failed to create userspace tracer counter cpu data for application user: uid = %d, pid = %d, application name = '%s'",
269 (int) app
->uid
, (int) app
->pid
,
271 goto error_create_counter_cpu_data
;
275 entry
->daemon_counter
= daemon_counter
;
276 entry
->counter
= counter
;
277 entry
->cpu_counters
= cpu_counters
;
279 lttng_ht_node_init_u64(&entry
->node
, app
->uid
);
280 lttng_ht_add_unique_u64(error_counter_uid_ht
, &entry
->node
);
284 error_create_counter_cpu_data
:
285 /* Teardown any allocated cpu counters. */
286 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
287 if (!cpu_counters
[i
]) {
289 * Early-exit when error occurred before all cpu
290 * counters could be initialized.
295 ustctl_release_object(-1, cpu_counters
[i
]);
296 free(cpu_counters
[i
]);
299 ustctl_release_object(-1, entry
->counter
);
300 free(entry
->counter
);
301 error_create_counter_data
:
302 ustctl_destroy_counter(daemon_counter
);
303 error_create_daemon_counter
:
305 /* Error occured before per-cpu SHMs were handed-off to ustctl. */
306 if (cpu_counter_fds
) {
307 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
308 if (cpu_counter_fds
[i
] < 0) {
310 * Early-exit when error occurred before all cpu
311 * counter shm fds could be initialized.
316 ret
= close(cpu_counter_fds
[i
]);
318 PERROR("Failed to close error counter per-CPU shm file descriptor: fd = %d", cpu_counter_fds
[i
]);
324 error_counter_cpus_alloc
:
325 error_counter_cpu_fds_alloc
:
330 free(cpu_counter_fds
);
335 enum event_notifier_error_accounting_status
send_counter_data_to_ust(
337 struct lttng_ust_abi_object_data
*new_counter
)
340 enum event_notifier_error_accounting_status status
;
342 /* Attach counter to trigger group. */
343 pthread_mutex_lock(&app
->sock_lock
);
344 ret
= ustctl_send_counter_data_to_ust(app
->sock
,
345 app
->event_notifier_group
.object
->handle
, new_counter
);
346 pthread_mutex_unlock(&app
->sock_lock
);
348 if (ret
!= -EPIPE
&& ret
!= -LTTNG_UST_ERR_EXITING
) {
349 ERR("Failed to send counter data to application: application name = '%s', pid = %d, ret = %d",
350 app
->name
, app
->pid
, ret
);
351 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
353 DBG3("Failed to send counter data to application (application is dead): application name = '%s', pid = %d, ret = %d",
354 app
->name
, app
->pid
, ret
);
355 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD
;
361 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
367 enum event_notifier_error_accounting_status
send_counter_cpu_data_to_ust(
369 struct lttng_ust_abi_object_data
*counter
,
370 struct lttng_ust_abi_object_data
*counter_cpu
)
373 enum event_notifier_error_accounting_status status
;
375 pthread_mutex_lock(&app
->sock_lock
);
376 ret
= ustctl_send_counter_cpu_data_to_ust(app
->sock
,
377 counter
, counter_cpu
);
378 pthread_mutex_unlock(&app
->sock_lock
);
380 if (ret
!= -EPIPE
&& ret
!= -LTTNG_UST_ERR_EXITING
) {
381 ERR("Failed to send counter CPU data to application: application name = '%s', pid = %d, ret = %d",
382 app
->name
, app
->pid
, ret
);
383 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
385 DBG3("Failed to send counter CPU data to application: application name = '%s', pid = %d, ret = %d",
386 app
->name
, app
->pid
, ret
);
387 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD
;
393 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
398 enum event_notifier_error_accounting_status
399 event_notifier_error_accounting_register_app(struct ust_app
*app
)
403 struct lttng_ust_abi_object_data
*new_counter
;
404 struct error_account_entry
*entry
;
405 enum event_notifier_error_accounting_status status
;
406 struct lttng_ust_abi_object_data
**cpu_counters
;
409 * Check if we already have a error counter for the user id of this
410 * app. If not, create one.
413 entry
= get_uid_accounting_entry(app
);
415 entry
= create_uid_accounting_entry(app
);
417 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
422 /* Duplicate counter object data. */
423 ret
= ustctl_duplicate_ust_object_data(&new_counter
,
426 ERR("Failed to duplicate event notifier error accounting counter for application user: application uid = %d, pid = %d, application name = '%s'",
427 (int) app
->uid
, (int) app
->pid
, app
->name
);
428 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
432 status
= send_counter_data_to_ust(app
, new_counter
);
433 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
434 ERR("Failed to send counter data to application tracer: status = %s, application uid = %d, pid = %d, application name = '%s'",
435 error_accounting_status_str(status
),
436 (int) app
->uid
, (int) app
->pid
, app
->name
);
437 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
438 goto error_send_counter_data
;
441 cpu_counters
= zmalloc(entry
->nr_counter_cpu_fds
* sizeof(struct lttng_ust_abi_object_data
));
443 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",
444 (int) app
->uid
, app
->name
, (int) app
->pid
,
445 entry
->nr_counter_cpu_fds
* sizeof(**cpu_counters
));
446 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
447 goto error_allocate_cpu_counters
;
450 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
451 struct lttng_ust_abi_object_data
*new_counter_cpu
= NULL
;
453 ret
= ustctl_duplicate_ust_object_data(&new_counter_cpu
,
454 entry
->cpu_counters
[i
]);
456 ERR("Failed to duplicate userspace tracer counter cpu data for application user: uid = %d, pid = %d, application name = '%s'",
457 (int) app
->uid
, (int) app
->pid
,
459 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
460 goto error_duplicate_cpu_counter
;
463 cpu_counters
[i
] = new_counter_cpu
;
465 status
= send_counter_cpu_data_to_ust(app
, new_counter
,
467 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
468 ERR("Failed to send counter cpu data to application tracer: status = %s, application uid = %d, pid = %d, application name = '%s'",
469 error_accounting_status_str(status
),
470 (int) app
->uid
, (int) app
->pid
,
472 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
473 goto error_send_cpu_counter_data
;
477 app
->event_notifier_group
.counter
= new_counter
;
479 app
->event_notifier_group
.nr_counter_cpu
= entry
->nr_counter_cpu_fds
;
480 app
->event_notifier_group
.counter_cpu
= cpu_counters
;
484 error_send_cpu_counter_data
:
485 error_duplicate_cpu_counter
:
486 /* Teardown any duplicated cpu counters. */
487 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
488 if (!cpu_counters
[i
]) {
490 * Early-exit when error occurred before all cpu
491 * counters could be initialized.
496 ustctl_release_object(-1, cpu_counters
[i
]);
497 free(cpu_counters
[i
]);
500 error_allocate_cpu_counters
:
501 error_send_counter_data
:
502 ustctl_release_object(-1, new_counter
);
509 enum event_notifier_error_accounting_status
510 event_notifier_error_accounting_unregister_app(struct ust_app
*app
)
512 enum event_notifier_error_accounting_status status
;
513 struct error_account_entry
*entry
;
517 entry
= get_uid_accounting_entry(app
);
519 ERR("Failed to find event notitifier error accounting entry on application teardown: pid = %d, application name = '%s'",
520 app
->pid
, app
->name
);
521 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
525 for (i
= 0; i
< app
->event_notifier_group
.nr_counter_cpu
; i
++) {
526 ustctl_release_object(app
->sock
,
527 app
->event_notifier_group
.counter_cpu
[i
]);
528 free(app
->event_notifier_group
.counter_cpu
[i
]);
531 free(app
->event_notifier_group
.counter_cpu
);
533 ustctl_release_object(app
->sock
, app
->event_notifier_group
.counter
);
534 free(app
->event_notifier_group
.counter
);
536 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
543 enum event_notifier_error_accounting_status
544 event_notifier_error_accounting_ust_get_count(
545 const struct lttng_trigger
*trigger
, uint64_t *count
)
547 struct lttng_ht_iter iter
;
548 struct error_account_entry
*uid_entry
;
549 uint64_t error_counter_index
, global_sum
= 0;
550 enum event_notifier_error_accounting_status status
;
551 size_t dimension_indexes
[1];
552 const uint64_t tracer_token
= lttng_trigger_get_tracer_token(trigger
);
555 * Go over all error counters (ignoring uid) as a trigger (and trigger
556 * errors) can be generated from any applications that this session
557 * daemon is managing.
562 status
= get_error_counter_index_for_token(
564 &error_counter_index
);
565 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
566 uid_t trigger_owner_uid
;
567 const char *trigger_name
;
569 get_trigger_info_for_log(trigger
, &trigger_name
,
572 ERR("Failed to retrieve index for tracer token: token = %" PRIu64
", trigger name = '%s', trigger owner uid = %d, status = %s",
573 tracer_token
, trigger_name
,
574 (int) trigger_owner_uid
,
575 error_accounting_status_str(status
));
579 dimension_indexes
[0] = error_counter_index
;
581 cds_lfht_for_each_entry(error_counter_uid_ht
->ht
, &iter
.iter
,
582 uid_entry
, node
.node
) {
584 int64_t local_value
= 0;
585 bool overflow
= false, underflow
= false;
587 ret
= ustctl_counter_aggregate(uid_entry
->daemon_counter
,
588 dimension_indexes
, &local_value
, &overflow
,
590 if (ret
|| local_value
< 0) {
591 uid_t trigger_owner_uid
;
592 const char *trigger_name
;
594 get_trigger_info_for_log(trigger
, &trigger_name
,
598 ERR("Failed to aggregate event notifier error counter values of trigger: trigger name = '%s', trigger owner uid = %d",
600 (int) trigger_owner_uid
);
601 } else if (local_value
< 0) {
602 ERR("Negative event notifier error counter value encountered during aggregation: trigger name = '%s', trigger owner uid = %d, value = %" PRId64
,
604 (int) trigger_owner_uid
,
610 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
614 /* Cast is safe as negative values are checked-for above. */
615 global_sum
+= (uint64_t) local_value
;
620 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
628 enum event_notifier_error_accounting_status
event_notifier_error_accounting_ust_clear(
629 const struct lttng_trigger
*trigger
)
631 struct lttng_ht_iter iter
;
632 struct error_account_entry
*uid_entry
;
633 uint64_t error_counter_index
;
634 enum event_notifier_error_accounting_status status
;
635 size_t dimension_index
;
636 const uint64_t tracer_token
= lttng_trigger_get_tracer_token(trigger
);
639 * Go over all error counters (ignoring uid) as a trigger (and trigger
640 * errors) can be generated from any applications that this session
641 * daemon is managing.
645 status
= get_error_counter_index_for_token(
647 &error_counter_index
);
648 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
649 uid_t trigger_owner_uid
;
650 const char *trigger_name
;
652 get_trigger_info_for_log(trigger
, &trigger_name
,
655 ERR("Failed to retrieve index for tracer token: token = %" PRIu64
", trigger name = '%s', trigger owner uid = %d, status = %s",
656 tracer_token
, trigger_name
,
657 (int) trigger_owner_uid
,
658 error_accounting_status_str(status
));
662 dimension_index
= error_counter_index
;
664 cds_lfht_for_each_entry(error_counter_uid_ht
->ht
, &iter
.iter
,
665 uid_entry
, node
.node
) {
666 const int ret
= ustctl_counter_clear(uid_entry
->daemon_counter
,
670 uid_t trigger_owner_uid
;
671 const char *trigger_name
;
673 get_trigger_info_for_log(trigger
, &trigger_name
,
675 ERR("Failed to clear event notifier counter value for trigger: counter uid = %d, trigger name = '%s', trigger owner uid = %d",
676 (int) uid_entry
->node
.key
, trigger_name
,
677 (int) trigger_owner_uid
);
678 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
683 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
688 #endif /* HAVE_LIBLTTNG_UST_CTL */
691 enum event_notifier_error_accounting_status
692 event_notifier_error_accounting_kernel_clear(
693 const struct lttng_trigger
*trigger
)
696 uint64_t error_counter_index
;
697 enum event_notifier_error_accounting_status status
;
698 struct lttng_kernel_counter_clear counter_clear
= {};
700 status
= get_error_counter_index_for_token(
701 lttng_trigger_get_tracer_token(trigger
),
702 &error_counter_index
);
703 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
704 uid_t trigger_owner_uid
;
705 const char *trigger_name
;
707 get_trigger_info_for_log(
708 trigger
, &trigger_name
, &trigger_owner_uid
);
710 ERR("Failed to get event notifier error counter index: trigger owner uid = %d, trigger name = '%s', status = '%s'",
711 trigger_owner_uid
, trigger_name
,
712 error_accounting_status_str(status
));
716 counter_clear
.index
.number_dimensions
= 1;
717 counter_clear
.index
.dimension_indexes
[0] = error_counter_index
;
719 ret
= kernctl_counter_clear(
720 kernel_error_accountant
.kernel_event_notifier_error_counter_fd
,
723 uid_t trigger_owner_uid
;
724 const char *trigger_name
;
726 get_trigger_info_for_log(
727 trigger
, &trigger_name
, &trigger_owner_uid
);
729 ERR("Failed to clear kernel event notifier error counter: trigger owner uid = %d, trigger name = '%s'",
730 trigger_owner_uid
, trigger_name
);
731 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
735 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
740 enum event_notifier_error_accounting_status
741 event_notifier_error_accounting_register_kernel(
742 int kernel_event_notifier_group_fd
)
744 int error_counter_fd
= -1, ret
;
745 enum event_notifier_error_accounting_status status
;
746 const struct lttng_kernel_counter_conf error_counter_conf
= {
747 .arithmetic
= LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR
,
748 .bitness
= sizeof(void *) == sizeof(uint32_t) ?
749 LTTNG_KERNEL_COUNTER_BITNESS_32
:
750 LTTNG_KERNEL_COUNTER_BITNESS_64
,
751 .global_sum_step
= 0,
752 .number_dimensions
= 1,
753 .dimensions
[0].size
= error_counter_size
,
754 .dimensions
[0].has_underflow
= false,
755 .dimensions
[0].has_overflow
= false,
758 ret
= kernctl_create_event_notifier_group_error_counter(
759 kernel_event_notifier_group_fd
, &error_counter_conf
);
761 PERROR("Failed to create event notifier group error counter through kernel ioctl: kernel_event_notifier_group_fd = %d",
762 kernel_event_notifier_group_fd
);
763 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
767 error_counter_fd
= ret
;
769 /* Prevent fd duplication after execlp(). */
770 ret
= fcntl(error_counter_fd
, F_SETFD
, FD_CLOEXEC
);
772 PERROR("Failed to set FD_CLOEXEC flag on event notifier error counter file descriptor: error_counter_fd = %d",
774 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
778 DBG("Created kernel event notifier group error counter: fd = %d",
781 kernel_error_accountant
.kernel_event_notifier_error_counter_fd
=
783 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
790 enum event_notifier_error_accounting_status
create_error_counter_index_for_token(
791 uint64_t tracer_token
, uint64_t *error_counter_index
)
793 struct index_ht_entry
*index_entry
;
794 enum lttng_index_allocator_status index_alloc_status
;
795 uint64_t local_error_counter_index
;
796 enum event_notifier_error_accounting_status status
;
798 /* Allocate a new index for that counter. */
799 index_alloc_status
= lttng_index_allocator_alloc(index_allocator
,
800 &local_error_counter_index
);
801 switch (index_alloc_status
) {
802 case LTTNG_INDEX_ALLOCATOR_STATUS_EMPTY
:
803 DBG("No indices left in the configured event notifier error counter: "
804 "number-of-indices = %"PRIu64
,
805 lttng_index_allocator_get_index_count(
807 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE
;
809 case LTTNG_INDEX_ALLOCATOR_STATUS_OK
:
812 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
816 index_entry
= zmalloc(sizeof(*index_entry
));
817 if (index_entry
== NULL
) {
818 PERROR("Failed to allocate event notifier error counter hash table entry");
819 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
823 index_entry
->error_counter_index
= local_error_counter_index
;
824 lttng_ht_node_init_u64(&index_entry
->node
, tracer_token
);
825 lttng_ht_add_unique_u64(error_counter_indexes_ht
, &index_entry
->node
);
827 DBG("Allocated error counter index for tracer token: tracer token = %" PRIu64
", index = %" PRIu64
,
828 tracer_token
, local_error_counter_index
);
829 *error_counter_index
= local_error_counter_index
;
830 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
835 enum event_notifier_error_accounting_status
836 event_notifier_error_accounting_register_event_notifier(
837 const struct lttng_trigger
*trigger
,
838 uint64_t *error_counter_index
)
840 enum event_notifier_error_accounting_status status
;
841 uint64_t local_error_counter_index
;
844 * Check if this event notifier already has a error counter index
847 status
= get_error_counter_index_for_token(
848 lttng_trigger_get_tracer_token(trigger
),
849 &local_error_counter_index
);
851 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND
:
853 uid_t trigger_owner_uid
;
854 const char *trigger_name
;
856 get_trigger_info_for_log(
857 trigger
, &trigger_name
, &trigger_owner_uid
);
859 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
,
860 trigger_name
, trigger_owner_uid
,
861 lttng_trigger_get_tracer_token(trigger
));
863 status
= create_error_counter_index_for_token(
864 lttng_trigger_get_tracer_token(trigger
),
865 &local_error_counter_index
);
866 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
867 ERR("Error creating index for token: status = %s, trigger name = '%s', trigger owner uid = %d",
868 error_accounting_status_str(status
),
869 trigger_name
, trigger_owner_uid
);
874 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
:
875 *error_counter_index
= local_error_counter_index
;
876 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
887 enum event_notifier_error_accounting_status
888 event_notifier_error_accounting_kernel_get_count(
889 const struct lttng_trigger
*trigger
, uint64_t *count
)
891 struct lttng_kernel_counter_aggregate counter_aggregate
= {};
892 enum event_notifier_error_accounting_status status
;
893 uint64_t error_counter_index
;
896 status
= get_error_counter_index_for_token(
897 lttng_trigger_get_tracer_token(trigger
), &error_counter_index
);
898 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
899 ERR("Error getting index for token: status=%s",
900 error_accounting_status_str(status
));
904 counter_aggregate
.index
.number_dimensions
= 1;
905 counter_aggregate
.index
.dimension_indexes
[0] = error_counter_index
;
907 assert(kernel_error_accountant
.kernel_event_notifier_error_counter_fd
);
909 ret
= kernctl_counter_get_aggregate_value(
910 kernel_error_accountant
.kernel_event_notifier_error_counter_fd
,
912 if (ret
|| counter_aggregate
.value
.value
< 0) {
913 uid_t trigger_owner_uid
;
914 const char *trigger_name
;
916 get_trigger_info_for_log(trigger
, &trigger_name
,
919 if (counter_aggregate
.value
.value
< 0) {
920 ERR("Invalid negative event notifier error counter value: trigger owner = %d, trigger name = '%s', value = %" PRId64
,
921 trigger_owner_uid
, trigger_name
,
922 counter_aggregate
.value
.value
);
924 ERR("Failed to getting event notifier error count: trigger owner = %d, trigger name = '%s', ret = %d",
925 trigger_owner_uid
, trigger_name
, ret
);
928 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
932 /* Error count can't be negative. */
933 assert(counter_aggregate
.value
.value
>= 0);
934 *count
= (uint64_t) counter_aggregate
.value
.value
;
936 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
942 enum event_notifier_error_accounting_status
943 event_notifier_error_accounting_get_count(
944 const struct lttng_trigger
*trigger
, uint64_t *count
)
946 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger
)) {
947 case LTTNG_DOMAIN_KERNEL
:
948 return event_notifier_error_accounting_kernel_get_count(
950 case LTTNG_DOMAIN_UST
:
951 #ifdef HAVE_LIBLTTNG_UST_CTL
952 return event_notifier_error_accounting_ust_get_count(trigger
, count
);
954 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
955 #endif /* HAVE_LIBLTTNG_UST_CTL */
962 enum event_notifier_error_accounting_status
963 event_notifier_error_accounting_clear(const struct lttng_trigger
*trigger
)
965 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger
)) {
966 case LTTNG_DOMAIN_KERNEL
:
967 return event_notifier_error_accounting_kernel_clear(trigger
);
968 case LTTNG_DOMAIN_UST
:
969 #ifdef HAVE_LIBLTTNG_UST_CTL
970 return event_notifier_error_accounting_ust_clear(trigger
);
972 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
973 #endif /* HAVE_LIBLTTNG_UST_CTL */
979 static void free_index_ht_entry(struct rcu_head
*head
)
981 struct index_ht_entry
*entry
= caa_container_of(head
,
982 struct index_ht_entry
, rcu_head
);
987 void event_notifier_error_accounting_unregister_event_notifier(
988 const struct lttng_trigger
*trigger
)
990 struct lttng_ht_iter iter
;
991 struct lttng_ht_node_u64
*node
;
992 const uint64_t tracer_token
= lttng_trigger_get_tracer_token(trigger
);
993 enum event_notifier_error_accounting_status status
;
995 status
= event_notifier_error_accounting_clear(trigger
);
996 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
997 /* Trigger details already logged by callee on error. */
998 ERR("Failed to clear event notifier error counter during unregistration of event notifier: status = '%s'",
999 error_accounting_status_str(status
));
1003 lttng_ht_lookup(error_counter_indexes_ht
, &tracer_token
, &iter
);
1004 node
= lttng_ht_iter_get_node_u64(&iter
);
1007 struct index_ht_entry
*index_entry
= caa_container_of(
1008 node
, typeof(*index_entry
), node
);
1009 enum lttng_index_allocator_status index_alloc_status
;
1011 index_alloc_status
= lttng_index_allocator_release(
1013 index_entry
->error_counter_index
);
1014 if (index_alloc_status
!= LTTNG_INDEX_ALLOCATOR_STATUS_OK
) {
1015 uid_t trigger_owner_uid
;
1016 const char *trigger_name
;
1018 get_trigger_info_for_log(trigger
, &trigger_name
,
1019 &trigger_owner_uid
);
1021 ERR("Failed to release event notifier error counter index: index = %" PRIu64
", trigger name = '%s', trigger owner uid = %d",
1022 index_entry
->error_counter_index
,
1023 trigger_name
, (int) trigger_owner_uid
);
1024 /* Don't exit, perform the rest of the clean-up. */
1027 del_ret
= lttng_ht_del(error_counter_indexes_ht
, &iter
);
1029 call_rcu(&index_entry
->rcu_head
, free_index_ht_entry
);
1035 #ifdef HAVE_LIBLTTNG_UST_CTL
1036 static void free_error_account_entry(struct rcu_head
*head
)
1039 struct error_account_entry
*entry
=
1040 caa_container_of(head
, typeof(*entry
), rcu_head
);
1042 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
1043 ustctl_release_object(-1, entry
->cpu_counters
[i
]);
1044 free(entry
->cpu_counters
[i
]);
1047 free(entry
->cpu_counters
);
1049 ustctl_release_object(-1, entry
->counter
);
1050 free(entry
->counter
);
1052 ustctl_destroy_counter(entry
->daemon_counter
);
1057 /* Not called without UST support. */
1058 static void free_error_account_entry(struct rcu_head
*head
) {}
1059 #endif /* HAVE_LIBLTTNG_UST_CTL */
1061 void event_notifier_error_accounting_fini(void)
1063 struct lttng_ht_iter iter
;
1064 struct error_account_entry
*uid_entry
;
1066 lttng_index_allocator_destroy(index_allocator
);
1068 if (kernel_error_accountant
.kernel_event_notifier_error_counter_fd
) {
1069 const int ret
= close(kernel_error_accountant
.kernel_event_notifier_error_counter_fd
);
1072 PERROR("Failed to close kernel event notifier error counter");
1077 * FIXME error account entries are not reference-counted and torn
1078 * down on last use. They exist from the moment of their first use
1079 * up until the teardown of the session daemon.
1082 cds_lfht_for_each_entry(error_counter_uid_ht
->ht
, &iter
.iter
,
1083 uid_entry
, node
.node
) {
1084 cds_lfht_del(error_counter_uid_ht
->ht
, &uid_entry
->node
.node
);
1085 call_rcu(&uid_entry
->rcu_head
, free_error_account_entry
);
1088 lttng_ht_destroy(error_counter_uid_ht
);
1091 * Will assert if some error counter indices were not released (an
1094 lttng_ht_destroy(error_counter_indexes_ht
);