summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/blk-cgroup.c16
-rw-r--r--include/linux/blk-cgroup.h6
2 files changed, 21 insertions, 1 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 2acef6a64954..c5dc833212e1 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -1006,6 +1006,21 @@ unlock:
return ret;
}
+static int blkcg_css_online(struct cgroup_subsys_state *css)
+{
+ struct blkcg *blkcg = css_to_blkcg(css);
+ struct blkcg *parent = blkcg_parent(blkcg);
+
+ /*
+ * blkcg_pin_online() is used to delay blkcg offline so that blkgs
+ * don't go offline while cgwbs are still active on them. Pin the
+ * parent so that offline always happens towards the root.
+ */
+ if (parent)
+ blkcg_pin_online(parent);
+ return 0;
+}
+
/**
* blkcg_init_queue - initialize blkcg part of request queue
* @q: request_queue to initialize
@@ -1199,6 +1214,7 @@ static void blkcg_exit(struct task_struct *tsk)
struct cgroup_subsys io_cgrp_subsys = {
.css_alloc = blkcg_css_alloc,
+ .css_online = blkcg_css_online,
.css_offline = blkcg_css_offline,
.css_free = blkcg_css_free,
.can_attach = blkcg_can_attach,
diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h
index 7fb7caa55a3d..35f8ffe92b70 100644
--- a/include/linux/blk-cgroup.h
+++ b/include/linux/blk-cgroup.h
@@ -436,8 +436,12 @@ static inline void blkcg_pin_online(struct blkcg *blkcg)
*/
static inline void blkcg_unpin_online(struct blkcg *blkcg)
{
- if (refcount_dec_and_test(&blkcg->online_pin))
+ do {
+ if (!refcount_dec_and_test(&blkcg->online_pin))
+ break;
blkcg_destroy_blkgs(blkcg);
+ blkcg = blkcg_parent(blkcg);
+ } while (blkcg);
}
/**