blkcg: use double locking instead of RCU for blkg synchronization
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / block / blk-cgroup.h
index 9537819c29c694daceed3b505eca31291f85541f..df73040a6a5feed591c14d35ff57b67945afc467 100644 (file)
@@ -164,6 +164,13 @@ struct blkg_policy_data {
        /* the blkg this per-policy data belongs to */
        struct blkio_group *blkg;
 
+       /* Configuration */
+       struct blkio_group_conf conf;
+
+       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));
 };
@@ -171,31 +178,22 @@ struct blkg_policy_data {
 struct blkio_group {
        /* Pointer to the associated request_queue, RCU protected */
        struct request_queue __rcu *q;
+       struct list_head q_node;
        struct hlist_node blkcg_node;
        struct blkio_cgroup *blkcg;
        /* Store cgroup path */
        char path[128];
-       /* policy which owns this blk group */
-       enum blkio_policy_id plid;
-
-       /* Configuration */
-       struct blkio_group_conf conf;
+       /* reference count */
+       int refcnt;
 
        /* 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;
+       struct blkg_policy_data *pd[BLKIO_NR_POLICIES];
 
-       struct blkg_policy_data *pd;
+       struct rcu_head rcu_head;
 };
 
 typedef void (blkio_init_group_fn)(struct blkio_group *blkg);
-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_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,
@@ -209,9 +207,6 @@ typedef void (blkio_update_group_write_iops_fn)(struct request_queue *q,
 
 struct blkio_policy_ops {
        blkio_init_group_fn *blkio_init_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_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;
@@ -233,7 +228,9 @@ 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
@@ -245,7 +242,7 @@ extern void blkg_destroy_all(struct request_queue *q);
 static inline void *blkg_to_pdata(struct blkio_group *blkg,
                              struct blkio_policy_type *pol)
 {
-       return blkg ? blkg->pd->pdata : NULL;
+       return blkg ? blkg->pd[pol->plid]->pdata : NULL;
 }
 
 /**
@@ -272,6 +269,35 @@ 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 {
@@ -285,13 +311,18 @@ 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
 
@@ -300,12 +331,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(                             \
@@ -328,41 +364,50 @@ 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_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 *
@@ -370,25 +415,26 @@ 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; }
-
 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 */