struct cl_host *ch;
u32 cl_id;
time_t cl_connect_time;
+ int setup_done; /* ioctl BLKTRACESETUP done */
struct io_info *ios;
};
static volatile int dp_entries;
/*
- * These synchronize master / thread interactions.
+ * These synchronize main / thread interactions.
*/
static pthread_cond_t mt_cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t mt_mutex = PTHREAD_MUTEX_INITIALIZER;
}
}
-static void setup_buts(void)
+static int setup_buts(void)
{
struct list_head *p;
+ int ret = 0;
__list_for_each(p, &devpaths) {
struct blk_user_trace_setup buts;
if (ioctl(dpp->fd, BLKTRACESETUP, &buts) >= 0) {
dpp->ncpus = max_cpus;
dpp->buts_name = strdup(buts.name);
+ dpp->setup_done = 1;
if (dpp->stats)
free(dpp->stats);
dpp->stats = calloc(dpp->ncpus, sizeof(*dpp->stats));
memset(dpp->stats, 0, dpp->ncpus * sizeof(*dpp->stats));
- } else
+ } else {
fprintf(stderr, "BLKTRACESETUP(2) %s failed: %d/%s\n",
dpp->path, errno, strerror(errno));
+ ret++;
+ }
}
+
+ return ret;
}
static void start_buts(void)
struct devpath *dpp = list_entry(p, struct devpath, head);
list_del(&dpp->head);
- __stop_trace(dpp->fd);
+ if (dpp->setup_done)
+ __stop_trace(dpp->fd);
close(dpp->fd);
if (dpp->heads)
return net_sendfile(iop);
}
-static int fill_ofname(struct io_info *iop, int cpu)
+static int fill_ofname(char *dst, int dstlen, char *subdir, char *buts_name,
+ int cpu)
{
int len;
struct stat sb;
- char *dst = iop->ofn;
if (output_dir)
- len = snprintf(iop->ofn, sizeof(iop->ofn), "%s/", output_dir);
+ len = snprintf(dst, dstlen, "%s/", output_dir);
else
- len = snprintf(iop->ofn, sizeof(iop->ofn), "./");
+ len = snprintf(dst, dstlen, "./");
- if (net_mode == Net_server) {
- struct cl_conn *nc = iop->nc;
-
- len += sprintf(dst + len, "%s-", nc->ch->hostname);
- len += strftime(dst + len, 64, "%F-%T/",
- gmtime(&iop->dpp->cl_connect_time));
- }
+ if (subdir)
+ len += snprintf(dst + len, dstlen - len, "%s", subdir);
- if (stat(iop->ofn, &sb) < 0) {
+ if (stat(dst, &sb) < 0) {
if (errno != ENOENT) {
fprintf(stderr,
"Destination dir %s stat failed: %d/%s\n",
- iop->ofn, errno, strerror(errno));
+ dst, errno, strerror(errno));
return 1;
}
/*
* trying to create the directory at once. It's harmless
* to let them try, so just detect the problem and move on.
*/
- if (mkdir(iop->ofn, 0755) < 0 && errno != EEXIST) {
+ if (mkdir(dst, 0755) < 0 && errno != EEXIST) {
fprintf(stderr,
"Destination dir %s can't be made: %d/%s\n",
- iop->ofn, errno, strerror(errno));
+ dst, errno, strerror(errno));
return 1;
}
}
if (output_name)
- snprintf(iop->ofn + len, sizeof(iop->ofn), "%s.blktrace.%d",
+ snprintf(dst + len, dstlen - len, "%s.blktrace.%d",
output_name, cpu);
else
- snprintf(iop->ofn + len, sizeof(iop->ofn), "%s.blktrace.%d",
- iop->dpp->buts_name, cpu);
+ snprintf(dst + len, dstlen - len, "%s.blktrace.%d",
+ buts_name, cpu);
return 0;
}
static int iop_open(struct io_info *iop, int cpu)
{
+ char hostdir[MAXPATHLEN + 64];
+
iop->ofd = -1;
- if (fill_ofname(iop, cpu))
+ if (net_mode == Net_server) {
+ struct cl_conn *nc = iop->nc;
+ int len;
+
+ len = snprintf(hostdir, sizeof(hostdir), "%s-",
+ nc->ch->hostname);
+ len += strftime(hostdir + len, sizeof(hostdir) - len, "%F-%T/",
+ gmtime(&iop->dpp->cl_connect_time));
+ } else {
+ hostdir[0] = 0;
+ }
+
+ if (fill_ofname(iop->ofn, sizeof(iop->ofn), hostdir,
+ iop->dpp->buts_name, cpu))
return 1;
iop->ofp = my_fopen(iop->ofn, "w+");
return 0;
}
+static int create_output_files(int cpu)
+{
+ char fname[MAXPATHLEN + 64];
+ struct list_head *p;
+ FILE *f;
+
+ __list_for_each(p, &devpaths) {
+ struct devpath *dpp = list_entry(p, struct devpath, head);
+
+ if (fill_ofname(fname, sizeof(fname), NULL, dpp->buts_name,
+ cpu))
+ return 1;
+ f = my_fopen(fname, "w+");
+ if (!f)
+ return 1;
+ fclose(f);
+ }
+ return 0;
+}
+
static void start_tracers(void)
{
int cpu, started = 0;
size_t alloc_size = CPU_ALLOC_SIZE(max_cpus);
for (cpu = 0; cpu < max_cpus; cpu++) {
- if (!CPU_ISSET_S(cpu, alloc_size, online_cpus))
+ if (!CPU_ISSET_S(cpu, alloc_size, online_cpus)) {
+ /*
+ * Create fake empty output files so that other tools
+ * like blkparse don't have to bother with sparse CPU
+ * number space.
+ */
+ if (create_output_files(cpu))
+ break;
continue;
+ }
if (start_tracer(cpu))
break;
started++;
if (net_mode == Net_client)
printf("blktrace: connecting to %s\n", hostname);
- setup_buts();
+ if (setup_buts())
+ return 1;
if (use_tracer_devpaths()) {
if (setup_tracer_devpaths())