===================================================================
@@ -250,6 +250,9 @@ struct io_group {
#ifdef CONFIG_DEBUG_GROUP_IOSCHED
unsigned short iocg_id;
+ dev_t dev;
+ /* How many times this group has been removed from active tree */
+ unsigned long dequeue;
#endif
};
===================================================================
@@ -12,6 +12,7 @@
#include "elevator-fq.h"
#include <linux/blktrace_api.h>
#include <linux/biotrack.h>
+#include <linux/seq_file.h>
/* Values taken from cfq */
const int elv_slice_sync = HZ / 10;
@@ -758,6 +759,18 @@ int __bfq_deactivate_entity(struct io_en
BUG_ON(sd->active_entity == entity);
BUG_ON(sd->next_active == entity);
+#ifdef CONFIG_DEBUG_GROUP_IOSCHED
+ {
+ struct io_group *iog = io_entity_to_iog(entity);
+ /*
+ * Keep track of how many times a group has been removed
+ * from active tree because it did not have any active
+ * backlogged ioq under it
+ */
+ if (iog)
+ iog->dequeue++;
+ }
+#endif
return ret;
}
@@ -1126,90 +1139,103 @@ STORE_FUNCTION(weight, 0, WEIGHT_MAX);
STORE_FUNCTION(ioprio_class, IOPRIO_CLASS_RT, IOPRIO_CLASS_IDLE);
#undef STORE_FUNCTION
-/*
- * traverse through all the io_groups associated with this cgroup and calculate
- * the aggr disk time received by all the groups on respective disks.
- */
-static u64 calculate_aggr_disk_time(struct io_cgroup *iocg)
+static int io_cgroup_disk_time_read(struct cgroup *cgroup,
+ struct cftype *cftype, struct seq_file *m)
{
+ struct io_cgroup *iocg;
struct io_group *iog;
struct hlist_node *n;
- u64 disk_time = 0;
+
+ if (!cgroup_lock_live_group(cgroup))
+ return -ENODEV;
+
+ iocg = cgroup_to_io_cgroup(cgroup);
rcu_read_lock();
+ spin_lock_irq(&iocg->lock);
hlist_for_each_entry_rcu(iog, n, &iocg->group_data, group_node) {
/*
* There might be groups which are not functional and
* waiting to be reclaimed upon cgoup deletion.
*/
- if (rcu_dereference(iog->key))
- disk_time += iog->entity.total_service;
+ if (rcu_dereference(iog->key)) {
+ seq_printf(m, "%u %u %lu\n", MAJOR(iog->dev),
+ MINOR(iog->dev),
+ iog->entity.total_service);
+ }
}
+ spin_unlock_irq(&iocg->lock);
rcu_read_unlock();
- return disk_time;
+ cgroup_unlock();
+
+ return 0;
}
-static u64 io_cgroup_disk_time_read(struct cgroup *cgroup,
- struct cftype *cftype)
+static int io_cgroup_disk_sectors_read(struct cgroup *cgroup,
+ struct cftype *cftype, struct seq_file *m)
{
struct io_cgroup *iocg;
- u64 ret;
+ struct io_group *iog;
+ struct hlist_node *n;
if (!cgroup_lock_live_group(cgroup))
return -ENODEV;
iocg = cgroup_to_io_cgroup(cgroup);
- spin_lock_irq(&iocg->lock);
- ret = jiffies_to_msecs(calculate_aggr_disk_time(iocg));
- spin_unlock_irq(&iocg->lock);
-
- cgroup_unlock();
-
- return ret;
-}
-
-/*
- * traverse through all the io_groups associated with this cgroup and calculate
- * the aggr number of sectors transferred by all the groups on respective disks.
- */
-static u64 calculate_aggr_disk_sectors(struct io_cgroup *iocg)
-{
- struct io_group *iog;
- struct hlist_node *n;
- u64 disk_sectors = 0;
rcu_read_lock();
+ spin_lock_irq(&iocg->lock);
hlist_for_each_entry_rcu(iog, n, &iocg->group_data, group_node) {
/*
* There might be groups which are not functional and
* waiting to be reclaimed upon cgoup deletion.
*/
- if (rcu_dereference(iog->key))
- disk_sectors += iog->entity.total_sector_service;
+ if (rcu_dereference(iog->key)) {
+ seq_printf(m, "%u %u %lu\n", MAJOR(iog->dev),
+ MINOR(iog->dev),
+ iog->entity.total_sector_service);
+ }
}
+ spin_unlock_irq(&iocg->lock);
rcu_read_unlock();
- return disk_sectors;
+ cgroup_unlock();
+
+ return 0;
}
-static u64 io_cgroup_disk_sectors_read(struct cgroup *cgroup,
- struct cftype *cftype)
+static int io_cgroup_disk_dequeue_read(struct cgroup *cgroup,
+ struct cftype *cftype, struct seq_file *m)
{
- struct io_cgroup *iocg;
- u64 ret;
+ struct io_cgroup *iocg = NULL;
+ struct io_group *iog = NULL;
+ struct hlist_node *n;
if (!cgroup_lock_live_group(cgroup))
return -ENODEV;
iocg = cgroup_to_io_cgroup(cgroup);
+
+ rcu_read_lock();
spin_lock_irq(&iocg->lock);
- ret = calculate_aggr_disk_sectors(iocg);
+ /* Loop through all the io groups and print statistics */
+ hlist_for_each_entry_rcu(iog, n, &iocg->group_data, group_node) {
+ /*
+ * There might be groups which are not functional and
+ * waiting to be reclaimed upon cgoup deletion.
+ */
+ if (rcu_dereference(iog->key)) {
+ seq_printf(m, "%u %u %lu\n", MAJOR(iog->dev),
+ MINOR(iog->dev), iog->dequeue);
+ }
+ }
spin_unlock_irq(&iocg->lock);
+ rcu_read_unlock();
cgroup_unlock();
- return ret;
+ return 0;
}
/**
@@ -1222,7 +1248,7 @@ static u64 io_cgroup_disk_sectors_read(s
* to the root has already an allocated group on @bfqd.
*/
struct io_group *io_group_chain_alloc(struct request_queue *q, void *key,
- struct cgroup *cgroup)
+ struct cgroup *cgroup, struct bio *bio)
{
struct io_cgroup *iocg;
struct io_group *iog, *leaf = NULL, *prev = NULL;
@@ -1250,8 +1276,13 @@ struct io_group *io_group_chain_alloc(st
io_group_init_entity(iocg, iog);
iog->my_entity = &iog->entity;
+
#ifdef CONFIG_DEBUG_GROUP_IOSCHED
iog->iocg_id = css_id(&iocg->css);
+ if (bio) {
+ struct gendisk *disk = bio->bi_bdev->bd_disk;
+ iog->dev = MKDEV(disk->major, disk->first_minor);
+ }
#endif
blk_init_request_list(&iog->rl);
@@ -1364,7 +1395,7 @@ void io_group_chain_link(struct request_
*/
struct io_group *io_find_alloc_group(struct request_queue *q,
struct cgroup *cgroup, struct elv_fq_data *efqd,
- int create)
+ int create, struct bio *bio)
{
struct io_cgroup *iocg = cgroup_to_io_cgroup(cgroup);
struct io_group *iog = NULL;
@@ -1375,7 +1406,7 @@ struct io_group *io_find_alloc_group(str
if (iog != NULL || !create)
return iog;
- iog = io_group_chain_alloc(q, key, cgroup);
+ iog = io_group_chain_alloc(q, key, cgroup, bio);
if (iog != NULL)
io_group_chain_link(q, key, cgroup, iog, efqd);
@@ -1481,7 +1512,7 @@ struct io_group *io_get_io_group(struct
goto out;
}
- iog = io_find_alloc_group(q, cgroup, efqd, create);
+ iog = io_find_alloc_group(q, cgroup, efqd, create, bio);
if (!iog) {
if (create)
iog = efqd->root_group;
@@ -1554,12 +1585,18 @@ struct cftype bfqio_files[] = {
},
{
.name = "disk_time",
- .read_u64 = io_cgroup_disk_time_read,
+ .read_seq_string = io_cgroup_disk_time_read,
},
{
.name = "disk_sectors",
- .read_u64 = io_cgroup_disk_sectors_read,
+ .read_seq_string = io_cgroup_disk_sectors_read,
},
+#ifdef CONFIG_DEBUG_GROUP_IOSCHED
+ {
+ .name = "disk_dequeue",
+ .read_seq_string = io_cgroup_disk_dequeue_read,
+ },
+#endif
};
int iocg_populate(struct cgroup_subsys *subsys, struct cgroup *cgroup)