fix hang when BLKTRACESETUP fails and "-o -" is used
[blktrace.git] / btt / devs.c
index a458a77b53cc2b9f376e6d729c3f27489b9c8ab9..12ce2cabd929703fb380bc8a977f697818070716 100644 (file)
 #define DEV_HASH(dev)  ((MAJOR(dev) ^ MINOR(dev)) & (N_DEV_HASH - 1))
 struct list_head       dev_heads[N_DEV_HASH];
 
-#if defined(DEBUG)
-void __dump_rb_node(struct rb_node *n)
+static inline void *dip_rb_mkhds(void)
 {
-       struct io *iop = rb_entry(n, struct io, rb_node);
-
-       dbg_ping();
-       if (iop->type == IOP_A)
-               __dump_iop2(stdout, iop, bilink_first_down(iop, NULL));
-       else
-               __dump_iop(stdout, iop, 0);
-       if (n->rb_left)
-               __dump_rb_node(n->rb_left);
-       if (n->rb_right)
-               __dump_rb_node(n->rb_right);
+       size_t len = N_IOP_TYPES * sizeof(struct rb_root);
+       return memset(malloc(len), 0, len);
 }
 
-void __dump_rb_tree(struct d_info *dip, enum iop_type type)
+static void __destroy(struct rb_node *n)
 {
-       struct rb_root *roots = dip->heads;
-       struct rb_root *root = &roots[type];
-       struct rb_node *n = root->rb_node;
-
        if (n) {
-               printf("\tIOP_%c\n", type2c(type));
-               __dump_rb_node(n);
+               struct io *iop = rb_entry(n, struct io, rb_node);
+
+               __destroy(n->rb_left);
+               __destroy(n->rb_right);
+               io_release(iop);
        }
 }
 
-void dump_rb_trees(void)
+static void __destroy_heads(struct rb_root *roots)
 {
        int i;
-       enum iop_type type;
-       struct d_info *dip;
-       struct list_head *p;
 
-       for (i = 0; i < N_DEV_HASH; i++) {
-               __list_for_each(p, &dev_heads[i]) {
-                       dip = list_entry(p, struct d_info, hash_head);
-                       printf("Trees for %3d,%-3d\n", MAJOR(dip->device),
-                              MINOR(dip->device));
-                       for (type = IOP_Q; type < N_IOP_TYPES; type++) {
-                               if (type != IOP_L)
-                                       __dump_rb_tree(dip, type);
-                       }
-               }
-       }
+       for (i = 0; i < N_IOP_TYPES; i++)
+               __destroy(roots[i].rb_node);
+
+       free(roots);
 }
-#endif
 
 void init_dev_heads(void)
 {
@@ -95,24 +73,87 @@ struct d_info *__dip_find(__u32 device)
        return NULL;
 }
 
-struct d_info *dip_add(__u32 device, struct io *iop)
+void __dip_exit(struct d_info *dip)
+{
+       list_del(&dip->all_head);
+       __destroy_heads(dip->heads);
+       region_exit(&dip->regions);
+       seeki_free(dip->seek_handle);
+       seeki_free(dip->q2q_handle);
+       aqd_free(dip->aqd_handle);
+       plat_free(dip->q2d_plat_handle);
+       plat_free(dip->q2c_plat_handle);
+       plat_free(dip->d2c_plat_handle);
+       p_live_free(dip->p_live_handle);
+       bno_dump_free(dip->bno_dump_handle);
+       unplug_hist_free(dip->up_hist_handle);
+       rstat_free(dip->rstat_handle);
+       if (output_all_data)
+               q2d_free(dip->q2d_priv);
+       if (dip->pit_fp)
+               fclose(dip->pit_fp);
+       free(dip);
+}
+
+void dip_exit(void)
+{
+       struct list_head *p, *q;
+
+       list_for_each_safe(p, q, &all_devs) {
+               struct d_info *dip = list_entry(p, struct d_info, all_head);
+               __dip_exit(dip);
+       }
+}
+
+static inline FILE *open_pit(struct d_info *dip)
+{
+       FILE *fp;
+       char str[272];
+
+       sprintf(str, "%s_pit.dat", dip->dip_name);
+       if ((fp = my_fopen(str, "w")) == NULL)
+               perror(str);
+
+       return fp;
+}
+
+struct d_info *dip_alloc(__u32 device, struct io *iop)
 {
        struct d_info *dip = __dip_find(device);
 
        if (dip == NULL) {
                dip = malloc(sizeof(struct d_info));
                memset(dip, 0, sizeof(*dip));
-               dip->heads = dip_rb_mkhds();
-               init_region(&dip->regions);
                dip->device = device;
+               dip->devmap = dev_map_find(device);
                dip->last_q = (__u64)-1;
-               dip->map = dev_map_find(device);
-               dip->seek_handle = seeki_init(device);
-               latency_init(dip);
-               list_add_tail(&dip->hash_head, &dev_heads[DEV_HASH(device)]);
-               list_add_tail(&dip->all_head, &all_devs);
+               dip->heads = dip_rb_mkhds();
+               region_init(&dip->regions);
                dip->start_time = BIT_TIME(iop->t.time);
                dip->pre_culling = 1;
+
+               mkhandle(dip, dip->dip_name, 256);
+
+               latency_alloc(dip);
+               dip->aqd_handle = aqd_alloc(dip);
+               dip->bno_dump_handle = bno_dump_alloc(dip);
+               dip->up_hist_handle = unplug_hist_alloc(dip);
+               dip->seek_handle = seeki_alloc(dip, "_d2d");
+               dip->q2q_handle = seeki_alloc(dip, "_q2q");
+               dip->q2d_plat_handle = plat_alloc(dip, "_q2d");
+               dip->q2c_plat_handle = plat_alloc(dip, "_q2c");
+               dip->d2c_plat_handle = plat_alloc(dip, "_d2c");
+               dip->rstat_handle = rstat_alloc(dip);
+               dip->p_live_handle = p_live_alloc();
+
+               if (per_io_trees)
+                       dip->pit_fp = open_pit(dip);
+
+               if (output_all_data)
+                       dip->q2d_priv = q2d_alloc();
+
+               list_add_tail(&dip->hash_head, &dev_heads[DEV_HASH(device)]);
+               list_add_tail(&dip->all_head, &all_devs);
                n_devs++;
        }
 
@@ -124,16 +165,12 @@ struct d_info *dip_add(__u32 device, struct io *iop)
        }
 
        iop->linked = dip_rb_ins(dip, iop);
