|
@@ -4760,6 +4760,7 @@ static void init_and_link_css(struct cgroup_subsys_state *css,
|
|
|
INIT_LIST_HEAD(&css->sibling);
|
|
|
INIT_LIST_HEAD(&css->children);
|
|
|
css->serial_nr = css_serial_nr_next++;
|
|
|
+ atomic_set(&css->online_cnt, 0);
|
|
|
|
|
|
if (cgroup_parent(cgrp)) {
|
|
|
css->parent = cgroup_css(cgroup_parent(cgrp), ss);
|
|
@@ -4782,6 +4783,10 @@ static int online_css(struct cgroup_subsys_state *css)
|
|
|
if (!ret) {
|
|
|
css->flags |= CSS_ONLINE;
|
|
|
rcu_assign_pointer(css->cgroup->subsys[ss->id], css);
|
|
|
+
|
|
|
+ atomic_inc(&css->online_cnt);
|
|
|
+ if (css->parent)
|
|
|
+ atomic_inc(&css->parent->online_cnt);
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
@@ -5019,10 +5024,15 @@ static void css_killed_work_fn(struct work_struct *work)
|
|
|
container_of(work, struct cgroup_subsys_state, destroy_work);
|
|
|
|
|
|
mutex_lock(&cgroup_mutex);
|
|
|
- offline_css(css);
|
|
|
- mutex_unlock(&cgroup_mutex);
|
|
|
|
|
|
- css_put(css);
|
|
|
+ do {
|
|
|
+ offline_css(css);
|
|
|
+ css_put(css);
|
|
|
+ /* @css can't go away while we're holding cgroup_mutex */
|
|
|
+ css = css->parent;
|
|
|
+ } while (css && atomic_dec_and_test(&css->online_cnt));
|
|
|
+
|
|
|
+ mutex_unlock(&cgroup_mutex);
|
|
|
}
|
|
|
|
|
|
/* css kill confirmation processing requires process context, bounce */
|
|
@@ -5031,8 +5041,10 @@ static void css_killed_ref_fn(struct percpu_ref *ref)
|
|
|
struct cgroup_subsys_state *css =
|
|
|
container_of(ref, struct cgroup_subsys_state, refcnt);
|
|
|
|
|
|
- INIT_WORK(&css->destroy_work, css_killed_work_fn);
|
|
|
- queue_work(cgroup_destroy_wq, &css->destroy_work);
|
|
|
+ if (atomic_dec_and_test(&css->online_cnt)) {
|
|
|
+ INIT_WORK(&css->destroy_work, css_killed_work_fn);
|
|
|
+ queue_work(cgroup_destroy_wq, &css->destroy_work);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|