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