sessiond: split event notifier error counter CLI options
[lttng-tools.git] / src / bin / lttng-sessiond / event-notifier-error-accounting.c
1 /*
2 * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #include <fcntl.h>
9 #include <sys/mman.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 #include <urcu/compiler.h>
13 #include <pthread.h>
14
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>
21
22 #include "event-notifier-error-accounting.h"
23 #include "lttng-ust-error.h"
24 #include "ust-app.h"
25
26 #define ERROR_COUNTER_INDEX_HT_INITIAL_SIZE 16
27
28 struct index_ht_entry {
29 struct lttng_ht_node_u64 node;
30 uint64_t error_counter_index;
31 struct rcu_head rcu_head;
32 };
33
34 struct ust_error_accounting_entry {
35 uid_t uid;
36 struct lttng_ht_node_u64 node;
37 struct rcu_head rcu_head;
38 struct ustctl_daemon_counter *daemon_counter;
39 /*
40 * Those `lttng_ust_abi_object_data` are anonymous handles to the counters
41 * objects.
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)`;
45 */
46 struct lttng_ust_abi_object_data *counter;
47 struct lttng_ust_abi_object_data **cpu_counters;
48 int nr_counter_cpu_fds;
49 };
50
51 struct kernel_error_accounting_entry {
52 int kernel_event_notifier_error_counter_fd;
53 };
54
55 static struct kernel_error_accounting_entry kernel_error_accountant;
56
57 /* Hashtable mapping uid to error_account_entry. */
58 static struct lttng_ht *error_counter_uid_ht;
59
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;
65 };
66
67 static struct error_accounting_state ust_state;
68 static struct error_accounting_state kernel_state;
69
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)
73 {
74 enum lttng_trigger_status trigger_status;
75
76 trigger_status = lttng_trigger_get_name(trigger, trigger_name);
77 switch (trigger_status) {
78 case LTTNG_TRIGGER_STATUS_OK:
79 break;
80 case LTTNG_TRIGGER_STATUS_UNSET:
81 *trigger_name = "(unset)";
82 break;
83 default:
84 abort();
85 }
86
87 trigger_status = lttng_trigger_get_owner_uid(trigger,
88 trigger_owner_uid);
89 assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
90 }
91
92 static inline
93 const char *error_accounting_status_str(
94 enum event_notifier_error_accounting_status status)
95 {
96 switch (status) {
97 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK:
98 return "OK";
99 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR:
100 return "ERROR";
101 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND:
102 return "NOT_FOUND";
103 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM:
104 return "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:
108 return "APP_DEAD";
109 default:
110 abort();
111 }
112 }
113
114 static
115 enum event_notifier_error_accounting_status
116 init_error_accounting_state(struct error_accounting_state *state,
117 uint64_t index_count)
118 {
119 enum event_notifier_error_accounting_status status;
120
121 assert(state);
122
123 state->number_indices = index_count;
124
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;
129 goto end;
130 }
131
132 state->indices_ht = lttng_ht_new(ERROR_COUNTER_INDEX_HT_INITIAL_SIZE,
133 LTTNG_HT_TYPE_U64);
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;
138 }
139
140 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
141 goto end;
142
143 error_indices_ht:
144 lttng_index_allocator_destroy(state->index_allocator);
145 state->index_allocator = NULL;
146 end:
147 return status;
148 }
149
150 static
151 void fini_error_accounting_state(struct error_accounting_state *state)
152 {
153 assert(state);
154
155 /*
156 * Will assert if some error counter indices were not released (an
157 * internal error).
158 */
159 lttng_ht_destroy(state->indices_ht);
160 lttng_index_allocator_destroy(state->index_allocator);
161 }
162
163 enum event_notifier_error_accounting_status
164 event_notifier_error_accounting_init(uint64_t buffer_size_kernel,
165 uint64_t buffer_size_ust)
166 {
167 enum event_notifier_error_accounting_status status;
168
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));
173 goto end;
174 }
175
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;
181 }
182
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;
188 goto error_uid_ht;
189 }
190
191 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
192 goto end;
193
194 error_uid_ht:
195 fini_error_accounting_state(&ust_state);
196 error_ust_state:
197 fini_error_accounting_state(&kernel_state);
198 end:
199 return status;
200 }
201
202 static
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)
206 {
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;
211
212 rcu_read_lock();
213 lttng_ht_lookup(state->indices_ht, &tracer_token, &iter);
214 node = lttng_ht_iter_get_node_u64(&iter);
215 if (node) {
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;
220 } else {
221 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND;
222 }
223
224 rcu_read_unlock();
225 return status;
226 }
227
228 #ifdef HAVE_LIBLTTNG_UST_CTL
229 static
230 struct ust_error_accounting_entry *get_uid_accounting_entry(const struct ust_app *app)
231 {
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;
236
237 lttng_ht_lookup(error_counter_uid_ht, &key, &iter);
238 node = lttng_ht_iter_get_node_u64(&iter);
239 if(node == NULL) {
240 entry = NULL;
241 } else {
242 entry = caa_container_of(node, struct ust_error_accounting_entry, node);
243 }
244
245 return entry;
246 }
247
248 static
249 struct ust_error_accounting_entry *create_uid_accounting_entry(
250 const struct ust_app *app)
251 {
252 int i, ret;
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,
261 };
262
263 entry = zmalloc(sizeof(struct ust_error_accounting_entry));
264 if (!entry) {
265 PERROR("Failed to allocate event notifier error acounting entry")
266 goto error;
267 }
268
269 entry->uid = app->uid;
270 entry->nr_counter_cpu_fds = ustctl_get_nr_cpu_per_counter();
271
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));
277 ret = -1;
278 goto error_counter_cpu_fds_alloc;
279 }
280
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;
284 }
285
286 cpu_counters = zmalloc(entry->nr_counter_cpu_fds * sizeof(struct lttng_ust_abi_object_data *));
287 if (!cpu_counters) {
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 *));
291 ret = -1;
292 goto error_counter_cpus_alloc;
293 }
294
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;
301 }
302 }
303
304 /*
305 * Ownership of the file descriptors transferred to the ustctl object.
306 */
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,
312 false);
313 if (!daemon_counter) {
314 goto error_create_daemon_counter;
315 }
316
317 ret = ustctl_create_counter_data(daemon_counter, &counter);
318 if (ret) {
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;
322 }
323
324 for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
325 ret = ustctl_create_counter_cpu_data(daemon_counter, i,
326 &cpu_counters[i]);
327 if (ret) {
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,
330 app->name);
331 goto error_create_counter_cpu_data;
332 }
333 }
334
335 entry->daemon_counter = daemon_counter;
336 entry->counter = counter;
337 entry->cpu_counters = cpu_counters;
338
339 lttng_ht_node_init_u64(&entry->node, app->uid);
340 lttng_ht_add_unique_u64(error_counter_uid_ht, &entry->node);
341
342 goto end;
343
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]) {
348 /*
349 * Early-exit when error occurred before all cpu
350 * counters could be initialized.
351 */
352 break;
353 }
354
355 ustctl_release_object(-1, cpu_counters[i]);
356 free(cpu_counters[i]);
357 }
358
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:
364 error_shm_alloc:
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) {
369 /*
370 * Early-exit when error occurred before all cpu
371 * counter shm fds could be initialized.
372 */
373 break;
374 }
375
376 ret = close(cpu_counter_fds[i]);
377 if (ret) {
378 PERROR("Failed to close error counter per-CPU shm file descriptor: fd = %d", cpu_counter_fds[i]);
379 }
380 }
381 }
382
383 free(cpu_counters);
384 error_counter_cpus_alloc:
385 error_counter_cpu_fds_alloc:
386 free(entry);
387 error:
388 entry = NULL;
389 end:
390 free(cpu_counter_fds);
391 return entry;
392 }
393
394 static
395 enum event_notifier_error_accounting_status send_counter_data_to_ust(
396 struct ust_app *app,
397 struct lttng_ust_abi_object_data *new_counter)
398 {
399 int ret;
400 enum event_notifier_error_accounting_status status;
401
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);
407 if (ret < 0) {
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;
412 } else {
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;
416 }
417
418 goto end;
419 }
420
421 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
422 end:
423 return status;
424 }
425
426 static
427 enum event_notifier_error_accounting_status send_counter_cpu_data_to_ust(
428 struct ust_app *app,
429 struct lttng_ust_abi_object_data *counter,
430 struct lttng_ust_abi_object_data *counter_cpu)
431 {
432 int ret;
433 enum event_notifier_error_accounting_status status;
434
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);
439 if (ret < 0) {
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;
444 } else {
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;
448 }
449
450 goto end;
451 }
452
453 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
454 end:
455 return status;
456 }
457
458 enum event_notifier_error_accounting_status
459 event_notifier_error_accounting_register_app(struct ust_app *app)
460 {
461 int ret;
462 uint64_t i;
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;
467
468 /*
469 * Check if we already have a error counter for the user id of this
470 * app. If not, create one.
471 */
472 rcu_read_lock();
473 entry = get_uid_accounting_entry(app);
474 if (entry == NULL) {
475 entry = create_uid_accounting_entry(app);
476 if (!entry) {
477 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
478 goto end;
479 }
480 }
481
482 /* Duplicate counter object data. */
483 ret = ustctl_duplicate_ust_object_data(&new_counter,
484 entry->counter);
485 if (ret) {
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;
489 goto end;
490 }
491
492 status = send_counter_data_to_ust(app, new_counter);
493 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
494 ERR("Failed to send counter data to application tracer: status = %s, application uid = %d, pid = %d, application name = '%s'",
495 error_accounting_status_str(status),
496 (int) app->uid, (int) app->pid, app->name);
497 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
498 goto error_send_counter_data;
499 }
500
501 cpu_counters = zmalloc(entry->nr_counter_cpu_fds * sizeof(struct lttng_ust_abi_object_data *));
502 if (!cpu_counters) {
503 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",
504 (int) app->uid, app->name, (int) app->pid,
505 entry->nr_counter_cpu_fds * sizeof(**cpu_counters));
506 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM;
507 goto error_allocate_cpu_counters;
508 }
509
510 for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
511 struct lttng_ust_abi_object_data *new_counter_cpu = NULL;
512
513 ret = ustctl_duplicate_ust_object_data(&new_counter_cpu,
514 entry->cpu_counters[i]);
515 if (ret) {
516 ERR("Failed to duplicate userspace tracer counter cpu data for application user: uid = %d, pid = %d, application name = '%s'",
517 (int) app->uid, (int) app->pid,
518 app->name);
519 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM;
520 goto error_duplicate_cpu_counter;
521 }
522
523 cpu_counters[i] = new_counter_cpu;
524
525 status = send_counter_cpu_data_to_ust(app, new_counter,
526 new_counter_cpu);
527 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
528 ERR("Failed to send counter cpu data to application tracer: status = %s, application uid = %d, pid = %d, application name = '%s'",
529 error_accounting_status_str(status),
530 (int) app->uid, (int) app->pid,
531 app->name);
532 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
533 goto error_send_cpu_counter_data;
534 }
535 }
536
537 app->event_notifier_group.counter = new_counter;
538 new_counter = NULL;
539 app->event_notifier_group.nr_counter_cpu = entry->nr_counter_cpu_fds;
540 app->event_notifier_group.counter_cpu = cpu_counters;
541 cpu_counters = NULL;
542 goto end;
543
544 error_send_cpu_counter_data:
545 error_duplicate_cpu_counter:
546 /* Teardown any duplicated cpu counters. */
547 for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
548 if (!cpu_counters[i]) {
549 /*
550 * Early-exit when error occurred before all cpu
551 * counters could be initialized.
552 */
553 break;
554 }
555
556 ustctl_release_object(-1, cpu_counters[i]);
557 free(cpu_counters[i]);
558 }
559
560 free(cpu_counters);
561
562 error_allocate_cpu_counters:
563 error_send_counter_data:
564 ustctl_release_object(-1, new_counter);
565 free(new_counter);
566 end:
567 rcu_read_unlock();
568 return status;
569 }
570
571 enum event_notifier_error_accounting_status
572 event_notifier_error_accounting_unregister_app(struct ust_app *app)
573 {
574 enum event_notifier_error_accounting_status status;
575 struct ust_error_accounting_entry *entry;
576 int i;
577
578 rcu_read_lock();
579 entry = get_uid_accounting_entry(app);
580 if (entry == NULL) {
581 ERR("Failed to find event notitifier error accounting entry on application teardown: pid = %d, application name = '%s'",
582 app->pid, app->name);
583 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
584 goto end;
585 }
586
587 for (i = 0; i < app->event_notifier_group.nr_counter_cpu; i++) {
588 ustctl_release_object(app->sock,
589 app->event_notifier_group.counter_cpu[i]);
590 free(app->event_notifier_group.counter_cpu[i]);
591 }
592
593 free(app->event_notifier_group.counter_cpu);
594
595 ustctl_release_object(app->sock, app->event_notifier_group.counter);
596 free(app->event_notifier_group.counter);
597
598 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
599 end:
600 rcu_read_unlock();
601 return status;
602 }
603
604 static
605 enum event_notifier_error_accounting_status
606 event_notifier_error_accounting_ust_get_count(
607 const struct lttng_trigger *trigger, uint64_t *count)
608 {
609 struct lttng_ht_iter iter;
610 struct ust_error_accounting_entry *uid_entry;
611 uint64_t error_counter_index, global_sum = 0;
612 enum event_notifier_error_accounting_status status;
613 size_t dimension_indexes[1];
614 const uint64_t tracer_token = lttng_trigger_get_tracer_token(trigger);
615 uid_t trigger_owner_uid;
616 const char *trigger_name;
617
618
619 rcu_read_lock();
620
621 get_trigger_info_for_log(trigger, &trigger_name, &trigger_owner_uid);
622
623 /*
624 * At the moment, the error counter index is domain wide. This means
625 * that if UID 1000 registers a event notifier and is allocated index 0
626 * in it's error counter, index zero will be unused in error counter of
627 * all other users.
628 */
629 status = get_error_counter_index_for_token(
630 &ust_state,
631 tracer_token,
632 &error_counter_index);
633 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
634
635 ERR("Failed to retrieve index for tracer token: token = %" PRIu64 ", trigger name = '%s', trigger owner uid = %d, status = %s",
636 tracer_token, trigger_name,
637 (int) trigger_owner_uid,
638 error_accounting_status_str(status));
639 goto end;
640 }
641
642 dimension_indexes[0] = error_counter_index;
643
644 /*
645 * Iterate over all the UID entries.
646 * We aggregate the value of all uid entries regardless of if the uid
647 * matches the trigger's uid because a user that is allowed to register
648 * a trigger to a given sessiond is also allowed to create an event
649 * notifier on all apps that this sessiond is aware of.
650 */
651 cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
652 uid_entry, node.node) {
653 int ret;
654 int64_t local_value = 0;
655 bool overflow = false, underflow = false;
656
657 ret = ustctl_counter_aggregate(uid_entry->daemon_counter,
658 dimension_indexes, &local_value, &overflow,
659 &underflow);
660 if (ret || local_value < 0) {
661 if (ret) {
662 ERR("Failed to aggregate event notifier error counter values of trigger: trigger name = '%s', trigger owner uid = %d",
663 trigger_name,
664 (int) trigger_owner_uid);
665 } else if (local_value < 0) {
666 ERR("Negative event notifier error counter value encountered during aggregation: trigger name = '%s', trigger owner uid = %d, value = %" PRId64,
667 trigger_name,
668 (int) trigger_owner_uid,
669 local_value);
670 } else {
671 abort();
672 }
673
674 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
675 goto end;
676 }
677
678 /* Cast is safe as negative values are checked-for above. */
679 global_sum += (uint64_t) local_value;
680 }
681
682 *count = global_sum;
683 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
684
685 end:
686 rcu_read_unlock();
687 return status;
688 }
689
690 static
691 enum event_notifier_error_accounting_status event_notifier_error_accounting_ust_clear(
692 const struct lttng_trigger *trigger)
693 {
694 struct lttng_ht_iter iter;
695 struct ust_error_accounting_entry *uid_entry;
696 uint64_t error_counter_index;
697 enum event_notifier_error_accounting_status status;
698 size_t dimension_index;
699 const uint64_t tracer_token = lttng_trigger_get_tracer_token(trigger);
700
701 /*
702 * Go over all error counters (ignoring uid) as a trigger (and trigger
703 * errors) can be generated from any applications that this session
704 * daemon is managing.
705 */
706
707 rcu_read_lock();
708 status = get_error_counter_index_for_token(
709 &ust_state,
710 tracer_token,
711 &error_counter_index);
712 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
713 uid_t trigger_owner_uid;
714 const char *trigger_name;
715
716 get_trigger_info_for_log(trigger, &trigger_name,
717 &trigger_owner_uid);
718
719 ERR("Failed to retrieve index for tracer token: token = %" PRIu64 ", trigger name = '%s', trigger owner uid = %d, status = %s",
720 tracer_token, trigger_name,
721 (int) trigger_owner_uid,
722 error_accounting_status_str(status));
723 goto end;
724 }
725
726 dimension_index = error_counter_index;
727
728 cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
729 uid_entry, node.node) {
730 const int ret = ustctl_counter_clear(uid_entry->daemon_counter,
731 &dimension_index);
732
733 if (ret) {
734 uid_t trigger_owner_uid;
735 const char *trigger_name;
736
737 get_trigger_info_for_log(trigger, &trigger_name,
738 &trigger_owner_uid);
739 ERR("Failed to clear event notifier counter value for trigger: counter uid = %d, trigger name = '%s', trigger owner uid = %d",
740 (int) uid_entry->node.key, trigger_name,
741 (int) trigger_owner_uid);
742 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
743 goto end;
744 }
745 }
746
747 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
748 end:
749 rcu_read_unlock();
750 return status;
751 }
752 #endif /* HAVE_LIBLTTNG_UST_CTL */
753
754 static
755 enum event_notifier_error_accounting_status
756 event_notifier_error_accounting_kernel_clear(
757 const struct lttng_trigger *trigger)
758 {
759 int ret;
760 uint64_t error_counter_index;
761 enum event_notifier_error_accounting_status status;
762 struct lttng_kernel_counter_clear counter_clear = {};
763
764 status = get_error_counter_index_for_token(
765 &kernel_state,
766 lttng_trigger_get_tracer_token(trigger),
767 &error_counter_index);
768 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
769 uid_t trigger_owner_uid;
770 const char *trigger_name;
771
772 get_trigger_info_for_log(
773 trigger, &trigger_name, &trigger_owner_uid);
774
775 ERR("Failed to get event notifier error counter index: trigger owner uid = %d, trigger name = '%s', status = '%s'",
776 trigger_owner_uid, trigger_name,
777 error_accounting_status_str(status));
778 goto end;
779 }
780
781 counter_clear.index.number_dimensions = 1;
782 counter_clear.index.dimension_indexes[0] = error_counter_index;
783
784 ret = kernctl_counter_clear(
785 kernel_error_accountant.kernel_event_notifier_error_counter_fd,
786 &counter_clear);
787 if (ret) {
788 uid_t trigger_owner_uid;
789 const char *trigger_name;
790
791 get_trigger_info_for_log(
792 trigger, &trigger_name, &trigger_owner_uid);
793
794 ERR("Failed to clear kernel event notifier error counter: trigger owner uid = %d, trigger name = '%s'",
795 trigger_owner_uid, trigger_name);
796 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
797 goto end;
798 }
799
800 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
801 end:
802 return status;
803 }
804
805 enum event_notifier_error_accounting_status
806 event_notifier_error_accounting_register_kernel(
807 int kernel_event_notifier_group_fd)
808 {
809 int error_counter_fd = -1, ret;
810 enum event_notifier_error_accounting_status status;
811 const struct lttng_kernel_counter_conf error_counter_conf = {
812 .arithmetic = LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR,
813 .bitness = sizeof(void *) == sizeof(uint32_t) ?
814 LTTNG_KERNEL_COUNTER_BITNESS_32 :
815 LTTNG_KERNEL_COUNTER_BITNESS_64,
816 .global_sum_step = 0,
817 .number_dimensions = 1,
818 .dimensions[0].size = kernel_state.number_indices,
819 .dimensions[0].has_underflow = false,
820 .dimensions[0].has_overflow = false,
821 };
822
823 ret = kernctl_create_event_notifier_group_error_counter(
824 kernel_event_notifier_group_fd, &error_counter_conf);
825 if (ret < 0) {
826 PERROR("Failed to create event notifier group error counter through kernel ioctl: kernel_event_notifier_group_fd = %d",
827 kernel_event_notifier_group_fd);
828 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
829 goto error;
830 }
831
832 error_counter_fd = ret;
833
834 /* Prevent fd duplication after execlp(). */
835 ret = fcntl(error_counter_fd, F_SETFD, FD_CLOEXEC);
836 if (ret < 0) {
837 PERROR("Failed to set FD_CLOEXEC flag on event notifier error counter file descriptor: error_counter_fd = %d",
838 error_counter_fd);
839 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
840 goto error;
841 }
842
843 DBG("Created kernel event notifier group error counter: fd = %d",
844 error_counter_fd);
845
846 kernel_error_accountant.kernel_event_notifier_error_counter_fd =
847 error_counter_fd;
848 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
849
850 error:
851 return status;
852 }
853
854 static
855 enum event_notifier_error_accounting_status create_error_counter_index_for_token(
856 struct error_accounting_state *state, uint64_t tracer_token,
857 uint64_t *error_counter_index)
858 {
859 struct index_ht_entry *index_entry;
860 enum lttng_index_allocator_status index_alloc_status;
861 uint64_t local_error_counter_index;
862 enum event_notifier_error_accounting_status status;
863
864 assert(state);
865
866 /* Allocate a new index for that counter. */
867 index_alloc_status = lttng_index_allocator_alloc(state->index_allocator,
868 &local_error_counter_index);
869 switch (index_alloc_status) {
870 case LTTNG_INDEX_ALLOCATOR_STATUS_EMPTY:
871 DBG("No indices left in the configured event notifier error counter: "
872 "number-of-indices = %"PRIu64,
873 lttng_index_allocator_get_index_count(
874 state->index_allocator));
875 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE;
876 goto end;
877 case LTTNG_INDEX_ALLOCATOR_STATUS_OK:
878 break;
879 default:
880 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
881 goto end;
882 }
883
884 index_entry = zmalloc(sizeof(*index_entry));
885 if (index_entry == NULL) {
886 PERROR("Failed to allocate event notifier error counter hash table entry");
887 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM;
888 goto end;
889 }
890
891 index_entry->error_counter_index = local_error_counter_index;
892 lttng_ht_node_init_u64(&index_entry->node, tracer_token);
893 lttng_ht_add_unique_u64(state->indices_ht, &index_entry->node);
894
895 DBG("Allocated error counter index for tracer token: tracer token = %" PRIu64 ", index = %" PRIu64,
896 tracer_token, local_error_counter_index);
897 *error_counter_index = local_error_counter_index;
898 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
899 end:
900 return status;
901 }
902
903 enum event_notifier_error_accounting_status
904 event_notifier_error_accounting_register_event_notifier(
905 const struct lttng_trigger *trigger,
906 uint64_t *error_counter_index)
907 {
908 enum event_notifier_error_accounting_status status;
909 uint64_t local_error_counter_index;
910 struct error_accounting_state *state;
911
912 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger)) {
913 case LTTNG_DOMAIN_KERNEL:
914 state = &kernel_state;
915 break;
916 case LTTNG_DOMAIN_UST:
917 state = &ust_state;
918 break;
919 default:
920 abort();
921 }
922
923 /*
924 * Check if this event notifier already has a error counter index
925 * assigned.
926 */
927 status = get_error_counter_index_for_token(state,
928 lttng_trigger_get_tracer_token(trigger),
929 &local_error_counter_index);
930 switch (status) {
931 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND:
932 {
933 uid_t trigger_owner_uid;
934 const char *trigger_name;
935
936 get_trigger_info_for_log(
937 trigger, &trigger_name, &trigger_owner_uid);
938
939 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,
940 trigger_name, trigger_owner_uid,
941 lttng_trigger_get_tracer_token(trigger));
942
943 status = create_error_counter_index_for_token(state,
944 lttng_trigger_get_tracer_token(trigger),
945 &local_error_counter_index);
946 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
947 ERR("Error creating index for token: status = %s, trigger name = '%s', trigger owner uid = %d",
948 error_accounting_status_str(status),
949 trigger_name, trigger_owner_uid);
950 goto end;
951 }
952 /* fall-through. */
953 }
954 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK:
955 *error_counter_index = local_error_counter_index;
956 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
957 break;
958 default:
959 break;
960 }
961
962 end:
963 return status;
964 }
965
966 static
967 enum event_notifier_error_accounting_status
968 event_notifier_error_accounting_kernel_get_count(
969 const struct lttng_trigger *trigger, uint64_t *count)
970 {
971 struct lttng_kernel_counter_aggregate counter_aggregate = {};
972 enum event_notifier_error_accounting_status status;
973 uint64_t error_counter_index;
974 int ret;
975
976 status = get_error_counter_index_for_token(
977 &kernel_state,
978 lttng_trigger_get_tracer_token(trigger),
979 &error_counter_index);
980 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
981 ERR("Error getting index for token: status=%s",
982 error_accounting_status_str(status));
983 goto end;
984 }
985
986 counter_aggregate.index.number_dimensions = 1;
987 counter_aggregate.index.dimension_indexes[0] = error_counter_index;
988
989 assert(kernel_error_accountant.kernel_event_notifier_error_counter_fd);
990
991 ret = kernctl_counter_get_aggregate_value(
992 kernel_error_accountant.kernel_event_notifier_error_counter_fd,
993 &counter_aggregate);
994 if (ret || counter_aggregate.value.value < 0) {
995 uid_t trigger_owner_uid;
996 const char *trigger_name;
997
998 get_trigger_info_for_log(trigger, &trigger_name,
999 &trigger_owner_uid);
1000
1001 if (counter_aggregate.value.value < 0) {
1002 ERR("Invalid negative event notifier error counter value: trigger owner = %d, trigger name = '%s', value = %" PRId64,
1003 trigger_owner_uid, trigger_name,
1004 counter_aggregate.value.value);
1005 } else {
1006 ERR("Failed to getting event notifier error count: trigger owner = %d, trigger name = '%s', ret = %d",
1007 trigger_owner_uid, trigger_name, ret);
1008 }
1009
1010 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
1011 goto end;
1012 }
1013
1014 /* Error count can't be negative. */
1015 assert(counter_aggregate.value.value >= 0);
1016 *count = (uint64_t) counter_aggregate.value.value;
1017
1018 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
1019
1020 end:
1021 return status;
1022 }
1023
1024 enum event_notifier_error_accounting_status
1025 event_notifier_error_accounting_get_count(
1026 const struct lttng_trigger *trigger, uint64_t *count)
1027 {
1028 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger)) {
1029 case LTTNG_DOMAIN_KERNEL:
1030 return event_notifier_error_accounting_kernel_get_count(
1031 trigger, count);
1032 case LTTNG_DOMAIN_UST:
1033 #ifdef HAVE_LIBLTTNG_UST_CTL
1034 return event_notifier_error_accounting_ust_get_count(trigger,
1035 count);
1036 #else
1037 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
1038 #endif /* HAVE_LIBLTTNG_UST_CTL */
1039 default:
1040 abort();
1041 }
1042 }
1043
1044 static
1045 enum event_notifier_error_accounting_status
1046 event_notifier_error_accounting_clear(const struct lttng_trigger *trigger)
1047 {
1048 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger)) {
1049 case LTTNG_DOMAIN_KERNEL:
1050 return event_notifier_error_accounting_kernel_clear(trigger);
1051 case LTTNG_DOMAIN_UST:
1052 #ifdef HAVE_LIBLTTNG_UST_CTL
1053 return event_notifier_error_accounting_ust_clear(trigger);
1054 #else
1055 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
1056 #endif /* HAVE_LIBLTTNG_UST_CTL */
1057 default:
1058 abort();
1059 }
1060 }
1061
1062 static void free_index_ht_entry(struct rcu_head *head)
1063 {
1064 struct index_ht_entry *entry = caa_container_of(head,
1065 struct index_ht_entry, rcu_head);
1066
1067 free(entry);
1068 }
1069
1070 void event_notifier_error_accounting_unregister_event_notifier(
1071 const struct lttng_trigger *trigger)
1072 {
1073 struct lttng_ht_iter iter;
1074 struct lttng_ht_node_u64 *node;
1075 const uint64_t tracer_token = lttng_trigger_get_tracer_token(trigger);
1076 enum event_notifier_error_accounting_status status;
1077 struct error_accounting_state *state;
1078
1079 status = event_notifier_error_accounting_clear(trigger);
1080 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
1081 /* Trigger details already logged by callee on error. */
1082 ERR("Failed to clear event notifier error counter during unregistration of event notifier: status = '%s'",
1083 error_accounting_status_str(status));
1084 }
1085
1086 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger)) {
1087 case LTTNG_DOMAIN_KERNEL:
1088 state = &kernel_state;
1089 break;
1090 case LTTNG_DOMAIN_UST:
1091 state = &ust_state;
1092 break;
1093 default:
1094 abort();
1095 }
1096
1097 rcu_read_lock();
1098 lttng_ht_lookup(state->indices_ht, &tracer_token, &iter);
1099 node = lttng_ht_iter_get_node_u64(&iter);
1100 if (node) {
1101 int del_ret;
1102 struct index_ht_entry *index_entry = caa_container_of(
1103 node, typeof(*index_entry), node);
1104 enum lttng_index_allocator_status index_alloc_status;
1105
1106 index_alloc_status = lttng_index_allocator_release(
1107 state->index_allocator,
1108 index_entry->error_counter_index);
1109 if (index_alloc_status != LTTNG_INDEX_ALLOCATOR_STATUS_OK) {
1110 uid_t trigger_owner_uid;
1111 const char *trigger_name;
1112
1113 get_trigger_info_for_log(trigger, &trigger_name,
1114 &trigger_owner_uid);
1115
1116 ERR("Failed to release event notifier error counter index: index = %" PRIu64 ", trigger name = '%s', trigger owner uid = %d",
1117 index_entry->error_counter_index,
1118 trigger_name, (int) trigger_owner_uid);
1119 /* Don't exit, perform the rest of the clean-up. */
1120 }
1121
1122 del_ret = lttng_ht_del(state->indices_ht, &iter);
1123 assert(!del_ret);
1124 call_rcu(&index_entry->rcu_head, free_index_ht_entry);
1125 }
1126
1127 rcu_read_unlock();
1128 }
1129
1130 #ifdef HAVE_LIBLTTNG_UST_CTL
1131 static void free_error_account_entry(struct rcu_head *head)
1132 {
1133 int i;
1134 struct ust_error_accounting_entry *entry =
1135 caa_container_of(head, typeof(*entry), rcu_head);
1136
1137 for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
1138 ustctl_release_object(-1, entry->cpu_counters[i]);
1139 free(entry->cpu_counters[i]);
1140 }
1141
1142 free(entry->cpu_counters);
1143
1144 ustctl_release_object(-1, entry->counter);
1145 free(entry->counter);
1146
1147 ustctl_destroy_counter(entry->daemon_counter);
1148
1149 free(entry);
1150 }
1151 #else
1152 /* Not called without UST support. */
1153 static void free_error_account_entry(struct rcu_head *head) {}
1154 #endif /* HAVE_LIBLTTNG_UST_CTL */
1155
1156 void event_notifier_error_accounting_fini(void)
1157 {
1158 struct lttng_ht_iter iter;
1159 struct ust_error_accounting_entry *uid_entry;
1160
1161 if (kernel_error_accountant.kernel_event_notifier_error_counter_fd) {
1162 const int ret = close(kernel_error_accountant.kernel_event_notifier_error_counter_fd);
1163
1164 if (ret) {
1165 PERROR("Failed to close kernel event notifier error counter");
1166 }
1167 }
1168
1169 /*
1170 * FIXME error account entries are not reference-counted and torn
1171 * down on last use. They exist from the moment of their first use
1172 * up until the teardown of the session daemon.
1173 */
1174 rcu_read_lock();
1175 cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
1176 uid_entry, node.node) {
1177 cds_lfht_del(error_counter_uid_ht->ht, &uid_entry->node.node);
1178 call_rcu(&uid_entry->rcu_head, free_error_account_entry);
1179 }
1180 rcu_read_unlock();
1181
1182 lttng_ht_destroy(error_counter_uid_ht);
1183
1184 fini_error_accounting_state(&kernel_state);
1185 fini_error_accounting_state(&ust_state);
1186 }
This page took 0.092143 seconds and 4 git commands to generate.