+ if (bit->time > pdi->last_read_time)
+ pdi->last_read_time = bit->time;
+
+ t = t_alloc();
+ memset(t, 0, sizeof(*t));
+ t->bit = bit;
+
+ if (msp->first == NULL)
+ msp->first = msp->last = t;
+ else {
+ msp->last->next = t;
+ msp->last = t;
+ }
+
+ ndone++;
+ }
+
+ return ndone;
+
+err:
+ if (bit) bit_free(bit);
+
+ cpu_mark_offline(pdi, pci->cpu);
+ close(pci->fd);
+ pci->fd = -1;
+
+ return ndone;
+}
+
+static struct ms_stream *ms_alloc(struct per_dev_info *pdi, int cpu)
+{
+ struct ms_stream *msp = malloc(sizeof(*msp));
+
+ msp->next = NULL;
+ msp->first = msp->last = NULL;
+ msp->pdi = pdi;
+ msp->cpu = cpu;
+
+ if (ms_prime(msp))
+ ms_sort(msp);
+
+ return msp;
+}
+
+static int setup_file(struct per_dev_info *pdi, int cpu)
+{
+ int len = 0;
+ struct stat st;
+ char *p, *dname;
+ struct per_cpu_info *pci = get_cpu_info(pdi, cpu);
+
+ pci->cpu = cpu;
+ pci->fdblock = -1;
+
+ p = strdup(pdi->name);
+ dname = dirname(p);
+ if (strcmp(dname, ".")) {
+ input_dir = dname;
+ p = strdup(pdi->name);
+ strcpy(pdi->name, basename(p));
+ }
+ free(p);
+
+ if (input_dir)
+ len = sprintf(pci->fname, "%s/", input_dir);
+
+ snprintf(pci->fname + len, sizeof(pci->fname)-1-len,
+ "%s.blktrace.%d", pdi->name, pci->cpu);
+ if (stat(pci->fname, &st) < 0)
+ return 0;
+ if (!st.st_size)
+ return 1;
+
+ pci->fd = open(pci->fname, O_RDONLY);
+ if (pci->fd < 0) {
+ perror(pci->fname);
+ return 0;
+ }
+
+ printf("Input file %s added\n", pci->fname);
+ cpu_mark_online(pdi, pci->cpu);
+
+ pdi->nfiles++;
+ ms_alloc(pdi, pci->cpu);
+
+ return 1;
+}
+
+static int handle(struct ms_stream *msp)
+{
+ struct trace *t;
+ struct per_dev_info *pdi;
+ struct per_cpu_info *pci;
+ struct blk_io_trace *bit;
+
+ t = ms_peek(msp);
+
+ bit = t->bit;
+ pdi = msp->pdi;
+ pci = get_cpu_info(pdi, msp->cpu);
+ pci->nelems++;
+ bit->time -= genesis_time;
+
+ if (t->bit->time > stopwatch_end)
+ return 0;
+
+ pdi->last_reported_time = bit->time;
+ if ((bit->action & (act_mask << BLK_TC_SHIFT))&&
+ t->bit->time >= stopwatch_start)
+ dump_trace(bit, pci, pdi);
+
+ ms_deq(msp);
+
+ if (text_output)
+ trace_rb_insert_last(pdi, t);
+ else {
+ bit_free(t->bit);
+ t_free(t);
+ }
+
+ return 1;
+}
+
+/*
+ * Check if we need to sanitize the name. We allow 'foo', or if foo.blktrace.X
+ * is given, then strip back down to 'foo' to avoid missing files.
+ */
+static int name_fixup(char *name)
+{
+ char *b;
+
+ if (!name)
+ return 1;
+
+ b = strstr(name, ".blktrace.");
+ if (b)
+ *b = '\0';
+
+ return 0;
+}
+
+static int do_file(void)
+{
+ int i, cpu, ret;
+ struct per_dev_info *pdi;
+
+ /*
+ * first prepare all files for reading
+ */
+ for (i = 0; i < ndevices; i++) {
+ pdi = &devices[i];
+ ret = name_fixup(pdi->name);
+ if (ret)
+ return ret;
+
+ for (cpu = 0; setup_file(pdi, cpu); cpu++)
+ ;
+
+ if (!cpu) {
+ fprintf(stderr,"No input files found for %s\n",
+ pdi->name);
+ return 1;
+ }
+ }
+
+ /*
+ * Get the initial time stamp
+ */
+ if (ms_head)
+ genesis_time = ms_peek_time(ms_head);
+
+ /*
+ * Keep processing traces while any are left
+ */
+ while (!is_done() && ms_head && handle(ms_head))
+ ;