blkcg: rename blkcg->cgwb_refcnt to ->online_pin and always use it
authorTejun Heo <tj@kernel.org>
Wed, 24 Jul 2019 17:37:22 +0000 (10:37 -0700)
committerJens Axboe <axboe@kernel.dk>
Wed, 1 Apr 2020 20:56:42 +0000 (14:56 -0600)
blkcg->cgwb_refcnt is used to delay blkcg offlining so that blkgs
don't get offlined while there are active cgwbs on them.  However, it
ends up making offlining unordered sometimes causing parents to be
offlined before children.

To fix it, we want child blkcgs to pin the parents' online states
turning the refcnt into a more generic online pinning mechanism.

In prepartion,

* blkcg->cgwb_refcnt -> blkcg->online_pin
* blkcg_cgwb_get/put() -> blkcg_pin/unpin_online()
* Take them out of CONFIG_CGROUP_WRITEBACK

Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-cgroup.c
include/linux/blk-cgroup.h
mm/backing-dev.c

index c15a260..2acef6a 100644 (file)
@@ -883,8 +883,8 @@ static void blkcg_css_offline(struct cgroup_subsys_state *css)
        /* this prevents anyone from attaching or migrating to this blkcg */
        wb_blkcg_offline(blkcg);
 
-       /* put the base cgwb reference allowing step 2 to be triggered */
-       blkcg_cgwb_put(blkcg);
+       /* put the base online pin allowing step 2 to be triggered */
+       blkcg_unpin_online(blkcg);
 }
 
 /**
@@ -983,11 +983,11 @@ blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
        }
 
        spin_lock_init(&blkcg->lock);
+       refcount_set(&blkcg->online_pin, 1);
        INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_NOWAIT | __GFP_NOWARN);
        INIT_HLIST_HEAD(&blkcg->blkg_list);
 #ifdef CONFIG_CGROUP_WRITEBACK
        INIT_LIST_HEAD(&blkcg->cgwb_list);
-       refcount_set(&blkcg->cgwb_refcnt, 1);
 #endif
        list_add_tail(&blkcg->all_blkcgs_node, &all_blkcgs);
 
index e4a6949..7fb7caa 100644 (file)
@@ -46,6 +46,7 @@ struct blkcg_gq;
 struct blkcg {
        struct cgroup_subsys_state      css;
        spinlock_t                      lock;
+       refcount_t                      online_pin;
 
        struct radix_tree_root          blkg_tree;
        struct blkcg_gq __rcu           *blkg_hint;
@@ -56,7 +57,6 @@ struct blkcg {
        struct list_head                all_blkcgs_node;
 #ifdef CONFIG_CGROUP_WRITEBACK
        struct list_head                cgwb_list;
-       refcount_t                      cgwb_refcnt;
 #endif
 };
 
@@ -412,47 +412,34 @@ static inline struct blkcg *cpd_to_blkcg(struct blkcg_policy_data *cpd)
 
 extern void blkcg_destroy_blkgs(struct blkcg *blkcg);
 
-#ifdef CONFIG_CGROUP_WRITEBACK
-
 /**
- * blkcg_cgwb_get - get a reference for blkcg->cgwb_list
+ * blkcg_pin_online - pin online state
  * @blkcg: blkcg of interest
  *
- * This is used to track the number of active wb's related to a blkcg.
+ * While pinned, a blkcg is kept online.  This is primarily used to
+ * impedance-match blkg and cgwb lifetimes so that blkg doesn't go offline
+ * while an associated cgwb is still active.
  */
-static inline void blkcg_cgwb_get(struct blkcg *blkcg)
+static inline void blkcg_pin_online(struct blkcg *blkcg)
 {
-       refcount_inc(&blkcg->cgwb_refcnt);
+       refcount_inc(&blkcg->online_pin);
 }
 
 /**
- * blkcg_cgwb_put - put a reference for @blkcg->cgwb_list
+ * blkcg_unpin_online - unpin online state
  * @blkcg: blkcg of interest
  *
- * This is used to track the number of active wb's related to a blkcg.
- * When this count goes to zero, all active wb has finished so the
+ * This is primarily used to impedance-match blkg and cgwb lifetimes so
+ * that blkg doesn't go offline while an associated cgwb is still active.
+ * When this count goes to zero, all active cgwbs have finished so the
  * blkcg can continue destruction by calling blkcg_destroy_blkgs().
- * This work may occur in cgwb_release_workfn() on the cgwb_release
- * workqueue.
  */
-static inline void blkcg_cgwb_put(struct blkcg *blkcg)
+static inline void blkcg_unpin_online(struct blkcg *blkcg)
 {
-       if (refcount_dec_and_test(&blkcg->cgwb_refcnt))
+       if (refcount_dec_and_test(&blkcg->online_pin))
                blkcg_destroy_blkgs(blkcg);
 }
 
-#else
-
-static inline void blkcg_cgwb_get(struct blkcg *blkcg) { }
-
-static inline void blkcg_cgwb_put(struct blkcg *blkcg)
-{
-       /* wb isn't being accounted, so trigger destruction right away */
-       blkcg_destroy_blkgs(blkcg);
-}
-
-#endif
-
 /**
  * blkg_path - format cgroup path of blkg
  * @blkg: blkg of interest
index 62f05f6..c81b4f3 100644 (file)
@@ -491,8 +491,8 @@ static void cgwb_release_workfn(struct work_struct *work)
        css_put(wb->blkcg_css);
        mutex_unlock(&wb->bdi->cgwb_release_mutex);
 
-       /* triggers blkg destruction if cgwb_refcnt becomes zero */
-       blkcg_cgwb_put(blkcg);
+       /* triggers blkg destruction if no online users left */
+       blkcg_unpin_online(blkcg);
 
        fprop_local_destroy_percpu(&wb->memcg_completions);
        percpu_ref_exit(&wb->refcnt);
@@ -592,7 +592,7 @@ static int cgwb_create(struct backing_dev_info *bdi,
                        list_add_tail_rcu(&wb->bdi_node, &bdi->wb_list);
                        list_add(&wb->memcg_node, memcg_cgwb_list);
                        list_add(&wb->blkcg_node, blkcg_cgwb_list);
-                       blkcg_cgwb_get(blkcg);
+                       blkcg_pin_online(blkcg);
                        css_get(memcg_css);
                        css_get(blkcg_css);
                }