]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - block/blk-cgroup.h
blkcg: add blkcg->id
[mirror_ubuntu-zesty-kernel.git] / block / blk-cgroup.h
index 7ebecf6ea8f10e8048c82e5a11a4d7d186fa7271..1cb8f764325861283cab4c6a42613ce053e41985 100644 (file)
@@ -29,14 +29,17 @@ enum blkio_policy_id {
 #ifdef CONFIG_BLK_CGROUP
 
 enum stat_type {
+       /* Number of IOs merged */
+       BLKIO_STAT_MERGED,
        /* Total time spent (in ns) between request dispatch to the driver and
         * request completion for IOs doen by this cgroup. This may not be
         * accurate when NCQ is turned on. */
-       BLKIO_STAT_SERVICE_TIME = 0,
+       BLKIO_STAT_SERVICE_TIME,
        /* Total time spent waiting in scheduler queue in ns */
        BLKIO_STAT_WAIT_TIME,
        /* Number of IOs queued up */
        BLKIO_STAT_QUEUED,
+
        /* All the single valued stats go below this */
        BLKIO_STAT_TIME,
 #ifdef CONFIG_DEBUG_BLK_CGROUP
@@ -50,6 +53,9 @@ enum stat_type {
 #endif
 };
 
+/* Types lower than this live in stat_arr and have subtypes */
+#define BLKIO_STAT_ARR_NR      (BLKIO_STAT_QUEUED + 1)
+
 /* Per cpu stats */
 enum stat_type_cpu {
        BLKIO_STAT_CPU_SECTORS,
@@ -57,8 +63,6 @@ enum stat_type_cpu {
        BLKIO_STAT_CPU_SERVICE_BYTES,
        /* Total IOs serviced, post merge */
        BLKIO_STAT_CPU_SERVICED,
-       /* Number of IOs merged */
-       BLKIO_STAT_CPU_MERGED,
        BLKIO_STAT_CPU_NR
 };
 
@@ -112,12 +116,16 @@ struct blkio_cgroup {
        unsigned int weight;
        spinlock_t lock;
        struct hlist_head blkg_list;
+
+       /* for policies to test whether associated blkcg has changed */
+       uint64_t id;
 };
 
 struct blkio_group_stats {
+       struct u64_stats_sync syncp;
        /* total disk time and nr sectors dispatched by this group */
        uint64_t time;
-       uint64_t stat_arr[BLKIO_STAT_QUEUED + 1][BLKIO_STAT_TOTAL];
+       uint64_t stat_arr[BLKIO_STAT_ARR_NR][BLKIO_STAT_TOTAL];
 #ifdef CONFIG_DEBUG_BLK_CGROUP
        /* Time not charged to this cgroup */
        uint64_t unaccounted_time;
@@ -131,21 +139,31 @@ struct blkio_group_stats {
 
        /* Total time spent waiting for it to be assigned a timeslice. */
        uint64_t group_wait_time;
-       uint64_t start_group_wait_time;
 
        /* Time spent idling for this blkio_group */
        uint64_t idle_time;
-       uint64_t start_idle_time;
        /*
         * Total time when we have requests queued and do not contain the
         * current active queue.
         */
        uint64_t empty_time;
+
+       /* fields after this shouldn't be cleared on stat reset */
+       uint64_t start_group_wait_time;
+       uint64_t start_idle_time;
        uint64_t start_empty_time;
        uint16_t flags;
 #endif
 };
 
+#ifdef CONFIG_DEBUG_BLK_CGROUP
+#define BLKG_STATS_DEBUG_CLEAR_START   \
+       offsetof(struct blkio_group_stats, unaccounted_time)
+#define BLKG_STATS_DEBUG_CLEAR_SIZE    \
+       (offsetof(struct blkio_group_stats, start_group_wait_time) - \
+        BLKG_STATS_DEBUG_CLEAR_START)
+#endif
+
 /* Per cpu blkio group stats */
 struct blkio_group_stats_cpu {
        uint64_t sectors;
@@ -159,33 +177,41 @@ struct blkio_group_conf {
        u64 bps[2];
 };
 
-struct blkio_group {
-       /* Pointer to the associated request_queue, RCU protected */
-       struct request_queue __rcu *q;
-       struct hlist_node blkcg_node;
-       unsigned short blkcg_id;
-       /* Store cgroup path */
-       char path[128];
-       /* policy which owns this blk group */
-       enum blkio_policy_id plid;
+/* per-blkg per-policy data */
+struct blkg_policy_data {
+       /* the blkg this per-policy data belongs to */
+       struct blkio_group *blkg;
 
        /* Configuration */
        struct blkio_group_conf conf;
 
-       /* Need to serialize the stats in the case of reset/update */
-       spinlock_t stats_lock;
        struct blkio_group_stats stats;
        /* Per cpu stats pointer */
        struct blkio_group_stats_cpu __percpu *stats_cpu;
+
+       /* pol->pdata_size bytes of private data used by policy impl */
+       char pdata[] __aligned(__alignof__(unsigned long long));
+};
+
+struct blkio_group {
+       /* Pointer to the associated request_queue */
+       struct request_queue *q;
+       struct list_head q_node;
+       struct hlist_node blkcg_node;
+       struct blkio_cgroup *blkcg;
+       /* Store cgroup path */
+       char path[128];
+       /* reference count */
+       int refcnt;
+
+       struct blkg_policy_data *pd[BLKIO_NR_POLICIES];
+
+       /* List of blkg waiting for per cpu stats memory to be allocated */
+       struct list_head alloc_node;
+       struct rcu_head rcu_head;
 };
 
-typedef struct blkio_group *(blkio_alloc_group_fn)(struct request_queue *q,
-                                                  struct blkio_cgroup *blkcg);
-typedef void (blkio_link_group_fn)(struct request_queue *q,
-                       struct blkio_group *blkg);
-typedef void (blkio_unlink_group_fn)(struct request_queue *q,
-                       struct blkio_group *blkg);
-typedef bool (blkio_clear_queue_fn)(struct request_queue *q);
+typedef void (blkio_init_group_fn)(struct blkio_group *blkg);
 typedef void (blkio_update_group_weight_fn)(struct request_queue *q,
                        struct blkio_group *blkg, unsigned int weight);
 typedef void (blkio_update_group_read_bps_fn)(struct request_queue *q,
@@ -198,10 +224,7 @@ typedef void (blkio_update_group_write_iops_fn)(struct request_queue *q,
                        struct blkio_group *blkg, unsigned int write_iops);
 
 struct blkio_policy_ops {
-       blkio_alloc_group_fn *blkio_alloc_group_fn;
-       blkio_link_group_fn *blkio_link_group_fn;
-       blkio_unlink_group_fn *blkio_unlink_group_fn;
-       blkio_clear_queue_fn *blkio_clear_queue_fn;
+       blkio_init_group_fn *blkio_init_group_fn;
        blkio_update_group_weight_fn *blkio_update_group_weight_fn;
        blkio_update_group_read_bps_fn *blkio_update_group_read_bps_fn;
        blkio_update_group_write_bps_fn *blkio_update_group_write_bps_fn;
@@ -213,18 +236,86 @@ struct blkio_policy_type {
        struct list_head list;
        struct blkio_policy_ops ops;
        enum blkio_policy_id plid;
+       size_t pdata_size;              /* policy specific private data size */
 };
 
+extern int blkcg_init_queue(struct request_queue *q);
+extern void blkcg_drain_queue(struct request_queue *q);
+extern void blkcg_exit_queue(struct request_queue *q);
+
 /* Blkio controller policy registration */
 extern void blkio_policy_register(struct blkio_policy_type *);
 extern void blkio_policy_unregister(struct blkio_policy_type *);
-extern void blkg_destroy_all(struct request_queue *q);
+extern void blkg_destroy_all(struct request_queue *q, bool destroy_root);
+extern void update_root_blkg_pd(struct request_queue *q,
+                               enum blkio_policy_id plid);
+
+/**
+ * blkg_to_pdata - get policy private data
+ * @blkg: blkg of interest
+ * @pol: policy of interest
+ *
+ * Return pointer to private data associated with the @blkg-@pol pair.
+ */
+static inline void *blkg_to_pdata(struct blkio_group *blkg,
+                             struct blkio_policy_type *pol)
+{
+       return blkg ? blkg->pd[pol->plid]->pdata : NULL;
+}
+
+/**
+ * pdata_to_blkg - get blkg associated with policy private data
+ * @pdata: policy private data of interest
+ * @pol: policy @pdata is for
+ *
+ * @pdata is policy private data for @pol.  Determine the blkg it's
+ * associated with.
+ */
+static inline struct blkio_group *pdata_to_blkg(void *pdata,
+                                               struct blkio_policy_type *pol)
+{
+       if (pdata) {
+               struct blkg_policy_data *pd =
+                       container_of(pdata, struct blkg_policy_data, pdata);
+               return pd->blkg;
+       }
+       return NULL;
+}
 
 static inline char *blkg_path(struct blkio_group *blkg)
 {
        return blkg->path;
 }
 
+/**
+ * blkg_get - get a blkg reference
+ * @blkg: blkg to get
+ *
+ * The caller should be holding queue_lock and an existing reference.
+ */
+static inline void blkg_get(struct blkio_group *blkg)
+{
+       lockdep_assert_held(blkg->q->queue_lock);
+       WARN_ON_ONCE(!blkg->refcnt);
+       blkg->refcnt++;
+}
+
+void __blkg_release(struct blkio_group *blkg);
+
+/**
+ * blkg_put - put a blkg reference
+ * @blkg: blkg to put
+ *
+ * The caller should be holding queue_lock.
+ */
+static inline void blkg_put(struct blkio_group *blkg)
+{
+       lockdep_assert_held(blkg->q->queue_lock);
+       WARN_ON_ONCE(blkg->refcnt <= 0);
+       if (!--blkg->refcnt)
+               __blkg_release(blkg);
+}
+
 #else
 
 struct blkio_group {
@@ -233,11 +324,23 @@ struct blkio_group {
 struct blkio_policy_type {
 };
 
+static inline int blkcg_init_queue(struct request_queue *q) { return 0; }
+static inline void blkcg_drain_queue(struct request_queue *q) { }
+static inline void blkcg_exit_queue(struct request_queue *q) { }
 static inline void blkio_policy_register(struct blkio_policy_type *blkiop) { }
 static inline void blkio_policy_unregister(struct blkio_policy_type *blkiop) { }
-static inline void blkg_destroy_all(struct request_queue *q) { }
-
+static inline void blkg_destroy_all(struct request_queue *q,
+                                   bool destory_root) { }
+static inline void update_root_blkg_pd(struct request_queue *q,
+                                      enum blkio_policy_id plid) { }
+
+static inline void *blkg_to_pdata(struct blkio_group *blkg,
+                               struct blkio_policy_type *pol) { return NULL; }
+static inline struct blkio_group *pdata_to_blkg(void *pdata,
+                               struct blkio_policy_type *pol) { return NULL; }
 static inline char *blkg_path(struct blkio_group *blkg) { return NULL; }
+static inline void blkg_get(struct blkio_group *blkg) { }
+static inline void blkg_put(struct blkio_group *blkg) { }
 
 #endif
 
@@ -246,12 +349,17 @@ static inline char *blkg_path(struct blkio_group *blkg) { return NULL; }
 #define BLKIO_WEIGHT_DEFAULT   500
 
 #ifdef CONFIG_DEBUG_BLK_CGROUP
-void blkiocg_update_avg_queue_size_stats(struct blkio_group *blkg);
+void blkiocg_update_avg_queue_size_stats(struct blkio_group *blkg,
+                                        struct blkio_policy_type *pol);
 void blkiocg_update_dequeue_stats(struct blkio_group *blkg,
-                               unsigned long dequeue);
-void blkiocg_update_set_idle_time_stats(struct blkio_group *blkg);
-void blkiocg_update_idle_time_stats(struct blkio_group *blkg);
-void blkiocg_set_start_empty_time(struct blkio_group *blkg);
+                                 struct blkio_policy_type *pol,
+                                 unsigned long dequeue);
+void blkiocg_update_set_idle_time_stats(struct blkio_group *blkg,
+                                       struct blkio_policy_type *pol);
+void blkiocg_update_idle_time_stats(struct blkio_group *blkg,
+                                   struct blkio_policy_type *pol);
+void blkiocg_set_start_empty_time(struct blkio_group *blkg,
+                                 struct blkio_policy_type *pol);
 
 #define BLKG_FLAG_FNS(name)                                            \
 static inline void blkio_mark_blkg_##name(                             \
@@ -274,67 +382,77 @@ BLKG_FLAG_FNS(idling)
 BLKG_FLAG_FNS(empty)
 #undef BLKG_FLAG_FNS
 #else
-static inline void blkiocg_update_avg_queue_size_stats(
-                                               struct blkio_group *blkg) {}
+static inline void blkiocg_update_avg_queue_size_stats(struct blkio_group *blkg,
+                       struct blkio_policy_type *pol) { }
 static inline void blkiocg_update_dequeue_stats(struct blkio_group *blkg,
-                                               unsigned long dequeue) {}
-static inline void blkiocg_update_set_idle_time_stats(struct blkio_group *blkg)
-{}
-static inline void blkiocg_update_idle_time_stats(struct blkio_group *blkg) {}
-static inline void blkiocg_set_start_empty_time(struct blkio_group *blkg) {}
+                       struct blkio_policy_type *pol, unsigned long dequeue) { }
+static inline void blkiocg_update_set_idle_time_stats(struct blkio_group *blkg,
+                       struct blkio_policy_type *pol) { }
+static inline void blkiocg_update_idle_time_stats(struct blkio_group *blkg,
+                       struct blkio_policy_type *pol) { }
+static inline void blkiocg_set_start_empty_time(struct blkio_group *blkg,
+                       struct blkio_policy_type *pol) { }
 #endif
 
 #ifdef CONFIG_BLK_CGROUP
 extern struct blkio_cgroup blkio_root_cgroup;
 extern struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup);
-extern struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk);
-extern int blkiocg_del_blkio_group(struct blkio_group *blkg);
+extern struct blkio_cgroup *bio_blkio_cgroup(struct bio *bio);
 extern struct blkio_group *blkg_lookup(struct blkio_cgroup *blkcg,
-                                      struct request_queue *q,
-                                      enum blkio_policy_id plid);
+                                      struct request_queue *q);
 struct blkio_group *blkg_lookup_create(struct blkio_cgroup *blkcg,
                                       struct request_queue *q,
                                       enum blkio_policy_id plid,
                                       bool for_root);
 void blkiocg_update_timeslice_used(struct blkio_group *blkg,
-                                       unsigned long time,
-                                       unsigned long unaccounted_time);
-void blkiocg_update_dispatch_stats(struct blkio_group *blkg, uint64_t bytes,
-                                               bool direction, bool sync);
+                                  struct blkio_policy_type *pol,
+                                  unsigned long time,
+                                  unsigned long unaccounted_time);
+void blkiocg_update_dispatch_stats(struct blkio_group *blkg,
+                                  struct blkio_policy_type *pol,
+                                  uint64_t bytes, bool direction, bool sync);
 void blkiocg_update_completion_stats(struct blkio_group *blkg,
-       uint64_t start_time, uint64_t io_start_time, bool direction, bool sync);
-void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction,
-                                       bool sync);
+                                    struct blkio_policy_type *pol,
+                                    uint64_t start_time,
+                                    uint64_t io_start_time, bool direction,
+                                    bool sync);
+void blkiocg_update_io_merged_stats(struct blkio_group *blkg,
+                                   struct blkio_policy_type *pol,
+                                   bool direction, bool sync);
 void blkiocg_update_io_add_stats(struct blkio_group *blkg,
-               struct blkio_group *curr_blkg, bool direction, bool sync);
+                                struct blkio_policy_type *pol,
+                                struct blkio_group *curr_blkg, bool direction,
+                                bool sync);
 void blkiocg_update_io_remove_stats(struct blkio_group *blkg,
-                                       bool direction, bool sync);
+                                   struct blkio_policy_type *pol,
+                                   bool direction, bool sync);
 #else
 struct cgroup;
 static inline struct blkio_cgroup *
 cgroup_to_blkio_cgroup(struct cgroup *cgroup) { return NULL; }
 static inline struct blkio_cgroup *
