[PATCH] blktrace: handle case where output directory is not set
[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 DEBUGFS_TYPE    0x64626720
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 = "no-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 *debugfs_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 = 1;
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                  debugfs_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                         debugfs_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         else
985                 len = sprintf(dst, "./");
986
987         if (net_mode == Net_server) {
988                 struct net_connection *nc = dip->nc;
989
990                 len += sprintf(dst + len, "%s-", inet_ntoa(nc->cl_in_addr));
991                 len += strftime(dst + len, 64, "%F-%T/", gmtime(&nc->connect_time));
992         }
993
994         if (stat(dst, &sb) < 0) {
995                 if (errno != ENOENT) {
996                         perror("stat");
997                         return 1;
998                 }
999                 if (mkdir(dst, 0755) < 0) {
1000                         perror(dst);
1001                         fprintf(stderr, "Can't make output dir\n");
1002                         return 1;
1003                 }
1004         }
1005
1006         if (output_name)
1007                 sprintf(dst + len, "%s.blktrace.%d", output_name, tip->cpu);
1008         else
1009                 sprintf(dst + len, "%s.blktrace.%d", buts_name, tip->cpu);
1010
1011         return 0;
1012 }
1013
1014 static void fill_ops(struct thread_information *tip)
1015 {
1016         /*
1017          * setup ops
1018          */
1019         if (net_mode == Net_client) {
1020                 if (net_use_sendfile) {
1021                         tip->get_subbuf = get_subbuf_sendfile;
1022                         tip->flush_subbuf = flush_subbuf_sendfile;
1023                 } else {
1024                         tip->get_subbuf = get_subbuf;
1025                         tip->flush_subbuf = flush_subbuf_net;
1026                 }
1027         } else {
1028                 if (tip->ofile_mmap)
1029                         tip->get_subbuf = mmap_subbuf;
1030                 else
1031                         tip->get_subbuf = get_subbuf;
1032
1033                 tip->flush_subbuf = flush_subbuf_file;
1034         }
1035                         
1036         if (net_mode == Net_server)
1037                 tip->read_data = read_data_net;
1038         else
1039                 tip->read_data = read_data_file;
1040 }
1041
1042 static int tip_open_output(struct device_information *dip,
1043                            struct thread_information *tip)
1044 {
1045         int pipeline = output_name && !strcmp(output_name, "-");
1046         int mode, vbuf_size;
1047         char op[128];
1048
1049         if (net_mode == Net_client) {
1050                 tip->ofile = NULL;
1051                 tip->ofile_stdout = 0;
1052                 tip->ofile_mmap = 0;
1053                 goto done;
1054         } else if (pipeline) {
1055                 tip->ofile = fdopen(STDOUT_FILENO, "w");
1056                 tip->ofile_stdout = 1;
1057                 tip->ofile_mmap = 0;
1058                 mode = _IOLBF;
1059                 vbuf_size = 512;
1060         } else {
1061                 if (fill_ofname(dip, tip, op, dip->buts_name))
1062                         return 1;
1063                 tip->ofile = fopen(op, "w+");
1064                 tip->ofile_stdout = 0;
1065                 tip->ofile_mmap = 1;
1066                 mode = _IOFBF;
1067                 vbuf_size = OFILE_BUF;
1068         }
1069
1070         if (tip->ofile == NULL) {
1071                 perror(op);
1072                 return 1;
1073         }
1074
1075         tip->ofile_buffer = malloc(vbuf_size);
1076         if (setvbuf(tip->ofile, tip->ofile_buffer, mode, vbuf_size)) {
1077                 perror("setvbuf");
1078                 close_thread(tip);
1079                 return 1;
1080         }
1081
1082 done:
1083         fill_ops(tip);
1084         return 0;
1085 }
1086
1087 static int start_threads(struct device_information *dip)
1088 {
1089         struct thread_information *tip;
1090         int j;
1091
1092         for_each_tip(dip, tip, j) {
1093                 tip->cpu = j;
1094                 tip->device = dip;
1095                 tip->events_processed = 0;
1096                 tip->fd = -1;
1097                 memset(&tip->fifo, 0, sizeof(tip->fifo));
1098                 tip->leftover_ts = NULL;
1099
1100                 if (tip_open_output(dip, tip))
1101                         return 1;
1102
1103                 if (pthread_create(&tip->thread, NULL, thread_main, tip)) {
1104                         perror("pthread_create");
1105                         close_thread(tip);
1106                         return 1;
1107                 }
1108         }
1109
1110         return 0;
1111 }
1112
1113 static void stop_threads(struct device_information *dip)
1114 {
1115         struct thread_information *tip;
1116         unsigned long ret;
1117         int i;
1118
1119         for_each_tip(dip, tip, i) {
1120                 (void) pthread_join(tip->thread, (void *) &ret);
1121                 close_thread(tip);
1122         }
1123 }
1124
1125 static void stop_all_threads(void)
1126 {
1127         struct device_information *dip;
1128         int i;
1129
1130         for_each_dip(dip, i)
1131                 stop_threads(dip);
1132 }
1133
1134 static void stop_all_tracing(void)
1135 {
1136         struct device_information *dip;
1137         int i;
1138
1139         for_each_dip(dip, i)
1140                 stop_trace(dip);
1141 }
1142
1143 static void exit_trace(int status)
1144 {
1145         if (!is_trace_stopped()) {
1146                 trace_stopped = 1;
1147                 stop_all_threads();
1148                 stop_all_tracing();
1149         }
1150
1151         exit(status);
1152 }
1153
1154 static int resize_devices(char *path)
1155 {
1156         int size = (ndevs + 1) * sizeof(struct device_information);
1157
1158         device_information = realloc(device_information, size);
1159         if (!device_information) {
1160                 fprintf(stderr, "Out of memory, device %s (%d)\n", path, size);
1161                 return 1;
1162         }
1163         device_information[ndevs].path = path;
1164         ndevs++;
1165         return 0;
1166 }
1167
1168 static int open_devices(void)
1169 {
1170         struct device_information *dip;
1171         int i;
1172
1173         for_each_dip(dip, i) {
1174                 dip->fd = open(dip->path, O_RDONLY | O_NONBLOCK);
1175                 if (dip->fd < 0) {
1176                         perror(dip->path);
1177                         return 1;
1178                 }
1179         }
1180
1181         return 0;
1182 }
1183
1184 static int start_devices(void)
1185 {
1186         struct device_information *dip;
1187         int i, j, size;
1188
1189         size = ncpus * sizeof(struct thread_information);
1190         thread_information = malloc(size * ndevs);
1191         if (!thread_information) {
1192                 fprintf(stderr, "Out of memory, threads (%d)\n", size * ndevs);
1193                 return 1;
1194         }
1195
1196         for_each_dip(dip, i) {
1197                 if (start_trace(dip)) {
1198                         close(dip->fd);
1199                         fprintf(stderr, "Failed to start trace on %s\n",
1200                                 dip->path);
1201                         break;
1202                 }
1203         }
1204
1205         if (i != ndevs) {
1206                 __for_each_dip(dip, device_information, i, j)
1207                         stop_trace(dip);
1208
1209                 return 1;
1210         }
1211
1212         for_each_dip(dip, i) {
1213                 dip->threads = thread_information + (i * ncpus);
1214                 if (start_threads(dip)) {
1215                         fprintf(stderr, "Failed to start worker threads\n");
1216                         break;
1217                 }
1218         }
1219
1220         if (i != ndevs) {
1221                 __for_each_dip(dip, device_information, i, j)
1222                         stop_threads(dip);
1223                 for_each_dip(dip, i)
1224                         stop_trace(dip);
1225
1226                 return 1;
1227         }
1228
1229         return 0;
1230 }
1231
1232 static void show_stats(struct device_information *dips, int ndips, int cpus)
1233 {
1234         struct device_information *dip;
1235         struct thread_information *tip;
1236         unsigned long long events_processed, data_read;
1237         unsigned long total_drops;
1238         int i, j, no_stdout = 0;
1239
1240         if (is_stat_shown())
1241                 return;
1242
1243         if (output_name && !strcmp(output_name, "-"))
1244                 no_stdout = 1;
1245
1246         stat_shown = 1;
1247
1248         total_drops = 0;
1249         __for_each_dip(dip, dips, ndips, i) {
1250                 if (!no_stdout)
1251                         printf("Device: %s\n", dip->path);
1252                 events_processed = 0;
1253                 data_read = 0;
1254                 __for_each_tip(dip, tip, cpus, j) {
1255                         if (!no_stdout)
1256                                 printf("  CPU%3d: %20lu events, %8llu KiB data\n",
1257                                         tip->cpu, tip->events_processed,
1258                                         (tip->data_read + 1023) >> 10);
1259                         events_processed += tip->events_processed;
1260                         data_read += tip->data_read;
1261                 }
1262                 total_drops += dip->drop_count;
1263                 if (!no_stdout)
1264                         printf("  Total:  %20llu events (dropped %lu), %8llu KiB data\n",
1265                                         events_processed, dip->drop_count,
1266                                         (data_read + 1023) >> 10);
1267         }
1268
1269         if (total_drops)
1270                 fprintf(stderr, "You have dropped events, consider using a larger buffer size (-b)\n");
1271 }
1272
1273 static struct device_information *net_get_dip(struct net_connection *nc,
1274                                               char *buts_name)
1275 {
1276         struct device_information *dip;
1277         int i;
1278
1279         for (i = 0; i < nc->ndevs; i++) {
1280                 dip = &nc->device_information[i];
1281
1282                 if (!strcmp(dip->buts_name, buts_name))
1283                         return dip;
1284         }
1285
1286         nc->device_information = realloc(nc->device_information, (nc->ndevs + 1) * sizeof(*dip));
1287         dip = &nc->device_information[nc->ndevs];
1288         memset(dip, 0, sizeof(*dip));
1289         dip->fd = -1;
1290         dip->nc = nc;
1291         strcpy(dip->buts_name, buts_name);
1292         dip->path = strdup(buts_name);
1293         dip->trace_started = 1;
1294         nc->ndevs++;
1295         dip->threads = malloc(nc->ncpus * sizeof(struct thread_information));
1296         memset(dip->threads, 0, nc->ncpus * sizeof(struct thread_information));
1297
1298         /*
1299          * open all files
1300          */
1301         for (i = 0; i < nc->ncpus; i++) {
1302                 struct thread_information *tip = &dip->threads[i];
1303
1304                 tip->cpu = i;
1305                 tip->device = dip;
1306                 tip->fd = -1;
1307
1308                 if (tip_open_output(dip, tip))
1309                         return NULL;
1310         }
1311
1312         return dip;
1313 }
1314
1315 static struct thread_information *net_get_tip(struct net_connection *nc,
1316                                               struct blktrace_net_hdr *bnh)
1317 {
1318         struct device_information *dip;
1319
1320         nc->ncpus = bnh->max_cpus;
1321         dip = net_get_dip(nc, bnh->buts_name);
1322         if (!dip->trace_started) {
1323                 fprintf(stderr, "Events for closed devices %s\n", dip->buts_name);
1324                 return NULL;
1325         }
1326
1327         return &dip->threads[bnh->cpu];
1328 }
1329
1330 static int net_get_header(struct net_connection *nc,
1331                           struct blktrace_net_hdr *bnh)
1332 {
1333         int fl = fcntl(nc->in_fd, F_GETFL);
1334         int bytes_left, ret;
1335         void *p = bnh;
1336
1337         fcntl(nc->in_fd, F_SETFL, fl | O_NONBLOCK);
1338         bytes_left = sizeof(*bnh);
1339         while (bytes_left && !is_done()) {
1340                 ret = recv(nc->in_fd, p, bytes_left, MSG_WAITALL);
1341                 if (ret < 0) {
1342                         if (errno != EAGAIN) {
1343                                 perror("recv header");
1344                                 return 1;
1345                         }
1346                         usleep(1000);
1347                         continue;
1348                 } else if (!ret) {
1349                         usleep(1000);
1350                         continue;
1351                 } else {
1352                         p += ret;
1353                         bytes_left -= ret;
1354                 }
1355         }
1356         fcntl(nc->in_fd, F_SETFL, fl & ~O_NONBLOCK);
1357         return bytes_left;
1358 }
1359
1360 /*
1361  * finalize a net client: truncate files, show stats, cleanup, etc
1362  */
1363 static void net_client_done(struct net_connection *nc)
1364 {
1365         struct device_information *dip;
1366         struct thread_information *tip;
1367         struct net_connection *last_nc;
1368         int i, j;
1369
1370         for_each_nc_dip(nc, dip, i)
1371                 __for_each_tip(dip, tip, nc->ncpus, j)
1372                         tip_ftrunc_final(tip);
1373
1374         show_stats(nc->device_information, nc->ndevs, nc->ncpus);
1375
1376         /*
1377          * cleanup for next run
1378          */
1379         for_each_nc_dip(nc, dip, i) {
1380                 __for_each_tip(dip, tip, nc->ncpus, j) {
1381                         if (tip->ofile)
1382                                 fclose(tip->ofile);
1383                 }
1384
1385                 free(dip->threads);
1386                 free(dip->path);
1387         }
1388
1389         free(nc->device_information);
1390         nc->device_information = NULL;
1391         nc->ncpus = nc->ndevs = 0;
1392
1393         close(nc->in_fd);
1394         nc->in_fd = -1;
1395
1396         net_connects--;
1397
1398         /*
1399          * now put last entry where this one was, a little nasty since we
1400          * need to adjust dip->nc as well
1401          */
1402         if (nc->connection_index != net_connects) {
1403                 last_nc = &net_connections[net_connects];
1404                 *nc = *last_nc;
1405                 for_each_nc_dip(nc, dip, i)
1406                         dip->nc = nc;
1407         }
1408
1409         stat_shown = 0;
1410 }
1411
1412 /*
1413  * handle incoming events from a net client
1414  */
1415 static int net_client_data(struct net_connection *nc)
1416 {
1417         struct thread_information *tip;
1418         struct blktrace_net_hdr bnh;
1419
1420         if (net_get_header(nc, &bnh))
1421                 return 1;
1422
1423         if (data_is_native == -1 && check_data_endianness(bnh.magic)) {
1424                 fprintf(stderr, "server: received data is bad\n");
1425                 return 1;
1426         }
1427
1428         if (!data_is_native) {
1429                 bnh.magic = be32_to_cpu(bnh.magic);
1430                 bnh.cpu = be32_to_cpu(bnh.cpu);
1431                 bnh.len = be32_to_cpu(bnh.len);
1432         }
1433
1434         if ((bnh.magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) {
1435                 fprintf(stderr, "server: bad data magic\n");
1436                 return 1;
1437         }
1438
1439         /*
1440          * len == 0 means that the other end signalled end-of-run
1441          */
1442         if (!bnh.len) {
1443                 /*
1444                  * overload cpu count with dropped events
1445                  */
1446                 struct device_information *dip;
1447
1448                 dip = net_get_dip(nc, bnh.buts_name);
1449                 dip->drop_count = bnh.cpu;
1450                 dip->trace_started = 0;
1451
1452                 printf("server: end of run for %s\n", dip->buts_name);
1453                 net_client_done(nc);
1454                 return 0;
1455         }
1456
1457         tip = net_get_tip(nc, &bnh);
1458         if (!tip)
1459                 return 1;
1460
1461         if (mmap_subbuf(tip, bnh.len))
1462                 return 1;
1463
1464         return 0;
1465 }
1466
1467 static void net_add_connection(int listen_fd, struct sockaddr_in *addr)
1468 {
1469         socklen_t socklen = sizeof(*addr);
1470         struct net_connection *nc;
1471
1472         if (net_connects == NET_MAX_CONNECTIONS) {
1473                 fprintf(stderr, "server: no more connections allowed\n");
1474                 return;
1475         }
1476
1477         nc = &net_connections[net_connects];
1478         memset(nc, 0, sizeof(*nc));
1479
1480         nc->in_fd = accept(listen_fd, (struct sockaddr *) addr, &socklen);
1481         if (nc->in_fd < 0) {
1482                 perror("accept");
1483                 return;
1484         }
1485
1486         printf("server: connection from %s\n", inet_ntoa(addr->sin_addr));
1487         time(&nc->connect_time);
1488         nc->connection_index = net_connects;
1489         nc->cl_in_addr = addr->sin_addr;
1490         net_connects++;
1491 }
1492
1493 /*
1494  * event driven loop, handle new incoming connections and data from
1495  * existing connections
1496  */
1497 static void net_server_handle_connections(int listen_fd,
1498                                           struct sockaddr_in *addr)
1499 {
1500         struct pollfd pfds[NET_MAX_CONNECTIONS + 1];
1501         int i, events;
1502
1503         printf("server: waiting for connections...\n");
1504
1505         while (!is_done()) {
1506                 /*
1507                  * the zero entry is for incoming connections, remaining
1508                  * entries for clients
1509                  */
1510                 pfds[0].fd = listen_fd;
1511                 pfds[0].events = POLLIN;
1512                 for (i = 0; i < net_connects; i++) {
1513                         pfds[i + 1].fd = net_connections[i].in_fd;
1514                         pfds[i + 1].events = POLLIN;
1515                 }
1516
1517                 events = poll(pfds, 1 + net_connects, -1);
1518                 if (events < 0) {
1519                         if (errno == EINTR)
1520                                 continue;
1521
1522                         perror("poll");
1523                         break;
1524                 } else if (!events)
1525                         continue;
1526
1527                 if (pfds[0].revents & POLLIN) {
1528                         net_add_connection(listen_fd, addr);
1529                         events--;
1530                 }
1531
1532                 for (i = 0; events && i < net_connects; i++) {
1533                         if (pfds[i + 1].revents & POLLIN) {
1534                                 net_client_data(&net_connections[i]);
1535                                 events--;
1536                         }
1537                 }
1538         }
1539 }
1540
1541 /*
1542  * Start here when we are in server mode - just fetch data from the network
1543  * and dump to files
1544  */
1545 static int net_server(void)
1546 {
1547         struct sockaddr_in addr;
1548         int fd, opt;
1549
1550         fd = socket(AF_INET, SOCK_STREAM, 0);
1551         if (fd < 0) {
1552                 perror("server: socket");
1553                 return 1;
1554         }
1555
1556         opt = 1;
1557         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
1558                 perror("setsockopt");
1559                 return 1;
1560         }
1561
1562         memset(&addr, 0, sizeof(addr));
1563         addr.sin_family = AF_INET;
1564         addr.sin_addr.s_addr = htonl(INADDR_ANY);
1565         addr.sin_port = htons(net_port);
1566
1567         if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1568                 perror("bind");
1569                 return 1;
1570         }
1571
1572         if (listen(fd, 1) < 0) {
1573                 perror("listen");
1574                 return 1;
1575         }
1576
1577         net_server_handle_connections(fd, &addr);
1578         return 0;
1579 }
1580
1581 /*
1582  * Setup outgoing network connection where we will transmit data
1583  */
1584 static int net_setup_client(void)
1585 {
1586         struct sockaddr_in addr;
1587         int fd;
1588
1589         fd = socket(AF_INET, SOCK_STREAM, 0);
1590         if (fd < 0) {
1591                 perror("client: socket");
1592                 return 1;
1593         }
1594
1595         memset(&addr, 0, sizeof(addr));
1596         addr.sin_family = AF_INET;
1597         addr.sin_port = htons(net_port);
1598
1599         if (inet_aton(hostname, &addr.sin_addr) != 1) {
1600                 struct hostent *hent = gethostbyname(hostname);
1601                 if (!hent) {
1602                         perror("gethostbyname");
1603                         return 1;
1604                 }
1605
1606                 memcpy(&addr.sin_addr, hent->h_addr, 4);
1607                 strcpy(hostname, hent->h_name);
1608         }
1609
1610         printf("blktrace: connecting to %s\n", hostname);
1611
1612         if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1613                 perror("client: connect");
1614                 return 1;
1615         }
1616
1617         printf("blktrace: connected!\n");
1618         net_out_fd = fd;
1619         return 0;
1620 }
1621
1622 static char usage_str[] = \
1623         "-d <dev> [ -r debugfs path ] [ -o <output> ] [-k ] [ -w time ]\n" \
1624         "[ -a action ] [ -A action mask ] [ -v ]\n\n" \
1625         "\t-d Use specified device. May also be given last after options\n" \
1626         "\t-r Path to mounted debugfs, defaults to /debug\n" \
1627         "\t-o File(s) to send output to\n" \
1628         "\t-D Directory to prepend to output file names\n" \
1629         "\t-k Kill a running trace\n" \
1630         "\t-w Stop after defined time, in seconds\n" \
1631         "\t-a Only trace specified actions. See documentation\n" \
1632         "\t-A Give trace mask as a single value. See documentation\n" \
1633         "\t-b Sub buffer size in KiB\n" \
1634         "\t-n Number of sub buffers\n" \
1635         "\t-l Run in network listen mode (blktrace server)\n" \
1636         "\t-h Run in network client mode, connecting to the given host\n" \
1637         "\t-p Network port to use (default 8462)\n" \
1638         "\t-s Make the network client use sendfile() to transfer data\n" \
1639         "\t-V Print program version info\n\n";
1640
1641 static void show_usage(char *program)
1642 {
1643         fprintf(stderr, "Usage: %s %s %s",program, blktrace_version, usage_str);
1644 }
1645
1646 int main(int argc, char *argv[])
1647 {
1648         static char default_debugfs_path[] = "/debug";
1649         struct statfs st;
1650         int i, c;
1651         int stop_watch = 0;
1652         int act_mask_tmp = 0;
1653
1654         while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) >= 0) {
1655                 switch (c) {
1656                 case 'a':
1657                         i = find_mask_map(optarg);
1658                         if (i < 0) {
1659                                 fprintf(stderr,"Invalid action mask %s\n",
1660                                         optarg);
1661                                 return 1;
1662                         }
1663                         act_mask_tmp |= i;
1664                         break;
1665
1666                 case 'A':
1667                         if ((sscanf(optarg, "%x", &i) != 1) || 
1668                                                         !valid_act_opt(i)) {
1669                                 fprintf(stderr,
1670                                         "Invalid set action mask %s/0x%x\n",
1671                                         optarg, i);
1672                                 return 1;
1673                         }
1674                         act_mask_tmp = i;
1675                         break;
1676
1677                 case 'd':
1678                         if (resize_devices(optarg) != 0)
1679                                 return 1;
1680                         break;
1681
1682                 case 'r':
1683                         debugfs_path = optarg;
1684                         break;
1685
1686                 case 'o':
1687                         output_name = optarg;
1688                         break;
1689                 case 'k':
1690                         kill_running_trace = 1;
1691                         break;
1692                 case 'w':
1693                         stop_watch = atoi(optarg);
1694                         if (stop_watch <= 0) {
1695                                 fprintf(stderr,
1696                                         "Invalid stopwatch value (%d secs)\n",
1697                                         stop_watch);
1698                                 return 1;
1699                         }
1700                         break;
1701                 case 'V':
1702                         printf("%s version %s\n", argv[0], blktrace_version);
1703                         return 0;
1704                 case 'b':
1705                         buf_size = strtoul(optarg, NULL, 10);
1706                         if (buf_size <= 0 || buf_size > 16*1024) {
1707                                 fprintf(stderr,
1708                                         "Invalid buffer size (%lu)\n",buf_size);
1709                                 return 1;
1710                         }
1711                         buf_size <<= 10;
1712                         break;
1713                 case 'n':
1714                         buf_nr = strtoul(optarg, NULL, 10);
1715                         if (buf_nr <= 0) {
1716                                 fprintf(stderr,
1717                                         "Invalid buffer nr (%lu)\n", buf_nr);
1718                                 return 1;
1719                         }
1720                         break;
1721                 case 'D':
1722                         output_dir = optarg;
1723                         break;
1724                 case 'h':
1725                         net_mode = Net_client;
1726                         strcpy(hostname, optarg);
1727                         break;
1728                 case 'l':
1729                         net_mode = Net_server;
1730                         break;
1731                 case 'p':
1732                         net_port = atoi(optarg);
1733                         break;
1734                 case 's':
1735                         net_use_sendfile = 0;
1736                         break;
1737                 default:
1738                         show_usage(argv[0]);
1739                         return 1;
1740                 }
1741         }
1742
1743         setlocale(LC_NUMERIC, "en_US");
1744
1745         page_size = getpagesize();
1746
1747         if (net_mode == Net_server)
1748                 return net_server();
1749
1750         while (optind < argc) {
1751                 if (resize_devices(argv[optind++]) != 0)
1752                         return 1;
1753         }
1754
1755         if (ndevs == 0) {
1756                 show_usage(argv[0]);
1757                 return 1;
1758         }
1759
1760         if (act_mask_tmp != 0)
1761                 act_mask = act_mask_tmp;
1762
1763         if (!debugfs_path)
1764                 debugfs_path = default_debugfs_path;
1765
1766         if (statfs(debugfs_path, &st) < 0) {
1767                 perror("statfs");
1768                 fprintf(stderr,"%s does not appear to be a valid path\n",
1769                         debugfs_path);
1770                 return 1;
1771         } else if (st.f_type != (long) DEBUGFS_TYPE) {
1772                 fprintf(stderr,"%s does not appear to be a debug filesystem\n",
1773                         debugfs_path);
1774                 return 1;
1775         }
1776
1777         if (open_devices() != 0)
1778                 return 1;
1779
1780         if (kill_running_trace) {
1781                 stop_all_traces();
1782                 return 0;
1783         }
1784
1785         ncpus = sysconf(_SC_NPROCESSORS_ONLN);
1786         if (ncpus < 0) {
1787                 fprintf(stderr, "sysconf(_SC_NPROCESSORS_ONLN) failed\n");
1788                 return 1;
1789         }
1790
1791         signal(SIGINT, handle_sigint);
1792         signal(SIGHUP, handle_sigint);
1793         signal(SIGTERM, handle_sigint);
1794         signal(SIGALRM, handle_sigint);
1795
1796         if (net_mode == Net_client && net_setup_client())
1797                 return 1;
1798
1799         if (start_devices() != 0)
1800                 return 1;
1801
1802         atexit(stop_all_tracing);
1803
1804         if (stop_watch)
1805                 alarm(stop_watch);
1806
1807         wait_for_threads();
1808
1809         if (!is_trace_stopped()) {
1810                 trace_stopped = 1;
1811                 stop_all_threads();
1812                 stop_all_traces();
1813         }
1814
1815         show_stats(device_information, ndevs, ncpus);
1816
1817         return 0;
1818 }
1819