3 * Linux Trace Toolkit Daemon
5 * This is a simple daemon that reads a few relay+debugfs channels and save
10 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
23 #include <sys/types.h>
33 #include <sys/syscall.h>
35 #include <asm/ioctls.h>
37 #include <linux/version.h>
40 #include <asm/ioctl.h>
41 #include <asm/types.h>
43 /* Get the next sub buffer that can be read. */
44 #define RELAY_GET_SUBBUF _IOR(0xF4, 0x00,__u32)
45 /* Release the oldest reserved (by "get") sub buffer. */
46 #define RELAY_PUT_SUBBUF _IOW(0xF4, 0x01,__u32)
47 /* returns the number of sub buffers in the per cpu channel. */
48 #define RELAY_GET_N_SUBBUFS _IOR(0xF4, 0x02,__u32)
49 /* returns the size of the sub buffers. */
50 #define RELAY_GET_SUBBUF_SIZE _IOR(0xF4, 0x03,__u32)
52 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
53 #include <linux/inotify.h>
54 /* From the inotify-tools 2.6 package */
55 static inline int inotify_init (void)
57 return syscall (__NR_inotify_init
);
60 static inline int inotify_add_watch (int fd
, const char *name
, __u32 mask
)
62 return syscall (__NR_inotify_add_watch
, fd
, name
, mask
);
65 static inline int inotify_rm_watch (int fd
, __u32 wd
)
67 return syscall (__NR_inotify_rm_watch
, fd
, wd
);
71 static inline int inotify_init (void)
76 static inline int inotify_add_watch (int fd
, const char *name
, __u32 mask
)
81 static inline int inotify_rm_watch (int fd
, __u32 wd
)
98 unsigned int n_subbufs
;
99 unsigned int subbuf_size
;
101 pthread_mutex_t mutex
;
104 struct channel_trace_fd
{
105 struct fd_pair
*pair
;
109 struct inotify_watch
{
111 char path_channel
[PATH_MAX
];
112 char path_trace
[PATH_MAX
];
115 struct inotify_watch_array
{
116 struct inotify_watch
*elem
;
120 static char *trace_name
= NULL
;
121 static char *channel_name
= NULL
;
122 static int daemon_mode
= 0;
123 static int append_mode
= 0;
124 static unsigned long num_threads
= 1;
125 volatile static int quit_program
= 0; /* For signal handler */
126 static int dump_flight_only
= 0;
127 static int dump_normal_only
= 0;
131 * -t directory Directory name of the trace to write to. Will be created.
132 * -c directory Root directory of the debugfs trace channels.
133 * -d Run in background (daemon).
134 * -a Trace append mode.
135 * -s Send SIGUSR1 to parent when ready for IO.
137 void show_arguments(void)
139 printf("Please use the following arguments :\n");
141 printf("-t directory Directory name of the trace to write to.\n"
142 " It will be created.\n");
143 printf("-c directory Root directory of the debugfs trace channels.\n");
144 printf("-d Run in background (daemon).\n");
145 printf("-a Append to an possibly existing trace.\n");
146 printf("-N Number of threads to start.\n");
147 printf("-f Dump only flight recorder channels.\n");
148 printf("-n Dump only normal channels.\n");
155 * Parses the command line arguments.
157 * Returns 1 if the arguments were correct, but doesn't ask for program
158 * continuation. Returns -1 if the arguments are incorrect, or 0 if OK.
160 int parse_arguments(int argc
, char **argv
)
166 if(strcmp(argv
[1], "-h") == 0) {
173 switch(argv
[argn
][0]) {
175 switch(argv
[argn
][1]) {
178 trace_name
= argv
[argn
+1];
184 channel_name
= argv
[argn
+1];
196 num_threads
= strtoul(argv
[argn
+1], NULL
, 0);
201 dump_flight_only
= 1;
204 dump_normal_only
= 1;
207 printf("Invalid argument '%s'.\n", argv
[argn
]);
213 printf("Invalid argument '%s'.\n", argv
[argn
]);
220 if(trace_name
== NULL
) {
221 printf("Please specify a trace name.\n");
226 if(channel_name
== NULL
) {
227 printf("Please specify a channel name.\n");
237 printf("Linux Trace Toolkit Trace Daemon " VERSION
"\n");
239 printf("Reading from debugfs directory : %s\n", channel_name
);
240 printf("Writing to trace directory : %s\n", trace_name
);
245 /* signal handling */
247 static void handler(int signo
)
249 printf("Signal %d received : exiting cleanly\n", signo
);
254 int open_buffer_file(char *filename
, char *path_channel
, char *path_trace
,
255 struct channel_trace_fd
*fd_pairs
)
259 struct stat stat_buf
;
261 if(strncmp(filename
, "flight-", sizeof("flight-")-1) != 0) {
262 if(dump_flight_only
) {
263 printf("Skipping normal channel %s\n", path_channel
);
267 if(dump_normal_only
) {
268 printf("Skipping flight channel %s\n", path_channel
);
272 printf("Opening file.\n");
274 fd_pairs
->pair
= realloc(fd_pairs
->pair
,
275 ++fd_pairs
->num_pairs
* sizeof(struct fd_pair
));
277 /* Open the channel in read mode */
278 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
=
279 open(path_channel
, O_RDONLY
| O_NONBLOCK
);
280 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
== -1) {
281 perror(path_channel
);
282 fd_pairs
->num_pairs
--;
283 return 0; /* continue */
285 /* Open the trace in write mode, only append if append_mode */
286 ret
= stat(path_trace
, &stat_buf
);
289 printf("Appending to file %s as requested\n", path_trace
);
291 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
=
292 open(path_trace
, O_WRONLY
|O_APPEND
,
293 S_IRWXU
|S_IRWXG
|S_IRWXO
);
295 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
== -1) {
299 printf("File %s exists, cannot open. Try append mode.\n", path_trace
);
304 if(errno
== ENOENT
) {
305 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
=
306 open(path_trace
, O_WRONLY
|O_CREAT
|O_EXCL
,
307 S_IRWXU
|S_IRWXG
|S_IRWXO
);
308 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
== -1) {
317 int open_channel_trace_pairs(char *subchannel_name
, char *subtrace_name
,
318 struct channel_trace_fd
*fd_pairs
, int *inotify_fd
,
319 struct inotify_watch_array
*iwatch_array
)
321 DIR *channel_dir
= opendir(subchannel_name
);
322 struct dirent
*entry
;
323 struct stat stat_buf
;
325 char path_channel
[PATH_MAX
];
326 int path_channel_len
;
327 char *path_channel_ptr
;
328 char path_trace
[PATH_MAX
];
330 char *path_trace_ptr
;
333 if(channel_dir
== NULL
) {
334 perror(subchannel_name
);
339 printf("Creating trace subdirectory %s\n", subtrace_name
);
340 ret
= mkdir(subtrace_name
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
342 if(errno
!= EEXIST
) {
343 perror(subtrace_name
);
349 strncpy(path_channel
, subchannel_name
, PATH_MAX
-1);
350 path_channel_len
= strlen(path_channel
);
351 path_channel
[path_channel_len
] = '/';
353 path_channel_ptr
= path_channel
+ path_channel_len
;
355 strncpy(path_trace
, subtrace_name
, PATH_MAX
-1);
356 path_trace_len
= strlen(path_trace
);
357 path_trace
[path_trace_len
] = '/';
359 path_trace_ptr
= path_trace
+ path_trace_len
;
362 iwatch_array
->elem
= realloc(iwatch_array
->elem
,
363 ++iwatch_array
->num
* sizeof(struct inotify_watch
));
365 printf("Adding inotify for channel %s\n", path_channel
);
366 iwatch_array
->elem
[iwatch_array
->num
-1].wd
= inotify_add_watch(*inotify_fd
, path_channel
, IN_CREATE
);
367 strcpy(iwatch_array
->elem
[iwatch_array
->num
-1].path_channel
, path_channel
);
368 strcpy(iwatch_array
->elem
[iwatch_array
->num
-1].path_trace
, path_trace
);
369 printf("Added inotify for channel %s, wd %u\n", iwatch_array
->elem
[iwatch_array
->num
-1].path_channel
,
370 iwatch_array
->elem
[iwatch_array
->num
-1].wd
);
373 while((entry
= readdir(channel_dir
)) != NULL
) {
375 if(entry
->d_name
[0] == '.') continue;
377 strncpy(path_channel_ptr
, entry
->d_name
, PATH_MAX
- path_channel_len
);
378 strncpy(path_trace_ptr
, entry
->d_name
, PATH_MAX
- path_trace_len
);
380 ret
= stat(path_channel
, &stat_buf
);
382 perror(path_channel
);
386 printf("Channel file : %s\n", path_channel
);
388 if(S_ISDIR(stat_buf
.st_mode
)) {
390 printf("Entering channel subdirectory...\n");
391 ret
= open_channel_trace_pairs(path_channel
, path_trace
, fd_pairs
,
392 inotify_fd
, iwatch_array
);
393 if(ret
< 0) continue;
394 } else if(S_ISREG(stat_buf
.st_mode
)) {
395 open_ret
= open_buffer_file(entry
->d_name
, path_channel
, path_trace
,
403 closedir(channel_dir
);
409 int read_subbuffer(struct fd_pair
*pair
)
411 unsigned int consumed_old
;
415 err
= ioctl(pair
->channel
, RELAY_GET_SUBBUF
,
417 printf("cookie : %u\n", consumed_old
);
420 perror("Reserving sub buffer failed (everything is normal, it is due to concurrency)");
424 err
= TEMP_FAILURE_RETRY(write(pair
->trace
,
426 + (consumed_old
& ((pair
->n_subbufs
* pair
->subbuf_size
)-1)),
431 perror("Error in writing to file");
435 err
= fsync(pair
->trace
);
438 perror("Error in writing to file");
443 err
= ioctl(pair
->channel
, RELAY_PUT_SUBBUF
, &consumed_old
);
446 if(errno
== EFAULT
) {
447 perror("Error in unreserving sub buffer\n");
448 } else if(errno
== EIO
) {
449 perror("Reader has been pushed by the writer, last subbuffer corrupted.");
450 /* FIXME : we may delete the last written buffer if we wish. */
461 int map_channels(struct channel_trace_fd
*fd_pairs
,
462 int idx_begin
, int idx_end
)
467 if(fd_pairs
->num_pairs
<= 0) {
468 printf("No channel to read\n");
472 /* Get the subbuf sizes and number */
474 for(i
=idx_begin
;i
<idx_end
;i
++) {
475 struct fd_pair
*pair
= &fd_pairs
->pair
[i
];
477 ret
= ioctl(pair
->channel
, RELAY_GET_N_SUBBUFS
,
480 perror("Error in getting the number of subbuffers");
483 ret
= ioctl(pair
->channel
, RELAY_GET_SUBBUF_SIZE
,
486 perror("Error in getting the size of the subbuffers");
489 ret
= pthread_mutex_init(&pair
->mutex
, NULL
); /* Fast mutex */
491 perror("Error in mutex init");
497 for(i
=idx_begin
;i
<idx_end
;i
++) {
498 struct fd_pair
*pair
= &fd_pairs
->pair
[i
];
500 pair
->mmap
= mmap(0, pair
->subbuf_size
* pair
->n_subbufs
, PROT_READ
,
501 MAP_SHARED
, pair
->channel
, 0);
502 if(pair
->mmap
== MAP_FAILED
) {
503 perror("Mmap error");
508 goto end
; /* success */
511 /* munmap only the successfully mmapped indexes */
514 for(j
=idx_begin
;j
<i
;j
++) {
515 struct fd_pair
*pair
= &fd_pairs
->pair
[j
];
518 err_ret
= munmap(pair
->mmap
, pair
->subbuf_size
* pair
->n_subbufs
);
520 perror("Error in munmap");
532 int unmap_channels(struct channel_trace_fd
*fd_pairs
)
538 for(j
=0;j
<fd_pairs
->num_pairs
;j
++) {
539 struct fd_pair
*pair
= &fd_pairs
->pair
[j
];
542 err_ret
= munmap(pair
->mmap
, pair
->subbuf_size
* pair
->n_subbufs
);
544 perror("Error in munmap");
547 err_ret
= pthread_mutex_destroy(&pair
->mutex
);
549 perror("Error in mutex destroy");
558 /* Inotify event arrived.
560 * Only support add file for now.
563 int read_inotify(int inotify_fd
,
564 struct channel_trace_fd
*fd_pairs
,
565 struct inotify_watch_array
*iwatch_array
)
567 char buf
[sizeof(struct inotify_event
) + PATH_MAX
];
568 char path_channel
[PATH_MAX
];
569 char path_trace
[PATH_MAX
];
571 struct inotify_event
*ievent
;
578 len
= read(inotify_fd
, buf
, sizeof(struct inotify_event
) + PATH_MAX
);
580 printf("Error in read from inotify FD %s.\n", strerror(len
));
583 while(offset
< len
) {
584 ievent
= (struct inotify_event
*)&(buf
[offset
]);
585 for(i
=0; i
<iwatch_array
->num
; i
++) {
586 if(iwatch_array
->elem
[i
].wd
== ievent
->wd
&&
587 ievent
->mask
== IN_CREATE
) {
588 printf("inotify wd %u event mask : %u for %s%s\n",
589 ievent
->wd
, ievent
->mask
,
590 iwatch_array
->elem
[i
].path_channel
, ievent
->name
);
591 old_num
= fd_pairs
->num_pairs
;
592 strcpy(path_channel
, iwatch_array
->elem
[i
].path_channel
);
593 strcat(path_channel
, ievent
->name
);
594 strcpy(path_trace
, iwatch_array
->elem
[i
].path_trace
);
595 strcat(path_trace
, ievent
->name
);
596 if(ret
= open_buffer_file(ievent
->name
, path_channel
,
597 path_trace
, fd_pairs
)) {
598 printf("Error opening buffer file\n");
601 if(ret
= map_channels(fd_pairs
, old_num
, fd_pairs
->num_pairs
)) {
602 printf("Error mapping channel\n");
608 offset
+= sizeof(*ievent
) + ievent
->len
;
617 * Read the debugfs channels and write them in the paired tracefiles.
619 * @fd_pairs : paired channels and trace files.
621 * returns 0 on success, -1 on error.
623 * Note that the high priority polled channels are consumed first. We then poll
624 * again to see if these channels are still in priority. Only when no
625 * high priority channel is left, we start reading low priority channels.
627 * Note that a channel is considered high priority when the buffer is almost
631 int read_channels(unsigned int thread_num
, struct channel_trace_fd
*fd_pairs
,
632 int inotify_fd
, struct inotify_watch_array
*iwatch_array
)
634 struct pollfd
*pollfd
= NULL
;
636 int num_rdy
, num_hup
;
640 unsigned int old_num
;
648 /* Start polling the FD. Keep one fd for inotify */
649 pollfd
= malloc((inotify_fds
+ fd_pairs
->num_pairs
) * sizeof(struct pollfd
));
652 pollfd
[0].fd
= inotify_fd
;
653 pollfd
[0].events
= POLLIN
|POLLPRI
;
656 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
657 pollfd
[inotify_fds
+i
].fd
= fd_pairs
->pair
[i
].channel
;
658 pollfd
[inotify_fds
+i
].events
= POLLIN
|POLLPRI
;
665 printf("Press a key for next poll...\n");
667 read(STDIN_FILENO
, &buf
, 1);
668 printf("Next poll (polling %d fd) :\n", 1+fd_pairs
->num_pairs
);
671 /* Have we received a signal ? */
672 if(quit_program
) break;
674 num_rdy
= poll(pollfd
, inotify_fds
+fd_pairs
->num_pairs
, -1);
676 perror("Poll error");
680 printf("Data received\n");
682 switch(pollfd
[0].revents
) {
684 printf("Error returned in polling inotify fd %d.\n", pollfd
[0].fd
);
687 printf("Polling inotify fd %d tells it has hung up.\n", pollfd
[0].fd
);
690 printf("Polling inotify fd %d tells fd is not open.\n", pollfd
[0].fd
);
694 printf("Polling inotify fd %d : data ready.\n", pollfd
[0].fd
);
695 old_num
= fd_pairs
->num_pairs
;
696 read_inotify(inotify_fd
, fd_pairs
, iwatch_array
);
697 pollfd
= realloc(pollfd
,
698 (inotify_fds
+ fd_pairs
->num_pairs
) * sizeof(struct pollfd
));
699 for(i
=old_num
;i
<fd_pairs
->num_pairs
;i
++) {
700 pollfd
[inotify_fds
+i
].fd
= fd_pairs
->pair
[i
].channel
;
701 pollfd
[inotify_fds
+i
].events
= POLLIN
|POLLPRI
;
707 for(i
=inotify_fds
;i
<inotify_fds
+fd_pairs
->num_pairs
;i
++) {
708 switch(pollfd
[i
].revents
) {
710 printf("Error returned in polling fd %d.\n", pollfd
[i
].fd
);
714 printf("Polling fd %d tells it has hung up.\n", pollfd
[i
].fd
);
718 printf("Polling fd %d tells fd is not open.\n", pollfd
[i
].fd
);
722 if(pthread_mutex_trylock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
) == 0) {
723 printf("Urgent read on fd %d\n", pollfd
[i
].fd
);
724 /* Take care of high priority channels first. */
726 /* it's ok to have an unavailable subbuffer */
727 ret
= read_subbuffer(&fd_pairs
->pair
[i
-inotify_fds
]);
728 if(ret
== EAGAIN
) ret
= 0;
730 ret
= pthread_mutex_unlock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
);
732 printf("Error in mutex unlock : %s\n", strerror(ret
));
737 /* If every buffer FD has hung up, we end the read loop here */
738 if(num_hup
== fd_pairs
->num_pairs
) break;
741 for(i
=inotify_fds
;i
<inotify_fds
+fd_pairs
->num_pairs
;i
++) {
742 switch(pollfd
[i
].revents
) {
744 if(pthread_mutex_trylock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
) == 0) {
745 /* Take care of low priority channels. */
746 printf("Normal read on fd %d\n", pollfd
[i
].fd
);
747 /* it's ok to have an unavailable subbuffer */
748 ret
= read_subbuffer(&fd_pairs
->pair
[i
-inotify_fds
]);
749 if(ret
== EAGAIN
) ret
= 0;
751 ret
= pthread_mutex_unlock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
);
753 printf("Error in mutex unlock : %s\n", strerror(ret
));
770 void close_channel_trace_pairs(struct channel_trace_fd
*fd_pairs
, int inotify_fd
,
771 struct inotify_watch_array
*iwatch_array
)
776 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
777 ret
= close(fd_pairs
->pair
[i
].channel
);
778 if(ret
== -1) perror("Close error on channel");
779 ret
= close(fd_pairs
->pair
[i
].trace
);
780 if(ret
== -1) perror("Close error on trace");
782 free(fd_pairs
->pair
);
783 free(iwatch_array
->elem
);
787 void * thread_main(void *arg
)
789 struct channel_trace_fd fd_pairs
= { NULL
, 0 };
791 struct inotify_watch_array inotify_watch_array
= { NULL
, 0 };
793 unsigned int thread_num
= (unsigned int)arg
;
795 inotify_fd
= inotify_init();
797 if(ret
= open_channel_trace_pairs(channel_name
, trace_name
, &fd_pairs
,
798 &inotify_fd
, &inotify_watch_array
))
801 if(ret
= map_channels(&fd_pairs
, 0, fd_pairs
.num_pairs
))
804 ret
= read_channels(thread_num
, &fd_pairs
, inotify_fd
, &inotify_watch_array
);
806 ret
|= unmap_channels(&fd_pairs
);
809 close_channel_trace_pairs(&fd_pairs
, inotify_fd
, &inotify_watch_array
);
817 int main(int argc
, char ** argv
)
820 struct sigaction act
;
825 ret
= parse_arguments(argc
, argv
);
827 if(ret
!= 0) show_arguments();
828 if(ret
< 0) return EINVAL
;
829 if(ret
> 0) return 0;
837 perror("An error occured while daemonizing.");
842 /* Connect the signal handlers */
843 act
.sa_handler
= handler
;
845 sigemptyset(&(act
.sa_mask
));
846 sigaddset(&(act
.sa_mask
), SIGTERM
);
847 sigaddset(&(act
.sa_mask
), SIGQUIT
);
848 sigaddset(&(act
.sa_mask
), SIGINT
);
849 sigaction(SIGTERM
, &act
, NULL
);
850 sigaction(SIGQUIT
, &act
, NULL
);
851 sigaction(SIGINT
, &act
, NULL
);
854 tids
= malloc(sizeof(pthread_t
) * num_threads
);
855 for(i
=0; i
<num_threads
; i
++) {
856 ret
= pthread_create(&tids
[i
], NULL
, thread_main
, (void*)i
);
858 perror("Error creating thread");
863 for(i
=0; i
<num_threads
; i
++) {
864 ret
= pthread_join(tids
[i
], &tret
);
866 perror("Error joining thread");
870 printf("Error %s occured in thread %u\n", strerror((int)tret
), i
);