-task_blkio_cgroup(struct task_struct *tsk) { return NULL; }
-
-static inline int
-blkiocg_del_blkio_group(struct blkio_group *blkg) { return 0; }
+bio_blkio_cgroup(struct bio *bio) { return NULL; }
 
 static inline struct blkio_group *blkg_lookup(struct blkio_cgroup *blkcg,
                                              void *key) { return NULL; }
 static inline void blkiocg_update_timeslice_used(struct blkio_group *blkg,
-                                               unsigned long time,
-                                               unsigned long unaccounted_time)
-{}
+                       struct blkio_policy_type *pol, unsigned long time,
+                       unsigned long unaccounted_time) { }
 static inline void blkiocg_update_dispatch_stats(struct blkio_group *blkg,
-                               uint64_t bytes, bool direction, bool sync) {}
+                       struct blkio_policy_type *pol, uint64_t bytes,
+                       bool direction, bool sync) { }
 static inline void blkiocg_update_completion_stats(struct blkio_group *blkg,
-               uint64_t start_time, uint64_t io_start_time, bool direction,
-               bool sync) {}
+                       struct blkio_policy_type *pol, uint64_t start_time,
+                       uint64_t io_start_time, bool direction, bool sync) { }
 static inline void blkiocg_update_io_merged_stats(struct blkio_group *blkg,
-                                               bool direction, bool sync) {}
+                       struct blkio_policy_type *pol, bool direction,
+                       bool sync) { }
 static inline void blkiocg_update_io_add_stats(struct blkio_group *blkg,
-               struct blkio_group *curr_blkg, bool direction, bool sync) {}
+                       struct blkio_policy_type *pol,
+                       struct blkio_group *curr_blkg, bool direction,
+                       bool sync) { }
 static inline void blkiocg_update_io_remove_stats(struct blkio_group *blkg,
-                                               bool direction, bool sync) {}
+                       struct blkio_policy_type *pol, bool direction,
+                       bool sync) { }
 #endif
 #endif /* _BLK_CGROUP_H */