Fix: sessiond: fix memory leak in receive_lttng_trigger
[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 error_account_entry {
35 struct lttng_ht_node_u64 node;
36 struct rcu_head rcu_head;
37 struct ustctl_daemon_counter *daemon_counter;
38 /*
39 * Those `lttng_ust_abi_object_data` are anonymous handles to the counters
40 * objects.
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)`;
44 */
45 struct lttng_ust_abi_object_data *counter;
46 struct lttng_ust_abi_object_data **cpu_counters;
47 int nr_counter_cpu_fds;
48 };
49
50 struct kernel_error_account_entry {
51 int kernel_event_notifier_error_counter_fd;
52 };
53
54 static struct kernel_error_account_entry kernel_error_accountant;
55
56 /* Hashtable mapping event notifier token to index_ht_entry. */
57 static struct lttng_ht *error_counter_indexes_ht;
58
59 /* Hashtable mapping uid to error_account_entry. */
60 static struct lttng_ht *error_counter_uid_ht;
61
62 static uint64_t error_counter_size;
63 static struct lttng_index_allocator *index_allocator;
64
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)
68 {
69 enum lttng_trigger_status trigger_status;
70
71 trigger_status = lttng_trigger_get_name(trigger, trigger_name);
72 switch (trigger_status) {
73 case LTTNG_TRIGGER_STATUS_OK:
74 break;
75 case LTTNG_TRIGGER_STATUS_UNSET:
76 *trigger_name = "(unset)";
77 break;
78 default:
79 abort();
80 }
81
82 trigger_status = lttng_trigger_get_owner_uid(trigger,
83 trigger_owner_uid);
84 assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
85 }
86
87 static inline
88 const char *error_accounting_status_str(
89 enum event_notifier_error_accounting_status status)
90 {
91 switch (status) {
92 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK:
93 return "OK";
94 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR:
95 return "ERROR";
96 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND:
97 return "NOT_FOUND";
98 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM:
99 return "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:
103 return "APP_DEAD";
104 default:
105 abort();
106 }
107 }
108
109 enum event_notifier_error_accounting_status
110 event_notifier_error_accounting_init(uint64_t nb_bucket)
111 {
112 enum event_notifier_error_accounting_status status;
113
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;
119 }
120
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;
127 }
128
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;
135 }
136
137 error_counter_size = nb_bucket;
138
139 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
140
141 error_index_allocator:
142 return status;
143 }
144
145 static
146 enum event_notifier_error_accounting_status get_error_counter_index_for_token(
147 uint64_t tracer_token, uint64_t *error_counter_index)
148 {
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;
153
154 rcu_read_lock();
155 lttng_ht_lookup(error_counter_indexes_ht, &tracer_token, &iter);
156 node = lttng_ht_iter_get_node_u64(&iter);
157 if (node) {
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;
162 } else {
163 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND;
164 }
165
166 rcu_read_unlock();
167 return status;
168 }
169
170 #ifdef HAVE_LIBLTTNG_UST_CTL
171 static
172 struct error_account_entry *get_uid_accounting_entry(const struct ust_app *app)
173 {
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;
178
179 lttng_ht_lookup(error_counter_uid_ht, &key, &iter);
180 node = lttng_ht_iter_get_node_u64(&iter);
181 if(node == NULL) {
182 entry = NULL;
183 } else {
184 entry = caa_container_of(node, struct error_account_entry, node);
185 }
186
187 return entry;
188 }
189
190 static
191 struct error_account_entry *create_uid_accounting_entry(
192 const struct ust_app *app)
193 {
194 int i, ret;
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,
203 };
204
205 entry = zmalloc(sizeof(struct error_account_entry));
206 if (!entry) {
207 PERROR("Failed to allocate event notifier error acounting entry")
208 goto error;
209 }
210
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));
217 ret = -1;
218 goto error_counter_cpu_fds_alloc;
219 }
220
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;
224 }
225
226 cpu_counters = zmalloc(entry->nr_counter_cpu_fds * sizeof(struct lttng_ust_abi_object_data *));
227 if (!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(struct lttng_ust_abi_object_data *));
231 ret = -1;
232 goto error_counter_cpus_alloc;
233 }
234
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;
241 }
242 }
243
244 /*
245 * Ownership of the file descriptors transferred to the ustctl object.
246 */
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,
252 false);
253 if (!daemon_counter) {
254 goto error_create_daemon_counter;
255 }
256
257 ret = ustctl_create_counter_data(daemon_counter, &counter);
258 if (ret) {
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;
262 }
263
264 for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
265 ret = ustctl_create_counter_cpu_data(daemon_counter, i,
266 &cpu_counters[i]);
267 if (ret) {
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,
270 app->name);
271 goto error_create_counter_cpu_data;
272 }
273 }
274
275 entry->daemon_counter = daemon_counter;
276 entry->counter = counter;
277 entry->cpu_counters = cpu_counters;
278
279 lttng_ht_node_init_u64(&entry->node, app->uid);
280 lttng_ht_add_unique_u64(error_counter_uid_ht, &entry->node);
281
282 goto end;
283
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]) {
288 /*
289 * Early-exit when error occurred before all cpu
290 * counters could be initialized.
291 */
292 break;
293 }
294
295 ustctl_release_object(-1, cpu_counters[i]);
296 free(cpu_counters[i]);
297 }
298
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:
304 error_shm_alloc:
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) {
309 /*
310 * Early-exit when error occurred before all cpu
311 * counter shm fds could be initialized.
312 */
313 break;
314 }
315
316 ret = close(cpu_counter_fds[i]);
317 if (ret) {
318 PERROR("Failed to close error counter per-CPU shm file descriptor: fd = %d", cpu_counter_fds[i]);
319 }
320 }
321 }
322
323 free(cpu_counters);
324 error_counter_cpus_alloc:
325 error_counter_cpu_fds_alloc:
326 free(entry);
327 error:
328 entry = NULL;
329 end:
330 free(cpu_counter_fds);
331 return entry;
332 }
333
334 static
335 enum event_notifier_error_accounting_status send_counter_data_to_ust(
336 struct ust_app *app,
337 struct lttng_ust_abi_object_data *new_counter)
338 {
339 int ret;
340 enum event_notifier_error_accounting_status status;
341
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);
347 if (ret < 0) {
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;
352 } else {
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;
356 }
357
358 goto end;
359 }
360
361 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
362 end:
363 return status;
364 }
365
366 static
367 enum event_notifier_error_accounting_status send_counter_cpu_data_to_ust(
368 struct ust_app *app,
369 struct lttng_ust_abi_object_data *counter,
370 struct lttng_ust_abi_object_data *counter_cpu)
371 {
372 int ret;
373 enum event_notifier_error_accounting_status status;
374
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);
379 if (ret < 0) {
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;
384 } else {
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;
388 }
389
390 goto end;
391 }
392
393 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
394 end:
395 return status;
396 }
397
398 enum event_notifier_error_accounting_status
399 event_notifier_error_accounting_register_app(struct ust_app *app)
400 {
401 int ret;
402 uint64_t i;
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;
407
408 /*
409 * Check if we already have a error counter for the user id of this
410 * app. If not, create one.
411 */
412 rcu_read_lock();
413 entry = get_uid_accounting_entry(app);
414 if (entry == NULL) {
415 entry = create_uid_accounting_entry(app);
416 if (!entry) {
417 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
418 goto end;
419 }
420 }
421
422 /* Duplicate counter object data. */
423 ret = ustctl_duplicate_ust_object_data(&new_counter,
424 entry->counter);
425 if (ret) {
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;
429 goto end;
430 }
431
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;
439 }
440
441 cpu_counters = zmalloc(entry->nr_counter_cpu_fds * sizeof(struct lttng_ust_abi_object_data *));
442 if (!cpu_counters) {
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;
448 }
449
450 for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
451 struct lttng_ust_abi_object_data *new_counter_cpu = NULL;
452
453 ret = ustctl_duplicate_ust_object_data(&new_counter_cpu,
454 entry->cpu_counters[i]);
455 if (ret) {
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,
458 app->name);
459 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM;
460 goto error_duplicate_cpu_counter;
461 }
462
463 cpu_counters[i] = new_counter_cpu;
464
465 status = send_counter_cpu_data_to_ust(app, new_counter,
466 new_counter_cpu);
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,
471 app->name);
472 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
473 goto error_send_cpu_counter_data;
474 }
475 }
476
477 app->event_notifier_group.counter = new_counter;
478 new_counter = NULL;
479 app->event_notifier_group.nr_counter_cpu = entry->nr_counter_cpu_fds;
480 app->event_notifier_group.counter_cpu = cpu_counters;
481 cpu_counters = NULL;
482 goto end;
483
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]) {
489 /*
490 * Early-exit when error occurred before all cpu
491 * counters could be initialized.
492 */
493 break;
494 }
495
496 ustctl_release_object(-1, cpu_counters[i]);
497 free(cpu_counters[i]);
498 }
499
500 free(cpu_counters);
501
502 error_allocate_cpu_counters:
503 error_send_counter_data:
504 ustctl_release_object(-1, new_counter);
505 free(new_counter);
506 end:
507 rcu_read_unlock();
508 return status;
509 }
510
511 enum event_notifier_error_accounting_status
512 event_notifier_error_accounting_unregister_app(struct ust_app *app)
513 {
514 enum event_notifier_error_accounting_status status;
515 struct error_account_entry *entry;
516 int i;
517
518 rcu_read_lock();
519 entry = get_uid_accounting_entry(app);
520 if (entry == NULL) {
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;
524 goto end;
525 }
526
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]);
531 }
532
533 free(app->event_notifier_group.counter_cpu);
534
535 ustctl_release_object(app->sock, app->event_notifier_group.counter);
536 free(app->event_notifier_group.counter);
537
538 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
539 end:
540 rcu_read_unlock();
541 return status;
542 }
543
544 static
545 enum event_notifier_error_accounting_status
546 event_notifier_error_accounting_ust_get_count(
547 const struct lttng_trigger *trigger, uint64_t *count)
548 {
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);
555
556 /*
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.
560 */
561
562 rcu_read_lock();
563
564 status = get_error_counter_index_for_token(
565 tracer_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;
570
571 get_trigger_info_for_log(trigger, &trigger_name,
572 &trigger_owner_uid);
573
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));
578 goto end;
579 }
580
581 dimension_indexes[0] = error_counter_index;
582
583 cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
584 uid_entry, node.node) {
585 int ret;
586 int64_t local_value = 0;
587 bool overflow = false, underflow = false;
588
589 ret = ustctl_counter_aggregate(uid_entry->daemon_counter,
590 dimension_indexes, &local_value, &overflow,
591 &underflow);
592 if (ret || local_value < 0) {
593 uid_t trigger_owner_uid;
594 const char *trigger_name;
595
596 get_trigger_info_for_log(trigger, &trigger_name,
597 &trigger_owner_uid);
598
599 if (ret) {
600 ERR("Failed to aggregate event notifier error counter values of trigger: trigger name = '%s', trigger owner uid = %d",
601 trigger_name,
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,
605 trigger_name,
606 (int) trigger_owner_uid,
607 local_value);
608 } else {
609 abort();
610 }
611
612 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
613 goto end;
614 }
615
616 /* Cast is safe as negative values are checked-for above. */
617 global_sum += (uint64_t) local_value;
618
619 }
620
621 *count = global_sum;
622 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
623
624 end:
625 rcu_read_unlock();
626 return status;
627 }
628
629 static
630 enum event_notifier_error_accounting_status event_notifier_error_accounting_ust_clear(
631 const struct lttng_trigger *trigger)
632 {
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);
639
640 /*
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.
644 */
645
646 rcu_read_lock();
647 status = get_error_counter_index_for_token(
648 tracer_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;
653
654 get_trigger_info_for_log(trigger, &trigger_name,
655 &trigger_owner_uid);
656
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));
661 goto end;
662 }
663
664 dimension_index = error_counter_index;
665
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,
669 &dimension_index);
670
671 if (ret) {
672 uid_t trigger_owner_uid;
673 const char *trigger_name;
674
675 get_trigger_info_for_log(trigger, &trigger_name,
676 &trigger_owner_uid);
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;
681 goto end;
682 }
683 }
684
685 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
686 end:
687 rcu_read_unlock();
688 return status;
689 }
690 #endif /* HAVE_LIBLTTNG_UST_CTL */
691
692 static
693 enum event_notifier_error_accounting_status
694 event_notifier_error_accounting_kernel_clear(
695 const struct lttng_trigger *trigger)
696 {
697 int ret;
698 uint64_t error_counter_index;
699 enum event_notifier_error_accounting_status status;
700 struct lttng_kernel_counter_clear counter_clear = {};
701
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;
708
709 get_trigger_info_for_log(
710 trigger, &trigger_name, &trigger_owner_uid);
711
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));
715 goto end;
716 }
717
718 counter_clear.index.number_dimensions = 1;
719 counter_clear.index.dimension_indexes[0] = error_counter_index;
720
721 ret = kernctl_counter_clear(
722 kernel_error_accountant.kernel_event_notifier_error_counter_fd,
723 &counter_clear);
724 if (ret) {
725 uid_t trigger_owner_uid;
726 const char *trigger_name;
727
728 get_trigger_info_for_log(
729 trigger, &trigger_name, &trigger_owner_uid);
730
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;
734 goto end;
735 }
736
737 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
738 end:
739 return status;
740 }
741
742 enum event_notifier_error_accounting_status
743 event_notifier_error_accounting_register_kernel(
744 int kernel_event_notifier_group_fd)
745 {
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,
758 };
759
760 ret = kernctl_create_event_notifier_group_error_counter(
761 kernel_event_notifier_group_fd, &error_counter_conf);
762 if (ret < 0) {
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;
766 goto error;
767 }
768
769 error_counter_fd = ret;
770
771 /* Prevent fd duplication after execlp(). */
772 ret = fcntl(error_counter_fd, F_SETFD, FD_CLOEXEC);
773 if (ret < 0) {
774 PERROR("Failed to set FD_CLOEXEC flag on event notifier error counter file descriptor: error_counter_fd = %d",
775 error_counter_fd);
776 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
777 goto error;
778 }
779
780 DBG("Created kernel event notifier group error counter: fd = %d",
781 error_counter_fd);
782
783 kernel_error_accountant.kernel_event_notifier_error_counter_fd =
784 error_counter_fd;
785 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
786
787 error:
788 return status;
789 }
790
791 static
792 enum event_notifier_error_accounting_status create_error_counter_index_for_token(
793 uint64_t tracer_token, uint64_t *error_counter_index)
794 {
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;
799
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(
808 index_allocator));
809 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE;
810 goto end;
811 case LTTNG_INDEX_ALLOCATOR_STATUS_OK:
812 break;
813 default:
814 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
815 goto end;
816 }
817
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;
822 goto end;
823 }
824
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);
828
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;
833 end:
834 return status;
835 }
836
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)
841 {
842 enum event_notifier_error_accounting_status status;
843 uint64_t local_error_counter_index;
844
845 /*
846 * Check if this event notifier already has a error counter index
847 * assigned.
848 */
849 status = get_error_counter_index_for_token(
850 lttng_trigger_get_tracer_token(trigger),
851 &local_error_counter_index);
852 switch (status) {
853 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND:
854 {
855 uid_t trigger_owner_uid;
856 const char *trigger_name;
857
858 get_trigger_info_for_log(
859 trigger, &trigger_name, &trigger_owner_uid);
860
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));
864
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);
872 goto end;
873 }
874 /* fall-through. */
875 }
876 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK:
877 *error_counter_index = local_error_counter_index;
878 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
879 break;
880 default:
881 break;
882 }
883
884 end:
885 return status;
886 }
887
888 static
889 enum event_notifier_error_accounting_status
890 event_notifier_error_accounting_kernel_get_count(
891 const struct lttng_trigger *trigger, uint64_t *count)
892 {
893 struct lttng_kernel_counter_aggregate counter_aggregate = {};
894 enum event_notifier_error_accounting_status status;
895 uint64_t error_counter_index;
896 int ret;
897
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));
903 goto end;
904 }
905
906 counter_aggregate.index.number_dimensions = 1;
907 counter_aggregate.index.dimension_indexes[0] = error_counter_index;
908
909 assert(kernel_error_accountant.kernel_event_notifier_error_counter_fd);
910
911 ret = kernctl_counter_get_aggregate_value(
912 kernel_error_accountant.kernel_event_notifier_error_counter_fd,
913 &counter_aggregate);
914 if (ret || counter_aggregate.value.value < 0) {
915 uid_t trigger_owner_uid;
916 const char *trigger_name;
917
918 get_trigger_info_for_log(trigger, &trigger_name,
919 &trigger_owner_uid);
920
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);
925 } else {
926 ERR("Failed to getting event notifier error count: trigger owner = %d, trigger name = '%s', ret = %d",
927 trigger_owner_uid, trigger_name, ret);
928 }
929
930 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
931 goto end;
932 }
933
934 /* Error count can't be negative. */
935 assert(counter_aggregate.value.value >= 0);
936 *count = (uint64_t) counter_aggregate.value.value;
937
938 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
939
940 end:
941 return status;
942 }
943
944 enum event_notifier_error_accounting_status
945 event_notifier_error_accounting_get_count(
946 const struct lttng_trigger *trigger, uint64_t *count)
947 {
948 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger)) {
949 case LTTNG_DOMAIN_KERNEL:
950 return event_notifier_error_accounting_kernel_get_count(
951 trigger, count);
952 case LTTNG_DOMAIN_UST:
953 #ifdef HAVE_LIBLTTNG_UST_CTL
954 return event_notifier_error_accounting_ust_get_count(trigger, count);
955 #else
956 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
957 #endif /* HAVE_LIBLTTNG_UST_CTL */
958 default:
959 abort();
960 }
961 }
962
963 static
964 enum event_notifier_error_accounting_status
965 event_notifier_error_accounting_clear(const struct lttng_trigger *trigger)
966 {
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);
973 #else
974 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
975 #endif /* HAVE_LIBLTTNG_UST_CTL */
976 default:
977 abort();
978 }
979 }
980
981 static void free_index_ht_entry(struct rcu_head *head)
982 {
983 struct index_ht_entry *entry = caa_container_of(head,
984 struct index_ht_entry, rcu_head);
985
986 free(entry);
987 }
988
989 void event_notifier_error_accounting_unregister_event_notifier(
990 const struct lttng_trigger *trigger)
991 {
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;
996
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));
1002 }
1003
1004 rcu_read_lock();
1005 lttng_ht_lookup(error_counter_indexes_ht, &tracer_token, &iter);
1006 node = lttng_ht_iter_get_node_u64(&iter);
1007 if (node) {
1008 int del_ret;
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;
1012
1013 index_alloc_status = lttng_index_allocator_release(
1014 index_allocator,
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;
1019
1020 get_trigger_info_for_log(trigger, &trigger_name,
1021 &trigger_owner_uid);
1022
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. */
1027 }
1028
1029 del_ret = lttng_ht_del(error_counter_indexes_ht, &iter);
1030 assert(!del_ret);
1031 call_rcu(&index_entry->rcu_head, free_index_ht_entry);
1032 }
1033
1034 rcu_read_unlock();
1035 }
1036
1037 #ifdef HAVE_LIBLTTNG_UST_CTL
1038 static void free_error_account_entry(struct rcu_head *head)
1039 {
1040 int i;
1041 struct error_account_entry *entry =
1042 caa_container_of(head, typeof(*entry), rcu_head);
1043
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]);
1047 }
1048
1049 free(entry->cpu_counters);
1050
1051 ustctl_release_object(-1, entry->counter);
1052 free(entry->counter);
1053
1054 ustctl_destroy_counter(entry->daemon_counter);
1055
1056 free(entry);
1057 }
1058 #else
1059 /* Not called without UST support. */
1060 static void free_error_account_entry(struct rcu_head *head) {}
1061 #endif /* HAVE_LIBLTTNG_UST_CTL */
1062
1063 void event_notifier_error_accounting_fini(void)
1064 {
1065 struct lttng_ht_iter iter;
1066 struct error_account_entry *uid_entry;
1067
1068 lttng_index_allocator_destroy(index_allocator);
1069
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);
1072
1073 if (ret) {
1074 PERROR("Failed to close kernel event notifier error counter");
1075 }
1076 }
1077
1078 /*
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.
1082 */
1083 rcu_read_lock();
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);
1088 }
1089 rcu_read_unlock();
1090 lttng_ht_destroy(error_counter_uid_ht);
1091
1092 /*
1093 * Will assert if some error counter indices were not released (an
1094 * internal error).
1095 */
1096 lttng_ht_destroy(error_counter_indexes_ht);
1097 }
This page took 0.090796 seconds and 4 git commands to generate.