Skip to content

Commit d49dcb4

Browse files
htejunShan Hai
authored andcommitted
cgroup: make sure a parent css isn't offlined before its children
There are three subsystem callbacks in css shutdown path - css_offline(), css_released() and css_free(). Except for css_released(), cgroup core didn't guarantee the order of invocation. css_offline() or css_free() could be called on a parent css before its children. This behavior is unexpected and led to bugs in cpu and memory controller. This patch updates offline path so that a parent css is never offlined before its children. Each css keeps online_cnt which reaches zero iff itself and all its children are offline and offline_css() is invoked only after online_cnt reaches zero. This fixes the memory controller bug and allows the fix for cpu controller. Signed-off-by: Tejun Heo <[email protected]> Reported-and-tested-by: Christian Borntraeger <[email protected]> Reported-by: Brian Christiansen <[email protected]> Link: http://lkml.kernel.org/g/[email protected] Link: http://lkml.kernel.org/g/CAKB58ikDkzc8REt31WBkD99+hxNzjK4+FBmhkgS+NVrC9vjMSg@mail.gmail.com Cc: Heiko Carstens <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: [email protected] Orabug: 27045648 (backport upstream commit aa226ff) Conflict: include/linux/cgroup-defs.h Fix a kABI breakage Signed-off-by: Shan Hai <[email protected]> Reviewed-by: Dhaval Giani <[email protected]>
1 parent e92e37e commit d49dcb4

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-5
lines changed

include/linux/cgroup.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ struct cgroup_subsys_state {
9191
/* percpu_ref killing and RCU release */
9292
struct rcu_head rcu_head;
9393
struct work_struct destroy_work;
94+
95+
/*
96+
* Incremented by online self and children. Used to guarantee that
97+
* parents are not offlined before their children.
98+
*/
99+
UEK_KABI_EXTEND(atomic_t online_cnt)
94100
};
95101

96102
/* bits in struct cgroup_subsys_state flags field */

kernel/cgroup.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4482,6 +4482,7 @@ static void init_and_link_css(struct cgroup_subsys_state *css,
44824482
INIT_LIST_HEAD(&css->sibling);
44834483
INIT_LIST_HEAD(&css->children);
44844484
css->serial_nr = css_serial_nr_next++;
4485+
atomic_set(&css->online_cnt, 0);
44854486

44864487
if (cgroup_parent(cgrp)) {
44874488
css->parent = cgroup_css(cgroup_parent(cgrp), ss);
@@ -4504,6 +4505,10 @@ static int online_css(struct cgroup_subsys_state *css)
45044505
if (!ret) {
45054506
css->flags |= CSS_ONLINE;
45064507
rcu_assign_pointer(css->cgroup->subsys[ss->id], css);
4508+
4509+
atomic_inc(&css->online_cnt);
4510+
if (css->parent)
4511+
atomic_inc(&css->parent->online_cnt);
45074512
}
45084513
return ret;
45094514
}
@@ -4738,10 +4743,15 @@ static void css_killed_work_fn(struct work_struct *work)
47384743
container_of(work, struct cgroup_subsys_state, destroy_work);
47394744

47404745
mutex_lock(&cgroup_mutex);
4741-
offline_css(css);
4742-
mutex_unlock(&cgroup_mutex);
47434746

4744-
css_put(css);
4747+
do {
4748+
offline_css(css);
4749+
css_put(css);
4750+
/* @css can't go away while we're holding cgroup_mutex */
4751+
css = css->parent;
4752+
} while (css && atomic_dec_and_test(&css->online_cnt));
4753+
4754+
mutex_unlock(&cgroup_mutex);
47454755
}
47464756

47474757
/* css kill confirmation processing requires process context, bounce */
@@ -4750,8 +4760,10 @@ static void css_killed_ref_fn(struct percpu_ref *ref)
47504760
struct cgroup_subsys_state *css =
47514761
container_of(ref, struct cgroup_subsys_state, refcnt);
47524762

4753-
INIT_WORK(&css->destroy_work, css_killed_work_fn);
4754-
queue_work(cgroup_destroy_wq, &css->destroy_work);
4763+
if (atomic_dec_and_test(&css->online_cnt)) {
4764+
INIT_WORK(&css->destroy_work, css_killed_work_fn);
4765+
queue_work(cgroup_destroy_wq, &css->destroy_work);
4766+
}
47554767
}
47564768

47574769
/**

0 commit comments

Comments
 (0)