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