-#if defined(DEBUG)
-       if (iop->linked) 
-               rb_tree_size++;
-#endif
-
        dip->end_time = BIT_TIME(iop->t.time);
+
        return dip;
 }
 
-void dip_rem(struct io *iop)
+void iop_rem_dip(struct io *iop)
 {
        if (iop->linked) {
                dip_rb_rem(iop);
@@ -141,7 +178,7 @@ void dip_rem(struct io *iop)
        }
 }
 
-void dip_foreach(struct io *iop, enum iop_type type, 
+void dip_foreach(struct io *iop, enum iop_type type,
                 void (*fnc)(struct io *iop, struct io *this), int rm_after)
 {
        if (rm_after) {
@@ -152,11 +189,10 @@ void dip_foreach(struct io *iop, enum iop_type type,
                dip_rb_fe(iop->dip, type, iop, fnc, &head);
                list_for_each_safe(p, q, &head) {
                        this = list_entry(p, struct io, f_head);
-                       LIST_DEL(&this->f_head);
+                       list_del(&this->f_head);
                        io_release(this);
                }
-       }
-       else
+       } else
                dip_rb_fe(iop->dip, type, iop, fnc, NULL);
 }
 
@@ -176,8 +212,7 @@ void dip_foreach_out(void (*func)(struct d_info *, void *), void *arg)
                struct list_head *p;
                __list_for_each(p, &all_devs)
                        func(list_entry(p, struct d_info, all_head), arg);
-       }
-       else {
+       } else {
                int i;
                struct d_info *dip;
                unsigned int mjr, mnr;
@@ -185,10 +220,7 @@ void dip_foreach_out(void (*func)(struct d_info *, void *), void *arg)
 
                while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
                        dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
-                       ASSERT(dip);
-
                        func(dip, arg);
-
                        p = strchr(p, ';');
                        if (p) p++;
                }
@@ -199,21 +231,48 @@ void dip_plug(__u32 dev, double cur_time)
 {
        struct d_info *dip = __dip_find(dev);
 
-       if (!dip || dip->is_plugged) return;
+       if (dip && !dip->is_plugged) {
+               dip->is_plugged = 1;
+               dip->last_plug = cur_time;
+       }
+}
+
+static inline void unplug(struct d_info *dip, double cur_time)
+{
+       dip->is_plugged = 0;
+       dip->plugged_time += (cur_time - dip->last_plug);
+}
+
+void dip_unplug(__u32 dev, double cur_time, __u64 nios_up)
+{
+       struct d_info *dip = __dip_find(dev);
 
-       dip->is_plugged = 1;
-       dip->last_plug = cur_time;
+       if (dip && dip->is_plugged) {
+               dip->nplugs++;
+               dip->nios_up += nios_up;
+               unplug(dip, cur_time);
+       }
 }
 
-void dip_unplug(__u32 dev, double cur_time, int is_timer)
+void dip_unplug_tm(__u32 dev, double cur_time, __u64 nios_up)
 {
        struct d_info *dip = __dip_find(dev);
 
-       if (!dip || !dip->is_plugged) return;
+       if (dip && dip->is_plugged) {
+               dip->nios_upt += nios_up;
+               dip->nplugs_t++;
+               unplug(dip, cur_time);
+       }
+}
 
-       dip->nplugs++;
-       if (is_timer) dip->n_timer_unplugs++;
+void dip_cleanup(void)
+{
+       struct list_head *p, *q;
 
-       dip->plugged_time += (cur_time - dip->last_plug);
-       dip->is_plugged = 0;
+       list_for_each_safe(p, q, &all_devs) {
+               struct d_info *dip = list_entry(p, struct d_info, all_head);
+
+               if (dip->n_qs == 0 && dip->n_ds == 0)
+                       __dip_exit(dip);
+       }
 }