Fix: disable event for JUL domain
[lttng-tools.git] / src / bin / lttng-sessiond / event.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #define _GNU_SOURCE
19 #include <errno.h>
20 #include <urcu/list.h>
21 #include <string.h>
22
23 #include <lttng/lttng.h>
24 #include <common/error.h>
25 #include <common/sessiond-comm/sessiond-comm.h>
26
27 #include "channel.h"
28 #include "event.h"
29 #include "kernel.h"
30 #include "lttng-sessiond.h"
31 #include "ust-ctl.h"
32 #include "ust-app.h"
33 #include "trace-kernel.h"
34 #include "trace-ust.h"
35
36 /*
37 * Add unique UST event based on the event name, filter bytecode and loglevel.
38 */
39 static void add_unique_ust_event(struct lttng_ht *ht,
40 struct ltt_ust_event *event)
41 {
42 struct cds_lfht_node *node_ptr;
43 struct ltt_ust_ht_key key;
44
45 assert(ht);
46 assert(ht->ht);
47 assert(event);
48
49 key.name = event->attr.name;
50 key.filter = (struct lttng_filter_bytecode *) event->filter;
51 key.loglevel = event->attr.loglevel;
52 key.exclusion = event->exclusion;
53
54 node_ptr = cds_lfht_add_unique(ht->ht,
55 ht->hash_fct(event->node.key, lttng_ht_seed),
56 trace_ust_ht_match_event, &key, &event->node.node);
57 assert(node_ptr == &event->node.node);
58 }
59
60 /*
61 * Setup a lttng_event used to enable *all* syscall tracing.
62 */
63 static void init_syscalls_kernel_event(struct lttng_event *event)
64 {
65 assert(event);
66
67 event->name[0] = '\0';
68 /*
69 * We use LTTNG_EVENT* here since the trace kernel creation will make the
70 * right changes for the kernel.
71 */
72 event->type = LTTNG_EVENT_SYSCALL;
73 }
74
75 /*
76 * Disable kernel tracepoint event for a channel from the kernel session.
77 */
78 int event_kernel_disable_tracepoint(struct ltt_kernel_channel *kchan,
79 char *event_name)
80 {
81 int ret;
82 struct ltt_kernel_event *kevent;
83
84 assert(kchan);
85
86 kevent = trace_kernel_get_event_by_name(event_name, kchan);
87 if (kevent == NULL) {
88 ret = LTTNG_ERR_NO_EVENT;
89 goto error;
90 }
91
92 ret = kernel_disable_event(kevent);
93 if (ret < 0) {
94 ret = LTTNG_ERR_KERN_DISABLE_FAIL;
95 goto error;
96 }
97
98 DBG("Kernel event %s disable for channel %s.",
99 kevent->event->name, kchan->channel->name);
100
101 ret = LTTNG_OK;
102
103 error:
104 return ret;
105 }
106
107 /*
108 * Disable kernel tracepoint events for a channel from the kernel session.
109 */
110 int event_kernel_disable_all_tracepoints(struct ltt_kernel_channel *kchan)
111 {
112 int ret;
113 struct ltt_kernel_event *kevent;
114
115 assert(kchan);
116
117 /* For each event in the kernel session */
118 cds_list_for_each_entry(kevent, &kchan->events_list.head, list) {
119 ret = kernel_disable_event(kevent);
120 if (ret < 0) {
121 /* We continue disabling the rest */
122 continue;
123 }
124 }
125 ret = LTTNG_OK;
126 return ret;
127 }
128
129 /*
130 * Disable kernel syscall events for a channel from the kernel session.
131 */
132 int event_kernel_disable_all_syscalls(struct ltt_kernel_channel *kchan)
133 {
134 ERR("Cannot disable syscall tracing for existing session. Please destroy session instead.");
135 return LTTNG_OK; /* Return OK so disable all succeeds */
136 }
137
138 /*
139 * Disable all kernel event for a channel from the kernel session.
140 */
141 int event_kernel_disable_all(struct ltt_kernel_channel *kchan)
142 {
143 int ret;
144
145 assert(kchan);
146
147 ret = event_kernel_disable_all_tracepoints(kchan);
148 if (ret != LTTNG_OK)
149 return ret;
150 ret = event_kernel_disable_all_syscalls(kchan);
151 return ret;
152 }
153
154 /*
155 * Enable kernel tracepoint event for a channel from the kernel session.
156 */
157 int event_kernel_enable_tracepoint(struct ltt_kernel_channel *kchan,
158 struct lttng_event *event)
159 {
160 int ret;
161 struct ltt_kernel_event *kevent;
162
163 assert(kchan);
164 assert(event);
165
166 kevent = trace_kernel_get_event_by_name(event->name, kchan);
167 if (kevent == NULL) {
168 ret = kernel_create_event(event, kchan);
169 if (ret < 0) {
170 switch (-ret) {
171 case EEXIST:
172 ret = LTTNG_ERR_KERN_EVENT_EXIST;
173 break;
174 case ENOSYS:
175 ret = LTTNG_ERR_KERN_EVENT_ENOSYS;
176 break;
177 default:
178 ret = LTTNG_ERR_KERN_ENABLE_FAIL;
179 break;
180 }
181 goto end;
182 }
183 } else if (kevent->enabled == 0) {
184 ret = kernel_enable_event(kevent);
185 if (ret < 0) {
186 ret = LTTNG_ERR_KERN_ENABLE_FAIL;
187 goto end;
188 }
189 } else {
190 /* At this point, the event is considered enabled */
191 ret = LTTNG_ERR_KERN_EVENT_EXIST;
192 goto end;
193 }
194
195 ret = LTTNG_OK;
196 end:
197 return ret;
198 }
199
200 /*
201 * Enable all kernel tracepoint events of a channel of the kernel session.
202 */
203 int event_kernel_enable_all_tracepoints(struct ltt_kernel_channel *kchan,
204 int kernel_tracer_fd)
205 {
206 int size, i, ret;
207 struct ltt_kernel_event *kevent;
208 struct lttng_event *event_list = NULL;
209
210 assert(kchan);
211
212 /* For each event in the kernel session */
213 cds_list_for_each_entry(kevent, &kchan->events_list.head, list) {
214 if (kevent->enabled == 0) {
215 ret = kernel_enable_event(kevent);
216 if (ret < 0) {
217 /* Enable failed but still continue */
218 continue;
219 }
220 }
221 }
222
223 size = kernel_list_events(kernel_tracer_fd, &event_list);
224 if (size < 0) {
225 ret = LTTNG_ERR_KERN_LIST_FAIL;
226 goto end;
227 }
228
229 for (i = 0; i < size; i++) {
230 kevent = trace_kernel_get_event_by_name(event_list[i].name, kchan);
231 if (kevent == NULL) {
232 /* Default event type for enable all */
233 event_list[i].type = LTTNG_EVENT_TRACEPOINT;
234 /* Enable each single tracepoint event */
235 ret = kernel_create_event(&event_list[i], kchan);
236 if (ret < 0) {
237 /* Ignore error here and continue */
238 }
239 }
240 }
241 free(event_list);
242
243 ret = LTTNG_OK;
244 end:
245 return ret;
246 }
247
248 /*
249 * Enable all kernel sycalls events of a channel of the kernel session.
250 */
251 int event_kernel_enable_all_syscalls(struct ltt_kernel_channel *kchan,
252 int kernel_tracer_fd)
253 {
254 int ret;
255 struct lttng_event event;
256
257 assert(kchan);
258
259 init_syscalls_kernel_event(&event);
260
261 DBG("Enabling all syscall tracing");
262
263 ret = kernel_create_event(&event, kchan);
264 if (ret < 0) {
265 if (ret == -EEXIST) {
266 ret = LTTNG_ERR_KERN_EVENT_EXIST;
267 } else {
268 ret = LTTNG_ERR_KERN_ENABLE_FAIL;
269 }
270 goto end;
271 }
272
273 ret = LTTNG_OK;
274 end:
275 return ret;
276 }
277
278 /*
279 * Enable all kernel events of a channel of the kernel session.
280 */
281 int event_kernel_enable_all(struct ltt_kernel_channel *kchan,
282 int kernel_tracer_fd)
283 {
284 int tp_ret;
285
286 assert(kchan);
287
288 tp_ret = event_kernel_enable_all_tracepoints(kchan, kernel_tracer_fd);
289 if (tp_ret != LTTNG_OK) {
290 goto end;
291 }
292
293 /*
294 * Reaching this code path means that all tracepoints were enabled without
295 * errors so we ignore the error value of syscalls.
296 *
297 * At the moment, failing to enable syscalls on "lttng enable-event -a -k"
298 * is not considered an error that need to be returned to the client since
299 * tracepoints did not fail. Future work will allow us to send back
300 * multiple errors to the client in one API call.
301 */
302 (void) event_kernel_enable_all_syscalls(kchan, kernel_tracer_fd);
303
304 end:
305 return tp_ret;
306 }
307
308 /*
309 * ============================
310 * UST : The Ultimate Frontier!
311 * ============================
312 */
313
314 /*
315 * Enable all UST tracepoints for a channel from a UST session.
316 */
317 int event_ust_enable_all_tracepoints(struct ltt_ust_session *usess,
318 struct ltt_ust_channel *uchan, struct lttng_filter_bytecode *filter)
319 {
320 int ret, i, size;
321 struct lttng_ht_iter iter;
322 struct ltt_ust_event *uevent = NULL;
323 struct lttng_event *events = NULL;
324
325 assert(usess);
326 assert(uchan);
327
328 rcu_read_lock();
329
330 /* Enable existing events */
331 cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent,
332 node.node) {
333 if (uevent->enabled == 0) {
334 ret = ust_app_enable_event_glb(usess, uchan, uevent);
335 if (ret < 0) {
336 continue;
337 }
338 uevent->enabled = 1;
339 }
340 }
341
342 /* Get all UST available events */
343 size = ust_app_list_events(&events);
344 if (size < 0) {
345 ret = LTTNG_ERR_UST_LIST_FAIL;
346 goto error;
347 }
348
349 for (i = 0; i < size; i++) {
350 /*
351 * Check if event exist and if so, continue since it was enable
352 * previously.
353 */
354 uevent = trace_ust_find_event(uchan->events, events[i].name, filter,
355 events[i].loglevel, NULL);
356 if (uevent != NULL) {
357 ret = ust_app_enable_event_pid(usess, uchan, uevent,
358 events[i].pid);
359 if (ret < 0) {
360 if (ret != -LTTNG_UST_ERR_EXIST) {
361 ret = LTTNG_ERR_UST_ENABLE_FAIL;
362 goto error;
363 }
364 }
365 continue;
366 }
367
368 /* Create ust event */
369 uevent = trace_ust_create_event(&events[i], filter, NULL);
370 if (uevent == NULL) {
371 ret = LTTNG_ERR_FATAL;
372 goto error_destroy;
373 }
374
375 /* Create event for the specific PID */
376 ret = ust_app_enable_event_pid(usess, uchan, uevent,
377 events[i].pid);
378 if (ret < 0) {
379 if (ret == -LTTNG_UST_ERR_EXIST) {
380 ret = LTTNG_ERR_UST_EVENT_EXIST;
381 goto error;
382 } else {
383 ret = LTTNG_ERR_UST_ENABLE_FAIL;
384 goto error_destroy;
385 }
386 }
387
388 uevent->enabled = 1;
389 /* Add ltt ust event to channel */
390 rcu_read_lock();
391 add_unique_ust_event(uchan->events, uevent);
392 rcu_read_unlock();
393 }
394 free(events);
395
396 rcu_read_unlock();
397 return LTTNG_OK;
398
399 error_destroy:
400 trace_ust_destroy_event(uevent);
401
402 error:
403 free(events);
404 rcu_read_unlock();
405 return ret;
406 }
407
408 /*
409 * Enable UST tracepoint event for a channel from a UST session.
410 */
411 int event_ust_enable_tracepoint(struct ltt_ust_session *usess,
412 struct ltt_ust_channel *uchan, struct lttng_event *event,
413 struct lttng_filter_bytecode *filter,
414 struct lttng_event_exclusion *exclusion)
415 {
416 int ret = LTTNG_OK, to_create = 0;
417 struct ltt_ust_event *uevent;
418
419 assert(usess);
420 assert(uchan);
421 assert(event);
422
423 rcu_read_lock();
424
425 uevent = trace_ust_find_event(uchan->events, event->name, filter,
426 event->loglevel, exclusion);
427 if (uevent == NULL) {
428 uevent = trace_ust_create_event(event, filter, exclusion);
429 if (uevent == NULL) {
430 ret = LTTNG_ERR_UST_ENABLE_FAIL;
431 goto error;
432 }
433
434 /* Valid to set it after the goto error since uevent is still NULL */
435 to_create = 1;
436 }
437
438 if (uevent->enabled) {
439 /* It's already enabled so everything is OK */
440 ret = LTTNG_ERR_UST_EVENT_ENABLED;
441 goto end;
442 }
443
444 uevent->enabled = 1;
445
446 if (to_create) {
447 /* Create event on all UST registered apps for session */
448 ret = ust_app_create_event_glb(usess, uchan, uevent);
449 } else {
450 /* Enable event on all UST registered apps for session */
451 ret = ust_app_enable_event_glb(usess, uchan, uevent);
452 }
453
454 if (ret < 0) {
455 if (ret == -LTTNG_UST_ERR_EXIST) {
456 ret = LTTNG_ERR_UST_EVENT_EXIST;
457 goto end;
458 } else {
459 ret = LTTNG_ERR_UST_ENABLE_FAIL;
460 goto error;
461 }
462 }
463
464 if (to_create) {
465 /* Add ltt ust event to channel */
466 add_unique_ust_event(uchan->events, uevent);
467 }
468
469 DBG("Event UST %s %s in channel %s", uevent->attr.name,
470 to_create ? "created" : "enabled", uchan->name);
471
472 ret = LTTNG_OK;
473
474 end:
475 rcu_read_unlock();
476 return ret;
477
478 error:
479 /*
480 * Only destroy event on creation time (not enabling time) because if the
481 * event is found in the channel (to_create == 0), it means that at some
482 * point the enable_event worked and it's thus valid to keep it alive.
483 * Destroying it also implies that we also destroy it's shadow copy to sync
484 * everyone up.
485 */
486 if (to_create) {
487 /* In this code path, the uevent was not added to the hash table */
488 trace_ust_destroy_event(uevent);
489 }
490 rcu_read_unlock();
491 return ret;
492 }
493
494 /*
495 * Disable UST tracepoint of a channel from a UST session.
496 */
497 int event_ust_disable_tracepoint(struct ltt_ust_session *usess,
498 struct ltt_ust_channel *uchan, char *event_name)
499 {
500 int ret;
501 struct ltt_ust_event *uevent;
502 struct lttng_ht_node_str *node;
503 struct lttng_ht_iter iter;
504 struct lttng_ht *ht;
505
506 assert(usess);
507 assert(uchan);
508 assert(event_name);
509
510 ht = uchan->events;
511
512 rcu_read_lock();
513
514 /*
515 * We use a custom lookup since we need the iterator for the next_duplicate
516 * call in the do while loop below.
517 */
518 cds_lfht_lookup(ht->ht, ht->hash_fct((void *) event_name, lttng_ht_seed),
519 trace_ust_ht_match_event_by_name, event_name, &iter.iter);
520 node = lttng_ht_iter_get_node_str(&iter);
521 if (node == NULL) {
522 DBG2("Trace UST event NOT found by name %s", event_name);
523 ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
524 goto error;
525 }
526
527 do {
528 uevent = caa_container_of(node, struct ltt_ust_event, node);
529 assert(uevent);
530
531 if (uevent->enabled == 0) {
532 /* It's already disabled so everything is OK */
533 goto next;
534 }
535
536 ret = ust_app_disable_event_glb(usess, uchan, uevent);
537 if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
538 ret = LTTNG_ERR_UST_DISABLE_FAIL;
539 goto error;
540 }
541 uevent->enabled = 0;
542
543 DBG2("Event UST %s disabled in channel %s", uevent->attr.name,
544 uchan->name);
545
546 next:
547 /* Get next duplicate event by name. */
548 cds_lfht_next_duplicate(ht->ht, trace_ust_ht_match_event_by_name,
549 event_name, &iter.iter);
550 node = lttng_ht_iter_get_node_str(&iter);
551 } while (node);
552
553 ret = LTTNG_OK;
554
555 error:
556 rcu_read_unlock();
557 return ret;
558 }
559
560 /*
561 * Disable all UST tracepoints for a channel from a UST session.
562 */
563 int event_ust_disable_all_tracepoints(struct ltt_ust_session *usess,
564 struct ltt_ust_channel *uchan)
565 {
566 int ret, i, size;
567 struct lttng_ht_iter iter;
568 struct ltt_ust_event *uevent = NULL;
569 struct lttng_event *events = NULL;
570
571 assert(usess);
572 assert(uchan);
573
574 rcu_read_lock();
575
576 /* Disabling existing events */
577 cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent,
578 node.node) {
579 if (uevent->enabled == 1) {
580 ret = event_ust_disable_tracepoint(usess, uchan,
581 uevent->attr.name);
582 if (ret < 0) {
583 continue;
584 }
585 }
586 }
587
588 /* Get all UST available events */
589 size = ust_app_list_events(&events);
590 if (size < 0) {
591 ret = LTTNG_ERR_UST_LIST_FAIL;
592 goto error;
593 }
594
595 for (i = 0; i < size; i++) {
596 ret = event_ust_disable_tracepoint(usess, uchan,
597 events[i].name);
598 if (ret != LTTNG_OK) {
599 /* Continue to disable the rest... */
600 continue;
601 }
602 }
603 free(events);
604
605 rcu_read_unlock();
606 return LTTNG_OK;
607
608 error:
609 free(events);
610 rcu_read_unlock();
611 return ret;
612 }
613
614 /*
615 * Enable all JUL event for a given UST session.
616 *
617 * Return LTTNG_OK on success or else a LTTNG_ERR* code.
618 */
619 int event_jul_enable_all(struct ltt_ust_session *usess,
620 struct lttng_event *event, struct lttng_filter_bytecode *filter)
621 {
622 int ret;
623 struct jul_event *jevent;
624 struct lttng_ht_iter iter;
625
626 assert(usess);
627
628 DBG("Event JUL enabling ALL events for session %" PRIu64, usess->id);
629
630 /* Enable event on JUL application through TCP socket. */
631 ret = event_jul_enable(usess, event, filter);
632 if (ret != LTTNG_OK) {
633 goto error;
634 }
635
636 /* Flag every event that they are now enabled. */
637 rcu_read_lock();
638 cds_lfht_for_each_entry(usess->domain_jul.events->ht, &iter.iter, jevent,
639 node.node) {
640 jevent->enabled = 1;
641 }
642 rcu_read_unlock();
643
644 ret = LTTNG_OK;
645
646 error:
647 return ret;
648 }
649
650 /*
651 * Enable a single JUL event for a given UST session.
652 *
653 * Return LTTNG_OK on success or else a LTTNG_ERR* code.
654 */
655 int event_jul_enable(struct ltt_ust_session *usess, struct lttng_event *event,
656 struct lttng_filter_bytecode *filter)
657 {
658 int ret, created = 0;
659 struct jul_event *jevent;
660
661 assert(usess);
662 assert(event);
663
664 DBG("Event JUL enabling %s for session %" PRIu64 " with loglevel type %d "
665 "and loglevel %d", event->name, usess->id, event->loglevel_type,
666 event->loglevel);
667
668 jevent = jul_find_event(event->name, event->loglevel, &usess->domain_jul);
669 if (!jevent) {
670 jevent = jul_create_event(event->name);
671 if (!jevent) {
672 ret = LTTNG_ERR_NOMEM;
673 goto error;
674 }
675 jevent->loglevel = event->loglevel;
676 jevent->loglevel_type = event->loglevel_type;
677 jevent->filter = filter;
678 created = 1;
679 }
680
681 /* Already enabled? */
682 if (jevent->enabled) {
683 goto end;
684 }
685
686 ret = jul_enable_event(jevent);
687 if (ret != LTTNG_OK) {
688 goto error;
689 }
690
691 /* If the event was created prior to the enable, add it to the domain. */
692 if (created) {
693 jul_add_event(jevent, &usess->domain_jul);
694 }
695
696 end:
697 return LTTNG_OK;
698
699 error:
700 if (created) {
701 jul_destroy_event(jevent);
702 }
703 return ret;
704 }
705
706 /*
707 * Disable a single JUL event for a given UST session.
708 *
709 * Return LTTNG_OK on success or else a LTTNG_ERR* code.
710 */
711 int event_jul_disable(struct ltt_ust_session *usess, char *event_name)
712 {
713 int ret;
714 char *ust_event_name;
715 struct jul_event *jevent;
716 struct ltt_ust_event *uevent = NULL;
717 struct ltt_ust_channel *uchan = NULL;
718
719 assert(usess);
720 assert(event_name);
721
722 DBG("Event JUL disabling %s for session %" PRIu64, event_name, usess->id);
723
724 jevent = jul_find_event_by_name(event_name, &usess->domain_jul);
725 if (!jevent) {
726 ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
727 goto error;
728 }
729
730 /* Already disabled? */
731 if (!jevent->enabled) {
732 goto end;
733 }
734
735 /*
736 * Disable it on the UST side. First get the channel reference then find
737 * the event and finally disable it.
738 */
739 uchan = trace_ust_find_channel_by_name(usess->domain_global.channels,
740 DEFAULT_JUL_CHANNEL_NAME);
741 if (!uchan) {
742 ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
743 goto error;
744 }
745
746 if (is_root) {
747 ust_event_name = DEFAULT_SYS_JUL_EVENT_NAME;
748 } else {
749 ust_event_name = DEFAULT_USER_JUL_EVENT_NAME;
750 }
751
752 /*
753 * The loglevel is hardcoded with 0 here since the agent ust event is set
754 * with the loglevel type to ALL thus the loglevel stays 0. The event's
755 * filter is the one handling the loglevel for agent.
756 */
757 uevent = trace_ust_find_event(uchan->events, ust_event_name,
758 jevent->filter, 0, NULL);
759 /* If the agent event exists, it must be available on the UST side. */
760 assert(uevent);
761
762 ret = ust_app_disable_event_glb(usess, uchan, uevent);
763 if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
764 ret = LTTNG_ERR_UST_DISABLE_FAIL;
765 goto error;
766 }
767 uevent->enabled = 0;
768
769 ret = jul_disable_event(jevent);
770 if (ret != LTTNG_OK) {
771 goto error;
772 }
773
774 end:
775 return LTTNG_OK;
776
777 error:
778 return ret;
779 }
780
781 /*
782 * Disable all JUL event for a given UST session.
783 *
784 * Return LTTNG_OK on success or else a LTTNG_ERR* code.
785 */
786 int event_jul_disable_all(struct ltt_ust_session *usess)
787 {
788 int ret;
789 struct jul_event *jevent;
790 struct lttng_ht_iter iter;
791
792 assert(usess);
793
794 /* Enable event on JUL application through TCP socket. */
795 ret = event_jul_disable(usess, "*");
796 if (ret != LTTNG_OK && ret != LTTNG_ERR_UST_EVENT_NOT_FOUND) {
797 goto error;
798 }
799
800 /* Flag every event that they are now enabled. */
801 rcu_read_lock();
802 cds_lfht_for_each_entry(usess->domain_jul.events->ht, &iter.iter, jevent,
803 node.node) {
804 if (!jevent->enabled) {
805 continue;
806 }
807
808 ret = event_jul_disable(usess, jevent->name);
809 if (ret != LTTNG_OK) {
810 rcu_read_unlock();
811 goto error;
812 }
813 }
814 rcu_read_unlock();
815
816 ret = LTTNG_OK;
817
818 error:
819 return ret;
820 }
This page took 0.07471 seconds and 4 git commands to generate.