cgroups: add per-thread subsystem callbacks
[sfrench/cifs-2.6.git] / block / blk-cgroup.c
index 34bfcefdd924c0c5e7f222c726ca5d30f05aed26..bcaf16ee6ad1ba321836413ee8841ab0bbde8f5e 100644 (file)
@@ -30,10 +30,8 @@ EXPORT_SYMBOL_GPL(blkio_root_cgroup);
 
 static struct cgroup_subsys_state *blkiocg_create(struct cgroup_subsys *,
                                                  struct cgroup *);
-static int blkiocg_can_attach(struct cgroup_subsys *, struct cgroup *,
-                             struct task_struct *, bool);
-static void blkiocg_attach(struct cgroup_subsys *, struct cgroup *,
-                          struct cgroup *, struct task_struct *, bool);
+static int blkiocg_can_attach_task(struct cgroup *, struct task_struct *);
+static void blkiocg_attach_task(struct cgroup *, struct task_struct *);
 static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *);
 static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
 
@@ -46,8 +44,8 @@ static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
 struct cgroup_subsys blkio_subsys = {
        .name = "blkio",
        .create = blkiocg_create,
-       .can_attach = blkiocg_can_attach,
-       .attach = blkiocg_attach,
+       .can_attach_task = blkiocg_can_attach_task,
+       .attach_task = blkiocg_attach_task,
        .destroy = blkiocg_destroy,
        .populate = blkiocg_populate,
 #ifdef CONFIG_BLK_CGROUP
@@ -400,14 +398,25 @@ void blkiocg_update_dispatch_stats(struct blkio_group *blkg,
                                uint64_t bytes, bool direction, bool sync)
 {
        struct blkio_group_stats_cpu *stats_cpu;
+       unsigned long flags;
+
+       /*
+        * Disabling interrupts to provide mutual exclusion between two
+        * writes on same cpu. It probably is not needed for 64bit. Not
+        * optimizing that case yet.
+        */
+       local_irq_save(flags);
 
        stats_cpu = this_cpu_ptr(blkg->stats_cpu);
 
+       u64_stats_update_begin(&stats_cpu->syncp);
        stats_cpu->sectors += bytes >> 9;
        blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICED],
                        1, direction, sync);
        blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICE_BYTES],
                        bytes, direction, sync);
+       u64_stats_update_end(&stats_cpu->syncp);
+       local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_dispatch_stats);
 
@@ -430,15 +439,27 @@ void blkiocg_update_completion_stats(struct blkio_group *blkg,
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_completion_stats);
 
+/*  Merged stats are per cpu.  */
 void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction,
                                        bool sync)
 {
+       struct blkio_group_stats_cpu *stats_cpu;
        unsigned long flags;
 
-       spin_lock_irqsave(&blkg->stats_lock, flags);
-       blkio_add_stat(blkg->stats.stat_arr[BLKIO_STAT_MERGED], 1, direction,
-                       sync);
-       spin_unlock_irqrestore(&blkg->stats_lock, flags);
+       /*
+        * Disabling interrupts to provide mutual exclusion between two
+        * writes on same cpu. It probably is not needed for 64bit. Not
+        * optimizing that case yet.
+        */
+       local_irq_save(flags);
+
+       stats_cpu = this_cpu_ptr(blkg->stats_cpu);
+
+       u64_stats_update_begin(&stats_cpu->syncp);
+       blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_MERGED], 1,
+                               direction, sync);
+       u64_stats_update_end(&stats_cpu->syncp);
+       local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats);
 
@@ -526,6 +547,30 @@ struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key)
 }
 EXPORT_SYMBOL_GPL(blkiocg_lookup_group);
 
+static void blkio_reset_stats_cpu(struct blkio_group *blkg)
+{
+       struct blkio_group_stats_cpu *stats_cpu;
+       int i, j, k;
+       /*
+        * Note: On 64 bit arch this should not be an issue. This has the
+        * possibility of returning some inconsistent value on 32bit arch
+        * as 64bit update on 32bit is non atomic. Taking care of this
+        * corner case makes code very complicated, like sending IPIs to
+        * cpus, taking care of stats of offline cpus etc.
+        *
+        * reset stats is anyway more of a debug feature and this sounds a
+        * corner case. So I am not complicating the code yet until and
+        * unless this becomes a real issue.
+        */
+       for_each_possible_cpu(i) {
+               stats_cpu = per_cpu_ptr(blkg->stats_cpu, i);
+               stats_cpu->sectors = 0;
+               for(j = 0; j < BLKIO_STAT_CPU_NR; j++)
+                       for (k = 0; k < BLKIO_STAT_TOTAL; k++)
+                               stats_cpu->stat_arr_cpu[j][k] = 0;
+       }
+}
+
 static int
 blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
 {
@@ -570,7 +615,11 @@ blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
                }
 #endif
                spin_unlock(&blkg->stats_lock);
+
+               /* Reset Per cpu stats which don't take blkg->stats_lock */
+               blkio_reset_stats_cpu(blkg);
        }
+
        spin_unlock_irq(&blkcg->lock);
        return 0;
 }
@@ -622,15 +671,21 @@ static uint64_t blkio_read_stat_cpu(struct blkio_group *blkg,
 {
        int cpu;
        struct blkio_group_stats_cpu *stats_cpu;
-       uint64_t val = 0;
+       u64 val = 0, tval;
 
        for_each_possible_cpu(cpu) {
+               unsigned int start;
                stats_cpu  = per_cpu_ptr(blkg->stats_cpu, cpu);
 
-               if (type == BLKIO_STAT_CPU_SECTORS)
-                       val += stats_cpu->sectors;
-               else
-                       val += stats_cpu->stat_arr_cpu[type][sub_type];
+               do {
+                       start = u64_stats_fetch_begin(&stats_cpu->syncp);
+                       if (type == BLKIO_STAT_CPU_SECTORS)
+                               tval = stats_cpu->sectors;
+                       else
+                               tval = stats_cpu->stat_arr_cpu[type][sub_type];
+               } while(u64_stats_fetch_retry(&stats_cpu->syncp, start));
+
+               val += tval;
        }
 
        return val;
@@ -1199,7 +1254,7 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
                                                BLKIO_STAT_WAIT_TIME, 1, 0);
                case BLKIO_PROP_io_merged:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_MERGED, 1, 0);
+                                               BLKIO_STAT_CPU_MERGED, 1, 1);
                case BLKIO_PROP_io_queued:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
                                                BLKIO_STAT_QUEUED, 1, 0);
@@ -1559,9 +1614,7 @@ done:
  * of the main cic data structures.  For now we allow a task to change
  * its cgroup only if it's the only owner of its ioc.
  */
-static int blkiocg_can_attach(struct cgroup_subsys *subsys,
-                               struct cgroup *cgroup, struct task_struct *tsk,
-                               bool threadgroup)
+static int blkiocg_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
 {
        struct io_context *ioc;
        int ret = 0;
@@ -1576,9 +1629,7 @@ static int blkiocg_can_attach(struct cgroup_subsys *subsys,
        return ret;
 }
 
-static void blkiocg_attach(struct cgroup_subsys *subsys, struct cgroup *cgroup,
-                               struct cgroup *prev, struct task_struct *tsk,
-                               bool threadgroup)
+static void blkiocg_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
 {
        struct io_context *ioc;