1e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat/*
2e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat * I/O monitor based on block queue trace data
3e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *
4e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat * Copyright IBM Corp. 2008
5e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *
6e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat * Author(s): Martin Peschke <mp3@de.ibm.com>
7e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *
8e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *  This program is free software; you can redistribute it and/or modify
9e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *  it under the terms of the GNU General Public License as published by
10e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *  the Free Software Foundation; either version 2 of the License, or
11e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *  (at your option) any later version.
12e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *
13e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *  This program is distributed in the hope that it will be useful,
14e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *  GNU General Public License for more details.
17e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *
18e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *  You should have received a copy of the GNU General Public License
19e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *  along with this program; if not, write to the Free Software
20e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat */
22e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
23e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <sys/types.h>
24e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <sys/stat.h>
25e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <fcntl.h>
26e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <unistd.h>
27e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <stdio.h>
28e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <stdlib.h>
29e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <string.h>
30e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <signal.h>
31e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <getopt.h>
32e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <errno.h>
33e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <locale.h>
34e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <libgen.h>
35e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <sys/msg.h>
36e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <pthread.h>
37e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include <time.h>
38e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
39e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include "blktrace.h"
40e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include "rbtree.h"
41e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include "jhash.h"
42e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#include "blkiomon.h"
43e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
44e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstruct trace {
45e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct blk_io_trace bit;
46e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct rb_node node;
47e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct trace *next;
48e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	long sequence;
49e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat};
50e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
51e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstruct rb_search {
52e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct rb_node **node_ptr;
53e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct rb_node *parent;
54e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat};
55e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
56e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstruct dstat_msg {
57e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	long mtype;
58e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct blkiomon_stat stat;
59e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat};
60e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
61e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstruct dstat {
62e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct dstat_msg msg;
63e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct rb_node node;
64e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct dstat *next;
65e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat};
66e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
67e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstruct output {
68e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	char *fn;
69e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	FILE *fp;
70e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	char *buf;
71e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	int pipe;
72e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat};
73e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
74e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic char blkiomon_version[] = "0.3";
75e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
76e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic FILE *ifp;
77e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int interval = -1;
78e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
79e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct trace *vacant_traces_list = NULL;
80e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int vacant_traces = 0;
81e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
82e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#define TRACE_HASH_SIZE 128
83e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstruct trace *thash[TRACE_HASH_SIZE] = {};
84e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
85e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct dstat *vacant_dstats_list = NULL;
86e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct rb_root dstat_tree[2] = { RB_ROOT, RB_ROOT };
87e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct dstat *dstat_list[2] = {};
88e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int dstat_curr = 0;
89e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
90e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct output drvdata, human, binary, debug;
91e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
92e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic char *msg_q_name = NULL;
93e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int msg_q_id = -1, msg_q = -1;
94e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic long msg_id = -1;
95e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
96e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic pthread_t interval_thread;
97e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic pthread_mutex_t dstat_mutex = PTHREAD_MUTEX_INITIALIZER;
98e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
99e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatint data_is_native = -1;
100e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
101e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int up = 1;
102e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
103e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat/* debugging */
104e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic long leftover = 0, driverdata = 0, match = 0, mismatch = 0, sequence = 0;
105e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
106e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic void dump_bit(struct trace *t, const char *descr)
107e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
108e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct blk_io_trace *bit = &t->bit;
109e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
110e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!debug.fn)
111e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return;
112e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
113e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "--- %s ---\n", descr);
114e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "magic    %16d\n", bit->magic);
115e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "sequence %16d\n", bit->sequence);
116e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "time     %16ld\n", (unsigned long)bit->time);
117e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "sector   %16ld\n", (unsigned long)bit->sector);
118e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "bytes    %16d\n", bit->bytes);
119e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "action   %16x\n", bit->action);
120e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "pid      %16d\n", bit->pid);
121e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "device   %16d\n", bit->device);
122e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "cpu      %16d\n", bit->cpu);
123e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "error    %16d\n", bit->error);
124e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "pdu_len  %16d\n", bit->pdu_len);
125e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
126e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "order    %16ld\n", t->sequence);
127e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
128e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
129e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic void dump_bits(struct trace *t1, struct trace *t2, const char *descr)
130e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
131e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct blk_io_trace *bit1 = &t1->bit;
132e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct blk_io_trace *bit2 = &t2->bit;
133e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
134e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!debug.fn)
135e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return;
136e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
137e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "--- %s ---\n", descr);
138e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "magic    %16d %16d\n", bit1->magic, bit2->magic);
139e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "sequence %16d %16d\n",
140e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		bit1->sequence, bit2->sequence);
141e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "time     %16ld %16ld\n",
142e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		(unsigned long)bit1->time, (unsigned long)bit2->time);
143e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "sector   %16ld %16ld\n",
144e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		(unsigned long)bit1->sector, (unsigned long)bit2->sector);
145e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "bytes    %16d %16d\n", bit1->bytes, bit2->bytes);
146e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "action   %16x %16x\n", bit1->action, bit2->action);
147e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "pid      %16d %16d\n", bit1->pid, bit2->pid);
148e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "device   %16d %16d\n", bit1->device, bit2->device);
149e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "cpu      %16d %16d\n", bit1->cpu, bit2->cpu);
150e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "error    %16d %16d\n", bit1->error, bit2->error);
151e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "pdu_len  %16d %16d\n", bit1->pdu_len, bit2->pdu_len);
152e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
153e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "order    %16ld %16ld\n", t1->sequence, t2->sequence);
154e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
155e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
156e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct dstat *blkiomon_alloc_dstat(void)
157e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
158e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct dstat *dstat;
159e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
160e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (vacant_dstats_list) {
161e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		dstat = vacant_dstats_list;
162e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		vacant_dstats_list = dstat->next;
163e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	} else
164e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		dstat = malloc(sizeof(*dstat));
165e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!dstat) {
166e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		fprintf(stderr,
167e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			"blkiomon: could not allocate device statistic");
168e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return NULL;
169e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
170e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
171e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	blkiomon_stat_init(&dstat->msg.stat);
172e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return dstat;
173e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
174e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
175e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct dstat *blkiomon_find_dstat(struct rb_search *search, __u32 device)
176e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
177e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct rb_node **p = &(dstat_tree[dstat_curr].rb_node);
178e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct rb_node *parent = NULL;
179e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct dstat *dstat;
180e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
181e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	while (*p) {
182e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		parent = *p;
183e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
184e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		dstat = rb_entry(parent, struct dstat, node);
185e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
186e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (dstat->msg.stat.device < device)
187e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			p = &(*p)->rb_left;
188e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		else if (dstat->msg.stat.device > device)
189e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			p = &(*p)->rb_right;
190e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		else
191e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			return dstat;
192e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
193e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	search->node_ptr = p;
194e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	search->parent = parent;
195e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return NULL;
196e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
197e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
198e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct dstat *blkiomon_get_dstat(__u32 device)
199e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
200e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct dstat *dstat;
201e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct rb_search search;
202e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
203e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	pthread_mutex_lock(&dstat_mutex);
204e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
205e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	dstat = blkiomon_find_dstat(&search, device);
206e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (dstat)
207e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		goto out;
208e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
209e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	dstat = blkiomon_alloc_dstat();
210e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!dstat)
211e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		goto out;
212e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
213e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	dstat->msg.stat.device = device;
214e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
215e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	rb_link_node(&dstat->node, search.parent, search.node_ptr);
216e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	rb_insert_color(&dstat->node, &dstat_tree[dstat_curr]);
217e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
218e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	dstat->next = dstat_list[dstat_curr];
219e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	dstat_list[dstat_curr] = dstat;
220e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
221e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatout:
222e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	pthread_mutex_unlock(&dstat_mutex);
223e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return dstat;
224e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
225e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
226e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int blkiomon_output_msg_q(struct dstat *dstat)
227e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
228e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!msg_q_name)
229e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 0;
230e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
231e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	dstat->msg.mtype = msg_id;
232e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return msgsnd(msg_q, &dstat->msg, sizeof(struct blkiomon_stat), 0);
233e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
234e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
235e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int blkiomon_output_binary(struct dstat *dstat)
236e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
237e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct blkiomon_stat *p = &dstat->msg.stat;
238e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
239e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!binary.fn)
240e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 0;
241e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
242e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (fwrite(p, sizeof(*p), 1, binary.fp) != 1)
243e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		goto failed;
244e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (binary.pipe && fflush(binary.fp))
245e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		goto failed;
246e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return 0;
247e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
248e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatfailed:
249e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(stderr, "blkiomon: could not write to %s\n", binary.fn);
250e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fclose(binary.fp);
251e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	binary.fn = NULL;
252e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return 1;
253e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
254e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
255e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct dstat *blkiomon_output(struct dstat *head, struct timespec *ts)
256e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
257e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct dstat *dstat, *tail = NULL;
258e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
259e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	for (dstat = head; dstat; dstat = dstat->next) {
260e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		dstat->msg.stat.time = ts->tv_sec;
261e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		blkiomon_stat_print(human.fp, &dstat->msg.stat);
262e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		blkiomon_stat_to_be(&dstat->msg.stat);
263e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		blkiomon_output_binary(dstat);
264e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		blkiomon_output_msg_q(dstat);
265e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		tail = dstat;
266e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
267e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return tail;
268e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
269e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
270e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic void *blkiomon_interval(void *data)
271e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
272e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct timespec wake, r;
273e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct dstat *head, *tail;
274e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	int finished;
275e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
276e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	clock_gettime(CLOCK_REALTIME, &wake);
277e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
278e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	while (1) {
279e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		wake.tv_sec += interval;
280e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &wake, &r)) {
281e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			fprintf(stderr, "blkiomon: interrupted sleep");
282e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			continue;
283e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		}
284e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
285e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		/* grab tree and make data gatherer build up another tree */
286e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		pthread_mutex_lock(&dstat_mutex);
287e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		finished = dstat_curr;
288e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		dstat_curr = dstat_curr ? 0 : 1;
289e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		pthread_mutex_unlock(&dstat_mutex);
290e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
291e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		head = dstat_list[finished];
292e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (!head)
293e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			continue;
294e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		dstat_list[finished] = NULL;
295e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		dstat_tree[finished] = RB_ROOT;
296e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		tail = blkiomon_output(head, &wake);
297e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
298e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		pthread_mutex_lock(&dstat_mutex);
299e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		tail->next = vacant_dstats_list;
300e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		vacant_dstats_list = head;
301e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		pthread_mutex_unlock(&dstat_mutex);
302e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
303e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return data;
304e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
305e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
306e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#define BLK_DATADIR(a) (((a) >> BLK_TC_SHIFT) & (BLK_TC_READ | BLK_TC_WRITE))
307e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
308e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int blkiomon_account(struct blk_io_trace *bit_d,
309e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			    struct blk_io_trace *bit_c)
310e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
311e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct dstat *dstat;
312e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct blkiomon_stat *p;
313e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	__u64 d2c = (bit_c->time - bit_d->time) / 1000; /* ns -> us */
314e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	__u32 size = bit_d->bytes;
315e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	__u64 thrput = size * 1000 / d2c;
316e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
317e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	dstat = blkiomon_get_dstat(bit_d->device);
318e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!dstat)
319e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
320e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	p = &dstat->msg.stat;
321e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
322e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (BLK_DATADIR(bit_c->action) & BLK_TC_READ) {
323e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		minmax_account(&p->thrput_r, thrput);
324e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		minmax_account(&p->size_r, size);
325e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		minmax_account(&p->d2c_r, d2c);
326e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	} else if (BLK_DATADIR(bit_c->action) & BLK_TC_WRITE) {
327e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		minmax_account(&p->thrput_w, thrput);
328e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		minmax_account(&p->size_w, size);
329e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		minmax_account(&p->d2c_w, d2c);
330e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	} else
331e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		p->bidir++;
332e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
333e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	histlog2_account(p->size_hist, size, &size_hist);
334e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	histlog2_account(p->d2c_hist, d2c, &d2c_hist);
335e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return 0;
336e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
337e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
338e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct trace *blkiomon_alloc_trace(void)
339e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
340e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct trace *t = vacant_traces_list;
341e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (t) {
342e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		vacant_traces_list = t->next;
343e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		vacant_traces--;
344e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	} else
345e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		t = malloc(sizeof(*t));
346e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	memset(t, 0, sizeof(*t));
347e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return t;
348e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
349e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
350e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic void blkiomon_free_trace(struct trace *t)
351e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
352e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (vacant_traces < 256) {
353e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		t->next = vacant_traces_list;
354e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		vacant_traces_list = t;
355e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		vacant_traces++;
356e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	} else
357e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		free(t);
358e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
359e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
360e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int action(int a)
361e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
362e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	int bits = BLK_TC_WRITE | BLK_TC_READ | BLK_TC_FS | BLK_TC_PC;
363e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return a & (BLK_TC_ACT(bits));
364e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
365e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
366e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic void blkiomon_store_trace(struct trace *t)
367e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
368e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	int i = t->bit.sector % TRACE_HASH_SIZE;
369e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
370e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	t->next = thash[i];
371e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	thash[i] = t;
372e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
373e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
374e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct trace *blkiomon_fetch_trace(struct blk_io_trace *bit)
375e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
376e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	int i = bit->sector % TRACE_HASH_SIZE;
377e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct trace *t, *prev = NULL;
378e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
379e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	for (t = thash[i]; t; t = t->next) {
380e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (t->bit.device == bit->device &&
381e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		    t->bit.sector == bit->sector &&
382e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		    action(t->bit.action) == action(bit->action)) {
383e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			if (prev)
384e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat				prev->next = t->next;
385e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			else
386e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat				thash[i] = t->next;
387e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			return t;
388e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		}
389e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		prev = t;
390e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
391e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return NULL;
392e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
393e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
394e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct trace *blkiomon_do_trace(struct trace *t)
395e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
396e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct trace *t_stored, *t_old, *t_young;
397e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
398e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	/* store trace if there is no match yet */
399e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	t_stored = blkiomon_fetch_trace(&t->bit);
400e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!t_stored) {
401e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		blkiomon_store_trace(t);
402e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return blkiomon_alloc_trace();
403e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
404e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
405e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	/* figure out older trace and younger trace */
406e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (t_stored->bit.time < t->bit.time) {
407e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		t_old = t_stored;
408e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		t_young = t;
409e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	} else {
410e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		t_old = t;
411e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		t_young = t_stored;
412e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
413e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
414e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	/* we need an older D trace and a younger C trace */
415e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (t_old->bit.action & BLK_TC_ACT(BLK_TC_ISSUE) &&
416e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	    t_young->bit.action & BLK_TC_ACT(BLK_TC_COMPLETE)) {
417e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		/* matching D and C traces - update statistics */
418e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		match++;
419e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		blkiomon_account(&t_old->bit, &t_young->bit);
420e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		blkiomon_free_trace(t_stored);
421e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return t;
422e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
423e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
424e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	/* no matching D and C traces - keep more recent trace */
425e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	dump_bits(t_old, t_young, "mismatch");
426e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	mismatch++;
427e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	blkiomon_store_trace(t_young);
428e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return t_old;
429e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
430e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
431e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int blkiomon_dump_drvdata(struct blk_io_trace *bit, void *pdu_buf)
432e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
433e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!drvdata.fn)
434e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 0;
435e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
436e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (fwrite(bit, sizeof(*bit), 1, drvdata.fp) != 1)
437e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		goto failed;
438e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (fwrite(pdu_buf, bit->pdu_len, 1, drvdata.fp) != 1)
439e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		goto failed;
440e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (drvdata.pipe && fflush(drvdata.fp))
441e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		goto failed;
442e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return 0;
443e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
444e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatfailed:
445e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(stderr, "blkiomon: could not write to %s\n", drvdata.fn);
446e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fclose(drvdata.fp);
447e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	drvdata.fn = NULL;
448e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return 1;
449e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
450e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
451e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int blkiomon_do_fifo(void)
452e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
453e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct trace *t;
454e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct blk_io_trace *bit;
455e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	void *pdu_buf = NULL;
456e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
457e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	t = blkiomon_alloc_trace();
458e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!t)
459e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
460e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	bit = &t->bit;
461e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
462e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	while (up) {
463e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (fread(bit, sizeof(*bit), 1, ifp) != 1) {
464e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			if (!feof(ifp))
465e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat				fprintf(stderr,
466e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat					"blkiomon: could not read trace");
467e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
468e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		}
469e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (ferror(ifp)) {
470e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			clearerr(ifp);
471e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			fprintf(stderr, "blkiomon: error while reading trace");
472e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
473e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		}
474e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
475e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (data_is_native == -1 && check_data_endianness(bit->magic)) {
476e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			fprintf(stderr, "blkiomon: endianess problem\n");
477e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
478e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		}
479e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
480e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		/* endianess */
481e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		trace_to_cpu(bit);
482e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (verify_trace(bit)) {
483e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			fprintf(stderr, "blkiomon: bad trace\n");
484e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
485e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		}
486e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
487e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		/* read additional trace payload */
488e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (bit->pdu_len) {
489e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			pdu_buf = realloc(pdu_buf, bit->pdu_len);
490e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			if (fread(pdu_buf, bit->pdu_len, 1, ifp) != 1) {
491e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat				clearerr(ifp);
492e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat				fprintf(stderr, "blkiomon: could not read payload\n");
493e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat				break;
494e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			}
495e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		}
496e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
497e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		t->sequence = sequence++;
498e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
499e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		/* forward low-level device driver trace to other tool */
500e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (bit->action & BLK_TC_ACT(BLK_TC_DRV_DATA)) {
501e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			driverdata++;
502e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			if (blkiomon_dump_drvdata(bit, pdu_buf)) {
503e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat				fprintf(stderr, "blkiomon: could not send trace\n");
504e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat				break;
505e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			}
506e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			continue;
507e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		}
508e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
509e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (!(bit->action & BLK_TC_ACT(BLK_TC_ISSUE | BLK_TC_COMPLETE)))
510e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			continue;
511e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
512e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		/* try to find matching trace and update statistics */
513e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		t = blkiomon_do_trace(t);
514e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (!t) {
515e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			fprintf(stderr, "blkiomon: could not alloc trace\n");
516e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
517e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		}
518e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		bit = &t->bit;
519e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		/* t and bit will be recycled for next incoming trace */
520e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
521e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	blkiomon_free_trace(t);
522e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	free(pdu_buf);
523e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return 0;
524e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
525e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
526e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int blkiomon_open_output(struct output *out)
527e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
528e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	int mode, vbuf_size;
529e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
530e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!out->fn)
531e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 0;
532e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
533e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!strcmp(out->fn, "-")) {
534e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		out->fp = fdopen(STDOUT_FILENO, "w");
535e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		mode = _IOLBF;
536e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		vbuf_size = 4096;
537e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		out->pipe = 1;
538e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	} else {
539e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		out->fp = fopen(out->fn, "w");
540e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		mode = _IOFBF;
541e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		vbuf_size = 128 * 1024;
542e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		out->pipe = 0;
543e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
544e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!out->fp)
545e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		goto failed;
546e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	out->buf = malloc(128 * 1024);
547e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (setvbuf(out->fp, out->buf, mode, vbuf_size))
548e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		goto failed;
549e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return 0;
550e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
551e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatfailed:
552e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(stderr, "blkiomon: could not write to %s\n", out->fn);
553e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	out->fn = NULL;
554e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	free(out->buf);
555e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return 1;
556e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
557e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
558e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic int blkiomon_open_msg_q(void)
559e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
560e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	key_t key;
561e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
562e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!msg_q_name)
563e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 0;
564e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!msg_q_id || msg_id <= 0)
565e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
566e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	key = ftok(msg_q_name, msg_q_id);
567e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (key == -1)
568e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
569e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	while (up) {
570e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		msg_q = msgget(key, S_IRWXU);
571e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		if (msg_q >= 0)
572e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
573e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
574e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return (msg_q >= 0 ? 0 : -1);
575e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
576e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
577e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic void blkiomon_debug(void)
578e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
579e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	int i;
580e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	struct trace *t;
581e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
582e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!debug.fn)
583e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return;
584e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
585e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	for (i = 0; i < TRACE_HASH_SIZE; i++)
586e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		for (t = thash[i]; t; t = t->next) {
587e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			dump_bit(t, "leftover");
588e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			leftover++;
589e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		}
590e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
591e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(debug.fp, "%ld leftover, %ld match, %ld mismatch, "
592e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		"%ld driverdata, %ld overall\n",
593e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		leftover, match, mismatch, driverdata, sequence);
594e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
595e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
596e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat#define S_OPTS "b:d:D:h:I:Q:q:m:V"
597e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
598e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic char usage_str[] = "\n\nblkiomon " \
599e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"-I <interval>       | --interval=<interval>\n" \
600e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"[ -h <file>         | --human-readable=<file> ]\n" \
601e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"[ -b <file>         | --binary=<file> ]\n" \
602e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"[ -D <file>         | --debug=<file> ]\n" \
603e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"[ -Q <path name>    | --msg-queue=<path name>]\n" \
604e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"[ -q <msg queue id> | --msg-queue-id=<msg queue id>]\n" \
605e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"[ -m <msg id>       | --msg-id=<msg id>]\n" \
606e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"[ -V                | --version ]\n\n" \
607e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"\t-I   Sample interval.\n" \
608e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"\t-h   Human-readable output file.\n" \
609e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"\t-b   Binary output file.\n" \
610e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"\t-d   Output file for data emitted by low level device driver.\n" \
611e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"\t-D   Output file for debugging data.\n" \
612e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"\t-Qqm Output to message queue using given ID for messages.\n" \
613e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	"\t-V   Print program version.\n\n";
614e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
615e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic struct option l_opts[] = {
616e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	{
617e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.name = "human-readable",
618e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.has_arg = required_argument,
619e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.flag = NULL,
620e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.val = 'h'
621e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	},
622e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	{
623e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.name = "binary",
624e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.has_arg = required_argument,
625e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.flag = NULL,
626e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.val = 'b'
627e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	},
628e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	{
629e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.name = "dump-lldd",
630e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.has_arg = required_argument,
631e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.flag = NULL,
632e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.val = 'd'
633e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	},
634e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	{
635e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.name = "debug",
636e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.has_arg = required_argument,
637e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.flag = NULL,
638e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.val = 'D'
639e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	},
640e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	{
641e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.name = "interval",
642e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.has_arg = required_argument,
643e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.flag = NULL,
644e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.val = 'I'
645e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	},
646e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	{
647e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.name = "msg-queue",
648e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.has_arg = required_argument,
649e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.flag = NULL,
650e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.val = 'Q'
651e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	},
652e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	{
653e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.name = "msg-queue-id",
654e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.has_arg = required_argument,
655e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.flag = NULL,
656e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.val = 'q'
657e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	},
658e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	{
659e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.name = "msg-id",
660e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.has_arg = required_argument,
661e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.flag = NULL,
662e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.val = 'm'
663e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	},
664e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	{
665e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.name = "version",
666e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.has_arg = no_argument,
667e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.flag = NULL,
668e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.val = 'V'
669e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	},
670e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	{
671e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		.name = NULL,
672e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
673e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat};
674e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
675e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatstatic void blkiomon_signal(int signal)
676e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
677e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	fprintf(stderr, "blkiomon: terminated by signal\n");
678e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	up = signal & 0;
679e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
680e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
681e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehatint main(int argc, char *argv[])
682e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat{
683e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	int c;
684e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
685e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	signal(SIGALRM, blkiomon_signal);
686e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	signal(SIGINT, blkiomon_signal);
687e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	signal(SIGTERM, blkiomon_signal);
688e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	signal(SIGQUIT, blkiomon_signal);
689e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
690e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) != -1) {
691e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		switch (c) {
692e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		case 'h':
693e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			human.fn = optarg;
694e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
695e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		case 'b':
696e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			binary.fn = optarg;
697e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
698e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		case 'd':
699e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			drvdata.fn = optarg;
700e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
701e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		case 'D':
702e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			debug.fn = optarg;
703e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
704e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		case 'I':
705e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			interval = atoi(optarg);
706e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
707e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		case 'Q':
708e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			msg_q_name = optarg;
709e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
710e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		case 'q':
711e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			msg_q_id = atoi(optarg);
712e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
713e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		case 'm':
714e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			msg_id = atoi(optarg);
715e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			break;
716e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		case 'V':
717e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			printf("%s version %s\n", argv[0], blkiomon_version);
718e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			return 0;
719e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		default:
720e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			fprintf(stderr, "Usage: %s", usage_str);
721e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat			return 1;
722e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		}
723e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
724e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
725e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (interval <= 0) {
726e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		fprintf(stderr, "Usage: %s", usage_str);
727e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
728e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
729e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
730e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	ifp = fdopen(STDIN_FILENO, "r");
731e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (!ifp) {
732e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		perror("blkiomon: could not open stdin for reading");
733e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
734e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
735e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
736e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (blkiomon_open_output(&human))
737e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
738e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (blkiomon_open_output(&binary))
739e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
740e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (blkiomon_open_output(&drvdata))
741e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
742e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (blkiomon_open_output(&debug))
743e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
744e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (blkiomon_open_msg_q())
745e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
746e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
747e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	if (pthread_create(&interval_thread, NULL, blkiomon_interval, NULL)) {
748e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		fprintf(stderr, "blkiomon: could not create thread");
749e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat		return 1;
750e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	}
751e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
752e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	blkiomon_do_fifo();
753e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat
754e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	blkiomon_debug();
755e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat	return 0;
756e20e1347b9914aa05e30548c15d7cd5e412cc0e2San Mehat}
757