3 * Linux Trace Toolkit Daemon
5 * This is a simple daemon that reads a few relay+debugfs channels and save
8 * CPU hot-plugging is supported using inotify.
11 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
26 #include <sys/types.h>
34 #include <sys/syscall.h>
36 #include <asm/ioctls.h>
38 #include <linux/version.h>
41 #include <asm/ioctl.h>
42 #include <asm/types.h>
44 /* Get the next sub buffer that can be read. */
45 #define RELAY_GET_SB _IOR(0xF5, 0x00,__u32)
46 /* Release the oldest reserved (by "get") sub buffer. */
47 #define RELAY_PUT_SB _IOW(0xF5, 0x01,__u32)
48 /* returns the number of sub buffers in the per cpu channel. */
49 #define RELAY_GET_N_SB _IOR(0xF5, 0x02,__u32)
50 /* returns the size of the current sub buffer. */
51 #define RELAY_GET_SB_SIZE _IOR(0xF5, 0x03, __u32)
52 /* returns the size of data to consume in the current sub-buffer. */
53 #define RELAY_GET_MAX_SB_SIZE _IOR(0xF5, 0x04, __u32)
56 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
57 #include <sys/inotify.h>
61 static inline int inotify_init (void)
66 static inline int inotify_add_watch (int fd
, const char *name
, __u32 mask
)
71 static inline int inotify_rm_watch (int fd
, __u32 wd
)
78 struct liblttd_callbacks
*callbacks
;
80 struct channel_trace_fd
{
85 struct inotify_watch
{
87 char path_channel
[PATH_MAX
];
88 char *base_path_channel
;
91 struct inotify_watch_array
{
92 struct inotify_watch
*elem
;
96 struct channel_trace_fd fd_pairs
= { NULL
, 0 };
98 struct inotify_watch_array inotify_watch_array
= { NULL
, 0 };
100 /* protects fd_pairs and inotify_watch_array */
101 pthread_rwlock_t fd_pairs_lock
= PTHREAD_RWLOCK_INITIALIZER
;
103 static char *channel_name
= NULL
;
104 static unsigned long num_threads
= 1;
105 volatile static int quit_program
= 0; /* For signal handler */
106 static int dump_flight_only
= 0;
107 static int dump_normal_only
= 0;
108 static int verbose_mode
= 0;
110 #define printf_verbose(fmt, args...) \
113 printf(fmt, ##args); \
117 int open_buffer_file(char *filename
, char *path_channel
,
118 char *base_path_channel
, struct channel_trace_fd
*fd_pairs
)
123 if(strncmp(filename
, "flight-", sizeof("flight-")-1) != 0) {
124 if(dump_flight_only
) {
125 printf_verbose("Skipping normal channel %s\n",
130 if(dump_normal_only
) {
131 printf_verbose("Skipping flight channel %s\n",
136 printf_verbose("Opening file.\n");
138 fd_pairs
->pair
= realloc(fd_pairs
->pair
,
139 ++fd_pairs
->num_pairs
* sizeof(struct fd_pair
));
141 /* Open the channel in read mode */
142 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
=
143 open(path_channel
, O_RDONLY
| O_NONBLOCK
);
144 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
== -1) {
145 perror(path_channel
);
146 fd_pairs
->num_pairs
--;
147 return 0; /* continue */
150 if(callbacks
->on_open_channel
) ret
= callbacks
->on_open_channel(
151 callbacks
, &fd_pairs
->pair
[fd_pairs
->num_pairs
-1],
156 close(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
);
157 fd_pairs
->num_pairs
--;
165 int open_channel_trace_pairs(char *subchannel_name
,
166 char *base_subchannel_name
,
167 struct channel_trace_fd
*fd_pairs
, int *inotify_fd
,
168 struct inotify_watch_array
*iwatch_array
)
170 DIR *channel_dir
= opendir(subchannel_name
);
171 struct dirent
*entry
;
172 struct stat stat_buf
;
174 char path_channel
[PATH_MAX
];
175 int path_channel_len
;
176 char *path_channel_ptr
;
177 char *base_subchannel_ptr
;
181 if(channel_dir
== NULL
) {
182 perror(subchannel_name
);
187 printf_verbose("Calling on new channels folder");
188 if(callbacks
->on_new_channels_folder
) ret
= callbacks
->
189 on_new_channels_folder(callbacks
,
190 base_subchannel_name
);
196 strncpy(path_channel
, subchannel_name
, PATH_MAX
-1);
197 path_channel_len
= strlen(path_channel
);
198 path_channel
[path_channel_len
] = '/';
200 path_channel_ptr
= path_channel
+ path_channel_len
;
201 base_subchannel_ptr
= path_channel
+
202 (base_subchannel_name
- subchannel_name
);
205 iwatch_array
->elem
= realloc(iwatch_array
->elem
,
206 ++iwatch_array
->num
* sizeof(struct inotify_watch
));
208 printf_verbose("Adding inotify for channel %s\n", path_channel
);
209 iwatch_array
->elem
[iwatch_array
->num
-1].wd
= inotify_add_watch(*inotify_fd
, path_channel
, IN_CREATE
);
210 strcpy(iwatch_array
->elem
[iwatch_array
->num
-1].path_channel
, path_channel
);
211 iwatch_array
->elem
[iwatch_array
->num
-1].base_path_channel
=
212 iwatch_array
->elem
[iwatch_array
->num
-1].path_channel
+
213 (base_subchannel_name
- subchannel_name
);
214 printf_verbose("Added inotify for channel %s, wd %u\n",
215 iwatch_array
->elem
[iwatch_array
->num
-1].path_channel
,
216 iwatch_array
->elem
[iwatch_array
->num
-1].wd
);
219 while((entry
= readdir(channel_dir
)) != NULL
) {
221 if(entry
->d_name
[0] == '.') continue;
223 strncpy(path_channel_ptr
, entry
->d_name
, PATH_MAX
- path_channel_len
);
225 ret
= stat(path_channel
, &stat_buf
);
227 perror(path_channel
);
231 printf_verbose("Channel file : %s\n", path_channel
);
233 if(S_ISDIR(stat_buf
.st_mode
)) {
235 printf_verbose("Entering channel subdirectory...\n");
236 ret
= open_channel_trace_pairs(path_channel
, base_subchannel_ptr
, fd_pairs
,
237 inotify_fd
, iwatch_array
);
238 if(ret
< 0) continue;
239 } else if(S_ISREG(stat_buf
.st_mode
)) {
240 open_ret
= open_buffer_file(entry
->d_name
, path_channel
, base_subchannel_ptr
,
248 closedir(channel_dir
);
254 int read_subbuffer(struct fd_pair
*pair
)
256 unsigned int consumed_old
, len
;
262 err
= ioctl(pair
->channel
, RELAY_GET_SB
, &consumed_old
);
263 printf_verbose("cookie : %u\n", consumed_old
);
266 perror("Reserving sub buffer failed (everything is normal, it is due to concurrency)");
270 err
= ioctl(pair
->channel
, RELAY_GET_SB_SIZE
, &len
);
273 perror("Getting sub-buffer len failed.");
277 if(callbacks
->on_read_subbuffer
) ret
= callbacks
->on_read_subbuffer(
278 callbacks
, pair
, len
);
282 err
= ioctl(pair
->channel
, RELAY_PUT_SB
, &consumed_old
);
285 if(errno
== EFAULT
) {
286 perror("Error in unreserving sub buffer\n");
287 } else if(errno
== EIO
) {
288 /* Should never happen with newer LTTng versions */
289 perror("Reader has been pushed by the writer, last sub-buffer corrupted.");
299 int map_channels(struct channel_trace_fd
*fd_pairs
,
300 int idx_begin
, int idx_end
)
305 if(fd_pairs
->num_pairs
<= 0) {
306 printf("No channel to read\n");
310 /* Get the subbuf sizes and number */
312 for(i
=idx_begin
;i
<idx_end
;i
++) {
313 struct fd_pair
*pair
= &fd_pairs
->pair
[i
];
315 ret
= ioctl(pair
->channel
, RELAY_GET_N_SB
, &pair
->n_sb
);
317 perror("Error in getting the number of sub-buffers");
320 ret
= ioctl(pair
->channel
, RELAY_GET_MAX_SB_SIZE
,
323 perror("Error in getting the max sub-buffer size");
326 ret
= pthread_mutex_init(&pair
->mutex
, NULL
); /* Fast mutex */
328 perror("Error in mutex init");
337 int unmap_channels(struct channel_trace_fd
*fd_pairs
)
343 for(j
=0;j
<fd_pairs
->num_pairs
;j
++) {
344 struct fd_pair
*pair
= &fd_pairs
->pair
[j
];
347 err_ret
= pthread_mutex_destroy(&pair
->mutex
);
349 perror("Error in mutex destroy");
358 /* Inotify event arrived.
360 * Only support add file for now.
363 int read_inotify(int inotify_fd
,
364 struct channel_trace_fd
*fd_pairs
,
365 struct inotify_watch_array
*iwatch_array
)
367 char buf
[sizeof(struct inotify_event
) + PATH_MAX
];
368 char path_channel
[PATH_MAX
];
370 struct inotify_event
*ievent
;
377 len
= read(inotify_fd
, buf
, sizeof(struct inotify_event
) + PATH_MAX
);
381 return 0; /* another thread got the data before us */
383 printf("Error in read from inotify FD %s.\n", strerror(len
));
386 while(offset
< len
) {
387 ievent
= (struct inotify_event
*)&(buf
[offset
]);
388 for(i
=0; i
<iwatch_array
->num
; i
++) {
389 if(iwatch_array
->elem
[i
].wd
== ievent
->wd
&&
390 ievent
->mask
== IN_CREATE
) {
392 "inotify wd %u event mask : %u for %s%s\n",
393 ievent
->wd
, ievent
->mask
,
394 iwatch_array
->elem
[i
].path_channel
,
396 old_num
= fd_pairs
->num_pairs
;
397 strcpy(path_channel
, iwatch_array
->elem
[i
].path_channel
);
398 strcat(path_channel
, ievent
->name
);
399 if(ret
= open_buffer_file(ievent
->name
, path_channel
,
400 path_channel
+ (iwatch_array
->elem
[i
].base_path_channel
-
401 iwatch_array
->elem
[i
].path_channel
), fd_pairs
)) {
402 printf("Error opening buffer file\n");
405 if(ret
= map_channels(fd_pairs
, old_num
, fd_pairs
->num_pairs
)) {
406 printf("Error mapping channel\n");
412 offset
+= sizeof(*ievent
) + ievent
->len
;
421 * Read the debugfs channels and write them in the paired tracefiles.
423 * @fd_pairs : paired channels and trace files.
425 * returns 0 on success, -1 on error.
427 * Note that the high priority polled channels are consumed first. We then poll
428 * again to see if these channels are still in priority. Only when no
429 * high priority channel is left, we start reading low priority channels.
431 * Note that a channel is considered high priority when the buffer is almost
435 int read_channels(unsigned long thread_num
, struct channel_trace_fd
*fd_pairs
,
436 int inotify_fd
, struct inotify_watch_array
*iwatch_array
)
438 struct pollfd
*pollfd
= NULL
;
441 int num_rdy
, num_hup
;
445 unsigned int old_num
;
453 pthread_rwlock_rdlock(&fd_pairs_lock
);
455 /* Start polling the FD. Keep one fd for inotify */
456 pollfd
= malloc((inotify_fds
+ fd_pairs
->num_pairs
) * sizeof(struct pollfd
));
459 pollfd
[0].fd
= inotify_fd
;
460 pollfd
[0].events
= POLLIN
|POLLPRI
;
463 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
464 pollfd
[inotify_fds
+i
].fd
= fd_pairs
->pair
[i
].channel
;
465 pollfd
[inotify_fds
+i
].events
= POLLIN
|POLLPRI
;
467 num_pollfd
= inotify_fds
+ fd_pairs
->num_pairs
;
470 pthread_rwlock_unlock(&fd_pairs_lock
);
476 printf("Press a key for next poll...\n");
478 read(STDIN_FILENO
, &buf
, 1);
479 printf("Next poll (polling %d fd) :\n", num_pollfd
);
482 /* Have we received a signal ? */
483 if(quit_program
) break;
485 num_rdy
= poll(pollfd
, num_pollfd
, -1);
488 perror("Poll error");
492 printf_verbose("Data received\n");
494 switch(pollfd
[0].revents
) {
497 "Error returned in polling inotify fd %d.\n",
502 "Polling inotify fd %d tells it has hung up.\n",
507 "Polling inotify fd %d tells fd is not open.\n",
513 "Polling inotify fd %d : data ready.\n",
516 pthread_rwlock_wrlock(&fd_pairs_lock
);
517 read_inotify(inotify_fd
, fd_pairs
, iwatch_array
);
518 pthread_rwlock_unlock(&fd_pairs_lock
);
524 for(i
=inotify_fds
;i
<num_pollfd
;i
++) {
525 switch(pollfd
[i
].revents
) {
528 "Error returned in polling fd %d.\n",
534 "Polling fd %d tells it has hung up.\n",
540 "Polling fd %d tells fd is not open.\n",
545 pthread_rwlock_rdlock(&fd_pairs_lock
);
546 if(pthread_mutex_trylock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
) == 0) {
548 "Urgent read on fd %d\n",
550 /* Take care of high priority channels first. */
552 /* it's ok to have an unavailable sub-buffer */
553 ret
= read_subbuffer(&fd_pairs
->pair
[i
-inotify_fds
]);
554 if(ret
== EAGAIN
) ret
= 0;
556 ret
= pthread_mutex_unlock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
);
558 printf("Error in mutex unlock : %s\n", strerror(ret
));
560 pthread_rwlock_unlock(&fd_pairs_lock
);
564 /* If every buffer FD has hung up, we end the read loop here */
565 if(num_hup
== num_pollfd
- inotify_fds
) break;
568 for(i
=inotify_fds
;i
<num_pollfd
;i
++) {
569 switch(pollfd
[i
].revents
) {
571 pthread_rwlock_rdlock(&fd_pairs_lock
);
572 if(pthread_mutex_trylock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
) == 0) {
573 /* Take care of low priority channels. */
575 "Normal read on fd %d\n",
577 /* it's ok to have an unavailable subbuffer */
578 ret
= read_subbuffer(&fd_pairs
->pair
[i
-inotify_fds
]);
579 if(ret
== EAGAIN
) ret
= 0;
581 ret
= pthread_mutex_unlock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
);
583 printf("Error in mutex unlock : %s\n", strerror(ret
));
585 pthread_rwlock_unlock(&fd_pairs_lock
);
591 /* Update pollfd array if an entry was added to fd_pairs */
592 pthread_rwlock_rdlock(&fd_pairs_lock
);
593 if((inotify_fds
+ fd_pairs
->num_pairs
) != num_pollfd
) {
594 pollfd
= realloc(pollfd
,
595 (inotify_fds
+ fd_pairs
->num_pairs
) * sizeof(struct pollfd
));
596 for(i
=num_pollfd
-inotify_fds
;i
<fd_pairs
->num_pairs
;i
++) {
597 pollfd
[inotify_fds
+i
].fd
= fd_pairs
->pair
[i
].channel
;
598 pollfd
[inotify_fds
+i
].events
= POLLIN
|POLLPRI
;
600 num_pollfd
= fd_pairs
->num_pairs
+ inotify_fds
;
602 pthread_rwlock_unlock(&fd_pairs_lock
);
604 /* NB: If the fd_pairs structure is updated by another thread from this
605 * point forward, the current thread will wait in the poll without
606 * monitoring the new channel. However, this thread will add the
607 * new channel on next poll (and this should not take too much time
608 * on a loaded system).
610 * This event is quite unlikely and can only occur if a CPU is
611 * hot-plugged while multple lttd threads are running.
623 void close_channel_trace_pairs(struct channel_trace_fd
*fd_pairs
, int inotify_fd
,
624 struct inotify_watch_array
*iwatch_array
)
629 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
630 ret
= close(fd_pairs
->pair
[i
].channel
);
631 if(ret
== -1) perror("Close error on channel");
632 if(callbacks
->on_close_channel
) {
633 ret
= callbacks
->on_close_channel(
634 callbacks
, &fd_pairs
->pair
[i
]);
635 if(ret
!= 0) perror("Error on close channel callback");
638 free(fd_pairs
->pair
);
639 free(iwatch_array
->elem
);
643 void * thread_main(void *arg
)
646 unsigned long thread_num
= (unsigned long)arg
;
648 if(callbacks
->on_new_thread
)
649 ret
= callbacks
->on_new_thread(callbacks
, thread_num
);
654 ret
= read_channels(thread_num
, &fd_pairs
, inotify_fd
, &inotify_watch_array
);
656 if(callbacks
->on_close_thread
)
657 callbacks
->on_close_thread(callbacks
, thread_num
);
662 /*on_close_thread has to be reentrant, it'll be called by many threads*/
663 int(*on_close_thread
)(struct liblttd_callbacks
*data
, unsigned long thread_num
);
669 inotify_fd
= inotify_init();
670 fcntl(inotify_fd
, F_SETFL
, O_NONBLOCK
);
672 if(ret
= open_channel_trace_pairs(channel_name
,
673 channel_name
+ strlen(channel_name
), &fd_pairs
,
674 &inotify_fd
, &inotify_watch_array
))
676 if (fd_pairs
.num_pairs
== 0) {
677 printf("No channel available for reading, exiting\n");
681 if(ret
= map_channels(&fd_pairs
, 0, fd_pairs
.num_pairs
))
686 close_channel_trace_pairs(&fd_pairs
, inotify_fd
, &inotify_watch_array
);
692 int liblttd_start(char *channel_path
, unsigned long n_threads
,
693 int flight_only
, int normal_only
, int verbose
,
694 struct liblttd_callbacks
*user_data
){
700 channel_name
= channel_path
;
701 num_threads
= n_threads
;
702 dump_flight_only
= flight_only
;
703 dump_normal_only
= normal_only
;
704 verbose_mode
= verbose
;
705 callbacks
= user_data
;
707 if(ret
= channels_init())
710 tids
= malloc(sizeof(pthread_t
) * num_threads
);
711 for(i
=0; i
<num_threads
; i
++) {
713 ret
= pthread_create(&tids
[i
], NULL
, thread_main
, (void*)i
);
715 perror("Error creating thread");
720 for(i
=0; i
<num_threads
; i
++) {
721 ret
= pthread_join(tids
[i
], &tret
);
723 perror("Error joining thread");
726 if((long)tret
!= 0) {
727 printf("Error %s occured in thread %ld\n",
728 strerror((long)tret
), i
);
733 ret
= unmap_channels(&fd_pairs
);
734 close_channel_trace_pairs(&fd_pairs
, inotify_fd
, &inotify_watch_array
);
738 if(callbacks
->on_trace_end
) callbacks
->on_trace_end(callbacks
);