* block queue tracing application
*
* Copyright (C) 2005 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "blktrace.h"
#include "barrier.h"
-static char blktrace_version[] = "0.99.1";
+static char blktrace_version[] = "0.99.3";
/*
* You may want to increase this even more, if you are logging at a high
#define DEBUGFS_TYPE 0x64626720
-#define S_OPTS "d:a:A:r:o:kw:Vb:n:D:lh:p:s"
+#define S_OPTS "d:a:A:r:o:kw:Vb:n:D:lh:p:sI:"
static struct option l_opts[] = {
{
.name = "dev",
.flag = NULL,
.val = 'd'
},
+ {
+ .name = "input-devs",
+ .has_arg = required_argument,
+ .flag = NULL,
+ .val = 'I'
+ },
{
.name = "act-mask",
.has_arg = required_argument,
volatile int trace_started;
unsigned long drop_count;
struct thread_information *threads;
+ unsigned long buf_size;
+ unsigned long buf_nr;
+ unsigned int page_size;
struct cl_host *ch;
u32 cl_id;
u32 max_cpus;
u32 len; /* length of following trace data */
u32 cl_id; /* id for set of client per-cpu connections */
+ u32 buf_size; /* client buf_size for this trace */
+ u32 buf_nr; /* client buf_nr for this trace */
+ u32 page_size; /* client page_size for this trace */
};
#define TRACE_NET_PORT (8462)
struct blk_user_trace_setup buts;
memset(&buts, 0, sizeof(buts));
- buts.buf_size = buf_size;
- buts.buf_nr = buf_nr;
+ buts.buf_size = dip->buf_size;
+ buts.buf_nr = dip->buf_nr;
buts.act_mask = act_mask;
if (ioctl(dip->fd, BLKTRACESETUP, &buts) < 0) {
{
int ofd = fileno(tip->ofile);
int ret;
+ unsigned long nr;
/*
* extend file, if we have to. use chunks of 16 subbuffers.
*/
- if (tip->fs_off + buf_size > tip->fs_buf_len) {
+ if (tip->fs_off + maxlen > tip->fs_buf_len) {
if (tip->fs_buf) {
munlock(tip->fs_buf, tip->fs_buf_len);
munmap(tip->fs_buf, tip->fs_buf_len);
tip->fs_buf = NULL;
}
- tip->fs_off = tip->fs_size & (page_size - 1);
- tip->fs_buf_len = (16 * buf_size) - tip->fs_off;
+ tip->fs_off = tip->fs_size & (tip->device->page_size - 1);
+ nr = max(16, tip->device->buf_nr);
+ tip->fs_buf_len = (nr * tip->device->buf_size) - tip->fs_off;
tip->fs_max_size += tip->fs_buf_len;
if (ftruncate(ofd, tip->fs_max_size) < 0) {
struct tip_subbuf *ts = malloc(sizeof(*ts));
int ret;
- ts->buf = malloc(buf_size);
+ ts->buf = malloc(tip->device->buf_size);
ts->max_len = maxlen;
ret = tip->read_data(tip, ts->buf, ts->max_len);
ts->len = ret;
tip->data_read += ret;
if (subbuf_fifo_queue(tip, ts))
- return -1;
+ ret = -1;
+ }
+
+ if (ret <= 0) {
+ free(ts->buf);
+ free(ts);
}
return ret;
}
while (!is_done()) {
- if (tip->get_subbuf(tip, buf_size) < 0)
+ if (tip->get_subbuf(tip, tip->device->buf_size) < 0)
break;
}
/*
* trace is stopped, pull data until we get a short read
*/
- while (tip->get_subbuf(tip, buf_size) > 0)
+ while (tip->get_subbuf(tip, tip->device->buf_size) > 0)
;
tip_ftrunc_final(tip);
hdr.max_cpus = ncpus;
hdr.len = len;
hdr.cl_id = getpid();
-
+ hdr.buf_size = tip->device->buf_size;
+ hdr.buf_nr = tip->device->buf_nr;
+ hdr.page_size = tip->device->page_size;
+
return write_data_net(net_out_fd[tip->cpu], &hdr, sizeof(hdr));
}
strcpy(hdr.buts_name, dip->buts_name);
hdr.cpu = get_dropped_count(dip->buts_name);
hdr.cl_id = getpid();
+ hdr.buf_size = dip->buf_size;
+ hdr.buf_nr = dip->buf_nr;
+ hdr.page_size = dip->page_size;
write_data_net(net_out_fd[0], &hdr, sizeof(hdr));
}
goto err;
tip->data_read += ts->len;
- tip->ofile_offset += buf_size;
ret = 1;
err:
free(ts);
struct stat sb;
unsigned int ready;
- wait_for_data(tip, 250);
+ wait_for_data(tip, -1);
if (fstat(tip->fd, &sb) < 0) {
perror("trace stat");
if (!buf_len)
return 0;
- while (1) {
- ret = fwrite(buf, buf_len, 1, tip->ofile);
- if (ret == 1)
- break;
-
- if (ret < 0) {
- perror("write");
- return 1;
- }
+ ret = fwrite(buf, buf_len, 1, tip->ofile);
+ if (ferror(tip->ofile) || ret != 1) {
+ perror("fwrite");
+ clearerr(tip->ofile);
+ return 1;
}
if (tip->ofile_stdout)
perror(dip->path);
return 1;
}
+ dip->buf_size = buf_size;
+ dip->buf_nr = buf_nr;
+ dip->page_size = page_size;
}
return 0;
fprintf(stderr, "Out of memory, threads (%d)\n", size * ndevs);
return 1;
}
+ memset(thread_information, 0, size * ndevs);
for_each_dip(dip, i) {
if (start_trace(dip)) {
}
static struct device_information *net_get_dip(struct net_connection *nc,
- char *buts_name, u32 cl_id)
+ struct blktrace_net_hdr *bnh)
{
struct device_information *dip, *cl_dip = NULL;
struct cl_host *ch = nc->ch;
for (i = 0; i < ch->ndevs; i++) {
dip = &ch->device_information[i];
- if (!strcmp(dip->buts_name, buts_name))
+ if (!strcmp(dip->buts_name, bnh->buts_name))
return dip;
- if (dip->cl_id == cl_id)
+ if (dip->cl_id == bnh->cl_id)
cl_dip = dip;
}
memset(dip, 0, sizeof(*dip));
dip->fd = -1;
dip->ch = ch;
- dip->cl_id = cl_id;
+ dip->cl_id = bnh->cl_id;
+ dip->buf_size = bnh->buf_size;
+ dip->buf_nr = bnh->buf_nr;
+ dip->page_size = bnh->page_size;
+
if (cl_dip)
dip->cl_connect_time = cl_dip->cl_connect_time;
else
dip->cl_connect_time = nc->connect_time;
- strcpy(dip->buts_name, buts_name);
- dip->path = strdup(buts_name);
+ strcpy(dip->buts_name, bnh->buts_name);
+ dip->path = strdup(bnh->buts_name);
dip->trace_started = 1;
ch->ndevs++;
dip->threads = malloc(nc->ncpus * sizeof(struct thread_information));
struct device_information *dip;
struct thread_information *tip;
- dip = net_get_dip(nc, bnh->buts_name, bnh->cl_id);
+ dip = net_get_dip(nc, bnh);
if (!dip->trace_started) {
fprintf(stderr, "Events for closed devices %s\n", dip->buts_name);
return NULL;
bnh.max_cpus = be32_to_cpu(bnh.max_cpus);
bnh.len = be32_to_cpu(bnh.len);
bnh.cl_id = be32_to_cpu(bnh.cl_id);
+ bnh.buf_size = be32_to_cpu(bnh.buf_size);
+ bnh.buf_nr = be32_to_cpu(bnh.buf_nr);
+ bnh.page_size = be32_to_cpu(bnh.page_size);
}
if ((bnh.magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) {
*/
struct device_information *dip;
- dip = net_get_dip(nc, bnh.buts_name, bnh.cl_id);
+ dip = net_get_dip(nc, &bnh);
dip->drop_count = bnh.cpu;
dip->trace_started = 0;
memset(ch, 0, sizeof(*ch));
ch->cl_in_addr = addr->sin_addr;
net_add_client_host(ch);
+
+ printf("server: connection from %s\n", inet_ntoa(addr->sin_addr));
}
ch->net_connections = realloc(ch->net_connections, (ch->nconn + 1) * sizeof(*nc));
nc = &ch->net_connections[ch->nconn++];
memset(nc, 0, sizeof(*nc));
- printf("server: connection from %s\n", inet_ntoa(addr->sin_addr));
time(&nc->connect_time);
nc->ch = ch;
nc->in_fd = in_fd;
static char usage_str[] = \
"-d <dev> [ -r debugfs path ] [ -o <output> ] [-k ] [ -w time ]\n" \
- "[ -a action ] [ -A action mask ] [ -v ]\n\n" \
+ "[ -a action ] [ -A action mask ] [ -I <devs file> ] [ -v ]\n\n" \
"\t-d Use specified device. May also be given last after options\n" \
- "\t-r Path to mounted debugfs, defaults to /debug\n" \
+ "\t-r Path to mounted debugfs, defaults to /sys/kernel/debug\n" \
"\t-o File(s) to send output to\n" \
"\t-D Directory to prepend to output file names\n" \
"\t-k Kill a running trace\n" \
"\t-h Run in network client mode, connecting to the given host\n" \
"\t-p Network port to use (default 8462)\n" \
"\t-s Make the network client NOT use sendfile() to transfer data\n" \
+ "\t-I Add devices found in <devs file>\n" \
"\t-V Print program version info\n\n";
static void show_usage(char *program)
int main(int argc, char *argv[])
{
- static char default_debugfs_path[] = "/debug";
+ static char default_debugfs_path[] = "/sys/kernel/debug";
struct statfs st;
int i, c;
int stop_watch = 0;
return 1;
break;
+ case 'I': {
+ char dev_line[256];
+ FILE *ifp = fopen(optarg, "r");
+
+ if (!ifp) {
+ fprintf(stderr,
+ "Invalid file for devices %s\n",
+ optarg);
+ return 1;
+ }
+
+ while (fscanf(ifp, "%s\n", dev_line) == 1)
+ if (resize_devices(strdup(dev_line)) != 0)
+ return 1;
+ break;
+ }
+
+
case 'r':
debugfs_path = optarg;
break;
page_size = getpagesize();
- if (net_mode == Net_server)
+ if (net_mode == Net_server) {
+ if (output_name) {
+ fprintf(stderr, "-o ignored in server mode\n");
+ output_name = NULL;
+ }
+
return net_server();
+ }
while (optind < argc) {
if (resize_devices(argv[optind++]) != 0)
signal(SIGHUP, handle_sigint);
signal(SIGTERM, handle_sigint);
signal(SIGALRM, handle_sigint);
+ signal(SIGPIPE, SIG_IGN);
if (net_mode == Net_client && net_setup_client())
return 1;