Fix: sessiond: error accounting: dereference of null pointer on error path
[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(**cpu_counters));
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(**cpu_counters));
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 error_allocate_cpu_counters:
501 error_send_counter_data:
502 ustctl_release_object(-1, new_counter);
503 free(new_counter);
504 end:
505 rcu_read_unlock();
506 return status;
507 }
508
509 enum event_notifier_error_accounting_status
510 event_notifier_error_accounting_unregister_app(struct ust_app *app)
511 {
512 enum event_notifier_error_accounting_status status;
513 struct error_account_entry *entry;
514 int i;
515
516 rcu_read_lock();
517 entry = get_uid_accounting_entry(app);
518 if (entry == NULL) {
519 ERR("Failed to find event notitifier error accounting entry on application teardown: pid = %d, application name = '%s'",
520 app->pid, app->name);
521 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
522 goto end;
523 }
524
525 for (i = 0; i < app->event_notifier_group.nr_counter_cpu; i++) {
526 ustctl_release_object(app->sock,
527 app->event_notifier_group.counter_cpu[i]);
528 free(app->event_notifier_group.counter_cpu[i]);
529 }
530
531 free(app->event_notifier_group.counter_cpu);
532
533 ustctl_release_object(app->sock, app->event_notifier_group.counter);
534 free(app->event_notifier_group.counter);
535
536 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
537 end:
538 rcu_read_unlock();
539 return status;
540 }
541
542 static
543 enum event_notifier_error_accounting_status
544 event_notifier_error_accounting_ust_get_count(
545 const struct lttng_trigger *trigger, uint64_t *count)
546 {
547 struct lttng_ht_iter iter;
548 struct error_account_entry *uid_entry;
549 uint64_t error_counter_index, global_sum = 0;
550 enum event_notifier_error_accounting_status status;
551 size_t dimension_indexes[1];
552 const uint64_t tracer_token = lttng_trigger_get_tracer_token(trigger);
553
554 /*
555 * Go over all error counters (ignoring uid) as a trigger (and trigger
556 * errors) can be generated from any applications that this session
557 * daemon is managing.
558 */
559
560 rcu_read_lock();
561
562 status = get_error_counter_index_for_token(
563 tracer_token,
564 &error_counter_index);
565 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
566 uid_t trigger_owner_uid;
567 const char *trigger_name;
568
569 get_trigger_info_for_log(trigger, &trigger_name,
570 &trigger_owner_uid);
571
572 ERR("Failed to retrieve index for tracer token: token = %" PRIu64 ", trigger name = '%s', trigger owner uid = %d, status = %s",
573 tracer_token, trigger_name,
574 (int) trigger_owner_uid,
575 error_accounting_status_str(status));
576 goto end;
577 }
578
579 dimension_indexes[0] = error_counter_index;
580
581 cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
582 uid_entry, node.node) {
583 int ret;
584 int64_t local_value = 0;
585 bool overflow = false, underflow = false;
586
587 ret = ustctl_counter_aggregate(uid_entry->daemon_counter,
588 dimension_indexes, &local_value, &overflow,
589 &underflow);
590 if (ret || local_value < 0) {
591 uid_t trigger_owner_uid;
592 const char *trigger_name;
593
594 get_trigger_info_for_log(trigger, &trigger_name,
595 &trigger_owner_uid);
596
597 if (ret) {
598 ERR("Failed to aggregate event notifier error counter values of trigger: trigger name = '%s', trigger owner uid = %d",
599 trigger_name,
600 (int) trigger_owner_uid);
601 } else if (local_value < 0) {
602 ERR("Negative event notifier error counter value encountered during aggregation: trigger name = '%s', trigger owner uid = %d, value = %" PRId64,
603 trigger_name,
604 (int) trigger_owner_uid,
605 local_value);
606 } else {
607 abort();
608 }
609
610 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
611 goto end;
612 }
613
614 /* Cast is safe as negative values are checked-for above. */
615 global_sum += (uint64_t) local_value;
616
617 }
618
619 *count = global_sum;
620 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
621
622 end:
623 rcu_read_unlock();
624 return status;
625 }
626
627 static
628 enum event_notifier_error_accounting_status event_notifier_error_accounting_ust_clear(
629 const struct lttng_trigger *trigger)
630 {
631 struct lttng_ht_iter iter;
632 struct error_account_entry *uid_entry;
633 uint64_t error_counter_index;
634 enum event_notifier_error_accounting_status status;
635 size_t dimension_index;
636 const uint64_t tracer_token = lttng_trigger_get_tracer_token(trigger);
637
638 /*
639 * Go over all error counters (ignoring uid) as a trigger (and trigger
640 * errors) can be generated from any applications that this session
641 * daemon is managing.
642 */
643
644 rcu_read_lock();
645 status = get_error_counter_index_for_token(
646 tracer_token,
647 &error_counter_index);
648 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
649 uid_t trigger_owner_uid;
650 const char *trigger_name;
651
652 get_trigger_info_for_log(trigger, &trigger_name,
653 &trigger_owner_uid);
654
655 ERR("Failed to retrieve index for tracer token: token = %" PRIu64 ", trigger name = '%s', trigger owner uid = %d, status = %s",
656 tracer_token, trigger_name,
657 (int) trigger_owner_uid,
658 error_accounting_status_str(status));
659 goto end;
660 }
661
662 dimension_index = error_counter_index;
663
664 cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
665 uid_entry, node.node) {
666 const int ret = ustctl_counter_clear(uid_entry->daemon_counter,
667 &dimension_index);
668
669 if (ret) {
670 uid_t trigger_owner_uid;
671 const char *trigger_name;
672
673 get_trigger_info_for_log(trigger, &trigger_name,
674 &trigger_owner_uid);
675 ERR("Failed to clear event notifier counter value for trigger: counter uid = %d, trigger name = '%s', trigger owner uid = %d",
676 (int) uid_entry->node.key, trigger_name,
677 (int) trigger_owner_uid);
678 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
679 goto end;
680 }
681 }
682
683 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
684 end:
685 rcu_read_unlock();
686 return status;
687 }
688 #endif /* HAVE_LIBLTTNG_UST_CTL */
689
690 static
691 enum event_notifier_error_accounting_status
692 event_notifier_error_accounting_kernel_clear(
693 const struct lttng_trigger *trigger)
694 {
695 int ret;
696 uint64_t error_counter_index;
697 enum event_notifier_error_accounting_status status;
698 struct lttng_kernel_counter_clear counter_clear = {};
699
700 status = get_error_counter_index_for_token(
701 lttng_trigger_get_tracer_token(trigger),
702 &error_counter_index);
703 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
704 uid_t trigger_owner_uid;
705 const char *trigger_name;
706
707 get_trigger_info_for_log(
708 trigger, &trigger_name, &trigger_owner_uid);
709
710 ERR("Failed to get event notifier error counter index: trigger owner uid = %d, trigger name = '%s', status = '%s'",
711 trigger_owner_uid, trigger_name,
712 error_accounting_status_str(status));
713 goto end;
714 }
715
716 counter_clear.index.number_dimensions = 1;
717 counter_clear.index.dimension_indexes[0] = error_counter_index;
718
719 ret = kernctl_counter_clear(
720 kernel_error_accountant.kernel_event_notifier_error_counter_fd,
721 &counter_clear);
722 if (ret) {
723 uid_t trigger_owner_uid;
724 const char *trigger_name;
725
726 get_trigger_info_for_log(
727 trigger, &trigger_name, &trigger_owner_uid);
728
729 ERR("Failed to clear kernel event notifier error counter: trigger owner uid = %d, trigger name = '%s'",
730 trigger_owner_uid, trigger_name);
731 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
732 goto end;
733 }
734
735 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
736 end:
737 return status;
738 }
739
740 enum event_notifier_error_accounting_status
741 event_notifier_error_accounting_register_kernel(
742 int kernel_event_notifier_group_fd)
743 {
744 int error_counter_fd = -1, ret;
745 enum event_notifier_error_accounting_status status;
746 const struct lttng_kernel_counter_conf error_counter_conf = {
747 .arithmetic = LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR,
748 .bitness = sizeof(void *) == sizeof(uint32_t) ?
749 LTTNG_KERNEL_COUNTER_BITNESS_32 :
750 LTTNG_KERNEL_COUNTER_BITNESS_64,
751 .global_sum_step = 0,
752 .number_dimensions = 1,
753 .dimensions[0].size = error_counter_size,
754 .dimensions[0].has_underflow = false,
755 .dimensions[0].has_overflow = false,
756 };
757
758 ret = kernctl_create_event_notifier_group_error_counter(
759 kernel_event_notifier_group_fd, &error_counter_conf);
760 if (ret < 0) {
761 PERROR("Failed to create event notifier group error counter through kernel ioctl: kernel_event_notifier_group_fd = %d",
762 kernel_event_notifier_group_fd);
763 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
764 goto error;
765 }
766
767 error_counter_fd = ret;
768
769 /* Prevent fd duplication after execlp(). */
770 ret = fcntl(error_counter_fd, F_SETFD, FD_CLOEXEC);
771 if (ret < 0) {
772 PERROR("Failed to set FD_CLOEXEC flag on event notifier error counter file descriptor: error_counter_fd = %d",
773 error_counter_fd);
774 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
775 goto error;
776 }
777
778 DBG("Created kernel event notifier group error counter: fd = %d",
779 error_counter_fd);
780
781 kernel_error_accountant.kernel_event_notifier_error_counter_fd =
782 error_counter_fd;
783 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
784
785 error:
786 return status;
787 }
788
789 static
790 enum event_notifier_error_accounting_status create_error_counter_index_for_token(
791 uint64_t tracer_token, uint64_t *error_counter_index)
792 {
793 struct index_ht_entry *index_entry;
794 enum lttng_index_allocator_status index_alloc_status;
795 uint64_t local_error_counter_index;
796 enum event_notifier_error_accounting_status status;
797
798 /* Allocate a new index for that counter. */
799 index_alloc_status = lttng_index_allocator_alloc(index_allocator,
800 &local_error_counter_index);
801 switch (index_alloc_status) {
802 case LTTNG_INDEX_ALLOCATOR_STATUS_EMPTY:
803 DBG("No indices left in the configured event notifier error counter: "
804 "number-of-indices = %"PRIu64,
805 lttng_index_allocator_get_index_count(
806 index_allocator));
807 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE;
808 goto end;
809 case LTTNG_INDEX_ALLOCATOR_STATUS_OK:
810 break;
811 default:
812 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
813 goto end;
814 }
815
816 index_entry = zmalloc(sizeof(*index_entry));
817 if (index_entry == NULL) {
818 PERROR("Failed to allocate event notifier error counter hash table entry");
819 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM;
820 goto end;
821 }
822
823 index_entry->error_counter_index = local_error_counter_index;
824 lttng_ht_node_init_u64(&index_entry->node, tracer_token);
825 lttng_ht_add_unique_u64(error_counter_indexes_ht, &index_entry->node);
826
827 DBG("Allocated error counter index for tracer token: tracer token = %" PRIu64 ", index = %" PRIu64,
828 tracer_token, local_error_counter_index);
829 *error_counter_index = local_error_counter_index;
830 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
831 end:
832 return status;
833 }
834
835 enum event_notifier_error_accounting_status
836 event_notifier_error_accounting_register_event_notifier(
837 const struct lttng_trigger *trigger,
838 uint64_t *error_counter_index)
839 {
840 enum event_notifier_error_accounting_status status;
841 uint64_t local_error_counter_index;
842
843 /*
844 * Check if this event notifier already has a error counter index
845 * assigned.
846 */
847 status = get_error_counter_index_for_token(
848 lttng_trigger_get_tracer_token(trigger),
849 &local_error_counter_index);
850 switch (status) {
851 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND:
852 {
853 uid_t trigger_owner_uid;
854 const char *trigger_name;
855
856 get_trigger_info_for_log(
857 trigger, &trigger_name, &trigger_owner_uid);
858
859 DBG("Event notifier error counter index not found for tracer token (allocating a new one): trigger name = '%s', trigger owner uid = %d, tracer token = %" PRIu64,
860 trigger_name, trigger_owner_uid,
861 lttng_trigger_get_tracer_token(trigger));
862
863 status = create_error_counter_index_for_token(
864 lttng_trigger_get_tracer_token(trigger),
865 &local_error_counter_index);
866 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
867 ERR("Error creating index for token: status = %s, trigger name = '%s', trigger owner uid = %d",
868 error_accounting_status_str(status),
869 trigger_name, trigger_owner_uid);
870 goto end;
871 }
872 /* fall-through. */
873 }
874 case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK:
875 *error_counter_index = local_error_counter_index;
876 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
877 break;
878 default:
879 break;
880 }
881
882 end:
883 return status;
884 }
885
886 static
887 enum event_notifier_error_accounting_status
888 event_notifier_error_accounting_kernel_get_count(
889 const struct lttng_trigger *trigger, uint64_t *count)
890 {
891 struct lttng_kernel_counter_aggregate counter_aggregate = {};
892 enum event_notifier_error_accounting_status status;
893 uint64_t error_counter_index;
894 int ret;
895
896 status = get_error_counter_index_for_token(
897 lttng_trigger_get_tracer_token(trigger), &error_counter_index);
898 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
899 ERR("Error getting index for token: status=%s",
900 error_accounting_status_str(status));
901 goto end;
902 }
903
904 counter_aggregate.index.number_dimensions = 1;
905 counter_aggregate.index.dimension_indexes[0] = error_counter_index;
906
907 assert(kernel_error_accountant.kernel_event_notifier_error_counter_fd);
908
909 ret = kernctl_counter_get_aggregate_value(
910 kernel_error_accountant.kernel_event_notifier_error_counter_fd,
911 &counter_aggregate);
912 if (ret || counter_aggregate.value.value < 0) {
913 uid_t trigger_owner_uid;
914 const char *trigger_name;
915
916 get_trigger_info_for_log(trigger, &trigger_name,
917 &trigger_owner_uid);
918
919 if (counter_aggregate.value.value < 0) {
920 ERR("Invalid negative event notifier error counter value: trigger owner = %d, trigger name = '%s', value = %" PRId64,
921 trigger_owner_uid, trigger_name,
922 counter_aggregate.value.value);
923 } else {
924 ERR("Failed to getting event notifier error count: trigger owner = %d, trigger name = '%s', ret = %d",
925 trigger_owner_uid, trigger_name, ret);
926 }
927
928 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
929 goto end;
930 }
931
932 /* Error count can't be negative. */
933 assert(counter_aggregate.value.value >= 0);
934 *count = (uint64_t) counter_aggregate.value.value;
935
936 status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
937
938 end:
939 return status;
940 }
941
942 enum event_notifier_error_accounting_status
943 event_notifier_error_accounting_get_count(
944 const struct lttng_trigger *trigger, uint64_t *count)
945 {
946 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger)) {
947 case LTTNG_DOMAIN_KERNEL:
948 return event_notifier_error_accounting_kernel_get_count(
949 trigger, count);
950 case LTTNG_DOMAIN_UST:
951 #ifdef HAVE_LIBLTTNG_UST_CTL
952 return event_notifier_error_accounting_ust_get_count(trigger, count);
953 #else
954 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
955 #endif /* HAVE_LIBLTTNG_UST_CTL */
956 default:
957 abort();
958 }
959 }
960
961 static
962 enum event_notifier_error_accounting_status
963 event_notifier_error_accounting_clear(const struct lttng_trigger *trigger)
964 {
965 switch (lttng_trigger_get_underlying_domain_type_restriction(trigger)) {
966 case LTTNG_DOMAIN_KERNEL:
967 return event_notifier_error_accounting_kernel_clear(trigger);
968 case LTTNG_DOMAIN_UST:
969 #ifdef HAVE_LIBLTTNG_UST_CTL
970 return event_notifier_error_accounting_ust_clear(trigger);
971 #else
972 return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
973 #endif /* HAVE_LIBLTTNG_UST_CTL */
974 default:
975 abort();
976 }
977 }
978
979 static void free_index_ht_entry(struct rcu_head *head)
980 {
981 struct index_ht_entry *entry = caa_container_of(head,
982 struct index_ht_entry, rcu_head);
983
984 free(entry);
985 }
986
987 void event_notifier_error_accounting_unregister_event_notifier(
988 const struct lttng_trigger *trigger)
989 {
990 struct lttng_ht_iter iter;
991 struct lttng_ht_node_u64 *node;
992 const uint64_t tracer_token = lttng_trigger_get_tracer_token(trigger);
993 enum event_notifier_error_accounting_status status;
994
995 status = event_notifier_error_accounting_clear(trigger);
996 if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
997 /* Trigger details already logged by callee on error. */
998 ERR("Failed to clear event notifier error counter during unregistration of event notifier: status = '%s'",
999 error_accounting_status_str(status));
1000 }
1001
1002 rcu_read_lock();
1003 lttng_ht_lookup(error_counter_indexes_ht, &tracer_token, &iter);
1004 node = lttng_ht_iter_get_node_u64(&iter);
1005 if (node) {
1006 int del_ret;
1007 struct index_ht_entry *index_entry = caa_container_of(
1008 node, typeof(*index_entry), node);
1009 enum lttng_index_allocator_status index_alloc_status;
1010
1011 index_alloc_status = lttng_index_allocator_release(
1012 index_allocator,
1013 index_entry->error_counter_index);
1014 if (index_alloc_status != LTTNG_INDEX_ALLOCATOR_STATUS_OK) {
1015 uid_t trigger_owner_uid;
1016 const char *trigger_name;
1017
1018 get_trigger_info_for_log(trigger, &trigger_name,
1019 &trigger_owner_uid);
1020
1021 ERR("Failed to release event notifier error counter index: index = %" PRIu64 ", trigger name = '%s', trigger owner uid = %d",
1022 index_entry->error_counter_index,
1023 trigger_name, (int) trigger_owner_uid);
1024 /* Don't exit, perform the rest of the clean-up. */
1025 }
1026
1027 del_ret = lttng_ht_del(error_counter_indexes_ht, &iter);
1028 assert(!del_ret);
1029 call_rcu(&index_entry->rcu_head, free_index_ht_entry);
1030 }
1031
1032 rcu_read_unlock();
1033 }
1034
1035 #ifdef HAVE_LIBLTTNG_UST_CTL
1036 static void free_error_account_entry(struct rcu_head *head)
1037 {
1038 int i;
1039 struct error_account_entry *entry =
1040 caa_container_of(head, typeof(*entry), rcu_head);
1041
1042 for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
1043 ustctl_release_object(-1, entry->cpu_counters[i]);
1044 free(entry->cpu_counters[i]);
1045 }
1046
1047 free(entry->cpu_counters);
1048
1049 ustctl_release_object(-1, entry->counter);
1050 free(entry->counter);
1051
1052 ustctl_destroy_counter(entry->daemon_counter);
1053
1054 free(entry);
1055 }
1056 #else
1057 /* Not called without UST support. */
1058 static void free_error_account_entry(struct rcu_head *head) {}
1059 #endif /* HAVE_LIBLTTNG_UST_CTL */
1060
1061 void event_notifier_error_accounting_fini(void)
1062 {
1063 struct lttng_ht_iter iter;
1064 struct error_account_entry *uid_entry;
1065
1066 lttng_index_allocator_destroy(index_allocator);
1067
1068 if (kernel_error_accountant.kernel_event_notifier_error_counter_fd) {
1069 const int ret = close(kernel_error_accountant.kernel_event_notifier_error_counter_fd);
1070
1071 if (ret) {
1072 PERROR("Failed to close kernel event notifier error counter");
1073 }
1074 }
1075
1076 /*
1077 * FIXME error account entries are not reference-counted and torn
1078 * down on last use. They exist from the moment of their first use
1079 * up until the teardown of the session daemon.
1080 */
1081 rcu_read_lock();
1082 cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
1083 uid_entry, node.node) {
1084 cds_lfht_del(error_counter_uid_ht->ht, &uid_entry->node.node);
1085 call_rcu(&uid_entry->rcu_head, free_error_account_entry);
1086 }
1087 rcu_read_unlock();
1088 lttng_ht_destroy(error_counter_uid_ht);
1089
1090 /*
1091 * Will assert if some error counter indices were not released (an
1092 * internal error).
1093 */
1094 lttng_ht_destroy(error_counter_indexes_ht);
1095 }
This page took 0.050972 seconds and 4 git commands to generate.