[PATCH] Mark as 0.99.1
[blktrace.git] / blktrace.c
1 /*
2  * block queue tracing application
3  *
4  * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21 #include <pthread.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <locale.h>
26 #include <signal.h>
27 #include <fcntl.h>
28 #include <string.h>
29 #include <sys/ioctl.h>
30 #include <sys/param.h>
31 #include <sys/statfs.h>
32 #include <sys/poll.h>
33 #include <sys/mman.h>
34 #include <sys/socket.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <sched.h>
38 #include <ctype.h>
39 #include <getopt.h>
40 #include <errno.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <netdb.h>
44 #include <sys/sendfile.h>
45
46 #include "blktrace.h"
47 #include "barrier.h"
48
49 static char blktrace_version[] = "0.99.1";
50
51 /*
52  * You may want to increase this even more, if you are logging at a high
53  * rate and see skipped/missed events
54  */
55 #define BUF_SIZE        (512 * 1024)
56 #define BUF_NR          (4)
57
58 #define OFILE_BUF       (128 * 1024)
59
60 #define RELAYFS_TYPE    0xF0B4A981
61
62 #define S_OPTS  "d:a:A:r:o:kw:Vb:n:D:lh:p:s"
63 static struct option l_opts[] = {
64         {
65                 .name = "dev",
66                 .has_arg = required_argument,
67                 .flag = NULL,
68                 .val = 'd'
69         },
70         {
71                 .name = "act-mask",
72                 .has_arg = required_argument,
73                 .flag = NULL,
74                 .val = 'a'
75         },
76         {
77                 .name = "set-mask",
78                 .has_arg = required_argument,
79                 .flag = NULL,
80                 .val = 'A'
81         },
82         {
83                 .name = "relay",
84                 .has_arg = required_argument,
85                 .flag = NULL,
86                 .val = 'r'
87         },
88         {
89                 .name = "output",
90                 .has_arg = required_argument,
91                 .flag = NULL,
92                 .val = 'o'
93         },
94         {
95                 .name = "kill",
96                 .has_arg = no_argument,
97                 .flag = NULL,
98                 .val = 'k'
99         },
100         {
101                 .name = "stopwatch",
102                 .has_arg = required_argument,
103                 .flag = NULL,
104                 .val = 'w'
105         },
106         {
107                 .name = "version",
108                 .has_arg = no_argument,
109                 .flag = NULL,
110                 .val = 'V'
111         },
112         {
113                 .name = "buffer-size",
114                 .has_arg = required_argument,
115                 .flag = NULL,
116                 .val = 'b'
117         },
118         {
119                 .name = "num-sub-buffers",
120                 .has_arg = required_argument,
121                 .flag = NULL,
122                 .val = 'n'
123         },
124         {
125                 .name = "output-dir",
126                 .has_arg = required_argument,
127                 .flag = NULL,
128                 .val = 'D'
129         },
130         {
131                 .name = "listen",
132                 .has_arg = no_argument,
133                 .flag = NULL,
134                 .val = 'l'
135         },
136         {
137                 .name = "host",
138                 .has_arg = required_argument,
139                 .flag = NULL,
140                 .val = 'h'
141         },
142         {
143                 .name = "port",
144                 .has_arg = required_argument,
145                 .flag = NULL,
146                 .val = 'p'
147         },
148         {
149                 .name = "sendfile",
150                 .has_arg = no_argument,
151                 .flag = NULL,
152                 .val = 's'
153         },
154         {
155                 .name = NULL,
156         }
157 };
158
159 struct tip_subbuf {
160         void *buf;
161         unsigned int len;
162         unsigned int max_len;
163 };
164
165 #define FIFO_SIZE       (1024)  /* should be plenty big! */
166 #define CL_SIZE         (128)   /* cache line, any bigger? */
167
168 struct tip_subbuf_fifo {
169         int tail __attribute__((aligned(CL_SIZE)));
170         int head __attribute__((aligned(CL_SIZE)));
171         struct tip_subbuf *q[FIFO_SIZE];
172 };
173
174 struct thread_information {
175         int cpu;
176         pthread_t thread;
177
178         int fd;
179         void *fd_buf;
180         char fn[MAXPATHLEN + 64];
181
182         FILE *ofile;
183         char *ofile_buffer;
184         off_t ofile_offset;
185         int ofile_stdout;
186         int ofile_mmap;
187
188         int (*get_subbuf)(struct thread_information *, unsigned int);
189         int (*flush_subbuf)(struct thread_information *, struct tip_subbuf *);
190         int (*read_data)(struct thread_information *, void *, unsigned int);
191
192         unsigned long events_processed;
193         unsigned long long data_read;
194         unsigned long long data_queued;
195         struct device_information *device;
196
197         int exited;
198
199         /*
200          * piped fifo buffers
201          */
202         struct tip_subbuf_fifo fifo;
203         struct tip_subbuf *leftover_ts;
204
205         /*
206          * mmap controlled output files
207          */
208         unsigned long long fs_size;
209         unsigned long long fs_max_size;
210         unsigned long fs_off;
211         void *fs_buf;
212         unsigned long fs_buf_len;
213 };
214
215 struct device_information {
216         int fd;
217         char *path;
218         char buts_name[32];
219         volatile int trace_started;
220         unsigned long drop_count;
221         struct thread_information *threads;
222         struct net_connection *nc;
223 };
224
225 static int ncpus;
226 static struct thread_information *thread_information;
227 static int ndevs;
228 static struct device_information *device_information;
229
230 /* command line option globals */
231 static char *relay_path;
232 static char *output_name;
233 static char *output_dir;
234 static int act_mask = ~0U;
235 static int kill_running_trace;
236 static unsigned long buf_size = BUF_SIZE;
237 static unsigned long buf_nr = BUF_NR;
238 static unsigned int page_size;
239
240 #define is_done()       (*(volatile int *)(&done))
241 static volatile int done;
242
243 #define is_trace_stopped()      (*(volatile int *)(&trace_stopped))
244 static volatile int trace_stopped;
245
246 #define is_stat_shown() (*(volatile int *)(&stat_shown))
247 static volatile int stat_shown;
248
249 int data_is_native = -1;
250
251 static void exit_trace(int status);
252
253 #define dip_tracing(dip)        (*(volatile int *)(&(dip)->trace_started))
254 #define dip_set_tracing(dip, v) ((dip)->trace_started = (v))
255
256 #define __for_each_dip(__d, __di, __e, __i)     \
257         for (__i = 0, __d = __di; __i < __e; __i++, __d++)
258
259 #define for_each_dip(__d, __i)          \
260         __for_each_dip(__d, device_information, ndevs, __i)
261 #define for_each_nc_dip(__nc, __d, __i)         \
262         __for_each_dip(__d, (__nc)->device_information, (__nc)->ndevs, __i)
263
264 #define __for_each_tip(__d, __t, __ncpus, __j)  \
265         for (__j = 0, __t = (__d)->threads; __j < __ncpus; __j++, __t++)
266 #define for_each_tip(__d, __t, __j)     \
267         __for_each_tip(__d, __t, ncpus, __j)
268
269 /*
270  * networking stuff follows. we include a magic number so we know whether
271  * to endianness convert or not
272  */
273 struct blktrace_net_hdr {
274         u32 magic;              /* same as trace magic */
275         char buts_name[32];     /* trace name */
276         u32 cpu;                /* for which cpu */
277         u32 max_cpus;
278         u32 len;                /* length of following trace data */
279 };
280
281 #define TRACE_NET_PORT          (8462)
282
283 enum {
284         Net_none = 0,
285         Net_server,
286         Net_client,
287 };
288
289 /*
290  * network cmd line params
291  */
292 static char hostname[MAXHOSTNAMELEN];
293 static int net_port = TRACE_NET_PORT;
294 static int net_mode = 0;
295 static int net_use_sendfile;
296
297 struct net_connection {
298         int in_fd;
299         time_t connect_time;
300         struct in_addr cl_in_addr;
301         struct device_information *device_information;
302         int ndevs;
303         int ncpus;
304         int connection_index;
305 };
306
307 #define NET_MAX_CONNECTIONS     (1024)
308 static struct net_connection net_connections[NET_MAX_CONNECTIONS];
309 static int net_connects;
310 static int net_out_fd = -1;
311
312 static void handle_sigint(__attribute__((__unused__)) int sig)
313 {
314         struct device_information *dip;
315         int i;
316
317         /*
318          * stop trace so we can reap currently produced data
319          */
320         for_each_dip(dip, i) {
321                 if (dip->fd == -1)
322                         continue;
323                 if (ioctl(dip->fd, BLKTRACESTOP) < 0)
324                         perror("BLKTRACESTOP");
325         }
326
327         done = 1;
328 }
329
330 static int get_dropped_count(const char *buts_name)
331 {
332         int fd;
333         char tmp[MAXPATHLEN + 64];
334
335         snprintf(tmp, sizeof(tmp), "%s/block/%s/dropped",
336                  relay_path, buts_name);
337
338         fd = open(tmp, O_RDONLY);
339         if (fd < 0) {
340                 /*
341                  * this may be ok, if the kernel doesn't support dropped counts
342                  */
343                 if (errno == ENOENT)
344                         return 0;
345
346                 fprintf(stderr, "Couldn't open dropped file %s\n", tmp);
347                 return -1;
348         }
349
350         if (read(fd, tmp, sizeof(tmp)) < 0) {
351                 perror(tmp);
352                 close(fd);
353                 return -1;
354         }
355
356         close(fd);
357
358         return atoi(tmp);
359 }
360
361 static int start_trace(struct device_information *dip)
362 {
363         struct blk_user_trace_setup buts;
364
365         memset(&buts, 0, sizeof(buts));
366         buts.buf_size = buf_size;
367         buts.buf_nr = buf_nr;
368         buts.act_mask = act_mask;
369
370         if (ioctl(dip->fd, BLKTRACESETUP, &buts) < 0) {
371                 perror("BLKTRACESETUP");
372                 return 1;
373         }
374
375         if (ioctl(dip->fd, BLKTRACESTART) < 0) {
376                 perror("BLKTRACESTART");
377                 return 1;
378         }
379
380         memcpy(dip->buts_name, buts.name, sizeof(dip->buts_name));
381         dip_set_tracing(dip, 1);
382         return 0;
383 }
384
385 static void stop_trace(struct device_information *dip)
386 {
387         if (dip_tracing(dip) || kill_running_trace) {
388                 dip_set_tracing(dip, 0);
389
390                 /*
391                  * should be stopped, just don't complain if it isn't
392                  */
393                 ioctl(dip->fd, BLKTRACESTOP);
394
395                 if (ioctl(dip->fd, BLKTRACETEARDOWN) < 0)
396                         perror("BLKTRACETEARDOWN");
397
398                 close(dip->fd);
399                 dip->fd = -1;
400         }
401 }
402
403 static void stop_all_traces(void)
404 {
405         struct device_information *dip;
406         int i;
407
408         for_each_dip(dip, i) {
409                 dip->drop_count = get_dropped_count(dip->buts_name);
410                 stop_trace(dip);
411         }
412 }
413
414 static void wait_for_data(struct thread_information *tip, int events)
415 {
416         struct pollfd pfd = { .fd = tip->fd, .events = events };
417
418         do {
419                 if (poll(&pfd, 1, 100) < 0) {
420                         perror("poll");
421                         break;
422                 }
423                 if (pfd.revents & events)
424                         break;
425                 if (tip->ofile_stdout)
426                         break;
427         } while (!is_done());
428 }
429
430 static int read_data_file(struct thread_information *tip, void *buf,
431                           unsigned int len)
432 {
433         int ret = 0;
434
435         do {
436                 wait_for_data(tip, POLLIN);
437
438                 ret = read(tip->fd, buf, len);
439                 if (!ret)
440                         continue;
441                 else if (ret > 0)
442                         return ret;
443                 else {
444                         if (errno != EAGAIN) {
445                                 perror(tip->fn);
446                                 fprintf(stderr,"Thread %d failed read of %s\n",
447                                         tip->cpu, tip->fn);
448                                 break;
449                         }
450                         continue;
451                 }
452         } while (!is_done());
453
454         return ret;
455
456 }
457
458 static int read_data_net(struct thread_information *tip, void *buf,
459                          unsigned int len)
460 {
461         struct net_connection *nc = tip->device->nc;
462         unsigned int bytes_left = len;
463         int ret = 0;
464
465         do {
466                 ret = recv(nc->in_fd, buf, bytes_left, MSG_WAITALL);
467
468                 if (!ret)
469                         continue;
470                 else if (ret < 0) {
471                         if (errno != EAGAIN) {
472                                 perror(tip->fn);
473                                 fprintf(stderr, "server: failed read\n");
474                                 return 0;
475                         }
476                         continue;
477                 } else {
478                         buf += ret;
479                         bytes_left -= ret;
480                 }
481         } while (!is_done() && bytes_left);
482
483         return len - bytes_left;
484 }
485
486 static inline struct tip_subbuf *
487 subbuf_fifo_dequeue(struct thread_information *tip)
488 {
489         const int head = tip->fifo.head;
490         const int next = (head + 1) & (FIFO_SIZE - 1);
491
492         if (head != tip->fifo.tail) {
493                 struct tip_subbuf *ts = tip->fifo.q[head];
494
495                 store_barrier();
496                 tip->fifo.head = next;
497                 return ts;
498         }
499
500         return NULL;
501 }
502
503 static inline int subbuf_fifo_queue(struct thread_information *tip,
504                                     struct tip_subbuf *ts)
505 {
506         const int tail = tip->fifo.tail;
507         const int next = (tail + 1) & (FIFO_SIZE - 1);
508
509         if (next != tip->fifo.head) {
510                 tip->fifo.q[tail] = ts;
511                 store_barrier();
512                 tip->fifo.tail = next;
513                 return 0;
514         }
515
516         fprintf(stderr, "fifo too small!\n");
517         return 1;
518 }
519
520 /*
521  * For file output, truncate and mmap the file appropriately
522  */
523 static int mmap_subbuf(struct thread_information *tip, unsigned int maxlen)
524 {
525         int ofd = fileno(tip->ofile);
526         int ret;
527
528         /*
529          * extend file, if we have to. use chunks of 16 subbuffers.
530          */
531         if (tip->fs_off + buf_size > tip->fs_buf_len) {
532                 if (tip->fs_buf) {
533                         munlock(tip->fs_buf, tip->fs_buf_len);
534                         munmap(tip->fs_buf, tip->fs_buf_len);
535                         tip->fs_buf = NULL;
536                 }
537
538                 tip->fs_off = tip->fs_size & (page_size - 1);
539                 tip->fs_buf_len = (16 * buf_size) - tip->fs_off;
540                 tip->fs_max_size += tip->fs_buf_len;
541
542                 if (ftruncate(ofd, tip->fs_max_size) < 0) {
543                         perror("ftruncate");
544                         return -1;
545                 }
546
547                 tip->fs_buf = mmap(NULL, tip->fs_buf_len, PROT_WRITE,
548                                    MAP_SHARED, ofd, tip->fs_size - tip->fs_off);
549                 if (tip->fs_buf == MAP_FAILED) {
550                         perror("mmap");
551                         return -1;
552                 }
553                 mlock(tip->fs_buf, tip->fs_buf_len);
554         }
555
556         ret = tip->read_data(tip, tip->fs_buf + tip->fs_off, maxlen);
557         if (ret >= 0) {
558                 tip->data_read += ret;
559                 tip->fs_size += ret;
560                 tip->fs_off += ret;
561                 return 0;
562         }
563
564         return -1;
565 }
566
567 /*
568  * Use the copy approach for pipes and network
569  */
570 static int get_subbuf(struct thread_information *tip, unsigned int maxlen)
571 {
572         struct tip_subbuf *ts = malloc(sizeof(*ts));
573         int ret;
574
575         ts->buf = malloc(buf_size);
576         ts->max_len = maxlen;
577
578         ret = tip->read_data(tip, ts->buf, ts->max_len);
579         if (ret > 0) {
580                 ts->len = ret;
581                 tip->data_read += ret;
582                 if (subbuf_fifo_queue(tip, ts))
583                         return -1;
584         }
585
586         return ret;
587 }
588
589 static int get_subbuf_sendfile(struct thread_information *tip,
590                                unsigned int maxlen)
591 {
592         struct tip_subbuf *ts;
593         struct stat sb;
594         unsigned int ready;
595
596         wait_for_data(tip, POLLMSG);
597
598         /*
599          * hack to get last data out, we can't use sendfile for that
600          */
601         if (is_done())
602                 return get_subbuf(tip, maxlen);
603
604         if (fstat(tip->fd, &sb) < 0) {
605                 perror("trace stat");
606                 return -1;
607         }
608         ready = sb.st_size - tip->data_queued;
609         if (!ready) {
610                 usleep(1000);
611                 return 0;
612         }
613
614         ts = malloc(sizeof(*ts));
615         ts->buf = NULL;
616         ts->max_len = 0;
617         ts->len = ready;
618         tip->data_queued += ready;
619
620         if (subbuf_fifo_queue(tip, ts))
621                 return -1;
622
623         return ready;
624 }
625
626 static void close_thread(struct thread_information *tip)
627 {
628         if (tip->fd != -1)
629                 close(tip->fd);
630         if (tip->ofile)
631                 fclose(tip->ofile);
632         if (tip->ofile_buffer)
633                 free(tip->ofile_buffer);
634         if (tip->fd_buf)
635                 free(tip->fd_buf);
636
637         tip->fd = -1;
638         tip->ofile = NULL;
639         tip->ofile_buffer = NULL;
640         tip->fd_buf = NULL;
641 }
642
643 static void tip_ftrunc_final(struct thread_information *tip)
644 {
645         /*
646          * truncate to right size and cleanup mmap
647          */
648         if (tip->ofile_mmap && tip->ofile) {
649                 int ofd = fileno(tip->ofile);
650
651                 if (tip->fs_buf)
652                         munmap(tip->fs_buf, tip->fs_buf_len);
653
654                 ftruncate(ofd, tip->fs_size);
655         }
656 }
657
658 static void *thread_main(void *arg)
659 {
660         struct thread_information *tip = arg;
661         pid_t pid = getpid();
662         cpu_set_t cpu_mask;
663
664         CPU_ZERO(&cpu_mask);
665         CPU_SET((tip->cpu), &cpu_mask);
666
667         if (sched_setaffinity(pid, sizeof(cpu_mask), &cpu_mask) == -1) {
668                 perror("sched_setaffinity");
669                 exit_trace(1);
670         }
671
672         snprintf(tip->fn, sizeof(tip->fn), "%s/block/%s/trace%d",
673                         relay_path, tip->device->buts_name, tip->cpu);
674         tip->fd = open(tip->fn, O_RDONLY);
675         if (tip->fd < 0) {
676                 perror(tip->fn);
677                 fprintf(stderr,"Thread %d failed open of %s\n", tip->cpu,
678                         tip->fn);
679                 exit_trace(1);
680         }
681
682         while (!is_done()) {
683                 if (tip->get_subbuf(tip, buf_size) < 0)
684                         break;
685         }
686
687         /*
688          * trace is stopped, pull data until we get a short read
689          */
690         while (tip->get_subbuf(tip, buf_size) > 0)
691                 ;
692
693         tip_ftrunc_final(tip);
694         tip->exited = 1;
695         return NULL;
696 }
697
698 static int write_data_net(int fd, void *buf, unsigned int buf_len)
699 {
700         unsigned int bytes_left = buf_len;
701         int ret;
702
703         while (bytes_left) {
704                 ret = send(fd, buf, bytes_left, 0);
705                 if (ret < 0) {
706                         perror("send");
707                         return 1;
708                 }
709
710                 buf += ret;
711                 bytes_left -= ret;
712         }
713
714         return 0;
715 }
716
717 static int net_send_header(struct thread_information *tip, unsigned int len)
718 {
719         struct blktrace_net_hdr hdr;
720
721         hdr.magic = BLK_IO_TRACE_MAGIC;
722         strcpy(hdr.buts_name, tip->device->buts_name);
723         hdr.cpu = tip->cpu;
724         hdr.max_cpus = ncpus;
725         hdr.len = len;
726
727         return write_data_net(net_out_fd, &hdr, sizeof(hdr));
728 }
729
730 /*
731  * send header with 0 length to signal end-of-run
732  */
733 static void net_client_send_close(void)
734 {
735         struct device_information *dip;
736         struct blktrace_net_hdr hdr;
737         int i;
738
739         for_each_dip(dip, i) {
740                 hdr.magic = BLK_IO_TRACE_MAGIC;
741                 hdr.max_cpus = ncpus;
742                 hdr.len = 0;
743                 strcpy(hdr.buts_name, dip->buts_name);
744                 hdr.cpu = get_dropped_count(dip->buts_name);
745
746                 write_data_net(net_out_fd, &hdr, sizeof(hdr));
747         }
748
749 }
750
751 static int flush_subbuf_net(struct thread_information *tip,
752                             struct tip_subbuf *ts)
753 {
754         if (net_send_header(tip, ts->len))
755                 return -1;
756         if (write_data_net(net_out_fd, ts->buf, ts->len))
757                 return -1;
758
759         free(ts->buf);
760         free(ts);
761         return 1;
762 }
763
764 static int net_sendfile(struct thread_information *tip, struct tip_subbuf *ts)
765 {
766         int ret = sendfile(net_out_fd, tip->fd, NULL, ts->len);
767
768         if (ret < 0) {
769                 perror("sendfile");
770                 return 1;
771         } else if (ret < (int) ts->len) {
772                 fprintf(stderr, "short sendfile send (%d of %d)\n", ret, ts->len);
773                 return 1;
774         }
775
776         return 0;
777 }
778
779 static int flush_subbuf_sendfile(struct thread_information *tip,
780                                  struct tip_subbuf *ts)
781 {
782         int ret = -1;
783
784         /*
785          * currently we cannot use sendfile() on the last bytes read, as they
786          * may not be a full subbuffer. get_subbuf_sendfile() falls back to
787          * the read approach for those, so use send() to ship them out
788          */
789         if (ts->buf)
790                 return flush_subbuf_net(tip, ts);
791         
792         if (net_send_header(tip, ts->len))
793                 goto err;
794         if (net_sendfile(tip, ts))
795                 goto err;
796
797         tip->data_read += ts->len;
798         tip->ofile_offset += buf_size;
799         ret = 1;
800 err:
801         free(ts);
802         return ret;
803 }
804
805 static int write_data(struct thread_information *tip, void *buf,
806                       unsigned int buf_len)
807 {
808         int ret;
809
810         if (!buf_len)
811                 return 0;
812
813         while (1) {
814                 ret = fwrite(buf, buf_len, 1, tip->ofile);
815                 if (ret == 1)
816                         break;
817
818                 if (ret < 0) {
819                         perror("write");
820                         return 1;
821                 }
822         }
823
824         if (tip->ofile_stdout)
825                 fflush(tip->ofile);
826
827         return 0;
828 }
829
830 static int flush_subbuf_file(struct thread_information *tip,
831                              struct tip_subbuf *ts)
832 {
833         unsigned int offset = 0;
834         struct blk_io_trace *t;
835         int pdu_len, events = 0;
836
837         /*
838          * surplus from last run
839          */
840         if (tip->leftover_ts) {
841                 struct tip_subbuf *prev_ts = tip->leftover_ts;
842
843                 if (prev_ts->len + ts->len > prev_ts->max_len) {
844                         prev_ts->max_len += ts->len;
845                         prev_ts->buf = realloc(prev_ts->buf, prev_ts->max_len);
846                 }
847
848                 memcpy(prev_ts->buf + prev_ts->len, ts->buf, ts->len);
849                 prev_ts->len += ts->len;
850
851                 free(ts->buf);
852                 free(ts);
853
854                 ts = prev_ts;
855                 tip->leftover_ts = NULL;
856         }
857
858         while (offset + sizeof(*t) <= ts->len) {
859                 t = ts->buf + offset;
860
861                 if (verify_trace(t)) {
862                         write_data(tip, ts->buf, offset);
863                         return -1;
864                 }
865
866                 pdu_len = t->pdu_len;
867
868                 if (offset + sizeof(*t) + pdu_len > ts->len)
869                         break;
870
871                 offset += sizeof(*t) + pdu_len;
872                 tip->events_processed++;
873                 tip->data_read += sizeof(*t) + pdu_len;
874                 events++;
875         }
876
877         if (write_data(tip, ts->buf, offset))
878                 return -1;
879
880         /*
881          * leftover bytes, save them for next time
882          */
883         if (offset != ts->len) {
884                 tip->leftover_ts = ts;
885                 ts->len -= offset;
886                 memmove(ts->buf, ts->buf + offset, ts->len);
887         } else {
888                 free(ts->buf);
889                 free(ts);
890         }
891
892         return events;
893 }
894
895 static int write_tip_events(struct thread_information *tip)
896 {
897         struct tip_subbuf *ts = subbuf_fifo_dequeue(tip);
898
899         if (ts)
900                 return tip->flush_subbuf(tip, ts);
901
902         return 0;
903 }
904
905 /*
906  * scans the tips we know and writes out the subbuffers we accumulate
907  */
908 static void get_and_write_events(void)
909 {
910         struct device_information *dip;
911         struct thread_information *tip;
912         int i, j, events, ret, tips_running;
913
914         while (!is_done()) {
915                 events = 0;
916
917                 for_each_dip(dip, i) {
918                         for_each_tip(dip, tip, j) {
919                                 ret = write_tip_events(tip);
920                                 if (ret > 0)
921                                         events += ret;
922                         }
923                 }
924
925                 if (!events)
926                         usleep(100000);
927         }
928
929         /*
930          * reap stored events
931          */
932         do {
933                 events = 0;
934                 tips_running = 0;
935                 for_each_dip(dip, i) {
936                         for_each_tip(dip, tip, j) {
937                                 ret = write_tip_events(tip);
938                                 if (ret > 0)
939                                         events += ret;
940                                 tips_running += !tip->exited;
941                         }
942                 }
943                 usleep(10);
944         } while (events || tips_running);
945 }
946
947 static void wait_for_threads(void)
948 {
949         /*
950          * for piped or network output, poll and fetch data for writeout.
951          * for files, we just wait around for trace threads to exit
952          */
953         if ((output_name && !strcmp(output_name, "-")) ||
954             net_mode == Net_client)
955                 get_and_write_events();
956         else {
957                 struct device_information *dip;
958                 struct thread_information *tip;
959                 int i, j, tips_running;
960
961                 do {
962                         tips_running = 0;
963                         usleep(100000);
964
965                         for_each_dip(dip, i)
966                                 for_each_tip(dip, tip, j)
967                                         tips_running += !tip->exited;
968                 } while (tips_running);
969         }
970
971         if (net_mode == Net_client)
972                 net_client_send_close();
973 }
974
975 static int fill_ofname(struct device_information *dip,
976                        struct thread_information *tip, char *dst,
977                        char *buts_name)
978 {
979         struct stat sb;
980         int len = 0;
981
982         if (output_dir)
983                 len = sprintf(dst, "%s/", output_dir);
984
985         if (net_mode == Net_server) {
986                 struct net_connection *nc = dip->nc;
987
988                 len += sprintf(dst + len, "%s-", inet_ntoa(nc->cl_in_addr));
989                 len += strftime(dst + len, 64, "%F-%T/", gmtime(&nc->connect_time));
990         }
991
992         if (stat(dst, &sb) < 0) {
993                 if (errno != ENOENT) {
994                         perror("stat");
995                         return 1;
996                 }
997                 if (mkdir(dst, 0755) < 0) {
998                         perror(dst);
999                         fprintf(stderr, "Can't make output dir\n");
1000                         return 1;
1001                 }
1002         }
1003
1004         if (output_name)
1005                 sprintf(dst + len, "%s.blktrace.%d", output_name, tip->cpu);
1006         else
1007                 sprintf(dst + len, "%s.blktrace.%d", buts_name, tip->cpu);
1008
1009         return 0;
1010 }
1011
1012 static void fill_ops(struct thread_information *tip)
1013 {
1014         /*
1015          * setup ops
1016          */
1017         if (net_mode == Net_client) {
1018                 if (net_use_sendfile) {
1019                         tip->get_subbuf = get_subbuf_sendfile;
1020                         tip->flush_subbuf = flush_subbuf_sendfile;
1021                 } else {
1022                         tip->get_subbuf = get_subbuf;
1023                         tip->flush_subbuf = flush_subbuf_net;
1024                 }
1025         } else {
1026                 if (tip->ofile_mmap)
1027                         tip->get_subbuf = mmap_subbuf;
1028                 else
1029                         tip->get_subbuf = get_subbuf;
1030
1031                 tip->flush_subbuf = flush_subbuf_file;
1032         }
1033                         
1034         if (net_mode == Net_server)
1035                 tip->read_data = read_data_net;
1036         else
1037                 tip->read_data = read_data_file;
1038 }
1039
1040 static int tip_open_output(struct device_information *dip,
1041                            struct thread_information *tip)
1042 {
1043         int pipeline = output_name && !strcmp(output_name, "-");
1044         int mode, vbuf_size;
1045         char op[128];
1046
1047         if (net_mode == Net_client) {
1048                 tip->ofile = NULL;
1049                 tip->ofile_stdout = 0;
1050                 tip->ofile_mmap = 0;
1051                 goto done;
1052         } else if (pipeline) {
1053                 tip->ofile = fdopen(STDOUT_FILENO, "w");
1054                 tip->ofile_stdout = 1;
1055                 tip->ofile_mmap = 0;
1056                 mode = _IOLBF;
1057                 vbuf_size = 512;
1058         } else {
1059                 if (fill_ofname(dip, tip, op, dip->buts_name))
1060                         return 1;
1061                 tip->ofile = fopen(op, "w+");
1062                 tip->ofile_stdout = 0;
1063                 tip->ofile_mmap = 1;
1064                 mode = _IOFBF;
1065                 vbuf_size = OFILE_BUF;
1066         }
1067
1068         if (tip->ofile == NULL) {
1069                 perror(op);
1070                 return 1;
1071         }
1072
1073         tip->ofile_buffer = malloc(vbuf_size);
1074         if (setvbuf(tip->ofile, tip->ofile_buffer, mode, vbuf_size)) {
1075                 perror("setvbuf");
1076                 close_thread(tip);
1077                 return 1;
1078         }
1079
1080 done:
1081         fill_ops(tip);
1082         return 0;
1083 }
1084
1085 static int start_threads(struct device_information *dip)
1086 {
1087         struct thread_information *tip;
1088         int j;
1089
1090         for_each_tip(dip, tip, j) {
1091                 tip->cpu = j;
1092                 tip->device = dip;
1093                 tip->events_processed = 0;
1094                 tip->fd = -1;
1095                 memset(&tip->fifo, 0, sizeof(tip->fifo));
1096                 tip->leftover_ts = NULL;
1097
1098                 if (tip_open_output(dip, tip))
1099                         return 1;
1100
1101                 if (pthread_create(&tip->thread, NULL, thread_main, tip)) {
1102                         perror("pthread_create");
1103                         close_thread(tip);
1104                         return 1;
1105                 }
1106         }
1107
1108         return 0;
1109 }
1110
1111 static void stop_threads(struct device_information *dip)
1112 {
1113         struct thread_information *tip;
1114         unsigned long ret;
1115         int i;
1116
1117         for_each_tip(dip, tip, i) {
1118                 (void) pthread_join(tip->thread, (void *) &ret);
1119                 close_thread(tip);
1120         }
1121 }
1122
1123 static void stop_all_threads(void)
1124 {
1125         struct device_information *dip;
1126         int i;
1127
1128         for_each_dip(dip, i)
1129                 stop_threads(dip);
1130 }
1131
1132 static void stop_all_tracing(void)
1133 {
1134         struct device_information *dip;
1135         int i;
1136
1137         for_each_dip(dip, i)
1138                 stop_trace(dip);
1139 }
1140
1141 static void exit_trace(int status)
1142 {
1143         if (!is_trace_stopped()) {
1144                 trace_stopped = 1;
1145                 stop_all_threads();
1146                 stop_all_tracing();
1147         }
1148
1149         exit(status);
1150 }
1151
1152 static int resize_devices(char *path)
1153 {
1154         int size = (ndevs + 1) * sizeof(struct device_information);
1155
1156         device_information = realloc(device_information, size);
1157         if (!device_information) {
1158                 fprintf(stderr, "Out of memory, device %s (%d)\n", path, size);
1159                 return 1;
1160         }
1161         device_information[ndevs].path = path;
1162         ndevs++;
1163         return 0;
1164 }
1165
1166 static int open_devices(void)
1167 {
1168         struct device_information *dip;
1169         int i;
1170
1171         for_each_dip(dip, i) {
1172                 dip->fd = open(dip->path, O_RDONLY | O_NONBLOCK);
1173                 if (dip->fd < 0) {
1174                         perror(dip->path);
1175                         return 1;
1176                 }
1177         }
1178
1179         return 0;
1180 }
1181
1182 static int start_devices(void)
1183 {
1184         struct device_information *dip;
1185         int i, j, size;
1186
1187         size = ncpus * sizeof(struct thread_information);
1188         thread_information = malloc(size * ndevs);
1189         if (!thread_information) {
1190                 fprintf(stderr, "Out of memory, threads (%d)\n", size * ndevs);
1191                 return 1;
1192         }
1193
1194         for_each_dip(dip, i) {
1195                 if (start_trace(dip)) {
1196                         close(dip->fd);
1197                         fprintf(stderr, "Failed to start trace on %s\n",
1198                                 dip->path);
1199                         break;
1200                 }
1201         }
1202
1203         if (i != ndevs) {
1204                 __for_each_dip(dip, device_information, i, j)
1205                         stop_trace(dip);
1206
1207                 return 1;
1208         }
1209
1210         for_each_dip(dip, i) {
1211                 dip->threads = thread_information + (i * ncpus);
1212                 if (start_threads(dip)) {
1213                         fprintf(stderr, "Failed to start worker threads\n");
1214                         break;
1215                 }
1216         }
1217
1218         if (i != ndevs) {
1219                 __for_each_dip(dip, device_information, i, j)
1220                         stop_threads(dip);
1221                 for_each_dip(dip, i)
1222                         stop_trace(dip);
1223
1224                 return 1;
1225         }
1226
1227         return 0;
1228 }
1229
1230 static void show_stats(struct device_information *dips, int ndips, int cpus)
1231 {
1232         struct device_information *dip;
1233         struct thread_information *tip;
1234         unsigned long long events_processed, data_read;
1235         unsigned long total_drops;
1236         int i, j, no_stdout = 0;
1237
1238         if (is_stat_shown())
1239                 return;
1240
1241         if (output_name && !strcmp(output_name, "-"))
1242                 no_stdout = 1;
1243
1244         stat_shown = 1;
1245
1246         total_drops = 0;
1247         __for_each_dip(dip, dips, ndips, i) {
1248                 if (!no_stdout)
1249                         printf("Device: %s\n", dip->path);
1250                 events_processed = 0;
1251                 data_read = 0;
1252                 __for_each_tip(dip, tip, cpus, j) {
1253                         if (!no_stdout)
1254                                 printf("  CPU%3d: %20lu events, %8llu KiB data\n",
1255                                         tip->cpu, tip->events_processed,
1256                                         (tip->data_read + 1023) >> 10);
1257                         events_processed += tip->events_processed;
1258                         data_read += tip->data_read;
1259                 }
1260                 total_drops += dip->drop_count;
1261                 if (!no_stdout)
1262                         printf("  Total:  %20llu events (dropped %lu), %8llu KiB data\n",
1263                                         events_processed, dip->drop_count,
1264                                         (data_read + 1023) >> 10);
1265         }
1266
1267         if (total_drops)
1268                 fprintf(stderr, "You have dropped events, consider using a larger buffer size (-b)\n");
1269 }
1270
1271 static struct device_information *net_get_dip(struct net_connection *nc,
1272                                               char *buts_name)
1273 {
1274         struct device_information *dip;
1275         int i;
1276
1277         for (i = 0; i < nc->ndevs; i++) {
1278                 dip = &nc->device_information[i];
1279
1280                 if (!strcmp(dip->buts_name, buts_name))
1281                         return dip;
1282         }
1283
1284         nc->device_information = realloc(nc->device_information, (nc->ndevs + 1) * sizeof(*dip));
1285         dip = &nc->device_information[nc->ndevs];
1286         memset(dip, 0, sizeof(*dip));
1287         dip->fd = -1;
1288         dip->nc = nc;
1289         strcpy(dip->buts_name, buts_name);
1290         dip->path = strdup(buts_name);
1291         dip->trace_started = 1;
1292         nc->ndevs++;
1293         dip->threads = malloc(nc->ncpus * sizeof(struct thread_information));
1294         memset(dip->threads, 0, nc->ncpus * sizeof(struct thread_information));
1295
1296         /*
1297          * open all files
1298          */
1299         for (i = 0; i < nc->ncpus; i++) {
1300                 struct thread_information *tip = &dip->threads[i];
1301
1302                 tip->cpu = i;
1303                 tip->device = dip;
1304                 tip->fd = -1;
1305
1306                 if (tip_open_output(dip, tip))
1307                         return NULL;
1308         }
1309
1310         return dip;
1311 }
1312
1313 static struct thread_information *net_get_tip(struct net_connection *nc,
1314                                               struct blktrace_net_hdr *bnh)
1315 {
1316         struct device_information *dip;
1317
1318         nc->ncpus = bnh->max_cpus;
1319         dip = net_get_dip(nc, bnh->buts_name);
1320         if (!dip->trace_started) {
1321                 fprintf(stderr, "Events for closed devices %s\n", dip->buts_name);
1322                 return NULL;
1323         }
1324
1325         return &dip->threads[bnh->cpu];
1326 }
1327
1328 static int net_get_header(struct net_connection *nc,
1329                           struct blktrace_net_hdr *bnh)
1330 {
1331         int fl = fcntl(nc->in_fd, F_GETFL);
1332         int bytes_left, ret;
1333         void *p = bnh;
1334
1335         fcntl(nc->in_fd, F_SETFL, fl | O_NONBLOCK);
1336         bytes_left = sizeof(*bnh);
1337         while (bytes_left && !is_done()) {
1338                 ret = recv(nc->in_fd, p, bytes_left, MSG_WAITALL);
1339                 if (ret < 0) {
1340                         if (errno != EAGAIN) {
1341                                 perror("recv header");
1342                                 return 1;
1343                         }
1344                         usleep(1000);
1345                         continue;
1346                 } else if (!ret) {
1347                         usleep(1000);
1348                         continue;
1349                 } else {
1350                         p += ret;
1351                         bytes_left -= ret;
1352                 }
1353         }
1354         fcntl(nc->in_fd, F_SETFL, fl & ~O_NONBLOCK);
1355         return bytes_left;
1356 }
1357
1358 /*
1359  * finalize a net client: truncate files, show stats, cleanup, etc
1360  */
1361 static void net_client_done(struct net_connection *nc)
1362 {
1363         struct device_information *dip;
1364         struct thread_information *tip;
1365         struct net_connection *last_nc;
1366         int i, j;
1367
1368         for_each_nc_dip(nc, dip, i)
1369                 __for_each_tip(dip, tip, nc->ncpus, j)
1370                         tip_ftrunc_final(tip);
1371
1372         show_stats(nc->device_information, nc->ndevs, nc->ncpus);
1373
1374         /*
1375          * cleanup for next run
1376          */
1377         for_each_nc_dip(nc, dip, i) {
1378                 __for_each_tip(dip, tip, nc->ncpus, j) {
1379                         if (tip->ofile)
1380                                 fclose(tip->ofile);
1381                 }
1382
1383                 free(dip->threads);
1384                 free(dip->path);
1385         }
1386
1387         free(nc->device_information);
1388         nc->device_information = NULL;
1389         nc->ncpus = nc->ndevs = 0;
1390
1391         close(nc->in_fd);
1392         nc->in_fd = -1;
1393
1394         net_connects--;
1395
1396         /*
1397          * now put last entry where this one was, a little nasty since we
1398          * need to adjust dip->nc as well
1399          */
1400         if (nc->connection_index != net_connects) {
1401                 last_nc = &net_connections[net_connects];
1402                 *nc = *last_nc;
1403                 for_each_nc_dip(nc, dip, i)
1404                         dip->nc = nc;
1405         }
1406
1407         stat_shown = 0;
1408 }
1409
1410 /*
1411  * handle incoming events from a net client
1412  */
1413 static int net_client_data(struct net_connection *nc)
1414 {
1415         struct thread_information *tip;
1416         struct blktrace_net_hdr bnh;
1417
1418         if (net_get_header(nc, &bnh))
1419                 return 1;
1420
1421         if (data_is_native == -1 && check_data_endianness(bnh.magic)) {
1422                 fprintf(stderr, "server: received data is bad\n");
1423                 return 1;
1424         }
1425
1426         if (!data_is_native) {
1427                 bnh.magic = be32_to_cpu(bnh.magic);
1428                 bnh.cpu = be32_to_cpu(bnh.cpu);
1429                 bnh.len = be32_to_cpu(bnh.len);
1430         }
1431
1432         if ((bnh.magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) {
1433                 fprintf(stderr, "server: bad data magic\n");
1434                 return 1;
1435         }
1436
1437         /*
1438          * len == 0 means that the other end signalled end-of-run
1439          */
1440         if (!bnh.len) {
1441                 /*
1442                  * overload cpu count with dropped events
1443                  */
1444                 struct device_information *dip;
1445
1446                 dip = net_get_dip(nc, bnh.buts_name);
1447                 dip->drop_count = bnh.cpu;
1448                 dip->trace_started = 0;
1449
1450                 printf("server: end of run for %s\n", dip->buts_name);
1451                 net_client_done(nc);
1452                 return 0;
1453         }
1454
1455         tip = net_get_tip(nc, &bnh);
1456         if (!tip)
1457                 return 1;
1458
1459         if (mmap_subbuf(tip, bnh.len))
1460                 return 1;
1461
1462         return 0;
1463 }
1464
1465 static void net_add_connection(int listen_fd, struct sockaddr_in *addr)
1466 {
1467         socklen_t socklen = sizeof(*addr);
1468         struct net_connection *nc;
1469
1470         if (net_connects == NET_MAX_CONNECTIONS) {
1471                 fprintf(stderr, "server: no more connections allowed\n");
1472                 return;
1473         }
1474
1475         nc = &net_connections[net_connects];
1476         memset(nc, 0, sizeof(*nc));
1477
1478         nc->in_fd = accept(listen_fd, (struct sockaddr *) addr, &socklen);
1479         if (nc->in_fd < 0) {
1480                 perror("accept");
1481                 return;
1482         }
1483
1484         printf("server: connection from %s\n", inet_ntoa(addr->sin_addr));
1485         time(&nc->connect_time);
1486         nc->connection_index = net_connects;
1487         nc->cl_in_addr = addr->sin_addr;
1488         net_connects++;
1489 }
1490
1491 /*
1492  * event driven loop, handle new incoming connections and data from
1493  * existing connections
1494  */
1495 static void net_server_handle_connections(int listen_fd,
1496                                           struct sockaddr_in *addr)
1497 {
1498         struct pollfd pfds[NET_MAX_CONNECTIONS + 1];
1499         int i, events;
1500
1501         printf("server: waiting for connections...\n");
1502
1503         while (!is_done()) {
1504                 /*
1505                  * the zero entry is for incoming connections, remaining
1506                  * entries for clients
1507                  */
1508                 pfds[0].fd = listen_fd;
1509                 pfds[0].events = POLLIN;
1510                 for (i = 0; i < net_connects; i++) {
1511                         pfds[i + 1].fd = net_connections[i].in_fd;
1512                         pfds[i + 1].events = POLLIN;
1513                 }
1514
1515                 events = poll(pfds, 1 + net_connects, -1);
1516                 if (events < 0) {
1517                         if (errno == EINTR)
1518                                 continue;
1519
1520                         perror("poll");
1521                         break;
1522                 } else if (!events)
1523                         continue;
1524
1525                 if (pfds[0].revents & POLLIN) {
1526                         net_add_connection(listen_fd, addr);
1527                         events--;
1528                 }
1529
1530                 for (i = 0; events && i < net_connects; i++) {
1531                         if (pfds[i + 1].revents & POLLIN) {
1532                                 net_client_data(&net_connections[i]);
1533                                 events--;
1534                         }
1535                 }
1536         }
1537 }
1538
1539 /*
1540  * Start here when we are in server mode - just fetch data from the network
1541  * and dump to files
1542  */
1543 static int net_server(void)
1544 {
1545         struct sockaddr_in addr;
1546         int fd, opt;
1547
1548         fd = socket(AF_INET, SOCK_STREAM, 0);
1549         if (fd < 0) {
1550                 perror("server: socket");
1551                 return 1;
1552         }
1553
1554         opt = 1;
1555         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
1556                 perror("setsockopt");
1557                 return 1;
1558         }
1559
1560         memset(&addr, 0, sizeof(addr));
1561         addr.sin_family = AF_INET;
1562         addr.sin_addr.s_addr = htonl(INADDR_ANY);
1563         addr.sin_port = htons(net_port);
1564
1565         if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1566                 perror("bind");
1567                 return 1;
1568         }
1569
1570         if (listen(fd, 1) < 0) {
1571                 perror("listen");
1572                 return 1;
1573         }
1574
1575         net_server_handle_connections(fd, &addr);
1576         return 0;
1577 }
1578
1579 /*
1580  * Setup outgoing network connection where we will transmit data
1581  */
1582 static int net_setup_client(void)
1583 {
1584         struct sockaddr_in addr;
1585         int fd;
1586
1587         fd = socket(AF_INET, SOCK_STREAM, 0);
1588         if (fd < 0) {
1589                 perror("client: socket");
1590                 return 1;
1591         }
1592
1593         memset(&addr, 0, sizeof(addr));
1594         addr.sin_family = AF_INET;
1595         addr.sin_port = htons(net_port);
1596
1597         if (inet_aton(hostname, &addr.sin_addr) != 1) {
1598                 struct hostent *hent = gethostbyname(hostname);
1599                 if (!hent) {
1600                         perror("gethostbyname");
1601                         return 1;
1602                 }
1603
1604                 memcpy(&addr.sin_addr, hent->h_addr, 4);
1605                 strcpy(hostname, hent->h_name);
1606         }
1607
1608         printf("blktrace: connecting to %s\n", hostname);
1609
1610         if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1611                 perror("client: connect");
1612                 return 1;
1613         }
1614
1615         printf("blktrace: connected!\n");
1616         net_out_fd = fd;
1617         return 0;
1618 }
1619
1620 static char usage_str[] = \
1621         "-d <dev> [ -r relay path ] [ -o <output> ] [-k ] [ -w time ]\n" \
1622         "[ -a action ] [ -A action mask ] [ -v ]\n\n" \
1623         "\t-d Use specified device. May also be given last after options\n" \
1624         "\t-r Path to mounted relayfs, defaults to /relay\n" \
1625         "\t-o File(s) to send output to\n" \
1626         "\t-D Directory to prepend to output file names\n" \
1627         "\t-k Kill a running trace\n" \
1628         "\t-w Stop after defined time, in seconds\n" \
1629         "\t-a Only trace specified actions. See documentation\n" \
1630         "\t-A Give trace mask as a single value. See documentation\n" \
1631         "\t-b Sub buffer size in KiB\n" \
1632         "\t-n Number of sub buffers\n" \
1633         "\t-l Run in network listen mode (blktrace server)\n" \
1634         "\t-h Run in network client mode, connecting to the given host\n" \
1635         "\t-p Network port to use (default 8462)\n" \
1636         "\t-s Make the network client use sendfile() to transfer data\n" \
1637         "\t-V Print program version info\n\n";
1638
1639 static void show_usage(char *program)
1640 {
1641         fprintf(stderr, "Usage: %s %s %s",program, blktrace_version, usage_str);
1642 }
1643
1644 int main(int argc, char *argv[])
1645 {
1646         static char default_relay_path[] = "/relay";
1647         struct statfs st;
1648         int i, c;
1649         int stop_watch = 0;
1650         int act_mask_tmp = 0;
1651
1652         while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) >= 0) {
1653                 switch (c) {
1654                 case 'a':
1655                         i = find_mask_map(optarg);
1656                         if (i < 0) {
1657                                 fprintf(stderr,"Invalid action mask %s\n",
1658                                         optarg);
1659                                 return 1;
1660                         }
1661                         act_mask_tmp |= i;
1662                         break;
1663
1664                 case 'A':
1665                         if ((sscanf(optarg, "%x", &i) != 1) || 
1666                                                         !valid_act_opt(i)) {
1667                                 fprintf(stderr,
1668                                         "Invalid set action mask %s/0x%x\n",
1669                                         optarg, i);
1670                                 return 1;
1671                         }
1672                         act_mask_tmp = i;
1673                         break;
1674
1675                 case 'd':
1676                         if (resize_devices(optarg) != 0)
1677                                 return 1;
1678                         break;
1679
1680                 case 'r':
1681                         relay_path = optarg;
1682                         break;
1683
1684                 case 'o':
1685                         output_name = optarg;
1686                         break;
1687                 case 'k':
1688                         kill_running_trace = 1;
1689                         break;
1690                 case 'w':
1691                         stop_watch = atoi(optarg);
1692                         if (stop_watch <= 0) {
1693                                 fprintf(stderr,
1694                                         "Invalid stopwatch value (%d secs)\n",
1695                                         stop_watch);
1696                                 return 1;
1697                         }
1698                         break;
1699                 case 'V':
1700                         printf("%s version %s\n", argv[0], blktrace_version);
1701                         return 0;
1702                 case 'b':
1703                         buf_size = strtoul(optarg, NULL, 10);
1704                         if (buf_size <= 0 || buf_size > 16*1024) {
1705                                 fprintf(stderr,
1706                                         "Invalid buffer size (%lu)\n",buf_size);
1707                                 return 1;
1708                         }
1709                         buf_size <<= 10;
1710                         break;
1711                 case 'n':
1712                         buf_nr = strtoul(optarg, NULL, 10);
1713                         if (buf_nr <= 0) {
1714                                 fprintf(stderr,
1715                                         "Invalid buffer nr (%lu)\n", buf_nr);
1716                                 return 1;
1717                         }
1718                         break;
1719                 case 'D':
1720                         output_dir = optarg;
1721                         break;
1722                 case 'h':
1723                         net_mode = Net_client;
1724                         strcpy(hostname, optarg);
1725                         break;
1726                 case 'l':
1727                         net_mode = Net_server;
1728                         break;
1729                 case 'p':
1730                         net_port = atoi(optarg);
1731                         break;
1732                 case 's':
1733                         net_use_sendfile = 1;
1734                         break;
1735                 default:
1736                         show_usage(argv[0]);
1737                         return 1;
1738                 }
1739         }
1740
1741         setlocale(LC_NUMERIC, "en_US");
1742
1743         page_size = getpagesize();
1744
1745         if (net_mode == Net_server)
1746                 return net_server();
1747
1748         while (optind < argc) {
1749                 if (resize_devices(argv[optind++]) != 0)
1750                         return 1;
1751         }
1752
1753         if (ndevs == 0) {
1754                 show_usage(argv[0]);
1755                 return 1;
1756         }
1757
1758         if (!relay_path)
1759                 relay_path = default_relay_path;
1760
1761         if (act_mask_tmp != 0)
1762                 act_mask = act_mask_tmp;
1763
1764         if (statfs(relay_path, &st) < 0) {
1765                 perror("statfs");
1766                 fprintf(stderr,"%s does not appear to be a valid path\n",
1767                         relay_path);
1768                 return 1;
1769         } else if (st.f_type != (long) RELAYFS_TYPE) {
1770                 fprintf(stderr,"%s does not appear to be a relay filesystem\n",
1771                         relay_path);
1772                 return 1;
1773         }
1774
1775         if (open_devices() != 0)
1776                 return 1;
1777
1778         if (kill_running_trace) {
1779                 stop_all_traces();
1780                 return 0;
1781         }
1782
1783         ncpus = sysconf(_SC_NPROCESSORS_ONLN);
1784         if (ncpus < 0) {
1785                 fprintf(stderr, "sysconf(_SC_NPROCESSORS_ONLN) failed\n");
1786                 return 1;
1787         }
1788
1789         signal(SIGINT, handle_sigint);
1790         signal(SIGHUP, handle_sigint);
1791         signal(SIGTERM, handle_sigint);
1792         signal(SIGALRM, handle_sigint);
1793
1794         if (net_mode == Net_client && net_setup_client())
1795                 return 1;
1796
1797         if (start_devices() != 0)
1798                 return 1;
1799
1800         atexit(stop_all_tracing);
1801
1802         if (stop_watch)
1803                 alarm(stop_watch);
1804
1805         wait_for_threads();
1806
1807         if (!is_trace_stopped()) {
1808                 trace_stopped = 1;
1809                 stop_all_threads();
1810                 stop_all_traces();
1811         }
1812
1813         show_stats(device_information, ndevs, ncpus);
1814
1815         return 0;
1816 }
1817