Change the UST event hash table match function
[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 "ust-ctl.h"
31 #include "ust-app.h"
32 #include "trace-kernel.h"
33 #include "trace-ust.h"
34
35 static void add_unique_ust_event(struct lttng_ht *ht,
36 struct ltt_ust_event *event)
37 {
38 struct cds_lfht_node *node_ptr;
39 struct ltt_ust_ht_key key;
40
41 assert(ht);
42 assert(ht->ht);
43 assert(event);
44
45 key.name = event->attr.name;
46 key.filter = (struct lttng_filter_bytecode *) event->filter;
47 key.loglevel = event->attr.loglevel;
48
49 node_ptr = cds_lfht_add_unique(ht->ht,
50 ht->hash_fct(event->node.key, lttng_ht_seed),
51 trace_ust_ht_match_event, &key, &event->node.node);
52 assert(node_ptr == &event->node.node);
53 }
54
55 /*
56 * Setup a lttng_event used to enable *all* syscall tracing.
57 */
58 static void init_syscalls_kernel_event(struct lttng_event *event)
59 {
60 event->name[0] = '\0';
61 /*
62 * We use LTTNG_EVENT* here since the trace kernel creation will make the
63 * right changes for the kernel.
64 */
65 event->type = LTTNG_EVENT_SYSCALL;
66 }
67
68 /*
69 * Return 1 if loglevels match or 0 on failure.
70 */
71 static int loglevel_match(struct ltt_ust_event *uevent,
72 enum lttng_ust_loglevel_type log_type, int loglevel)
73 {
74 /*
75 * For the loglevel type ALL, the loglevel is set to -1 but the event
76 * received by the session daemon is 0 which does not match the negative
77 * value in the existing event.
78 */
79 if (log_type == LTTNG_UST_LOGLEVEL_ALL) {
80 loglevel = -1;
81 }
82
83 if (uevent == NULL || uevent->attr.loglevel_type != log_type ||
84 uevent->attr.loglevel != loglevel) {
85 goto no_match;
86 }
87
88 return 1;
89
90 no_match:
91 return 0;
92 }
93
94 /*
95 * Disable kernel tracepoint event for a channel from the kernel session.
96 */
97 int event_kernel_disable_tracepoint(struct ltt_kernel_session *ksession,
98 struct ltt_kernel_channel *kchan, char *event_name)
99 {
100 int ret;
101 struct ltt_kernel_event *kevent;
102
103 kevent = trace_kernel_get_event_by_name(event_name, kchan);
104 if (kevent == NULL) {
105 ret = LTTNG_ERR_NO_EVENT;
106 goto error;
107 }
108
109 ret = kernel_disable_event(kevent);
110 if (ret < 0) {
111 ret = LTTNG_ERR_KERN_DISABLE_FAIL;
112 goto error;
113 }
114
115 DBG("Kernel event %s disable for channel %s.",
116 kevent->event->name, kchan->channel->name);
117
118 ret = LTTNG_OK;
119
120 error:
121 return ret;
122 }
123
124 /*
125 * Disable kernel tracepoint events for a channel from the kernel session.
126 */
127 int event_kernel_disable_all_tracepoints(struct ltt_kernel_session *ksession,
128 struct ltt_kernel_channel *kchan)
129 {
130 int ret;
131 struct ltt_kernel_event *kevent;
132
133 /* For each event in the kernel session */
134 cds_list_for_each_entry(kevent, &kchan->events_list.head, list) {
135 ret = kernel_disable_event(kevent);
136 if (ret < 0) {
137 /* We continue disabling the rest */
138 continue;
139 }
140 }
141 ret = LTTNG_OK;
142 return ret;
143 }
144
145 /*
146 * Disable kernel syscall events for a channel from the kernel session.
147 */
148 int event_kernel_disable_all_syscalls(struct ltt_kernel_session *ksession,
149 struct ltt_kernel_channel *kchan)
150 {
151 ERR("Cannot disable syscall tracing for existing session. Please destroy session instead.");
152 return LTTNG_OK; /* Return OK so disable all succeeds */
153 }
154
155 /*
156 * Disable all kernel event for a channel from the kernel session.
157 */
158 int event_kernel_disable_all(struct ltt_kernel_session *ksession,
159 struct ltt_kernel_channel *kchan)
160 {
161 int ret;
162
163 ret = event_kernel_disable_all_tracepoints(ksession, kchan);
164 if (ret != LTTNG_OK)
165 return ret;
166 ret = event_kernel_disable_all_syscalls(ksession, kchan);
167 return ret;
168 }
169
170 /*
171 * Enable kernel tracepoint event for a channel from the kernel session.
172 */
173 int event_kernel_enable_tracepoint(struct ltt_kernel_session *ksession,
174 struct ltt_kernel_channel *kchan, struct lttng_event *event)
175 {
176 int ret;
177 struct ltt_kernel_event *kevent;
178
179 kevent = trace_kernel_get_event_by_name(event->name, kchan);
180 if (kevent == NULL) {
181 ret = kernel_create_event(event, kchan);
182 if (ret < 0) {
183 switch (-ret) {
184 case EEXIST:
185 ret = LTTNG_ERR_KERN_EVENT_EXIST;
186 break;
187 case ENOSYS:
188 ret = LTTNG_ERR_KERN_EVENT_ENOSYS;
189 break;
190 default:
191 ret = LTTNG_ERR_KERN_ENABLE_FAIL;
192 break;
193 }
194 goto end;
195 }
196 } else if (kevent->enabled == 0) {
197 ret = kernel_enable_event(kevent);
198 if (ret < 0) {
199 ret = LTTNG_ERR_KERN_ENABLE_FAIL;
200 goto end;
201 }
202 } else {
203 /* At this point, the event is considered enabled */
204 ret = LTTNG_ERR_KERN_EVENT_EXIST;
205 goto end;
206 }
207
208 ret = LTTNG_OK;
209 end:
210 return ret;
211 }
212
213 /*
214 * Enable all kernel tracepoint events of a channel of the kernel session.
215 */
216 int event_kernel_enable_all_tracepoints(struct ltt_kernel_session *ksession,
217 struct ltt_kernel_channel *kchan, int kernel_tracer_fd)
218 {
219 int size, i, ret;
220 struct ltt_kernel_event *kevent;
221 struct lttng_event *event_list = NULL;
222
223 /* For each event in the kernel session */
224 cds_list_for_each_entry(kevent, &kchan->events_list.head, list) {
225 if (kevent->enabled == 0) {
226 ret = kernel_enable_event(kevent);
227 if (ret < 0) {
228 /* Enable failed but still continue */
229 continue;
230 }
231 }
232 }
233
234 size = kernel_list_events(kernel_tracer_fd, &event_list);
235 if (size < 0) {
236 ret = LTTNG_ERR_KERN_LIST_FAIL;
237 goto end;
238 }
239
240 for (i = 0; i < size; i++) {
241 kevent = trace_kernel_get_event_by_name(event_list[i].name, kchan);
242 if (kevent == NULL) {
243 /* Default event type for enable all */
244 event_list[i].type = LTTNG_EVENT_TRACEPOINT;
245 /* Enable each single tracepoint event */
246 ret = kernel_create_event(&event_list[i], kchan);
247 if (ret < 0) {
248 /* Ignore error here and continue */
249 }
250 }
251 }
252 free(event_list);
253
254 ret = LTTNG_OK;
255 end:
256 return ret;
257
258 }
259
260 /*
261 * Enable all kernel tracepoint events of a channel of the kernel session.
262 */
263 int event_kernel_enable_all_syscalls(struct ltt_kernel_session *ksession,
264 struct ltt_kernel_channel *kchan, int kernel_tracer_fd)
265 {
266 int ret;
267 struct lttng_event event;
268
269 init_syscalls_kernel_event(&event);
270
271 DBG("Enabling all syscall tracing");
272
273 ret = kernel_create_event(&event, kchan);
274 if (ret < 0) {
275 if (ret == -EEXIST) {
276 ret = LTTNG_ERR_KERN_EVENT_EXIST;
277 } else {
278 ret = LTTNG_ERR_KERN_ENABLE_FAIL;
279 }
280 goto end;
281 }
282
283 ret = LTTNG_OK;
284 end:
285 return ret;
286 }
287
288 /*
289 * Enable all kernel events of a channel of the kernel session.
290 */
291 int event_kernel_enable_all(struct ltt_kernel_session *ksession,
292 struct ltt_kernel_channel *kchan, int kernel_tracer_fd)
293 {
294 int tp_ret;
295
296 tp_ret = event_kernel_enable_all_tracepoints(ksession, kchan, kernel_tracer_fd);
297 if (tp_ret != LTTNG_OK) {
298 goto end;
299 }
300
301 /*
302 * Reaching this code path means that all tracepoints were enabled without
303 * errors so we ignore the error value of syscalls.
304 *
305 * At the moment, failing to enable syscalls on "lttng enable-event -a -k"
306 * is not considered an error that need to be returned to the client since
307 * tracepoints did not fail. Future work will allow us to send back
308 * multiple errors to the client in one API call.
309 */
310 (void) event_kernel_enable_all_syscalls(ksession, kchan, kernel_tracer_fd);
311
312 end:
313 return tp_ret;
314 }
315
316 /*
317 * ============================
318 * UST : The Ultimate Frontier!
319 * ============================
320 */
321
322 /*
323 * Enable all UST tracepoints for a channel from a UST session.
324 */
325 int event_ust_enable_all_tracepoints(struct ltt_ust_session *usess, int domain,
326 struct ltt_ust_channel *uchan)
327 {
328 int ret, i, size;
329 struct lttng_ht_iter iter;
330 struct ltt_ust_event *uevent = NULL;
331 struct lttng_event *events = NULL;
332
333 switch (domain) {
334 case LTTNG_DOMAIN_UST:
335 {
336 /* Enable existing events */
337 cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent,
338 node.node) {
339 if (uevent->enabled == 0) {
340 ret = ust_app_enable_event_glb(usess, uchan, uevent);
341 if (ret < 0) {
342 continue;
343 }
344 uevent->enabled = 1;
345 }
346 }
347
348 /* Get all UST available events */
349 size = ust_app_list_events(&events);
350 if (size < 0) {
351 ret = LTTNG_ERR_UST_LIST_FAIL;
352 goto error;
353 }
354
355 for (i = 0; i < size; i++) {
356 /*
357 * Check if event exist and if so, continue since it was enable
358 * previously.
359 */
360 uevent = trace_ust_find_event(uchan->events, events[i].name, NULL,
361 events[i].loglevel);
362 if (uevent != NULL) {
363 ret = ust_app_enable_event_pid(usess, uchan, uevent,
364 events[i].pid);
365 if (ret < 0) {
366 if (ret != -LTTNG_UST_ERR_EXIST) {
367 ret = LTTNG_ERR_UST_ENABLE_FAIL;
368 goto error;
369 }
370 }
371 continue;
372 }
373
374 /* Create ust event */
375 uevent = trace_ust_create_event(&events[i]);
376 if (uevent == NULL) {
377 ret = LTTNG_ERR_FATAL;
378 goto error_destroy;
379 }
380
381 /* Create event for the specific PID */
382 ret = ust_app_enable_event_pid(usess, uchan, uevent,
383 events[i].pid);
384 if (ret < 0) {
385 if (ret == -LTTNG_UST_ERR_EXIST) {
386 ret = LTTNG_ERR_UST_EVENT_EXIST;
387 goto error;
388 } else {
389 ret = LTTNG_ERR_UST_ENABLE_FAIL;
390 goto error_destroy;
391 }
392 }
393
394 uevent->enabled = 1;
395 /* Add ltt ust event to channel */
396 rcu_read_lock();
397 add_unique_ust_event(uchan->events, uevent);
398 rcu_read_unlock();
399 }
400
401 free(events);
402 break;
403 }
404 #if 0
405 case LTTNG_DOMAIN_UST_EXEC_NAME:
406 case LTTNG_DOMAIN_UST_PID:
407 case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
408 #endif
409 default:
410 ret = LTTNG_ERR_UND;
411 goto error;
412 }
413
414 return LTTNG_OK;
415
416 error_destroy:
417 trace_ust_destroy_event(uevent);
418
419 error:
420 free(events);
421 return ret;
422 }
423
424 /*
425 * Enable UST tracepoint event for a channel from a UST session.
426 */
427 int event_ust_enable_tracepoint(struct ltt_ust_session *usess, int domain,
428 struct ltt_ust_channel *uchan, struct lttng_event *event)
429 {
430 int ret = LTTNG_OK, to_create = 0;
431 struct ltt_ust_event *uevent;
432
433 DBG3("Enable ust: %s l:%d f:%p", event->name, event->loglevel, NULL);
434
435 rcu_read_lock();
436
437 uevent = trace_ust_find_event(uchan->events, event->name, NULL,
438 event->loglevel);
439 if (uevent == NULL) {
440 uevent = trace_ust_create_event(event);
441 if (uevent == NULL) {
442 ret = LTTNG_ERR_UST_ENABLE_FAIL;
443 goto error;
444 }
445 /* Valid to set it after the goto error since uevent is still NULL */
446 to_create = 1;
447 }
448
449 /* Check loglevels */
450 ret = loglevel_match(uevent, event->loglevel_type, event->loglevel);
451 if (ret == 0) {
452 /*
453 * No match meaning that the user tried to enable a known event but
454 * with a different loglevel.
455 */
456 DBG("Enable event %s does not match existing event %s with loglevel "
457 "respectively of %d and %d", event->name, uevent->attr.name,
458 uevent->attr.loglevel, event->loglevel);
459 ret = LTTNG_ERR_EVENT_EXIST_LOGLEVEL;
460 goto error;
461 }
462
463 if (uevent->enabled) {
464 /* It's already enabled so everything is OK */
465 ret = LTTNG_OK;
466 goto end;
467 }
468
469 uevent->enabled = 1;
470
471 switch (domain) {
472 case LTTNG_DOMAIN_UST:
473 {
474 if (to_create) {
475 /* Create event on all UST registered apps for session */
476 ret = ust_app_create_event_glb(usess, uchan, uevent);
477 } else {
478 /* Enable event on all UST registered apps for session */
479 ret = ust_app_enable_event_glb(usess, uchan, uevent);
480 }
481
482 if (ret < 0) {
483 if (ret == -LTTNG_UST_ERR_EXIST) {
484 ret = LTTNG_ERR_UST_EVENT_EXIST;
485 goto end;
486 } else {
487 ret = LTTNG_ERR_UST_ENABLE_FAIL;
488 goto error;
489 }
490 }
491 break;
492 }
493 #if 0
494 case LTTNG_DOMAIN_UST_EXEC_NAME:
495 case LTTNG_DOMAIN_UST_PID:
496 case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
497 #endif
498 default:
499 ret = LTTNG_ERR_UND;
500 goto end;
501 }
502
503 if (to_create) {
504 /* Add ltt ust event to channel */
505 add_unique_ust_event(uchan->events, uevent);
506 }
507
508 DBG("Event UST %s %s in channel %s", uevent->attr.name,
509 to_create ? "created" : "enabled", uchan->name);
510
511 ret = LTTNG_OK;
512
513 end:
514 rcu_read_unlock();
515 return ret;
516
517 error:
518 /*
519 * Only destroy event on creation time (not enabling time) because if the
520 * event is found in the channel (to_create == 0), it means that at some
521 * point the enable_event worked and it's thus valid to keep it alive.
522 * Destroying it also implies that we also destroy it's shadow copy to sync
523 * everyone up.
524 */
525 if (to_create) {
526 /* In this code path, the uevent was not added to the hash table */
527 trace_ust_destroy_event(uevent);
528 }
529 rcu_read_unlock();
530 return ret;
531 }
532
533 /*
534 * Disable UST tracepoint of a channel from a UST session.
535 */
536 int event_ust_disable_tracepoint(struct ltt_ust_session *usess, int domain,
537 struct ltt_ust_channel *uchan, char *event_name)
538 {
539 int ret;
540 struct ltt_ust_event *uevent;
541 struct lttng_ht_node_str *node;
542 struct lttng_ht_iter iter;
543 void *orig_match_fct;
544 struct lttng_ht *ht;
545
546 ht = uchan->events;
547
548 /* Save match function so we can use the event by name match. */
549 orig_match_fct = (void *) ht->match_fct;
550 ht->match_fct = trace_ust_ht_match_event_by_name;
551
552 rcu_read_lock();
553 lttng_ht_lookup(ht, (void *) event_name, &iter);
554 node = lttng_ht_iter_get_node_str(&iter);
555 if (node == NULL) {
556 DBG2("Trace UST event NOT found by name %s", event_name);
557 ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
558 goto error;
559 }
560
561 do {
562 uevent = caa_container_of(node, struct ltt_ust_event, node);
563 if (uevent->enabled == 0) {
564 /* It's already disabled so everything is OK */
565 ret = LTTNG_OK;
566 continue;
567 }
568
569 switch (domain) {
570 case LTTNG_DOMAIN_UST:
571 ret = ust_app_disable_event_glb(usess, uchan, uevent);
572 if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
573 ret = LTTNG_ERR_UST_DISABLE_FAIL;
574 goto error;
575 }
576 break;
577 #if 0
578 case LTTNG_DOMAIN_UST_EXEC_NAME:
579 case LTTNG_DOMAIN_UST_PID:
580 case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
581 #endif
582 default:
583 ret = LTTNG_ERR_UND;
584 goto error;
585 }
586
587 uevent->enabled = 0;
588
589 /* Get next duplicate event by name. */
590 cds_lfht_next_duplicate(ht->ht, trace_ust_ht_match_event_by_name,
591 event_name, &iter.iter);
592 node = lttng_ht_iter_get_node_str(&iter);
593 } while (node);
594
595 ret = LTTNG_OK;
596
597 DBG2("Event UST %s disabled in channel %s", uevent->attr.name,
598 uchan->name);
599 error:
600 ht->match_fct = orig_match_fct;
601 rcu_read_unlock();
602 return ret;
603 }
604
605 /*
606 * Disable all UST tracepoints for a channel from a UST session.
607 */
608 int event_ust_disable_all_tracepoints(struct ltt_ust_session *usess, int domain,
609 struct ltt_ust_channel *uchan)
610 {
611 int ret, i, size;
612 struct lttng_ht_iter iter;
613 struct ltt_ust_event *uevent = NULL;
614 struct lttng_event *events = NULL;
615
616 switch (domain) {
617 case LTTNG_DOMAIN_UST:
618 {
619 /* Disabling existing events */
620 cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent,
621 node.node) {
622 if (uevent->enabled == 1) {
623 ret = ust_app_disable_event_glb(usess, uchan, uevent);
624 if (ret < 0) {
625 continue;
626 }
627 uevent->enabled = 0;
628 }
629 }
630
631 /* Get all UST available events */
632 size = ust_app_list_events(&events);
633 if (size < 0) {
634 ret = LTTNG_ERR_UST_LIST_FAIL;
635 goto error;
636 }
637
638 for (i = 0; i < size; i++) {
639 ret = event_ust_disable_tracepoint(usess, domain, uchan,
640 events[i].name);
641 if (ret != LTTNG_OK) {
642 /* Continue to disable the rest... */
643 continue;
644 }
645 }
646
647 free(events);
648 break;
649 }
650 #if 0
651 case LTTNG_DOMAIN_UST_EXEC_NAME:
652 case LTTNG_DOMAIN_UST_PID:
653 case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
654 #endif
655 default:
656 ret = LTTNG_ERR_UND;
657 goto error;
658 }
659
660 return LTTNG_OK;
661
662 error:
663 free(events);
664 return ret;
665 }
This page took 0.067228 seconds and 4 git commands to generate.