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
]);
502 error_allocate_cpu_counters
:
503 error_send_counter_data
:
504 ustctl_release_object(-1, new_counter
);
511 enum event_notifier_error_accounting_status
512 event_notifier_error_accounting_unregister_app(struct ust_app
*app
)
514 enum event_notifier_error_accounting_status status
;
515 struct error_account_entry
*entry
;
519 entry
= get_uid_accounting_entry(app
);
521 ERR("Failed to find event notitifier error accounting entry on application teardown: pid = %d, application name = '%s'",
522 app
->pid
, app
->name
);
523 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
527 for (i
= 0; i
< app
->event_notifier_group
.nr_counter_cpu
; i
++) {
528 ustctl_release_object(app
->sock
,
529 app
->event_notifier_group
.counter_cpu
[i
]);
530 free(app
->event_notifier_group
.counter_cpu
[i
]);
533 free(app
->event_notifier_group
.counter_cpu
);
535 ustctl_release_object(app
->sock
, app
->event_notifier_group
.counter
);
536 free(app
->event_notifier_group
.counter
);
538 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
545 enum event_notifier_error_accounting_status
546 event_notifier_error_accounting_ust_get_count(
547 const struct lttng_trigger
*trigger
, uint64_t *count
)
549 struct lttng_ht_iter iter
;
550 struct error_account_entry
*uid_entry
;
551 uint64_t error_counter_index
, global_sum
= 0;
552 enum event_notifier_error_accounting_status status
;
553 size_t dimension_indexes
[1];
554 const uint64_t tracer_token
= lttng_trigger_get_tracer_token(trigger
);
557 * Go over all error counters (ignoring uid) as a trigger (and trigger
558 * errors) can be generated from any applications that this session
559 * daemon is managing.
564 status
= get_error_counter_index_for_token(
566 &error_counter_index
);
567 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
568 uid_t trigger_owner_uid
;
569 const char *trigger_name
;
571 get_trigger_info_for_log(trigger
, &trigger_name
,
574 ERR("Failed to retrieve index for tracer token: token = %" PRIu64
", trigger name = '%s', trigger owner uid = %d, status = %s",
575 tracer_token
, trigger_name
,
576 (int) trigger_owner_uid
,
577 error_accounting_status_str(status
));
581 dimension_indexes
[0] = error_counter_index
;
583 cds_lfht_for_each_entry(error_counter_uid_ht
->ht
, &iter
.iter
,
584 uid_entry
, node
.node
) {
586 int64_t local_value
= 0;
587 bool overflow
= false, underflow
= false;
589 ret
= ustctl_counter_aggregate(uid_entry
->daemon_counter
,
590 dimension_indexes
, &local_value
, &overflow
,
592 if (ret
|| local_value
< 0) {
593 uid_t trigger_owner_uid
;
594 const char *trigger_name
;
596 get_trigger_info_for_log(trigger
, &trigger_name
,
600 ERR("Failed to aggregate event notifier error counter values of trigger: trigger name = '%s', trigger owner uid = %d",
602 (int) trigger_owner_uid
);
603 } else if (local_value
< 0) {
604 ERR("Negative event notifier error counter value encountered during aggregation: trigger name = '%s', trigger owner uid = %d, value = %" PRId64
,
606 (int) trigger_owner_uid
,
612 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
616 /* Cast is safe as negative values are checked-for above. */
617 global_sum
+= (uint64_t) local_value
;
622 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
630 enum event_notifier_error_accounting_status
event_notifier_error_accounting_ust_clear(
631 const struct lttng_trigger
*trigger
)
633 struct lttng_ht_iter iter
;
634 struct error_account_entry
*uid_entry
;
635 uint64_t error_counter_index
;
636 enum event_notifier_error_accounting_status status
;
637 size_t dimension_index
;
638 const uint64_t tracer_token
= lttng_trigger_get_tracer_token(trigger
);
641 * Go over all error counters (ignoring uid) as a trigger (and trigger
642 * errors) can be generated from any applications that this session
643 * daemon is managing.
647 status
= get_error_counter_index_for_token(
649 &error_counter_index
);
650 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
651 uid_t trigger_owner_uid
;
652 const char *trigger_name
;
654 get_trigger_info_for_log(trigger
, &trigger_name
,
657 ERR("Failed to retrieve index for tracer token: token = %" PRIu64
", trigger name = '%s', trigger owner uid = %d, status = %s",
658 tracer_token
, trigger_name
,
659 (int) trigger_owner_uid
,
660 error_accounting_status_str(status
));
664 dimension_index
= error_counter_index
;
666 cds_lfht_for_each_entry(error_counter_uid_ht
->ht
, &iter
.iter
,
667 uid_entry
, node
.node
) {
668 const int ret
= ustctl_counter_clear(uid_entry
->daemon_counter
,
672 uid_t trigger_owner_uid
;
673 const char *trigger_name
;
675 get_trigger_info_for_log(trigger
, &trigger_name
,
677 ERR("Failed to clear event notifier counter value for trigger: counter uid = %d, trigger name = '%s', trigger owner uid = %d",
678 (int) uid_entry
->node
.key
, trigger_name
,
679 (int) trigger_owner_uid
);
680 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
685 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
690 #endif /* HAVE_LIBLTTNG_UST_CTL */
693 enum event_notifier_error_accounting_status
694 event_notifier_error_accounting_kernel_clear(
695 const struct lttng_trigger
*trigger
)
698 uint64_t error_counter_index
;
699 enum event_notifier_error_accounting_status status
;
700 struct lttng_kernel_counter_clear counter_clear
= {};
702 status
= get_error_counter_index_for_token(
703 lttng_trigger_get_tracer_token(trigger
),
704 &error_counter_index
);
705 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
706 uid_t trigger_owner_uid
;
707 const char *trigger_name
;
709 get_trigger_info_for_log(
710 trigger
, &trigger_name
, &trigger_owner_uid
);
712 ERR("Failed to get event notifier error counter index: trigger owner uid = %d, trigger name = '%s', status = '%s'",
713 trigger_owner_uid
, trigger_name
,
714 error_accounting_status_str(status
));
718 counter_clear
.index
.number_dimensions
= 1;
719 counter_clear
.index
.dimension_indexes
[0] = error_counter_index
;
721 ret
= kernctl_counter_clear(
722 kernel_error_accountant
.kernel_event_notifier_error_counter_fd
,
725 uid_t trigger_owner_uid
;
726 const char *trigger_name
;
728 get_trigger_info_for_log(
729 trigger
, &trigger_name
, &trigger_owner_uid
);
731 ERR("Failed to clear kernel event notifier error counter: trigger owner uid = %d, trigger name = '%s'",
732 trigger_owner_uid
, trigger_name
);
733 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
737 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
742 enum event_notifier_error_accounting_status
743 event_notifier_error_accounting_register_kernel(
744 int kernel_event_notifier_group_fd
)
746 int error_counter_fd
= -1, ret
;
747 enum event_notifier_error_accounting_status status
;
748 const struct lttng_kernel_counter_conf error_counter_conf
= {
749 .arithmetic
= LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR
,
750 .bitness
= sizeof(void *) == sizeof(uint32_t) ?
751 LTTNG_KERNEL_COUNTER_BITNESS_32
:
752 LTTNG_KERNEL_COUNTER_BITNESS_64
,
753 .global_sum_step
= 0,
754 .number_dimensions
= 1,
755 .dimensions
[0].size
= error_counter_size
,
756 .dimensions
[0].has_underflow
= false,
757 .dimensions
[0].has_overflow
= false,
760 ret
= kernctl_create_event_notifier_group_error_counter(
761 kernel_event_notifier_group_fd
, &error_counter_conf
);
763 PERROR("Failed to create event notifier group error counter through kernel ioctl: kernel_event_notifier_group_fd = %d",
764 kernel_event_notifier_group_fd
);
765 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
769 error_counter_fd
= ret
;
771 /* Prevent fd duplication after execlp(). */
772 ret
= fcntl(error_counter_fd
, F_SETFD
, FD_CLOEXEC
);
774 PERROR("Failed to set FD_CLOEXEC flag on event notifier error counter file descriptor: error_counter_fd = %d",
776 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
780 DBG("Created kernel event notifier group error counter: fd = %d",
783 kernel_error_accountant
.kernel_event_notifier_error_counter_fd
=
785 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
792 enum event_notifier_error_accounting_status
create_error_counter_index_for_token(
793 uint64_t tracer_token
, uint64_t *error_counter_index
)
795 struct index_ht_entry
*index_entry
;
796 enum lttng_index_allocator_status index_alloc_status
;
797 uint64_t local_error_counter_index
;
798 enum event_notifier_error_accounting_status status
;
800 /* Allocate a new index for that counter. */
801 index_alloc_status
= lttng_index_allocator_alloc(index_allocator
,
802 &local_error_counter_index
);
803 switch (index_alloc_status
) {
804 case LTTNG_INDEX_ALLOCATOR_STATUS_EMPTY
:
805 DBG("No indices left in the configured event notifier error counter: "
806 "number-of-indices = %"PRIu64
,
807 lttng_index_allocator_get_index_count(
809 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE
;
811 case LTTNG_INDEX_ALLOCATOR_STATUS_OK
:
814 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
818 index_entry
= zmalloc(sizeof(*index_entry
));
819 if (index_entry
== NULL
) {
820 PERROR("Failed to allocate event notifier error counter hash table entry");
821 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM
;
825 index_entry
->error_counter_index
= local_error_counter_index
;
826 lttng_ht_node_init_u64(&index_entry
->node
, tracer_token
);
827 lttng_ht_add_unique_u64(error_counter_indexes_ht
, &index_entry
->node
);
829 DBG("Allocated error counter index for tracer token: tracer token = %" PRIu64
", index = %" PRIu64
,
830 tracer_token
, local_error_counter_index
);
831 *error_counter_index
= local_error_counter_index
;
832 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
837 enum event_notifier_error_accounting_status
838 event_notifier_error_accounting_register_event_notifier(
839 const struct lttng_trigger
*trigger
,
840 uint64_t *error_counter_index
)
842 enum event_notifier_error_accounting_status status
;
843 uint64_t local_error_counter_index
;
846 * Check if this event notifier already has a error counter index
849 status
= get_error_counter_index_for_token(
850 lttng_trigger_get_tracer_token(trigger
),
851 &local_error_counter_index
);
853 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND
:
855 uid_t trigger_owner_uid
;
856 const char *trigger_name
;
858 get_trigger_info_for_log(
859 trigger
, &trigger_name
, &trigger_owner_uid
);
861 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
,
862 trigger_name
, trigger_owner_uid
,
863 lttng_trigger_get_tracer_token(trigger
));
865 status
= create_error_counter_index_for_token(
866 lttng_trigger_get_tracer_token(trigger
),
867 &local_error_counter_index
);
868 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
869 ERR("Error creating index for token: status = %s, trigger name = '%s', trigger owner uid = %d",
870 error_accounting_status_str(status
),
871 trigger_name
, trigger_owner_uid
);
876 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
:
877 *error_counter_index
= local_error_counter_index
;
878 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
889 enum event_notifier_error_accounting_status
890 event_notifier_error_accounting_kernel_get_count(
891 const struct lttng_trigger
*trigger
, uint64_t *count
)
893 struct lttng_kernel_counter_aggregate counter_aggregate
= {};
894 enum event_notifier_error_accounting_status status
;
895 uint64_t error_counter_index
;
898 status
= get_error_counter_index_for_token(
899 lttng_trigger_get_tracer_token(trigger
), &error_counter_index
);
900 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
901 ERR("Error getting index for token: status=%s",
902 error_accounting_status_str(status
));
906 counter_aggregate
.index
.number_dimensions
= 1;
907 counter_aggregate
.index
.dimension_indexes
[0] = error_counter_index
;
909 assert(kernel_error_accountant
.kernel_event_notifier_error_counter_fd
);
911 ret
= kernctl_counter_get_aggregate_value(
912 kernel_error_accountant
.kernel_event_notifier_error_counter_fd
,
914 if (ret
|| counter_aggregate
.value
.value
< 0) {
915 uid_t trigger_owner_uid
;
916 const char *trigger_name
;
918 get_trigger_info_for_log(trigger
, &trigger_name
,
921 if (counter_aggregate
.value
.value
< 0) {
922 ERR("Invalid negative event notifier error counter value: trigger owner = %d, trigger name = '%s', value = %" PRId64
,
923 trigger_owner_uid
, trigger_name
,
924 counter_aggregate
.value
.value
);
926 ERR("Failed to getting event notifier error count: trigger owner = %d, trigger name = '%s', ret = %d",
927 trigger_owner_uid
, trigger_name
, ret
);
930 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR
;
934 /* Error count can't be negative. */
935 assert(counter_aggregate
.value
.value
>= 0);
936 *count
= (uint64_t) counter_aggregate
.value
.value
;
938 status
= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
944 enum event_notifier_error_accounting_status
945 event_notifier_error_accounting_get_count(
946 const struct lttng_trigger
*trigger
, uint64_t *count
)
948 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger
)) {
949 case LTTNG_DOMAIN_KERNEL
:
950 return event_notifier_error_accounting_kernel_get_count(
952 case LTTNG_DOMAIN_UST
:
953 #ifdef HAVE_LIBLTTNG_UST_CTL
954 return event_notifier_error_accounting_ust_get_count(trigger
, count
);
956 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
957 #endif /* HAVE_LIBLTTNG_UST_CTL */
964 enum event_notifier_error_accounting_status
965 event_notifier_error_accounting_clear(const struct lttng_trigger
*trigger
)
967 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger
)) {
968 case LTTNG_DOMAIN_KERNEL
:
969 return event_notifier_error_accounting_kernel_clear(trigger
);
970 case LTTNG_DOMAIN_UST
:
971 #ifdef HAVE_LIBLTTNG_UST_CTL
972 return event_notifier_error_accounting_ust_clear(trigger
);
974 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
;
975 #endif /* HAVE_LIBLTTNG_UST_CTL */
981 static void free_index_ht_entry(struct rcu_head
*head
)
983 struct index_ht_entry
*entry
= caa_container_of(head
,
984 struct index_ht_entry
, rcu_head
);
989 void event_notifier_error_accounting_unregister_event_notifier(
990 const struct lttng_trigger
*trigger
)
992 struct lttng_ht_iter iter
;
993 struct lttng_ht_node_u64
*node
;
994 const uint64_t tracer_token
= lttng_trigger_get_tracer_token(trigger
);
995 enum event_notifier_error_accounting_status status
;
997 status
= event_notifier_error_accounting_clear(trigger
);
998 if (status
!= EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK
) {
999 /* Trigger details already logged by callee on error. */
1000 ERR("Failed to clear event notifier error counter during unregistration of event notifier: status = '%s'",
1001 error_accounting_status_str(status
));
1005 lttng_ht_lookup(error_counter_indexes_ht
, &tracer_token
, &iter
);
1006 node
= lttng_ht_iter_get_node_u64(&iter
);
1009 struct index_ht_entry
*index_entry
= caa_container_of(
1010 node
, typeof(*index_entry
), node
);
1011 enum lttng_index_allocator_status index_alloc_status
;
1013 index_alloc_status
= lttng_index_allocator_release(
1015 index_entry
->error_counter_index
);
1016 if (index_alloc_status
!= LTTNG_INDEX_ALLOCATOR_STATUS_OK
) {
1017 uid_t trigger_owner_uid
;
1018 const char *trigger_name
;
1020 get_trigger_info_for_log(trigger
, &trigger_name
,
1021 &trigger_owner_uid
);
1023 ERR("Failed to release event notifier error counter index: index = %" PRIu64
", trigger name = '%s', trigger owner uid = %d",
1024 index_entry
->error_counter_index
,
1025 trigger_name
, (int) trigger_owner_uid
);
1026 /* Don't exit, perform the rest of the clean-up. */
1029 del_ret
= lttng_ht_del(error_counter_indexes_ht
, &iter
);
1031 call_rcu(&index_entry
->rcu_head
, free_index_ht_entry
);
1037 #ifdef HAVE_LIBLTTNG_UST_CTL
1038 static void free_error_account_entry(struct rcu_head
*head
)
1041 struct error_account_entry
*entry
=
1042 caa_container_of(head
, typeof(*entry
), rcu_head
);
1044 for (i
= 0; i
< entry
->nr_counter_cpu_fds
; i
++) {
1045 ustctl_release_object(-1, entry
->cpu_counters
[i
]);
1046 free(entry
->cpu_counters
[i
]);
1049 free(entry
->cpu_counters
);
1051 ustctl_release_object(-1, entry
->counter
);
1052 free(entry
->counter
);
1054 ustctl_destroy_counter(entry
->daemon_counter
);
1059 /* Not called without UST support. */
1060 static void free_error_account_entry(struct rcu_head
*head
) {}
1061 #endif /* HAVE_LIBLTTNG_UST_CTL */
1063 void event_notifier_error_accounting_fini(void)
1065 struct lttng_ht_iter iter
;
1066 struct error_account_entry
*uid_entry
;
1068 lttng_index_allocator_destroy(index_allocator
);
1070 if (kernel_error_accountant
.kernel_event_notifier_error_counter_fd
) {
1071 const int ret
= close(kernel_error_accountant
.kernel_event_notifier_error_counter_fd
);
1074 PERROR("Failed to close kernel event notifier error counter");
1079 * FIXME error account entries are not reference-counted and torn
1080 * down on last use. They exist from the moment of their first use
1081 * up until the teardown of the session daemon.
1084 cds_lfht_for_each_entry(error_counter_uid_ht
->ht
, &iter
.iter
,
1085 uid_entry
, node
.node
) {
1086 cds_lfht_del(error_counter_uid_ht
->ht
, &uid_entry
->node
.node
);
1087 call_rcu(&uid_entry
->rcu_head
, free_error_account_entry
);
1090 lttng_ht_destroy(error_counter_uid_ht
);
1093 * Will assert if some error counter indices were not released (an
1096 lttng_ht_destroy(error_counter_indexes_ht
);