95463aa50fc96c6d6dfc67b8837fc08daa507dbf
[lttng-tools.git] / ltt-sessiond / kernel-ctl.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
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #define _GNU_SOURCE
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "lttngerr.h"
28 #include "ltt-sessiond.h"
29 #include "libkernelctl.h"
30 #include "kernel-ctl.h"
31
32 /*
33 * kernel_add_channel_context
34 *
35 * Add context on a kernel channel.
36 */
37 int kernel_add_channel_context(struct ltt_kernel_channel *chan,
38 struct lttng_kernel_context *ctx)
39 {
40 int ret;
41
42 DBG("Adding context to channel %s", chan->channel->name);
43 ret = kernctl_add_context(chan->fd, ctx);
44 if (ret < 0) {
45 perror("add context ioctl");
46 goto error;
47 }
48
49 chan->ctx = malloc(sizeof(struct lttng_kernel_context));
50 if (chan->ctx == NULL) {
51 perror("malloc event context");
52 goto error;
53 }
54
55 memcpy(chan->ctx, ctx, sizeof(struct lttng_kernel_context));
56
57 return 0;
58
59 error:
60 return ret;
61 }
62
63 /*
64 * kernel_add_event_context
65 *
66 * Add context on a kernel event.
67 */
68 int kernel_add_event_context(struct ltt_kernel_event *event,
69 struct lttng_kernel_context *ctx)
70 {
71 int ret;
72
73 DBG("Adding context to event %s", event->event->name);
74 ret = kernctl_add_context(event->fd, ctx);
75 if (ret < 0) {
76 perror("add context ioctl");
77 goto error;
78 }
79
80 event->ctx = malloc(sizeof(struct lttng_kernel_context));
81 if (event->ctx == NULL) {
82 perror("malloc event context");
83 goto error;
84 }
85
86 memcpy(event->ctx, ctx, sizeof(struct lttng_kernel_context));
87
88 return 0;
89
90 error:
91 return ret;
92 }
93
94 /*
95 * kernel_create_session
96 *
97 * Create a new kernel session, register it to the kernel tracer and add it to
98 * the session daemon session.
99 */
100 int kernel_create_session(struct ltt_session *session, int tracer_fd)
101 {
102 int ret;
103 struct ltt_kernel_session *lks;
104
105 /* Allocate data structure */
106 lks = trace_create_kernel_session();
107 if (lks == NULL) {
108 ret = -1;
109 goto error;
110 }
111
112 /* Kernel tracer session creation */
113 ret = kernctl_create_session(tracer_fd);
114 if (ret < 0) {
115 perror("ioctl kernel create session");
116 goto error;
117 }
118
119 lks->fd = ret;
120 /* Prevent fd duplication after execlp() */
121 ret = fcntl(lks->fd, F_SETFD, FD_CLOEXEC);
122 if (ret < 0) {
123 perror("fcntl session fd");
124 }
125
126 lks->kconsumer_fds_sent = 0;
127 session->kernel_session = lks;
128 session->kern_session_count++;
129
130 DBG("Kernel session created (fd: %d)", lks->fd);
131
132 return 0;
133
134 error:
135 return ret;
136 }
137
138 /*
139 * kernel_create_channel
140 *
141 * Create a kernel channel, register it to the kernel tracer and add it to the
142 * kernel session.
143 */
144 int kernel_create_channel(struct ltt_kernel_session *session, struct lttng_channel *chan)
145 {
146 int ret;
147 struct ltt_kernel_channel *lkc;
148
149 /* Allocate kernel channel */
150 lkc = trace_create_kernel_channel(chan);
151 if (lkc == NULL) {
152 goto error;
153 }
154
155 /* Kernel tracer channel creation */
156 ret = kernctl_create_channel(session->fd, &lkc->channel->attr);
157 if (ret < 0) {
158 perror("ioctl kernel create channel");
159 goto error;
160 }
161
162 /* Setup the channel fd */
163 lkc->fd = ret;
164 /* Prevent fd duplication after execlp() */
165 ret = fcntl(lkc->fd, F_SETFD, FD_CLOEXEC);
166 if (ret < 0) {
167 perror("fcntl session fd");
168 }
169
170 /* Add channel to session */
171 cds_list_add(&lkc->list, &session->channel_list.head);
172 session->channel_count++;
173
174 DBG("Kernel channel %s created (fd: %d and path: %s)",
175 lkc->channel->name, lkc->fd, lkc->pathname);
176
177 return 0;
178
179 error:
180 return -1;
181 }
182
183 /*
184 * kernel_create_event
185 *
186 * Create a kernel event, enable it to the kernel tracer and add it to the
187 * channel event list of the kernel session.
188 */
189 int kernel_create_event(struct lttng_event *ev, struct ltt_kernel_channel *channel)
190 {
191 int ret;
192 struct ltt_kernel_event *event;
193
194 event = trace_create_kernel_event(ev);
195 if (event == NULL) {
196 goto error;
197 }
198
199 ret = kernctl_create_event(channel->fd, event->event);
200 if (ret < 0) {
201 perror("create event ioctl");
202 goto free_event;
203 }
204
205 event->fd = ret;
206 /* Prevent fd duplication after execlp() */
207 ret = fcntl(event->fd, F_SETFD, FD_CLOEXEC);
208 if (ret < 0) {
209 perror("fcntl session fd");
210 }
211
212 /* Add event to event list */
213 cds_list_add(&event->list, &channel->events_list.head);
214 DBG("Event %s created (fd: %d)", ev->name, event->fd);
215
216 return 0;
217
218 free_event:
219 free(event);
220 error:
221 return -1;
222 }
223
224 /*
225 * kernel_disable_channel
226 *
227 * Disable a kernel channel.
228 */
229 int kernel_disable_channel(struct ltt_kernel_channel *chan)
230 {
231 int ret;
232
233 ret = kernctl_disable(chan->fd);
234 if (ret < 0) {
235 perror("disable chan ioctl");
236 ret = errno;
237 goto error;
238 }
239
240 chan->enabled = 0;
241 DBG("Kernel channel %s disabled (fd: %d)", chan->channel->name, chan->fd);
242
243 return 0;
244
245 error:
246 return ret;
247 }
248
249 /*
250 * kernel_enable_channel
251 *
252 * Enable a kernel channel.
253 */
254 int kernel_enable_channel(struct ltt_kernel_channel *chan)
255 {
256 int ret;
257
258 ret = kernctl_enable(chan->fd);
259 if (ret < 0) {
260 perror("enable chan ioctl");
261 ret = errno;
262 goto error;
263 }
264
265 chan->enabled = 1;
266 DBG("Kernel channel %s enabled (fd: %d)", chan->channel->name, chan->fd);
267
268 return 0;
269
270 error:
271 return ret;
272 }
273
274 /*
275 * kernel_enable_event
276 *
277 * Enable a kernel event.
278 */
279 int kernel_enable_event(struct ltt_kernel_event *event)
280 {
281 int ret;
282
283 ret = kernctl_enable(event->fd);
284 if (ret < 0) {
285 perror("enable event ioctl");
286 goto error;
287 }
288
289 event->enabled = 1;
290 DBG("Kernel event %s enabled (fd: %d)", event->event->name, event->fd);
291
292 return 0;
293
294 error:
295 return ret;
296 }
297
298 /*
299 * kernel_disable_event
300 *
301 * Disable a kernel event.
302 */
303 int kernel_disable_event(struct ltt_kernel_event *event)
304 {
305 int ret;
306
307 ret = kernctl_disable(event->fd);
308 if (ret < 0) {
309 perror("disable event ioctl");
310 goto error;
311 }
312
313 event->enabled = 0;
314 DBG("Kernel event %s disabled (fd: %d)", event->event->name, event->fd);
315
316 return 0;
317
318 error:
319 return ret;
320 }
321
322 /*
323 * kernel_open_metadata
324 *
325 * Create kernel metadata, open from the kernel tracer and add it to the
326 * kernel session.
327 */
328 int kernel_open_metadata(struct ltt_kernel_session *session)
329 {
330 int ret;
331 struct ltt_kernel_metadata *lkm;
332
333 /* Allocate kernel metadata */
334 lkm = trace_create_kernel_metadata();
335 if (lkm == NULL) {
336 goto error;
337 }
338
339 /* Kernel tracer metadata creation */
340 ret = kernctl_open_metadata(session->fd, &lkm->conf->attr);
341 if (ret < 0) {
342 goto error;
343 }
344
345 lkm->fd = ret;
346 /* Prevent fd duplication after execlp() */
347 ret = fcntl(lkm->fd, F_SETFD, FD_CLOEXEC);
348 if (ret < 0) {
349 perror("fcntl session fd");
350 }
351
352 session->metadata = lkm;
353
354 DBG("Kernel metadata opened (fd: %d and path: %s)", lkm->fd, lkm->pathname);
355
356 return 0;
357
358 error:
359 return -1;
360 }
361
362 /*
363 * kernel_start_session
364 *
365 * Start tracing session.
366 */
367 int kernel_start_session(struct ltt_kernel_session *session)
368 {
369 int ret;
370
371 ret = kernctl_start_session(session->fd);
372 if (ret < 0) {
373 perror("ioctl start session");
374 goto error;
375 }
376
377 DBG("Kernel session started");
378
379 return 0;
380
381 error:
382 return ret;
383 }
384
385 /*
386 * kernel_wait_quiescent
387 *
388 * Make a kernel wait to make sure in-flight probe have completed.
389 */
390 void kernel_wait_quiescent(int fd)
391 {
392 int ret;
393
394 DBG("Kernel quiescent wait on %d", fd);
395
396 ret = kernctl_wait_quiescent(fd);
397 if (ret < 0) {
398 perror("wait quiescent ioctl");
399 ERR("Kernel quiescent wait failed");
400 }
401 }
402
403 /*
404 * kernel_metadata_flush_buffer
405 *
406 * Force flush buffer of metadata.
407 */
408 int kernel_metadata_flush_buffer(int fd)
409 {
410 int ret;
411
412 ret = kernctl_buffer_flush(fd);
413 if (ret < 0) {
414 ERR("Fail to flush metadata buffers %d (ret: %d", fd, ret);
415 }
416
417 return 0;
418 }
419
420 /*
421 * kernel_flush_buffer
422 *
423 * Force flush buffer for channel.
424 */
425 int kernel_flush_buffer(struct ltt_kernel_channel *channel)
426 {
427 int ret;
428 struct ltt_kernel_stream *stream;
429
430 DBG("Flush buffer for channel %s", channel->channel->name);
431
432 cds_list_for_each_entry(stream, &channel->stream_list.head, list) {
433 DBG("Flushing channel stream %d", stream->fd);
434 ret = kernctl_buffer_flush(stream->fd);
435 if (ret < 0) {
436 perror("ioctl");
437 ERR("Fail to flush buffer for stream %d (ret: %d)",
438 stream->fd, ret);
439 }
440 }
441
442 return 0;
443 }
444
445 /*
446 * kernel_stop_session
447 *
448 * Stop tracing session.
449 */
450 int kernel_stop_session(struct ltt_kernel_session *session)
451 {
452 int ret;
453
454 ret = kernctl_stop_session(session->fd);
455 if (ret < 0) {
456 goto error;
457 }
458
459 DBG("Kernel session stopped");
460
461 return 0;
462
463 error:
464 return ret;
465 }
466
467 /*
468 * kernel_open_channel_stream
469 *
470 * Open stream of channel, register it to the kernel tracer and add it
471 * to the stream list of the channel.
472 *
473 * Return the number of created stream. Else, a negative value.
474 */
475 int kernel_open_channel_stream(struct ltt_kernel_channel *channel)
476 {
477 int ret;
478 struct ltt_kernel_stream *lks;
479
480 while ((ret = kernctl_create_stream(channel->fd)) > 0) {
481 lks = trace_create_kernel_stream();
482 if (lks == NULL) {
483 close(ret);
484 goto error;
485 }
486
487 lks->fd = ret;
488 /* Prevent fd duplication after execlp() */
489 ret = fcntl(lks->fd, F_SETFD, FD_CLOEXEC);
490 if (ret < 0) {
491 perror("fcntl session fd");
492 }
493
494 ret = asprintf(&lks->pathname, "%s/trace_%d",
495 channel->pathname, channel->stream_count);
496 if (ret < 0) {
497 perror("asprintf kernel create stream");
498 goto error;
499 }
500
501 /* Add stream to channe stream list */
502 cds_list_add(&lks->list, &channel->stream_list.head);
503 channel->stream_count++;
504
505 DBG("Kernel stream %d created (fd: %d, state: %d, path: %s)",
506 channel->stream_count, lks->fd, lks->state, lks->pathname);
507 }
508
509 return channel->stream_count;
510
511 error:
512 return -1;
513 }
514
515 /*
516 * kernel_open_metadata_stream
517 *
518 * Open the metadata stream and set it to the kernel session.
519 */
520 int kernel_open_metadata_stream(struct ltt_kernel_session *session)
521 {
522 int ret;
523
524 ret = kernctl_create_stream(session->metadata->fd);
525 if (ret < 0) {
526 perror("kernel create metadata stream");
527 goto error;
528 }
529
530 DBG("Kernel metadata stream created (fd: %d)", ret);
531 session->metadata_stream_fd = ret;
532 /* Prevent fd duplication after execlp() */
533 ret = fcntl(session->metadata_stream_fd, F_SETFD, FD_CLOEXEC);
534 if (ret < 0) {
535 perror("fcntl session fd");
536 }
537
538 return 0;
539
540 error:
541 return -1;
542 }
543
544 /*
545 * kernel_list_events
546 *
547 * Get the event list from the kernel tracer and return that list in the CTF
548 * format.
549 */
550 ssize_t kernel_list_events(int tracer_fd, char **list)
551 {
552 int fd;
553 char *buf, *line = NULL;
554 size_t nb, nbmem, total = 0;
555 ssize_t size;
556 FILE *fp;
557
558 fd = kernctl_tracepoint_list(tracer_fd);
559 if (fd < 0) {
560 perror("kernel tracepoint list");
561 goto error;
562 }
563
564 fp = fdopen(fd, "r");
565 if (fp == NULL) {
566 perror("kernel tracepoint list fdopen");
567 goto error;
568 }
569
570 /*
571 * Init memory size counter
572 * See kernel-ctl.h for explanation of this value
573 */
574 nbmem = KERNEL_EVENT_LIST_SIZE;
575 buf = malloc(nbmem);
576
577 while ((size = getline(&line, &nb, fp)) != -1) {
578 if (total + size > nbmem) {
579 DBG("Reallocating event list from %zd to %zd bytes", nbmem,
580 total + size + KERNEL_EVENT_LIST_SIZE);
581 /* Adding the default size again */
582 nbmem = total + size + KERNEL_EVENT_LIST_SIZE;
583 buf = realloc(buf, nbmem);
584 if (buf == NULL) {
585 perror("realloc list events");
586 goto error;
587 }
588 }
589 memcpy(buf + total, line, size);
590 total += size;
591 }
592
593 *list = buf;
594
595 DBG("Kernel list events done");
596
597 return total;
598
599 error:
600 return -1;
601 }
This page took 0.039847 seconds and 3 git commands to generate.