SoW-2020-0003: Trace Hit Counters
[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 struct index_ht_entry {
27 struct lttng_ht_node_u64 node;
28 uint64_t error_counter_index;
29 struct rcu_head rcu_head;
30 };
31
32 struct error_account_entry {
33 struct lttng_ht_node_u64 node;
34 struct rcu_head rcu_head;
35 struct ustctl_daemon_counter *daemon_counter;
36 /*
37 * Those `lttng_ust_object_data` are anonymous handles to the counters
38 * objects.
39 * They are only used to be duplicated for each new applications of the
40 * user. To destroy them, call with the `sock` parameter set to -1.
41 * e.g. `ustctl_release_object(-1, data)`;
42 */
43 struct lttng_ust_object_data *counter;
44 struct lttng_ust_object_data **cpu_counters;
45 int nr_counter_cpu_fds;
46 };
47
48 struct kernel_error_account_entry {
49 int kernel_event_notifier_error_counter_fd;
50 };
51
52 static struct kernel_error_account_entry kernel_error_accountant = { 0 };
53
54 /* Hashtable mapping event notifier token to index_ht_entry */
55 static struct lttng_ht *error_counter_indexes_ht;
56
57 /* Hashtable mapping uid to error_account_entry */
58 static struct lttng_ht *error_counter_uid_ht;
59
60 static uint64_t error_counter_size = 0;
61 struct lttng_index_allocator *index_allocator;
62
63 static inline
64 const char *error_accounting_status_str(
65 enum event_notifier_error_accounting_status status)
66 {
67 switch (status) {
68 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK:
69 return "OK";
70 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR:
71 return "ERROR";
72 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND:
73 return "NOT_FOUND";
74 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM:
75 return "NOMEM";
76 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE:
77 return "NO_INDEX_AVAILABLE";
78 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD:
79 return "APP_DEAD";
80 default:
81 abort();
82 }
83 }
84
85 enum event_notifier_error_accounting_status
86 event_notifier_error_accounting_init(uint64_t nb_bucket)
87 {
88 enum event_notifier_error_accounting_status status;
89
90 index_allocator = lttng_index_allocator_create(nb_bucket);
91 if (!index_allocator) {
92 ERR("Failed to allocate event notifier error counter index");
93 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM;
94 goto error_index_allocator;
95 }
96
97 error_counter_indexes_ht = lttng_ht_new(16, LTTNG_HT_TYPE_U64);
98 error_counter_uid_ht = lttng_ht_new(16, LTTNG_HT_TYPE_U64);
99 error_counter_size = nb_bucket;
100
101 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
102
103 error_index_allocator:
104 return status;
105 }
106
107 static
108 enum event_notifier_error_accounting_status get_error_counter_index_for_token(
109 uint64_t tracer_token, uint64_t *error_counter_index)
110 {
111 struct lttng_ht_node_u64 *node;
112 struct lttng_ht_iter iter;
113 struct index_ht_entry *index_entry;;
114 enum event_notifier_error_accounting_status status;
115
116 lttng_ht_lookup(error_counter_indexes_ht, &tracer_token, &iter);
117 node = lttng_ht_iter_get_node_u64(&iter);
118 if (node) {
119 index_entry = caa_container_of(node, struct index_ht_entry, node);
120 *error_counter_index = index_entry->error_counter_index;
121 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
122 } else {
123 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND;
124 }
125
126 return status;
127 }
128
129 #ifdef HAVE_LIBLTTNG_UST_CTL
130 static
131 struct error_account_entry *get_uid_accounting_entry(const struct ust_app *app)
132 {
133 struct error_account_entry *entry;
134 struct lttng_ht_node_u64 *node;
135 struct lttng_ht_iter iter;
136 uint64_t key = app->uid;
137
138 lttng_ht_lookup(error_counter_uid_ht, &key, &iter);
139 node = lttng_ht_iter_get_node_u64(&iter);
140 if(node == NULL) {
141 entry = NULL;
142 } else {
143 entry = caa_container_of(node, struct error_account_entry, node);
144 }
145
146 return entry;
147 }
148
149 static
150 struct error_account_entry *create_uid_accounting_entry(
151 const struct ust_app *app)
152 {
153 int i, ret;
154 struct ustctl_counter_dimension dimension[1] = {0};
155 struct ustctl_daemon_counter *daemon_counter;
156 struct lttng_ust_object_data *counter, **counter_cpus;
157 int *counter_cpu_fds;
158 struct error_account_entry *entry = NULL;
159
160 entry = zmalloc(sizeof(struct error_account_entry));
161 if (!entry) {
162 PERROR("Allocating event notifier error acounting entry")
163 goto error;
164 }
165
166 entry->nr_counter_cpu_fds = ustctl_get_nr_cpu_per_counter();
167 counter_cpu_fds = zmalloc(entry->nr_counter_cpu_fds * sizeof(*counter_cpu_fds));
168 if (!counter_cpu_fds) {
169 ret = -1;
170 goto error_counter_cpu_fds_alloc;
171 }
172
173 counter_cpus = zmalloc(entry->nr_counter_cpu_fds * sizeof(**counter_cpus));
174 if (!counter_cpus) {
175 ret = -1;
176 goto error_counter_cpus_alloc;
177 }
178
179 for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
180 counter_cpu_fds[i] = shm_create_anonymous("event-notifier-error-accounting");
181 //FIXME error handling
182 }
183
184
185 dimension[0].size = error_counter_size;
186 dimension[0].has_underflow = false;
187 dimension[0].has_overflow = false;
188
189 daemon_counter = ustctl_create_counter(1, dimension, 0, -1,
190 entry->nr_counter_cpu_fds, counter_cpu_fds,
191 USTCTL_COUNTER_BITNESS_32,
192 USTCTL_COUNTER_ARITHMETIC_MODULAR,
193 USTCTL_COUNTER_ALLOC_PER_CPU,
194 false);
195 assert(daemon_counter);
196
197 ret = ustctl_create_counter_data(daemon_counter, &counter);
198 assert(ret == 0);
199
200 for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
201 ret = ustctl_create_counter_cpu_data(daemon_counter, i,
202 &counter_cpus[i]);
203 assert(ret == 0);
204 }
205
206 entry->daemon_counter = daemon_counter;
207 entry->counter = counter;
208 entry->cpu_counters = counter_cpus;
209
210 lttng_ht_node_init_u64(&entry->node, app->uid);
211 lttng_ht_add_unique_u64(error_counter_uid_ht, &entry->node);
212
213 free(counter_cpu_fds);
214
215 goto end;
216
217 error_counter_cpus_alloc:
218 free(counter_cpu_fds);
219 error_counter_cpu_fds_alloc:
220 free(entry);
221 error:
222 entry = NULL;
223 end:
224 return entry;
225 }
226
227 static
228 enum event_notifier_error_accounting_status send_counter_data_to_ust(
229 struct ust_app *app,
230 struct lttng_ust_object_data *new_counter)
231 {
232 int ret;
233 enum event_notifier_error_accounting_status status;
234
235 /* Attach counter to trigger group */
236 pthread_mutex_lock(&app->sock_lock);
237 ret = ustctl_send_counter_data_to_ust(app->sock,
238 app->event_notifier_group.object->handle, new_counter);
239 pthread_mutex_unlock(&app->sock_lock);
240 if (ret < 0) {
241 if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
242 ERR("Error ustctl send counter data to app pid: %d with ret %d",
243 app->pid, ret);
244 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
245 } else {
246 DBG3("UST app send counter data to ust failed. Application is dead.");
247 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD;
248 }
249 goto end;
250 }
251
252 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
253 end:
254 return status;
255 }
256
257 static
258 enum event_notifier_error_accounting_status send_counter_cpu_data_to_ust(
259 struct ust_app *app,
260 struct lttng_ust_object_data *counter,
261 struct lttng_ust_object_data *counter_cpu)
262 {
263 int ret;
264 enum event_notifier_error_accounting_status status;
265
266 pthread_mutex_lock(&app->sock_lock);
267 ret = ustctl_send_counter_cpu_data_to_ust(app->sock,
268 counter, counter_cpu);
269 pthread_mutex_unlock(&app->sock_lock);
270 if (ret < 0) {
271 if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
272 ERR("Error ustctl send counter cpu data to app pid: %d with ret %d",
273 app->pid, ret);
274 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
275 } else {
276 DBG3("UST app send counter cpu data to ust failed. Application is dead.");
277 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD;
278 }
279 goto end;
280 }
281
282 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
283 end:
284 return status;
285 }
286
287 enum event_notifier_error_accounting_status event_notifier_error_accounting_register_app(
288 struct ust_app *app)
289 {
290 int ret;
291 uint64_t i;
292 struct lttng_ust_object_data *new_counter;
293 struct error_account_entry *entry;
294 enum event_notifier_error_accounting_status status;
295
296 /*
297 * Check if we already have a error counter for the user id of this
298 * app. If not, create one.
299 */
300 rcu_read_lock();
301 entry = get_uid_accounting_entry(app);
302 if (entry == NULL) {
303 entry = create_uid_accounting_entry(app);
304 }
305
306 /* Duplicate counter object data*/
307 ret = ustctl_duplicate_ust_object_data(&new_counter,
308 entry->counter);
309 assert(ret == 0);
310
311 status = send_counter_data_to_ust(app, new_counter);
312 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
313 ERR("Error sending counter data to UST tracer: status=%s",
314 error_accounting_status_str(status));
315 goto end;
316 }
317
318
319 app->event_notifier_group.counter = new_counter;
320 app->event_notifier_group.nr_counter_cpu = entry->nr_counter_cpu_fds;
321 app->event_notifier_group.counter_cpu =
322 zmalloc(entry->nr_counter_cpu_fds * sizeof(struct lttng_ust_object_data));
323
324 for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
325 struct lttng_ust_object_data *new_counter_cpu = NULL;
326
327 ret = ustctl_duplicate_ust_object_data(&new_counter_cpu,
328 entry->cpu_counters[i]);
329 assert(ret == 0);
330
331 status = send_counter_cpu_data_to_ust(app, new_counter,
332 new_counter_cpu);
333 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
334 ERR("Error sending counter cpu data to UST tracer: status=%s",
335 error_accounting_status_str(status));
336 goto end;
337 }
338 app->event_notifier_group.counter_cpu[i] = new_counter_cpu;
339 }
340
341 end:
342 rcu_read_unlock();
343 return status;
344 }
345
346 enum event_notifier_error_accounting_status
347 event_notifier_error_accounting_unregister_app(struct ust_app *app)
348 {
349 enum event_notifier_error_accounting_status status;
350 struct error_account_entry *entry;
351 int i;
352
353 rcu_read_lock();
354 entry = get_uid_accounting_entry(app);
355 if (entry == NULL) {
356 ERR("Event notitifier error accounting entry not found on app teardown");
357 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
358 goto end;
359 }
360
361 for (i = 0; i < app->event_notifier_group.nr_counter_cpu; i++) {
362 ustctl_release_object(app->sock,
363 app->event_notifier_group.counter_cpu[i]);
364 free(app->event_notifier_group.counter_cpu[i]);
365 }
366
367 free(app->event_notifier_group.counter_cpu);
368
369 ustctl_release_object(app->sock, app->event_notifier_group.counter);
370 free(app->event_notifier_group.counter);
371
372 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
373 end:
374 rcu_read_unlock();
375 return status;
376 }
377
378 static
379 enum event_notifier_error_accounting_status
380 event_notifier_error_accounting_ust_get_count(
381 const struct lttng_trigger *trigger, uint64_t *count)
382 {
383 struct lttng_ht_iter iter;
384 struct error_account_entry *uid_entry;
385 uint64_t error_counter_index, global_sum = 0;
386 enum event_notifier_error_accounting_status status;
387 size_t dimension_indexes[1];
388
389 /*
390 * Go over all error counters (ignoring uid) as a trigger (and trigger
391 * errors) can be generated from any applications that this session
392 * daemon is managing.
393 */
394
395 rcu_read_lock();
396
397 status = get_error_counter_index_for_token(
398 lttng_trigger_get_tracer_token(trigger), &error_counter_index);
399 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
400 ERR("Error getting index for token: status=%s",
401 error_accounting_status_str(status));
402 goto end;
403 }
404
405 dimension_indexes[0] = error_counter_index;
406
407 cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
408 uid_entry, node.node) {
409 int ret;
410 int64_t local_value = 0;
411 bool overflow = 0, underflow = 0;
412 ret = ustctl_counter_aggregate(uid_entry->daemon_counter,
413 dimension_indexes, &local_value, &overflow,
414 &underflow);
415 assert(ret == 0);
416
417 /* should always be zero or above. */
418 assert(local_value >= 0);
419 global_sum += (uint64_t) local_value;
420
421 }
422
423
424 *count = global_sum;
425 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
426
427 end:
428 rcu_read_unlock();
429 return status;
430 }
431
432 static
433 enum event_notifier_error_accounting_status event_notifier_error_accounting_ust_clear(
434 const struct lttng_trigger *trigger)
435 {
436 struct lttng_ht_iter iter;
437 struct error_account_entry *uid_entry;
438 uint64_t error_counter_index;
439 enum event_notifier_error_accounting_status status;
440 size_t dimension_indexes[1];
441
442 /*
443 * Go over all error counters (ignoring uid) as a trigger (and trigger
444 * errors) can be generated from any applications that this session
445 * daemon is managing.
446 */
447
448 rcu_read_lock();
449 status = get_error_counter_index_for_token(
450 lttng_trigger_get_tracer_token(trigger),
451 &error_counter_index);
452 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
453 ERR("Error getting index for token: status=%s",
454 error_accounting_status_str(status));
455 goto end;
456 }
457
458 dimension_indexes[0] = error_counter_index;
459
460 cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
461 uid_entry, node.node) {
462 int ret;
463 ret = ustctl_counter_clear(uid_entry->daemon_counter,
464 dimension_indexes);
465 assert(ret == 0);
466 }
467
468 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
469 end:
470 rcu_read_unlock();
471 return status;
472 }
473 #endif /* HAVE_LIBLTTNG_UST_CTL */
474
475 static
476 enum event_notifier_error_accounting_status event_notifier_error_accounting_kernel_clear(
477 const struct lttng_trigger *trigger)
478 {
479 int ret;
480 uint64_t error_counter_index;
481 enum event_notifier_error_accounting_status status;
482 struct lttng_kernel_counter_clear counter_clear = {0};
483
484 rcu_read_lock();
485 status = get_error_counter_index_for_token(
486 lttng_trigger_get_tracer_token(trigger),
487 &error_counter_index);
488 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
489 ERR("Error getting index for token: status=%s",
490 error_accounting_status_str(status));
491 goto end;
492 }
493
494 counter_clear.index.number_dimensions = 1;
495 counter_clear.index.dimension_indexes[0] = error_counter_index;
496
497 ret = kernctl_counter_clear(
498 kernel_error_accountant.kernel_event_notifier_error_counter_fd,
499 &counter_clear);
500 if (ret) {
501 ERR("Error clearing event notifier error counter");
502 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
503 goto end;
504 }
505
506 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
507 end:
508 rcu_read_unlock();
509 return status;
510 }
511
512 enum event_notifier_error_accounting_status event_notifier_error_accounting_register_kernel(
513 int kernel_event_notifier_group_fd)
514 {
515 int local_fd = -1, ret;
516 enum event_notifier_error_accounting_status status;
517 struct lttng_kernel_counter_conf error_counter_conf = {0};
518
519 error_counter_conf.arithmetic = LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR;
520 error_counter_conf.bitness = LTTNG_KERNEL_COUNTER_BITNESS_64;
521 error_counter_conf.global_sum_step = 0;
522 error_counter_conf.number_dimensions = 1;
523 error_counter_conf.dimensions[0].size = error_counter_size;
524 error_counter_conf.dimensions[0].has_underflow = false;
525 error_counter_conf.dimensions[0].has_overflow = false;
526
527 ret = kernctl_create_event_notifier_group_error_counter(
528 kernel_event_notifier_group_fd, &error_counter_conf);
529 if (ret < 0) {
530 PERROR("ioctl kernel create event notifier group error counter");
531 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
532 goto error;
533 }
534
535 /* Store locally */
536 local_fd = ret;
537
538 /* Prevent fd duplication after execlp() */
539 ret = fcntl(local_fd, F_SETFD, FD_CLOEXEC);
540 if (ret < 0) {
541 PERROR("fcntl event notifier error counter fd");
542 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
543 goto error;
544 }
545
546 DBG("Kernel event notifier group error counter (fd: %d)", local_fd);
547
548 kernel_error_accountant.kernel_event_notifier_error_counter_fd = local_fd;
549 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
550
551 error:
552 return status;
553 }
554
555 static
556 enum event_notifier_error_accounting_status create_error_counter_index_for_token(
557 uint64_t tracer_token, uint64_t *error_counter_index)
558 {
559 struct index_ht_entry *index_entry;;
560 enum lttng_index_allocator_status index_alloc_status;
561 uint64_t local_error_counter_index;
562 enum event_notifier_error_accounting_status status;
563
564 /* Allocate a new index for that counter. */
565 index_alloc_status = lttng_index_allocator_alloc(index_allocator,
566 &local_error_counter_index);
567 switch (index_alloc_status) {
568 case LTTNG_INDEX_ALLOCATOR_STATUS_EMPTY:
569 DBG("No more index available in the configured event notifier error counter:"
570 "number-of-indices=%"PRIu64,
571 lttng_index_allocator_get_index_count(
572 index_allocator));
573 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE;
574 goto end;
575 case LTTNG_INDEX_ALLOCATOR_STATUS_OK:
576 break;
577 default:
578 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
579 goto end;
580 }
581
582 index_entry = zmalloc(sizeof(*index_entry));
583 if (index_entry == NULL) {
584 PERROR("Event notifier error counter hashtable entry zmalloc");
585 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM;
586 goto end;
587 }
588
589 index_entry->error_counter_index = local_error_counter_index;
590 lttng_ht_node_init_u64(&index_entry->node, tracer_token);
591
592 lttng_ht_add_unique_u64(error_counter_indexes_ht, &index_entry->node);
593
594 *error_counter_index = local_error_counter_index;
595 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
596 end:
597 return status;
598 }
599
600 enum event_notifier_error_accounting_status event_notifier_error_accounting_register_event_notifier(
601 const struct lttng_trigger *trigger,
602 uint64_t *error_counter_index)
603 {
604 enum event_notifier_error_accounting_status status;
605 uint64_t local_error_counter_index;
606
607 rcu_read_lock();
608 /*
609 * Check if this event notifier already has a error counter index
610 * assigned.
611 */
612 status = get_error_counter_index_for_token(
613 lttng_trigger_get_tracer_token(trigger),
614 &local_error_counter_index);
615 switch (status) {
616 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND:
617 DBG("Event notifier error counter index for this tracer token not found. Allocating a new one.");
618 status = create_error_counter_index_for_token(
619 lttng_trigger_get_tracer_token(trigger),
620 &local_error_counter_index);
621 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
622 ERR("Error creating index for token: status=%s",
623 error_accounting_status_str(status));
624 goto end;
625 }
626 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK:
627 *error_counter_index = local_error_counter_index;
628 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
629 break;
630 default:
631 break;
632 }
633
634 end:
635 rcu_read_unlock();
636 return status;
637 }
638
639 static
640 enum event_notifier_error_accounting_status event_notifier_error_accounting_kernel_get_count(
641 const struct lttng_trigger *trigger, uint64_t *count)
642 {
643 struct lttng_kernel_counter_aggregate counter_aggregate = {0};
644 enum event_notifier_error_accounting_status status;
645 uint64_t error_counter_index;
646 int ret;
647
648 rcu_read_lock();
649 status = get_error_counter_index_for_token(
650 lttng_trigger_get_tracer_token(trigger), &error_counter_index);
651 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
652 ERR("Error getting index for token: status=%s",
653 error_accounting_status_str(status));
654 goto end;
655 }
656
657 counter_aggregate.index.number_dimensions = 1;
658 counter_aggregate.index.dimension_indexes[0] = error_counter_index;
659
660 assert(kernel_error_accountant.kernel_event_notifier_error_counter_fd);
661
662 ret = kernctl_counter_get_aggregate_value(
663 kernel_error_accountant.kernel_event_notifier_error_counter_fd,
664 &counter_aggregate);
665 if (ret) {
666 ERR("Error getting event notifier error count.");
667 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
668 goto end;
669 }
670
671 if (counter_aggregate.value.value < 0) {
672 ERR("Event notifier error counter less than zero.");
673 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
674 goto end;
675 }
676
677 /* Error count can't be negative. */
678 assert(counter_aggregate.value.value >= 0);
679 *count = (uint64_t) counter_aggregate.value.value;
680
681 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
682
683 end:
684 rcu_read_unlock();
685 return status;
686 }
687
688 enum event_notifier_error_accounting_status event_notifier_error_accounting_get_count(
689 const struct lttng_trigger *trigger, uint64_t *count)
690 {
691 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger)) {
692 case LTTNG_DOMAIN_KERNEL:
693 return event_notifier_error_accounting_kernel_get_count(trigger, count);
694 case LTTNG_DOMAIN_UST:
695 #ifdef HAVE_LIBLTTNG_UST_CTL
696 return event_notifier_error_accounting_ust_get_count(trigger, count);
697 #else
698 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
699 #endif /* HAVE_LIBLTTNG_UST_CTL */
700 default:
701 abort();
702 }
703 }
704
705 static
706 enum event_notifier_error_accounting_status event_notifier_error_accounting_clear(
707 const struct lttng_trigger *trigger)
708 {
709 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger)) {
710 case LTTNG_DOMAIN_KERNEL:
711 return event_notifier_error_accounting_kernel_clear(trigger);
712 case LTTNG_DOMAIN_UST:
713 #ifdef HAVE_LIBLTTNG_UST_CTL
714 return event_notifier_error_accounting_ust_clear(trigger);
715 #else
716 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
717 #endif /* HAVE_LIBLTTNG_UST_CTL */
718 default:
719 abort();
720 }
721 }
722
723 static void free_index_ht_entry(struct rcu_head *head)
724 {
725 struct index_ht_entry *entry = caa_container_of(head,
726 struct index_ht_entry, rcu_head);
727 free(entry);
728 }
729
730 void event_notifier_error_accounting_unregister_event_notifier(
731 const struct lttng_trigger *trigger)
732 {
733 struct lttng_ht_iter iter;
734 struct lttng_ht_node_u64 *node;
735 struct index_ht_entry *index_entry;
736 enum event_notifier_error_accounting_status status;
737 enum lttng_index_allocator_status index_alloc_status;
738 uint64_t tracer_token = lttng_trigger_get_tracer_token(trigger);
739
740 status = event_notifier_error_accounting_clear(trigger);
741 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
742 ERR("Error clearing event notifier error counter index: status=%s",
743 error_accounting_status_str(status));
744 }
745
746 rcu_read_lock();
747 lttng_ht_lookup(error_counter_indexes_ht, &tracer_token, &iter);
748 node = lttng_ht_iter_get_node_u64(&iter);
749 if(node) {
750 index_entry = caa_container_of(node, struct index_ht_entry, node);
751 index_alloc_status = lttng_index_allocator_release(
752 index_allocator,
753 index_entry->error_counter_index);
754 if (index_alloc_status != LTTNG_INDEX_ALLOCATOR_STATUS_OK) {
755 ERR("Error releasing event notifier error counter index: status=%s",
756 error_accounting_status_str(status));
757 }
758
759 lttng_ht_del(error_counter_indexes_ht, &iter);
760 call_rcu(&index_entry->rcu_head, free_index_ht_entry);
761 }
762 rcu_read_unlock();
763 }
764
765 static void free_error_account_entry(struct rcu_head *head)
766 {
767 struct error_account_entry *entry = caa_container_of(head,
768 struct error_account_entry, rcu_head);
769 #ifdef HAVE_LIBLTTNG_UST_CTL
770 int i;
771 for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
772 ustctl_release_object(-1, entry->cpu_counters[i]);
773 free(entry->cpu_counters[i]);
774 }
775
776 free(entry->cpu_counters);
777
778 ustctl_release_object(-1, entry->counter);
779 free(entry->counter);
780
781 ustctl_destroy_counter(entry->daemon_counter);
782 #endif /* HAVE_LIBLTTNG_UST_CTL */
783
784 free(entry);
785 }
786
787 void event_notifier_error_accounting_fini(void)
788 {
789 struct lttng_ht_iter iter;
790 struct index_ht_entry *index_entry;
791 struct error_account_entry *uid_entry;
792
793 lttng_index_allocator_destroy(index_allocator);
794
795 if (kernel_error_accountant.kernel_event_notifier_error_counter_fd) {
796 int ret = close(kernel_error_accountant.kernel_event_notifier_error_counter_fd);
797 if (ret) {
798 PERROR("Closing kernel event notifier error counter");
799 }
800 }
801
802 rcu_read_lock();
803
804 cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
805 uid_entry, node.node) {
806 cds_lfht_del(error_counter_uid_ht->ht, &uid_entry->node.node);
807 call_rcu(&uid_entry->rcu_head, free_error_account_entry);
808 }
809
810 cds_lfht_for_each_entry(error_counter_indexes_ht->ht, &iter.iter,
811 index_entry, node.node) {
812 cds_lfht_del(error_counter_indexes_ht->ht, &index_entry->node.node);
813 call_rcu(&index_entry->rcu_head, free_index_ht_entry);
814 }
815
816 rcu_read_unlock();
817
818 lttng_ht_destroy(error_counter_uid_ht);
819 lttng_ht_destroy(error_counter_indexes_ht);
820 }
This page took 0.046436 seconds and 5 git commands to generate.