3 * Linux Trace Toolkit Daemon
5 * This is a simple daemon that reads a few relayfs channels and save them in a
10 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
23 #include <sys/types.h>
35 #include <asm/ioctl.h>
36 #include <asm/types.h>
38 /* Get the next sub buffer that can be read. */
39 #define RELAYFS_GET_SUBBUF _IOR(0xF4, 0x00,__u32)
40 /* Release the oldest reserved (by "get") sub buffer. */
41 #define RELAYFS_PUT_SUBBUF _IOW(0xF4, 0x01,__u32)
42 /* returns the number of sub buffers in the per cpu channel. */
43 #define RELAYFS_GET_N_SUBBUFS _IOR(0xF4, 0x02,__u32)
44 /* returns the size of the sub buffers. */
45 #define RELAYFS_GET_SUBBUF_SIZE _IOR(0xF4, 0x03,__u32)
59 unsigned int n_subbufs
;
60 unsigned int subbuf_size
;
64 struct channel_trace_fd
{
69 static char *trace_name
= NULL
;
70 static char *channel_name
= NULL
;
71 static int daemon_mode
= 0;
72 static int append_mode
= 0;
73 static unsigned long num_threads
= 1;
74 volatile static int quit_program
= 0; /* For signal handler */
78 * -t directory Directory name of the trace to write to. Will be created.
79 * -c directory Root directory of the relayfs trace channels.
80 * -d Run in background (daemon).
81 * -a Trace append mode.
82 * -s Send SIGUSR1 to parent when ready for IO.
84 void show_arguments(void)
86 printf("Please use the following arguments :\n");
88 printf("-t directory Directory name of the trace to write to.\n"
89 " It will be created.\n");
90 printf("-c directory Root directory of the relayfs trace channels.\n");
91 printf("-d Run in background (daemon).\n");
92 printf("-a Append to an possibly existing trace.\n");
93 printf("-n Number of threads to start.\n");
100 * Parses the command line arguments.
102 * Returns 1 if the arguments were correct, but doesn't ask for program
103 * continuation. Returns -1 if the arguments are incorrect, or 0 if OK.
105 int parse_arguments(int argc
, char **argv
)
111 if(strcmp(argv
[1], "-h") == 0) {
118 switch(argv
[argn
][0]) {
120 switch(argv
[argn
][1]) {
123 trace_name
= argv
[argn
+1];
129 channel_name
= argv
[argn
+1];
141 num_threads
= strtoul(argv
[argn
+1], NULL
, 0);
146 printf("Invalid argument '%s'.\n", argv
[argn
]);
152 printf("Invalid argument '%s'.\n", argv
[argn
]);
159 if(trace_name
== NULL
) {
160 printf("Please specify a trace name.\n");
165 if(channel_name
== NULL
) {
166 printf("Please specify a channel name.\n");
176 printf("Linux Trace Toolkit Trace Daemon\n");
178 printf("Reading from relayfs directory : %s\n", channel_name
);
179 printf("Writing to trace directory : %s\n", trace_name
);
184 /* signal handling */
186 static void handler(int signo
)
188 printf("Signal %d received : exiting cleanly\n", signo
);
194 int open_channel_trace_pairs(char *subchannel_name
, char *subtrace_name
,
195 struct channel_trace_fd
*fd_pairs
)
197 DIR *channel_dir
= opendir(subchannel_name
);
198 struct dirent
*entry
;
199 struct stat stat_buf
;
201 char path_channel
[PATH_MAX
];
202 int path_channel_len
;
203 char *path_channel_ptr
;
204 char path_trace
[PATH_MAX
];
206 char *path_trace_ptr
;
209 if(channel_dir
== NULL
) {
210 perror(subchannel_name
);
215 printf("Creating trace subdirectory %s\n", subtrace_name
);
216 ret
= mkdir(subtrace_name
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
218 if(errno
!= EEXIST
) {
219 perror(subtrace_name
);
225 strncpy(path_channel
, subchannel_name
, PATH_MAX
-1);
226 path_channel_len
= strlen(path_channel
);
227 path_channel
[path_channel_len
] = '/';
229 path_channel_ptr
= path_channel
+ path_channel_len
;
231 strncpy(path_trace
, subtrace_name
, PATH_MAX
-1);
232 path_trace_len
= strlen(path_trace
);
233 path_trace
[path_trace_len
] = '/';
235 path_trace_ptr
= path_trace
+ path_trace_len
;
237 while((entry
= readdir(channel_dir
)) != NULL
) {
239 if(entry
->d_name
[0] == '.') continue;
241 strncpy(path_channel_ptr
, entry
->d_name
, PATH_MAX
- path_channel_len
);
242 strncpy(path_trace_ptr
, entry
->d_name
, PATH_MAX
- path_trace_len
);
244 ret
= stat(path_channel
, &stat_buf
);
246 perror(path_channel
);
250 printf("Channel file : %s\n", path_channel
);
252 if(S_ISDIR(stat_buf
.st_mode
)) {
254 printf("Entering channel subdirectory...\n");
255 ret
= open_channel_trace_pairs(path_channel
, path_trace
, fd_pairs
);
256 if(ret
< 0) continue;
257 } else if(S_ISREG(stat_buf
.st_mode
)) {
258 printf("Opening file.\n");
260 fd_pairs
->pair
= realloc(fd_pairs
->pair
,
261 ++fd_pairs
->num_pairs
* sizeof(struct fd_pair
));
263 /* Open the channel in read mode */
264 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
=
265 open(path_channel
, O_RDONLY
| O_NONBLOCK
);
266 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
== -1) {
267 perror(path_channel
);
268 fd_pairs
->num_pairs
--;
271 /* Open the trace in write mode, only append if append_mode */
272 ret
= stat(path_trace
, &stat_buf
);
275 printf("Appending to file %s as requested\n", path_trace
);
277 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
=
278 open(path_trace
, O_WRONLY
|O_APPEND
,
279 S_IRWXU
|S_IRWXG
|S_IRWXO
);
281 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
== -1) {
285 printf("File %s exists, cannot open. Try append mode.\n", path_trace
);
290 if(errno
== ENOENT
) {
291 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
=
292 open(path_trace
, O_WRONLY
|O_CREAT
|O_EXCL
,
293 S_IRWXU
|S_IRWXG
|S_IRWXO
);
294 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
== -1) {
303 closedir(channel_dir
);
309 int read_subbuffer(struct fd_pair
*pair
)
311 unsigned int consumed_old
;
315 err
= ioctl(pair
->channel
, RELAYFS_GET_SUBBUF
,
317 printf("cookie : %u\n", consumed_old
);
319 perror("Error in reserving sub buffer");
324 err
= TEMP_FAILURE_RETRY(write(pair
->trace
,
326 + (consumed_old
& ((pair
->n_subbufs
* pair
->subbuf_size
)-1)),
330 perror("Error in writing to file");
337 err
= ioctl(pair
->channel
, RELAYFS_PUT_SUBBUF
, &consumed_old
);
339 if(errno
== -EFAULT
) {
340 perror("Error in unreserving sub buffer");
342 } else if(errno
== -EIO
) {
343 perror("Reader has been pushed by the writer, last subbuffer corrupted.");
344 /* FIXME : we may delete the last written buffer if we wish. */
356 int map_channels(struct channel_trace_fd
*fd_pairs
)
361 if(fd_pairs
->num_pairs
<= 0) {
362 printf("No channel to read\n");
366 /* Get the subbuf sizes and number */
368 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
369 struct fd_pair
*pair
= &fd_pairs
->pair
[i
];
371 ret
= ioctl(pair
->channel
, RELAYFS_GET_N_SUBBUFS
,
374 perror("Error in getting the number of subbuffers");
377 ret
= ioctl(pair
->channel
, RELAYFS_GET_SUBBUF_SIZE
,
380 perror("Error in getting the size of the subbuffers");
386 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
387 struct fd_pair
*pair
= &fd_pairs
->pair
[i
];
389 pair
->mmap
= mmap(0, pair
->subbuf_size
* pair
->n_subbufs
, PROT_READ
,
390 MAP_SHARED
, pair
->channel
, 0);
391 if(pair
->mmap
== MAP_FAILED
) {
392 perror("Mmap error");
399 /* munmap only the successfully mmapped indexes */
403 struct fd_pair
*pair
= &fd_pairs
->pair
[j
];
406 err_ret
= munmap(pair
->mmap
, pair
->subbuf_size
* pair
->n_subbufs
);
408 perror("Error in munmap");
420 int unmap_channels(struct channel_trace_fd
*fd_pairs
)
426 for(j
=0;j
<fd_pairs
->num_pairs
;j
++) {
427 struct fd_pair
*pair
= &fd_pairs
->pair
[j
];
430 err_ret
= munmap(pair
->mmap
, pair
->subbuf_size
* pair
->n_subbufs
);
432 perror("Error in munmap");
443 * Read the relayfs channels and write them in the paired tracefiles.
445 * @fd_pairs : paired channels and trace files.
447 * returns 0 on success, -1 on error.
449 * Note that the high priority polled channels are consumed first. We then poll
450 * again to see if these channels are still in priority. Only when no
451 * high priority channel is left, we start reading low priority channels.
453 * Note that a channel is considered high priority when the buffer is almost
457 int read_channels(struct channel_trace_fd
*fd_pairs
)
459 struct pollfd
*pollfd
;
461 int num_rdy
, num_hup
;
465 /* Start polling the FD */
467 pollfd
= malloc(fd_pairs
->num_pairs
* sizeof(struct pollfd
));
469 /* Note : index in pollfd is the same index as fd_pair->pair */
470 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
471 pollfd
[i
].fd
= fd_pairs
->pair
[i
].channel
;
472 pollfd
[i
].events
= POLLIN
|POLLPRI
;
479 printf("Press a key for next poll...\n");
481 read(STDIN_FILENO
, &buf
, 1);
482 printf("Next poll (polling %d fd) :\n", fd_pairs
->num_pairs
);
485 /* Have we received a signal ? */
486 if(quit_program
) break;
488 num_rdy
= poll(pollfd
, fd_pairs
->num_pairs
, -1);
490 perror("Poll error");
494 printf("Data received\n");
496 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
497 switch(pollfd
[i
].revents
) {
499 printf("Error returned in polling fd %d.\n", pollfd
[i
].fd
);
503 printf("Polling fd %d tells it has hung up.\n", pollfd
[i
].fd
);
507 printf("Polling fd %d tells fd is not open.\n", pollfd
[i
].fd
);
511 printf("Urgent read on fd %d\n", pollfd
[i
].fd
);
512 /* Take care of high priority channels first. */
514 ret
|= read_subbuffer(&fd_pairs
->pair
[i
]);
518 /* If every FD has hung up, we end the read loop here */
519 if(num_hup
== fd_pairs
->num_pairs
) break;
522 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
523 switch(pollfd
[i
].revents
) {
525 /* Take care of low priority channels. */
526 printf("Normal read on fd %d\n", pollfd
[i
].fd
);
527 ret
|= read_subbuffer(&fd_pairs
->pair
[i
]);
543 void close_channel_trace_pairs(struct channel_trace_fd
*fd_pairs
)
548 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
549 ret
= close(fd_pairs
->pair
[i
].channel
);
550 if(ret
== -1) perror("Close error on channel");
551 ret
= close(fd_pairs
->pair
[i
].trace
);
552 if(ret
== -1) perror("Close error on trace");
554 free(fd_pairs
->pair
);
557 int main(int argc
, char ** argv
)
560 struct channel_trace_fd fd_pairs
= { NULL
, 0 };
561 struct sigaction act
;
563 ret
= parse_arguments(argc
, argv
);
565 if(ret
!= 0) show_arguments();
566 if(ret
< 0) return EINVAL
;
567 if(ret
> 0) return 0;
575 perror("An error occured while daemonizing.");
580 /* Connect the signal handlers */
581 act
.sa_handler
= handler
;
583 sigemptyset(&(act
.sa_mask
));
584 sigaddset(&(act
.sa_mask
), SIGTERM
);
585 sigaddset(&(act
.sa_mask
), SIGQUIT
);
586 sigaddset(&(act
.sa_mask
), SIGINT
);
587 sigaction(SIGTERM
, &act
, NULL
);
588 sigaction(SIGQUIT
, &act
, NULL
);
589 sigaction(SIGINT
, &act
, NULL
);
592 if(ret
= open_channel_trace_pairs(channel_name
, trace_name
, &fd_pairs
))
595 if(ret
= map_channels(&fd_pairs
))
598 ret
= read_channels(&fd_pairs
);
600 ret
|= unmap_channels(&fd_pairs
);
603 close_channel_trace_pairs(&fd_pairs
);